To get started with snapshot testing in iOS, here are the detailed steps to integrate and utilize this powerful testing approach:
👉 Skip the hassle and get the ready to use 100% working script (Link in the comments section of the YouTube Video) (Latest test 31/05/2025)
Check more on: How to Bypass Cloudflare Turnstile & Cloudflare WAF – Reddit, How to Bypass Cloudflare Turnstile, Cloudflare WAF & reCAPTCHA v3 – Medium, How to Bypass Cloudflare Turnstile, WAF & reCAPTCHA v3 – LinkedIn Article
-
Add a Snapshot Testing Library: The most popular choice is
iOSSnapshotTestCase
by Facebook orSnapshotTesting
by Point-Free.- For
iOSSnapshotTestCase
Objective-C/Swift:- Using CocoaPods: Add
pod 'iOSSnapshotTestCase'
to your test target in your Podfile, then runpod install
. - Using Swift Package Manager SPM: While not officially supported by Facebook, you might find community forks or manual integration guides. For pure Swift projects,
SnapshotTesting
is a better SPM fit.
- Using CocoaPods: Add
- For
SnapshotTesting
Pure Swift:- Using Swift Package Manager: In Xcode, go to
File > Add Packages...
, then enter the repository URL:https://github.com/pointfreeco/swift-snapshot-testing
. Choose your test target.
- Using Swift Package Manager: In Xcode, go to
- For
-
Configure Your Test Target:
- Ensure your test target has
HOST_APPLICATION_TARGET
set to your main app target in its Build Settings, under “Testing.” This allows your tests to access your app’s UI components. - For
iOSSnapshotTestCase
, you might need to setFB_REFERENCE_IMAGE_DIR
to a custom path e.g.,$SOURCE_ROOT/$PROJECT_NAMETests/ReferenceImages
in your test target’s Build Settings under “User-Defined.” This defines where reference images are stored.SnapshotTesting
typically handles this automatically in a__Snapshots__
directory next to your test file.
- Ensure your test target has
-
Write Your First Snapshot Test:
- Import the chosen framework e.g.,
import iOSSnapshotTestCase
orimport SnapshotTesting
. - Create a test class that inherits from
FBSnapshotTestCase
for Facebook’s library or a standardXCTestCase
for Point-Free’s. - Instantiate the UI component you want to test e.g., a
UIView
,UIViewController
, or a customUITableViewCell
. - Configure the component with the desired state e.g., set
text
,image
,data
for a cell. - Use the snapshot assertion:
- For
iOSSnapshotTestCase
:FBSnapshotVerifyViewviewOrController, "optional_identifier_for_test_case"
orFBSnapshotVerifyViewControllerviewController, "optional_identifier"
. - For
SnapshotTesting
:assertSnapshotmatching: viewOrController, as: .image
orassertSnapshotmatching: viewController, as: .imageon: .iPhone8
. The latter allows specifying device configurations.
- For
- Import the chosen framework e.g.,
-
Generate Reference Images First Run:
- When you run your snapshot tests for the first time or when
recordMode
is enabled foriOSSnapshotTestCase
, the tests will fail. This is intentional. - For
iOSSnapshotTestCase
: Setself.recordMode = true
in yoursetUp
method temporarily, then run the tests. This will generate the reference images. Crucially, remember to setself.recordMode = false
or remove the line afterwards. - For
SnapshotTesting
: When a snapshot fails, it will automatically save the new snapshot and a diff image. To approve the new snapshot as the reference, you usually delete the old reference image from the__Snapshots__
folder and rerun the test, or manually copy the “new” snapshot over the “reference” one. Some tools likeSnapshotTesting
also offer environment variables e.g.,DIFF_SNAPSHOTS = 1
to help manage this.
- When you run your snapshot tests for the first time or when
-
Run Tests and Review Diffs:
- Subsequent runs will compare the generated snapshot against the stored reference image.
- If there’s a visual difference, the test will fail, and a “diff” image will be generated, highlighting the discrepancies. This is where snapshot testing shines, quickly catching unintended UI changes.
Snapshot testing is an incredibly efficient way to ensure your UI remains consistent across code changes, refactorings, and even OS updates.
It minimizes manual QA effort for visual regressions and ensures a polished user experience.
The Undeniable Case for Snapshot Testing in iOS Development
Snapshot testing, also known as visual regression testing, is a powerful technique for iOS developers to ensure the consistency and integrity of their user interfaces.
In essence, it captures a “snapshot” of a UI component like a UIView
or UIViewController
at a specific state and saves it as a reference image.
Subsequent test runs then compare the current rendering of that component against the stored reference.
If there are any visual differences, the test fails, alerting developers to unintended UI regressions.
This method is particularly invaluable in complex applications where manual visual verification becomes time-consuming and prone to human error.
It offers a safety net, allowing developers to refactor code, update dependencies, or integrate new features with confidence, knowing that the existing UI remains as expected.
What is Snapshot Testing and Why Does it Matter?
Snapshot testing is a form of automated testing that verifies the appearance of UI components.
Instead of asserting individual properties like x.isHidden == true
or label.text == "Hello"
, it asserts the entire rendered output.
This holistic approach catches a wide array of visual bugs, from subtle pixel shifts to significant layout breaks.
It matters immensely because the user experience is paramount, and visual consistency directly impacts how users perceive and interact with an application. Download xcode on mac
A well-implemented snapshot testing suite can drastically reduce the time spent on manual UI testing, freeing up valuable developer and QA resources.
Moreover, it creates a visual “contract” for UI components, making it clear when changes occur, whether intentional or not.
- Catching Visual Regressions: The primary benefit is identifying unintended changes to the UI. A simple change in a
UILabel
‘s font size, a misalignedUIImageView
, or a hiddenUIButton
can be instantly flagged. - Faster Feedback Loop: Instead of deploying to a device or simulator and manually navigating to specific screens, snapshot tests run quickly within the test suite, providing immediate feedback on UI integrity.
- Refactoring Confidence: Developers can refactor large portions of their codebase, knowing that if any visual components are inadvertently altered, the tests will fail, preventing regressions from shipping.
- Cross-Device/OS Compatibility: While basic snapshot tests are often run on a single simulator, advanced configurations allow for capturing snapshots across various device sizes, orientations, and even different iOS versions by managing multiple reference image sets, ensuring broader compatibility. This is crucial as Apple frequently introduces new screen sizes and safe areas.
- Documentation by Example: Snapshot tests inherently serve as visual documentation of how UI components should look in various states. New team members can quickly grasp the intended appearance of complex views by examining the reference images.
The Core Principles: Recording and Verification
At its heart, snapshot testing operates on two fundamental principles: recording and verification.
These steps form a continuous cycle in the development workflow, ensuring UI stability.
- Recording Reference Images: The first time a snapshot test is run for a particular UI component or when a component’s intended appearance changes, the test framework captures a “reference” image. This image represents the desired state of the UI component. These reference images are typically stored within the project’s test bundle, often in a dedicated directory. It’s crucial that these reference images are committed to version control Git, etc. alongside the code, as they are part of the “source of truth” for the UI. Without them, other developers pulling the project would have no baseline for comparison.
- Verifying Against Reference Images: In subsequent test runs, the framework renders the current state of the UI component and compares it pixel by pixel or using a perceptual diff algorithm against the previously recorded reference image. If the two images are identical within a defined tolerance, the test passes. If there are differences, the test fails, and typically, a “diff” image is generated, visually highlighting the areas where the current snapshot deviates from the reference. This immediate visual feedback is incredibly powerful for debugging.
Setting Up Your iOS Project for Snapshot Testing
Proper setup is key to a smooth snapshot testing workflow.
This involves choosing a framework, configuring your Xcode project, and understanding where reference images will reside.
- Choosing a Snapshot Testing Framework:
iOSSnapshotTestCase
by Facebook: This is the original and widely adopted framework, written in Objective-C but fully compatible with Swift. It’s robust and provides good control over recording and verification. However, it requires manually settingrecordMode
for generating new snapshots. As of late 2023, it has over 1.6k stars on GitHub.SnapshotTesting
by Point-Free: A modern, pure Swift alternative that leverages Swift’s powerful type system. It’s highly flexible, supports various snapshot strategies images, recursive descriptions, etc., and offers more granular control over device configurations. ItsassertSnapshot
function is very idiomatic Swift. It boasts over 3.2k stars on GitHub, indicating its growing popularity.- Other Options: While these two dominate, other niche frameworks exist, but for most iOS projects, one of these two will be the optimal choice.
- Integrating with CocoaPods or Swift Package Manager SPM:
- CocoaPods: For
iOSSnapshotTestCase
, addpod 'iOSSnapshotTestCase'
to your test target in your Podfile. ForSnapshotTesting
, if you prefer CocoaPods, addpod 'SnapshotTesting'
to your test target. Remember to runpod install
after modifying the Podfile. - SPM: This is the recommended modern approach for Swift projects. For
SnapshotTesting
, go toFile > Add Packages...
in Xcode and paste the repository URLhttps://github.com/pointfreeco/swift-snapshot-testing
. Select your test target.
- CocoaPods: For
- Xcode Project Configuration:
- Test Target Association: Ensure your UI test bundle is linked to your main application target. In your test target’s Build Settings, locate “Host Application” under “Testing” and select your main app target. This allows the test bundle to instantiate and render views from your application.
- Reference Image Directory: For
iOSSnapshotTestCase
, you’ll often need to set a “User-Defined” build setting namedFB_REFERENCE_IMAGE_DIR
to a path like$SOURCE_ROOT/$PROJECT_NAMETests/ReferenceImages
. This tells the framework where to find and store the reference images.SnapshotTesting
by default creates a__Snapshots__
folder alongside each test file, which is often more convenient and avoids conflicts for large projects.
Writing Effective Snapshot Tests: Best Practices
To maximize the benefits of snapshot testing, it’s essential to write tests that are focused, maintainable, and robust.
This involves isolating UI components and handling dynamic content gracefully.
- Isolate UI Components: The golden rule of unit testing applies here: test one thing at a time. Instead of snapshotting entire
UIViewController
s with complex navigation stacks, focus on individualUIView
subclasses, custom cellsUITableViewCell
,UICollectionViewCell
, or smaller view hierarchies. This makes tests faster, easier to debug, and more stable. You can mock or inject data to ensure views are in specific states. - Handle Dynamic Content: UI components often display dynamic content e.g., user names, dates, network-fetched images. Hardcoding this dynamic data into your test setup is crucial.
- Fixed Data: For
UILabel
s, set specific text values. ForUIImageView
s, use static, bundled images or images generated with a known pattern. - Time & Date: Mock
Date
objects or useCalendar
components with fixed values to avoid tests failing simply because the time changed. - Network Responses: Ensure that any data loaded from a network is replaced with mock data or local stubs within your test environment. This makes tests independent of network availability and backend changes.
- Fixed Data: For
- Test Different States: A single snapshot test for a component is rarely sufficient. Consider all relevant states:
- Empty State: What does a
UITableView
look like with no data? - Loading State: How does a view appear while data is being fetched e.g., activity indicators?
- Error State: What happens when an API call fails?
- Content Variations: Test different lengths of text, various image sizes, or different enum cases for a custom view.
- Accessibility States: Consider testing views with
UIContentSizeCategory
changes Dynamic Type to ensure layout holds up for users with accessibility needs.
- Empty State: What does a
- Name Tests Descriptively: Use clear, concise names for your test methods and any optional identifiers you pass to the snapshot assertion. For instance,
test_UserCardView_loggedInState
ortest_EmptySearchResultsView_noResults
makes it immediately apparent what the test is verifying. This helps immensely when reviewing diffs. - Don’t Snapshot Everything: While tempting, snapshotting every single
UIViewController
in your app can lead to a massive, slow, and brittle test suite. Prioritize complex custom views, reusable components, and critical screens that are prone to visual regressions. Focus on views that have custom drawing, complex layouts, or are difficult to verify through traditional unit tests.
Advanced Snapshot Testing Techniques
Beyond the basics, several advanced techniques can make your snapshot testing suite even more powerful and adaptable to real-world complexities.
- Testing on Multiple Devices and Orientations:
swift assertSnapshotmatching: myView, as: .imageon: .iPhoneSE, named: "iPhoneSE"
How to use css rgba- Looping Through Configurations: You can create loops to iterate through a predefined set of device configurations, generating a snapshot for each. This is invaluable for ensuring responsive layouts.
- Handling Dynamic Type Accessibility:
-
Snapshot tests can verify how your UI adapts to different
UIContentSizeCategory
settings. -
You can set the
preferredContentSizeCategory
on yourUITraitCollection
when rendering a view for a snapshot. -
Example using
SnapshotTesting
:Let traitCollection = UITraitCollectionpreferredContentSizeCategory: .extraExtraLarge
AssertSnapshotmatching: myLabel, as: .imagetraits: traitCollection
-
This is a critical accessibility check, ensuring your app remains usable for users who require larger text sizes.
-
- Testing Views with Animations or Asynchronous Content:
- Snapshot tests are inherently synchronous. For views with animations or content that loads asynchronously e.g., images from a URL, you need to ensure the animation completes or the content is loaded before the snapshot is taken.
- Delaying Snapshot: For simple animations, a small delay e.g.,
XCTestExpectation
with aDispatchQueue.main.asyncAfter
might work, but this makes tests slow and brittle. - Mocking & Stubs: The preferred approach is to mock or stub out the asynchronous aspects. For images, provide a local
UIImage
. For animations, ensure they are either completed or the view is in its final state before snapshotting. If an animation is critical to the visual, you might need to test its start and end states. SnapshotTesting
‘swait
parameter: Some strategies offer await
parameter to delay the snapshot until a condition is met or a fixed duration passes, but again, use sparingly.
- Integrating with CI/CD Pipelines:
- Snapshot tests are ideal for CI/CD. When a pull request is opened, the CI server can run the snapshot tests.
- If a test fails, the CI system can typically display the generated diff images as artifacts, making it easy for developers to review changes without needing to run tests locally. This automates visual regression checks and prevents unintended UI changes from being merged.
- Tools like Fastlane’s
scan
or directxcodebuild
commands can run your tests. Many CI platforms have built-in support for viewing test results and artifacts.
Debugging Snapshot Test Failures
A failing snapshot test can initially seem daunting, but effective debugging strategies can quickly pinpoint the cause of the discrepancy. The key is understanding the diff image.
- Understanding the Diff Image: When a snapshot test fails, the testing framework will typically generate three images:
- Reference Image: The previously approved snapshot.
- Failed or New Image: The snapshot generated during the current test run.
- Diff Image: A third image that visually highlights the differences between the reference and failed images. Often, this is an overlay where differing pixels are colored e.g., red or magenta.
- Where to Find Them: These images are usually stored in a temporary directory e.g.,
DerivedData/…/Logs/Test
foriOSSnapshotTestCase
or alongside your test file in__Snapshots__
forSnapshotTesting
. The Xcode test navigator might also show an attachment with these images for failed tests.
- Common Causes of Failure:
- Intentional Change: You updated the UI and need to record a new reference image. This is a “good” failure.
- Layout Issues: Auto Layout constraints might be breaking, causing views to shift or resize unexpectedly. Look for changes in position, size, or overlapping elements.
- Content Changes: Text, images, or data displayed in the view might have changed. Ensure your test setup provides consistent, mocked data.
- Device/OS Differences: A change in the simulator or iOS version can sometimes cause subtle rendering differences e.g., font rendering, blur effects.
- Pixel Snapping: Minor pixel shifts due to floating-point calculations or rendering engine quirks. Sometimes, a small
pixelTolerance
orperceptualTolerance
can be set in the snapshot assertion to ignore these negligible differences, but use this cautiously. - Asynchronous Loading: If content is loading asynchronously, the snapshot might be taken before the content is fully rendered.
- Debugging Steps:
- Examine the Diff Image: This is your primary diagnostic tool. The diff image immediately shows what changed. Zoom in if necessary.
- Compare Reference vs. Failed: Look at the reference image and the failed image side-by-side to understand the nature of the change. Is it a color change, position shift, size difference, or content change?
- Inspect the UI in a Simulator: If the change is significant, run the app in a simulator and manually navigate to the view in question, trying to replicate the test’s setup. Use Xcode’s View Debugger
Debug > View Hierarchy
to inspect the actual runtime layout and properties of the UI elements. - Check Test Setup: Double-check that your test is setting up the UI component exactly as intended, providing all necessary mock data, sizes, and states.
- Re-record if Intentional: If the change is intended, record a new reference image.
- For
iOSSnapshotTestCase
: Setself.recordMode = true
insetUp
temporarily, run the test, then remove/comment out the line. - For
SnapshotTesting
: Delete the old reference image from the__Snapshots__
folder and re-run the test. the new “failed” image will become the new reference.
- For
Managing and Maintaining Snapshot Tests
A well-maintained snapshot test suite is a living asset.
Neglecting it can lead to frustration and distrust in the tests. Proactive management is key.
- Version Control for Reference Images: Absolutely crucial. Reference images must be committed to your version control system e.g., Git alongside your code. They are part of the “source of truth” for your UI. This ensures that all developers on the team are working with the same baseline. If reference images are not version-controlled, different developers will generate different baselines, leading to constant false failures.
- Dealing with “Expected” Changes: When UI changes are intentional and approved, the corresponding snapshot reference images must be updated. This is often the most manual part of snapshot testing.
- Local Update: Run the tests in record mode for
iOSSnapshotTestCase
or delete existing references and re-run forSnapshotTesting
. - CI/CD Integration: Advanced CI setups might allow for approving diffs directly from the CI pipeline, but for most teams, it involves pulling the branch, running tests locally to generate new references, and committing them.
- Regular Review: Periodically review your reference images. Are they still accurate? Are there tests for outdated UI? Remove tests for deprecated components.
- Local Update: Run the tests in record mode for
- Performance Considerations:
- Snapshot tests can be slower than pure unit tests because they involve rendering UI.
- Run on a Fast Simulator: Use a recent, fast simulator e.g., the latest iPhone model or even a Mac simulator if applicable for macOS apps or cross-platform UI.
- Avoid Over-Snapshotting: As mentioned, don’t snapshot every single view. Focus on critical, complex, or reusable components.
- Parallelization: Xcode’s test runner can parallelize tests across multiple cores, which can speed up large test suites.
- Clean DerivedData: Regularly clean your
DerivedData
folderXcode > Product > Clean Build Folder
to avoid stale test artifacts.
- When Not to Use Snapshot Testing:
- Interactive Elements: Snapshot tests are primarily for visual appearance. They don’t verify user interaction taps, swipes, gestures. For these, traditional UI tests XCUITest or integration tests are more appropriate.
- Highly Dynamic/Procedural Views: Views that change constantly based on complex, non-deterministic logic might be challenging to snapshot. Consider breaking them down into smaller, more controllable sub-components.
- External Content: Views that display external web content e.g.,
WKWebView
are generally not suitable for snapshot testing due to the non-deterministic nature of web rendering. - Performance-Critical Paths: If a test takes too long, it might be better to verify the component with traditional unit tests, focusing on its data output or specific property changes.
Frequently Asked Questions
What is snapshot testing in iOS?
Snapshot testing in iOS is a technique where you capture a visual representation a “snapshot” of a UI component, such as a UIView
or UIViewController
, and save it as a reference image. Ios unit testing tutorial
Subsequent test runs compare the current rendering of that component against the stored reference.
If any visual differences are found, the test fails, indicating a potential UI regression.
What are the main benefits of using snapshot testing in iOS?
The main benefits include catching visual regressions quickly, reducing the need for manual UI verification, increasing confidence during refactoring, ensuring UI consistency across different device sizes/orientations, and providing living visual documentation for UI components.
What are the popular snapshot testing frameworks for iOS?
The two most popular snapshot testing frameworks for iOS are iOSSnapshotTestCase
by Facebook Objective-C, but Swift compatible and SnapshotTesting
by Point-Free pure Swift.
How do I install SnapshotTesting
in my iOS project?
You can install SnapshotTesting
using Swift Package Manager SPM. In Xcode, go to File > Add Packages...
, then enter the repository URL https://github.com/pointfreeco/swift-snapshot-testing
. Select your test target.
How do I install iOSSnapshotTestCase
in my iOS project?
You can install iOSSnapshotTestCase
using CocoaPods.
Add pod 'iOSSnapshotTestCase'
to your test target in your Podfile, then run pod install
.
Where are reference images stored for snapshot tests?
For iOSSnapshotTestCase
, reference images are typically stored in a directory you specify in your test target’s Build Settings e.g., $SOURCE_ROOT/$PROJECT_NAMETests/ReferenceImages
. For SnapshotTesting
, they are usually stored in a __Snapshots__
folder alongside your test file.
Should reference images be committed to version control?
Yes, absolutely.
Reference images are a crucial part of your test suite’s “source of truth” and must be committed to your version control system e.g., Git to ensure all developers on the team are comparing against the same baseline. Jest vs mocha vs jasmine
How do I generate new reference images for snapshot tests?
For iOSSnapshotTestCase
, you temporarily set self.recordMode = true
in your test’s setUp
method, run the test, and then remove/comment out the line.
For SnapshotTesting
, you typically delete the old reference image from the __Snapshots__
folder, then re-run the test, which will save the new “failed” image as the new reference.
What happens when a snapshot test fails?
When a snapshot test fails, the testing framework usually generates a “diff” image, which visually highlights the differences between the current snapshot and the stored reference image.
It also typically saves the new, failing snapshot for comparison.
What are common reasons for snapshot test failures?
Common reasons include intentional UI changes that require updating the reference image, unintended layout issues, changes in displayed content text, images, subtle rendering differences across different simulator versions or iOS versions, and issues with asynchronous content loading.
Can snapshot testing replace traditional UI testing XCUITest?
No, snapshot testing is a complementary technique. It excels at verifying the appearance of UI components, but it does not verify user interaction taps, swipes, gestures, navigation flows. For interaction testing, traditional UI tests like XCUITest are still necessary.
How can I test different device sizes and orientations with snapshot tests?
How do I test for Dynamic Type accessibility with snapshot tests?
You can test for Dynamic Type by setting the preferredContentSizeCategory
on your UITraitCollection
when rendering a view for a snapshot.
This allows you to verify how your UI adapts to different text sizes.
Can I snapshot a WKWebView
?
It’s generally not recommended to snapshot WKWebView
instances directly.
The content rendered within a WKWebView
is external and can be highly dynamic, leading to brittle and unreliable tests. How to test redirect with cypress
Focus on snapshotting your native UI components instead.
How can I make snapshot tests faster?
To speed up snapshot tests, focus on snapshotting individual, isolated UI components rather than entire view hierarchies, run tests on a fast simulator, and leverage Xcode’s test parallelization. Avoid over-snapshotting every single view.
What should I do if a snapshot test fails due to an intentional UI change?
If a snapshot test fails due to an intentional and approved UI change, you need to update the reference image.
Follow the process for generating new reference images for your chosen framework and commit the updated images to version control.
How do snapshot tests help with refactoring code?
Snapshot tests provide a safety net during refactoring.
By verifying the visual output of UI components, they quickly alert you if any code changes inadvertently alter the appearance, allowing you to refactor with confidence.
Can snapshot tests verify animations?
Snapshot tests are primarily for static visual verification.
While you can snapshot the start and end states of an animation, verifying the animation’s smoothness or intermediate frames is not their strength.
For this, manual testing or more specialized animation testing tools would be needed.
Is it okay to use DispatchQueue.main.asyncAfter
to delay snapshots for asynchronous content?
While possible, it’s generally discouraged as it makes tests slower and more brittle. Regression test plan
The preferred approach is to mock or stub any asynchronous data or images so that your view is in a consistent, fully loaded state before the snapshot is taken.
How do snapshot tests integrate with CI/CD pipelines?
Snapshot tests are ideal for CI/CD.
When a pull request is opened, the CI server can run the snapshot tests.
If a test fails, the CI system can typically display the generated diff images as artifacts, automating visual regression checks and preventing unintended UI changes from being merged.
Leave a Reply