Skip to content

Commit

Permalink
Release/0.3.0 (#49)
Browse files Browse the repository at this point in the history
* Update podspec version [ci skip]

* fix layer test case to generate the gradient that is visible in the test image

* support SceneKit, SpriteKit and GLKView

* only use layer.render to capture images for views instead of drawing twice with drawHierarchy+layer.render

* Format ksdiff command output so it stands out on the console

* toMatchSnapshot methods named: + device
  • Loading branch information
skyweb07 committed Sep 19, 2018
1 parent c7d16b2 commit 44350f6
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Snap.swift.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'Snap.swift'
s.version = '0.2.3'
s.version = '0.3.0'
s.summary = 'Snapshot testing in a snap'

s.description = <<-DESC
Expand Down
2 changes: 1 addition & 1 deletion Snap/Core/Application/Actions/CompareImages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ struct CompareImages {
let referencePath = testTarget.reference(for: .reference).path
let failedPath = testTarget.reference(for: .failed).path

print("🌈 Execute this command to see image diff on Kaleidoscope: ksdiff \(referencePath.path) \(failedPath.path)")
print("🌈 Execute this command to see image diff on Kaleidoscope:\n\nksdiff \(referencePath.path) \(failedPath.path)\n")
}
}
}
2 changes: 2 additions & 0 deletions Snap/Core/Application/Matcher/Matcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ public protocol Nameable {
public protocol DeviceMatcher {
func toMatchSnapshot(`for` devices: [Device])
func toMatchSnapshot(`for` allDevices: AllDevices)
func toMatchSnapshot(named name: String?, `for` devices: [Device])
func toMatchSnapshot(named name: String?, `for` allDevices: AllDevices)
}
16 changes: 12 additions & 4 deletions Snap/Core/Application/Matcher/SnapshotViewMatcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ struct SnapshotViewMatcher: ViewMatcher {
toMatchSnapshot(named: nil)
}

func toMatchSnapshot(for devices: [Device]) {
func toMatchSnapshot(named: String?, for devices: [Device]) {
devices.forEach { device in
self.toMatchSnapshot(named: nil, with: device)
self.toMatchSnapshot(named: named, with: device)
}
}

func toMatchSnapshot(for allDevices: AllDevices) {
func toMatchSnapshot(named: String?, for allDevices: AllDevices) {
var deviceList = [Device]()

switch allDevices {
Expand All @@ -48,9 +48,17 @@ struct SnapshotViewMatcher: ViewMatcher {
}

deviceList.forEach { device in
self.toMatchSnapshot(named: nil, with: device)
self.toMatchSnapshot(named: named, with: device)
}
}

func toMatchSnapshot(for devices: [Device]) {
self.toMatchSnapshot(named: nil, for: devices)
}

func toMatchSnapshot(for allDevices: AllDevices) {
self.toMatchSnapshot(named: nil, for: allDevices)
}

func toMatchSnapshot(named: String?) {
toMatchSnapshot(named: named, with: nil)
Expand Down
32 changes: 30 additions & 2 deletions Snap/Core/Infrastructure/Extension/UIView/UIView+Render.swift
Original file line number Diff line number Diff line change
@@ -1,16 +1,45 @@
import UIKit
import SpriteKit
import SceneKit

/**
Adds a static image view on top of all SCNViews, GLKViews and SKViews for the given view hierarchy so these can be captured. Returns the created views.
*/
func addImagesForRenderedViews(_ view: UIView) -> [UIView] {

func add(_ image: UIImage) -> [UIView] {
let imageView = UIImageView(image: image)
imageView.frame = view.bounds
view.addSubview(imageView)
return [imageView]
}

if let scnview = view as? SCNView {
return add(scnview.snapshot())
} else if let glview = view as? GLKView {
return add(glview.snapshot)
} else if let skview = view as? SKView {
return add(UIImage(cgImage: skview.texture(from: skview.scene!)!.cgImage()))
} else {
return view.subviews.flatMap(addImagesForRenderedViews)
}
}

extension UIView {
/// Extract image data with the whole hierarchy from `UIView`
func render() -> UIImage? {

// SpriteKit refuses to draw its hierarchy: render an image of the spritekit view and add it to the view to be able to capture it
let addedViews = addImagesForRenderedViews(self)
defer { addedViews.forEach { $0.removeFromSuperview() } }

if #available(iOS 10.0, *) {
let imageRendererFormat = UIGraphicsImageRendererFormat.default()
imageRendererFormat.opaque = true
let renderer = UIGraphicsImageRenderer(
bounds: bounds
)
return renderer.image { context in
drawHierarchy(in: bounds, afterScreenUpdates: true)
layer.render(in: context.cgContext)
}
}
Expand All @@ -21,7 +50,6 @@ extension UIView {
UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0.0)

let context = UIGraphicsGetCurrentContext()!
drawHierarchy(in: bounds, afterScreenUpdates: true)
layer.render(in: context)
return UIGraphicsGetImageFromCurrentImageContext()
}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
53 changes: 51 additions & 2 deletions SnapTests/SnapTests.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import XCTest
import UIKit
import SpriteKit
import SceneKit

private final class SnapTests: XCTestCase {

Expand Down Expand Up @@ -34,8 +36,8 @@ private final class SnapTests: XCTestCase {
UIColor.white.cgColor
]
layer.locations = [0.0, 1.0]
layer.startPoint = CGPoint(x: 0.0, y: 1.0)
layer.endPoint = CGPoint(x: 0.0, y: 1.0)
layer.startPoint = CGPoint(x: 0.0, y: 0.0)
layer.endPoint = CGPoint(x: 1.0, y: 0.0)

expect(layer).toMatchSnapshot()
}
Expand Down Expand Up @@ -67,4 +69,51 @@ private final class SnapTests: XCTestCase {

expect(view).toMatchSnapshot(for: .iPadDevices)
}

func test_spritekit_view() {
let scene = SKScene(size: CGSize(width: 100, height: 100))
scene.backgroundColor = .yellow

let rect = SKShapeNode(rectOf: CGSize(width: 10, height: 10))
rect.fillColor = .red
rect.strokeColor = .clear
rect.position = CGPoint(x: 50, y: 50)
scene.addChild(rect)

let view = SKView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
view.presentScene(scene)

expect(view).toMatchSnapshot()
}

func test_scenekit_view() {
let scene = SCNScene()

// light
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = .omni
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
scene.rootNode.addChildNode(lightNode)

// cube
let cubeGeometry = SCNBox(width: 5, height: 5, length: 5, chamferRadius: 0)
cubeGeometry.firstMaterial!.diffuse.contents = UIColor.red
let cubeNode = SCNNode(geometry: cubeGeometry)
scene.rootNode.addChildNode(cubeNode)

// camera
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
cameraNode.position = SCNVector3(x: 10, y: 10, z: 10)
cameraNode.constraints = [SCNLookAtConstraint(target: cubeNode)]

let view = SCNView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
view.backgroundColor = .yellow
view.scene = scene

expect(view).toMatchSnapshot()
}

}

0 comments on commit 44350f6

Please sign in to comment.