A low-maintenance, simple framework for a snapshot testing, which takes into account a snapshot difference factor
CornSnapshotTesting
A low-maintenance, simple framework for a snapshot testing, which takes into account a snapshot difference factor (must have if you’re using CI).
Table of contents
Installation
Swift Package manager
The Swift Package Manager is a powerful tool for managing the distribution of Swift code.
It’s integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies.
Therefore it’s so easy to import CornSnapshotTesting
dependency into your project.
- Open project settings.
- Switch to the
Package Dependencies
tab. - Tap on
+
button. - Past the current repository link or search for
CornSnapshotTesting
.
Feel free to check the official documentation to get more information about how to add a Package Dependency.
To add the CornSnapshotTesting
to your Swift package, add the dependency into the Package.swift:
dependencies: [
.package(url: "https://github.com/popcornomnom/corn-snapshot-testing.git", from: upToNextMajor(from: "1.0.0")),
]
Key Features
- Compares the snapshot of the current window with the previously saved reference image.
TheassertSnapshot
method is available in any sub-class ofXCTestCase
; - The test result depends on the similarity of images, taking into account the
tolerance
factor.
It’s important value if you are usingCI
to run your tests and have the image quality discrepancy between your local machine and theCI
tool’s virtual machine; - By default, the snapshot folder path is equal to the caller’s file path. But you can change the
path
if necessary; - Reference, actual and difference images are attached to the test results as
XCTAttachments
.
Image difference factor is also available in a test error message. - The difference image highlights the areas of difference between the two snapshots.
Usage
assertSnapshot
The assertSnapshot
method captures the current device’s window snapshot and compares it with a previously saved reference image.
The reference image won’t be changed in case of a failed test result.
Make sure that you call the assertSnapshot
method when an app is already launched.
This method accepts the next parameters:
- delay: The time interval in seconds after which the snapshot will be taken. For example, the time needed for an animation to be completed.
- name: The snapshot file’s name. By default, this value is equal to the function name.
- path: The path to the folder where the snapshot is placed. By default, this value is equal to the caller’s file path.
- folderComponents: Additional components of the path for subfolders.
- interfaceStyle: The current interface appearance of the app during the test. It’s used to add the current app theme to the snapshot file name.
All arguments are optional.
The assertSnapshot
is available for external use, but not for an override on purpose.
Example 1:
func testMainScreen() throws {
// Given -
// Mock dynamic content here, such as images, json responses if needed.
// Launch the app.
let app = XCUIApplication()
app.launch()
// When - screen is visible.
waitUntilMainScreenIsVisible()
// Then -
// Asserts snapshot with name `testMainScreen-iPhone-8.png`
// by `${current-file-path}\Snapshots\` path after 0 seconds.
assertSnapshot()
}
Test case: After stackView
spacing
has been changed +30pt
:
Reference | Actual | Difference |
---|---|---|
Example 2:
func testMainScreenInDarkMode() throws {
// Given - stab the current user interface.
let app = XCUIApplication()
app.launch(interfaceStyle: .dark)
//
// When - screen is visible.
waitUntilMainScreenIsVisible()
// Then
// Asserts snapshot with name "custom-name-dark-iPhone-8.png",
// by `${current-file-path}\Snapshots\Main screen` path,
// after 2 seconds.
assertSnapshot(delay: 2, name: "custom name",
folderComponents: "Main screen",
interfaceStyle: .dark)
}
tolerance
An example of changing tolerance factor:
CornSnapshotConfiguration.current.tolerance = 0.25 // tolerance used for Bitrise CI
By default, the tolerance
value is 0
, meaning CornSnapshotTesting
framework expects snapshots to match pixel-to-pixel.
If you use the CI
tool to run tests, you may have a difference in the image quality between devices.
Therefore, I would recommend using a higher tolerance
value (for instance 0.25
).
higlighterColor
CornSnapshotConfiguration.current.higlighterColor = .yellow
The color used by the difference image to highlight the areas of difference between the two snapshots.
By default higlighterColor
is red
.
Important
To replace the reference image remove the previous one and run the test once more.
How to check failed tests
You can find a reference, actual and difference images in failed test artifacts. The image similarity factor is also available in the corresponding test results.
Name structure of the snapshot:
{snapshot name}-{theme}-{device name}.png
This name convention was chosen on purpose taking into account that if attachments sorted by name, all images related to one test will be grouped together.
Contributing
During CornSnapshotTesting
framework development I aimed to include essential functionality into 1.0.0
version, to make it convenient to integrate into any project. With this intent, I’ve added only SPM support because it’s available in any Xcode project. Also, I kept a few more points for improvement unimplemented.
If some functionality is missing, or you have any suggestions on how to improve the framework or you have time to make CornSnapshotTesting
better by helping with the implementation of points bellow, feel free to create the Pull Request, Issue or ask me directly. (PR should be in suggestions format and shouldn’t break the core logic).
What’s not there yet
-
CocoaPods
,Carthage
support; - macOS, tvOS support;
- Integration tests support – Asserting the current simulator window helps to keep the snapshot testing independent from the project implementation, but it would be nice to have
assertSnapshot(view: UIView, delay: _, name: _, folderComponents: _, interfaceStyle: _)
method in place; - Tests.
Footnotes
From the author
I hope publishing this framework as open-source will make a contribution to the community and help someone to save time by using what I’ve written and tested.
Credits
A heartfelt thanks to Miloskiy for the awesome design!
Also thanks to @Chieh Wang for help by suggesting to dig more into Vision direction.
Your support has made this project happen.
Licence
Blog popcornomnom.com ·
GitHub @popcornomnom ·
Linkedin @popcornomnom