• Stars
    star
    3,737
  • Rank 11,808 (Top 0.3 %)
  • Language
    Swift
  • License
    MIT License
  • Created over 7 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

πŸ“Έ Delightful Swift snapshot testing.

πŸ“Έ SnapshotTesting

CI Slack

Delightful Swift snapshot testing.

Usage

Once installed, no additional configuration is required. You can import the SnapshotTesting module and call the assertSnapshot function.

import SnapshotTesting
import XCTest

class MyViewControllerTests: XCTestCase {
  func testMyViewController() {
    let vc = 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 setting the record parameter to true on the assertion or setting isRecording globally.

assertSnapshot(of: vc, as: .image, record: true)

// or globally

isRecording = true
assertSnapshot(of: vc, as: .image)

Snapshot Anything

While most snapshot testing libraries in the Swift community are limited to UIImages of UIViews, SnapshotTesting can work with any format of any value on any Swift platform!

The assertSnapshot 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 representation and against 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 test Encodable values against their JSON and property 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://www.apple.com/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, any value 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!

Documentation

The latest documentation is available here.

Installation

Xcode

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 a test target instead, as documented in the last step, below.

  1. From the File menu, navigate through Swift Packages and select Add Package Dependency….
  2. Enter package repository URL: https://github.com/pointfreeco/swift-snapshot-testing.
  3. Confirm the version and let Xcode resolve the package.
  4. On the final dialog, update SnapshotTesting's Add to Target column 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).

Swift Package Manager

If you want to use SnapshotTesting in any other project that uses SwiftPM, add the package as a dependency in Package.swift:

dependencies: [
  .package(
    url: "https://github.com/pointfreeco/swift-snapshot-testing",
    from: "1.12.0"
  ),
]

Next, add SnapshotTesting as a dependency of your test target:

targets: [
  .target(name: "MyApp"),
  .testTarget(
    name: "MyAppTests",
    dependencies: [
      "MyApp",
      .product(name: "SnapshotTesting", package: "swift-snapshot-testing"),
    ]
  )
]

Features

  • Dozens of snapshot strategies. Snapshot testing isn't just for UIViews and CALayers. Write snapshots against any value.
  • 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 is true 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 Kaleidoscope (or your diff tool of choice).
    SnapshotTesting.diffTool = "ksdiff"

Plug-ins

Have you written your own SnapshotTesting plug-in? Add it here and submit a pull request!

Related Tools

  • iOSSnapshotTestCase helped introduce screen shot testing to a broad audience in the iOS community. Experience with it inspired the creation of this library.

  • Jest brought 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.

Learn More

SnapshotTesting was designed with witness-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 by Brandon Williams and Stephen Celis.

Witness-oriented programming and the design of this library was explored in the following Point-Free episodes:

video poster image

License

This library is released under the MIT license. See LICENSE for details.

More Repositories

1

swift-composable-architecture

A library for building applications in a consistent and understandable way, with composition, testing, and ergonomics in mind.
Swift
12,150
star
2

isowords

Open source game built in SwiftUI and the Composable Architecture.
Swift
2,667
star
3

swift-navigation

Bringing simple and powerful navigation tools to all Swift platforms, inspired by SwiftUI.
Swift
1,950
star
4

swift-dependencies

A dependency management library inspired by SwiftUI's "environment."
Swift
1,527
star
5

swift-tagged

🏷 A wrapper type for safer, expressive code.
Swift
1,364
star
6

swift-overture

🎼 A library for function composition.
Swift
1,139
star
7

pointfreeco

🎬 The source for www.pointfree.co, a video series on functional programming and the Swift programming language.
Swift
1,098
star
8

episode-code-samples

πŸ’Ύ Point-Free episode code.
Swift
950
star
9

swift-case-paths

🧰 Case paths extends the key path hierarchy to enum cases.
Swift
905
star
10

swift-parsing

A library for turning nebulous data into well-structured data, with a focus on composition, performance, generality, and ergonomics.
Swift
847
star
11

swift-nonempty

🎁 A compile-time guarantee that a collection contains a value.
Swift
839
star
12

swift-custom-dump

A collection of tools for debugging, diffing, and testing your application's data structures.
Swift
795
star
13

swift-html

πŸ—Ί A Swift DSL for type-safe, extensible, and transformable HTML documents.
Swift
760
star
14

combine-schedulers

⏰ A few schedulers that make working with Combine more testable and more versatile.
Swift
701
star
15

swift-perception

Observable tools, backported.
Swift
536
star
16

swift-identified-collections

A library of data structures for working with collections of identifiable elements in an ergonomic, performant way.
Swift
529
star
17

swift-web

πŸ•Έ A collection of Swift server-side frameworks for handling HTML, CSS, routing and middleware.
Swift
481
star
18

swift-prelude

🎢 A collection of types and functions that enhance the Swift language.
Swift
469
star
19

swift-validated

πŸ›‚ A result type that accumulates multiple errors.
Swift
392
star
20

swift-issue-reporting

Report issues in your application and library code as Xcode runtime warnings, breakpoints, assertions, and do so in a testable manner.
Swift
361
star
21

swift-url-routing

A bidirectional router with more type safety and less fuss.
Swift
347
star
22

swift-concurrency-extras

Useful, testable Swift concurrency.
Swift
315
star
23

swift-gen

🎱 Composable, transformable, controllable randomness.
Swift
266
star
24

swift-macro-testing

Magical testing tools for Swift macros.
Swift
263
star
25

swift-clocks

⏰ A few clocks that make working with Swift concurrency more testable and more versatile.
Swift
258
star
26

syncups

A rebuild of Apple’s β€œScrumdinger” application using modern, best practices for SwiftUI development.
Swift
205
star
27

swift-enum-properties

🀝 Struct and enum data access in harmony.
Swift
200
star
28

composable-core-location

A library that bridges the Composable Architecture and Core Location.
Swift
108
star
29

vapor-routing

A bidirectional Vapor router with more type safety and less fuss.
Swift
89
star
30

swift-html-vapor

πŸ’§ Vapor plugin for type-safe, transformable HTML views.
Swift
84
star
31

swift-playground-templates

🏫 A collection of helpful Xcode playground templates.
Makefile
81
star
32

pointfreeco-server

Point-Free server code.
40
star
33

TrySyncUps

The starting project for our try! Swift 2024 Composable Architecture workshop.
Swift
38
star
34

composable-core-motion

A library that bridges the Composable Architecture and Core Motion.
Swift
29
star
35

swift-boundaries

🐣 Functional core, imperative shell.
Swift
28
star
36

swift-quickcheck

🏁 An implementation of QuickCheck in Swift.
Swift
25
star
37

swift-either

For those times you want A or B!
Swift
21
star
38

swift-algebras

Algebraic laws bundled into concrete data types.
20
star
39

swift-parser-printer

↔️ Parsing and printing
Swift
15
star
40

swift-html-kitura

☁️ Kitura plugin for type-safe, transformable HTML views.
Swift
14
star
41

swiftui-navigation

This package is now Swift Navigation:
Swift
13
star
42

homebrew-swift

Ruby
3
star
43

swift-bugs

3
star
44

Ccmark

Swift
2
star
45

.github

1
star