Delightful Swift snapshot testing.
Onceinstalled,no additional configuration is required.You can import the
SnapshotTesting
module and call theassertSnapshot
function.
import SnapshotTesting
import XCTest
classMyViewControllerTests:XCTestCase{
functestMyViewController(){
letvc=MyViewController()
assertSnapshot(of:vc,as:.image)
}
}
When an assertion first runs, a snapshot is automatically recorded to disk and the test will fail, printing out the file path of any newly-recorded reference.
❌ failed - No reference was found on disk. Automatically recorded snapshot:…
open "…/MyAppTests/__Snapshots__/MyViewControllerTests/testMyViewController.png"
Re-run "testMyViewController" to test against the newly-recorded snapshot.
Repeat test runs will load this reference and compare it with the runtime value. If they don't match, the test will fail and describe the difference. Failures can be inspected from Xcode's Report Navigator or by inspecting the file URLs of the failure.
You can record a new reference by customizing snapshots inline with the assertion, or using the
withSnapshotTesting
tool:
// Record just this one snapshot
assertSnapshot(of:vc,as:.image,record:.all)
// Record all snapshots in a scope:
withSnapshotTesting(record:.all){
assertSnapshot(of:vc1,as:.image)
assertSnapshot(of:vc2,as:.image)
assertSnapshot(of:vc3,as:.image)
}
// Record all snapshots in an XCTestCase subclass:
classFeatureTests:XCTestCase{
overridefuncinvokeTest(){
withSnapshotTesting(record:.all){
super.invokeTest()
}
}
}
While most snapshot testing libraries in the Swift community are limited toUIImage
s ofUIView
s,
SnapshotTesting can work withanyformat ofanyvalue onanySwift platform!
TheassertSnapshot
function accepts a value and any snapshot strategy that value supports. This
means that a view or view controller can be tested against an image representationandagainst a
textual representation of its properties and subview hierarchy.
assertSnapshot(of:vc,as:.image)
assertSnapshot(of:vc,as:.recursiveDescription)
View testing is highly configurable. You can override trait collections (for specific size classes and content size categories) and generate device-agnostic snapshots, all from a single simulator.
assertSnapshot(of:vc,as:.image(on:.iPhoneSe))
assertSnapshot(of:vc,as:.recursiveDescription(on:.iPhoneSe))
assertSnapshot(of:vc,as:.image(on:.iPhoneSe(.landscape)))
assertSnapshot(of:vc,as:.recursiveDescription(on:.iPhoneSe(.landscape)))
assertSnapshot(of:vc,as:.image(on:.iPhoneX))
assertSnapshot(of:vc,as:.recursiveDescription(on:.iPhoneX))
assertSnapshot(of:vc,as:.image(on:.iPadMini(.portrait)))
assertSnapshot(of:vc,as:.recursiveDescription(on:.iPadMini(.portrait)))
Warning Snapshots must be compared using the exact same simulator that originally took the reference to avoid discrepancies between images.
Better yet, SnapshotTesting isn't limited to views and view controllers! There are a number of available snapshot strategies to choose from.
For example, you can snapshot test URL requests (e.g.,those that your API client prepares).
assertSnapshot(of:urlRequest,as:.raw)
// POST http://localhost:8080/account
// Cookie: pf_session={ "userId": "1" }
//
// email=blob%40pointfree.co&name=Blob
And you can snapshot testEncodable
values against their JSONandproperty list representations.
assertSnapshot(of:user,as:.json)
// {
// "bio": "Blobbed around the world.",
// "id": 1,
// "name": "Blobby"
// }
assertSnapshot(of:user,as:.plist)
// <?xml version= "1.0" encoding= "UTF-8"?>
// <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
// "http:// apple /DTDs/PropertyList-1.0.dtd" >
// <plist version= "1.0" >
// <dict>
// <key>bio</key>
// <string>Blobbed around the world.</string>
// <key>id</key>
// <integer>1</integer>
// <key>name</key>
// <string>Blobby</string>
// </dict>
// </plist>
In fact,anyvalue can be snapshot-tested by default using its mirror!
assertSnapshot(of:user,as:.dump)
// ▿ User
// - bio: "Blobbed around the world."
// - id: 1
// - name: "Blobby"
If your data can be represented as an image, text, or data, you can write a snapshot test for it!
The latest documentation is available here.
Warning By default, Xcode will try to add the SnapshotTesting package to your project's main application/framework target. Please ensure that SnapshotTesting is added to atesttarget instead, as documented in the last step, below.
- From theFilemenu, navigate throughSwift Packagesand select Add Package Dependency….
- Enter package repository URL:
https://github /pointfreeco/swift-snapshot-testing
. - Confirm the version and let Xcode resolve the package.
- On the final dialog, update SnapshotTesting'sAdd to Targetcolumn to a test target that will contain snapshot tests (if you have more than one test target, you can later add SnapshotTesting to them by manually linking the library in its build phase).
If you want to use SnapshotTesting in any other project that uses
SwiftPM,add the package as a dependency inPackage.swift
:
dependencies:[
.package(
url:"https://github /pointfreeco/swift-snapshot-testing",
from:"1.12.0"
),
]
Next, addSnapshotTesting
as a dependency of your test target:
targets:[
.target(name:"MyApp"),
.testTarget(
name:"MyAppTests",
dependencies:[
"MyApp",
.product(name:"SnapshotTesting",package:"swift-snapshot-testing"),
]
)
]
- Dozens of snapshot strategies.Snapshot
testing isn't just for
UIView
s andCALayer
s. Write snapshots againstanyvalue. - Write your own snapshot strategies. If you can convert it to an image, string, data, or your own diffable format, you can snapshot test it! Build your own snapshot strategies from scratch or transform existing ones.
- No configuration required.Don't fuss with scheme settings and environment variables. Snapshots are automatically saved alongside your tests.
- More hands-off.New snapshots are recorded whether
isRecording
mode istrue
or not. - Subclass-free.Assert from any XCTest case or Quick spec.
- Device-agnostic snapshots.Render views and view controllers for specific devices and trait collections from a single simulator.
- First-class Xcode support.Image differences are captured as XCTest attachments. Text differences are rendered in inline error messages.
- Supports any platform that supports Swift.Write snapshot tests for iOS, Linux, macOS, and tvOS.
- SceneKit, SpriteKit, and WebKit support.Most snapshot testing libraries don't support these view subclasses.
Codable
support.Snapshot encodable data structures into their JSON and property list representations.- Custom diff tool integration.Configure failure messages to print diff commands for
Kaleidoscopeor your diff tool of choice.
SnapshotTesting.diffToolCommand={"ksdiff\($0)\($1)"}
-
AccessibilitySnapshotadds easy regression testing for iOS accessibility.
-
AccessibilitySnapshotColorBlindness adds snapshot strategies for color blindness simulation on iOS views, view controllers and images.
-
GRDBSnapshotTestingadds snapshot strategy for testing SQLite database migrations made withGRDB.
-
Nimble-SnapshotTestingadds Nimblematchers for SnapshotTesting to be used by Swift Package Manager.
-
Prefiregenerating Snapshot Tests via Swift Package Plugins using SwiftUI
Preview
-
PreviewSnapshotsshare
View
configurations between SwiftUI Previews and snapshot tests and generate several snapshots with a single test assertion. -
swift-htmlis a Swift DSL for type-safe, extensible, and transformable HTML documents and includes an
HtmlSnapshotTesting
module to snapshot test its HTML documents. -
swift-snapshot-testing-nimbleadds Nimblematchers for SnapshotTesting.
-
swift-snapshot-testing-stitchadds the ability to stitch multiple UIView's or UIViewController's together in a single test.
-
SnapshotTestingDumpAdds support to useswift-custom-dumpby using
customDump
strategy forAny
-
SnapshotTestingHEICadds image support using the HEIC storage format which reduces file sizes in comparison to PNG.
-
SnapshotVisionadds snapshot strategy for text recognition on views and images. Uses Apples Vision framework.
Have you written your own SnapshotTesting plug-in? Add it hereand submit a pull request!
-
iOSSnapshotTestCase
helped introduce screen shot testing to a broad audience in the iOS community. Experience with it inspired the creation of this library. -
Jestbrought generalized snapshot testing to the JavaScript community with a polished user experience. Several features of this library (diffing, automatically capturing new snapshots) were directly influenced.
SnapshotTesting was designed withwitness-oriented programming.
This concept (and more) are explored thoroughly in a series of episodes on Point-Free,a video series exploring functional programming and Swift hosted byBrandon Williamsand Stephen Celis.
Witness-oriented programming and the design of this library was explored in the following Point-Freeepisodes:
- Episode 33:Protocol Witnesses: Part 1
- Episode 34:Protocol Witnesses: Part 2
- Episode 35:Advanced Protocol Witnesses: Part 1
- Episode 36:Advanced Protocol Witnesses: Part 2
- Episode 37:Protocol-Oriented Library Design: Part 1
- Episode 38:Protocol-Oriented Library Design: Part 2
- Episode 39:Witness-Oriented Library Design
- Episode 40:Async Functional Refactoring
- Episode 41:A Tour of Snapshot Testing 🆓
This library is released under the MIT license. SeeLICENSEfor details.