swift-snapshot-testing

Automatically record app data into test assertions. Snapshot tests capture the entirety of a data structure and cover far more surface area than a typical unit test.

The design of this library has been covered in "Snapshot Testing in Swift".

swift-snapshot-testing

Stability

This library should be considered alpha, and not stable. Breaking changes will happen often.

Installation

Swift Package Manager

import PackageDescription

let package = Package(
  dependencies: [
    .package(url: "https://github.com/pointfreeco/swift-snapshot-testing.git", .branch("master")),
  ]
)

Cocoapods

target 'Tests' do
  pod 'SnapshotTesting', :git => 'https://github.com/pointfreeco/swift-snapshot-testing.git'
end

Usage

Snapshot Testing provides an assertSnapshot function, which records data structures as text or images accordingly.

Here's how you might test a URL request you've prepared for your app's API client:

import SnapshotTesting
import XCTest

class ApiServiceTests: XCTestCase {
  func testUrlRequestPreparation() {
    let service = ApiService()
    let request = service
      .prepare(endpoint: .createArticle("Hello, world!"))

    assertSnapshot(matching: request)
  }
}

The above will render as the following text to __Snapshots__/ApiServiceTests/testUrlRequestPreparation.0.txt:

▿ https://api.site.com/articles?oauth_token=deadbeef
  ▿ url: Optional(https://api.site.com/articles?oauth_token=deadbeef)
    ▿ some: https://api.site.com/articles?oauth_token=deadbeef
      - _url: https://api.site.com/articles?oauth_token=deadbeef #0
        - super: NSObject
  - cachePolicy: 0
  - timeoutInterval: 60.0
  - mainDocumentURL: nil
  - networkServiceType: __ObjC.NSURLRequest.NetworkServiceType
  - allowsCellularAccess: true
  ▿ httpMethod: Optional("POST")
    - some: "POST"
  ▿ allHTTPHeaderFields: Optional(["App-Version": "42"])
    ▿ some: 1 key/value pairs
      ▿ (2 elements)
        - key: "App-Version"
        - value: "42"
  ▿ httpBody: Optional(19 bytes)
    ▿ some: "body=Hello%20world!"
  - httpBodyStream: nil
  - httpShouldHandleCookies: true
  - httpShouldUsePipelining: false

Renderable data will write as an image. This includes UIImages and NSImages, but also data that is typically viewed visually, like UIViews and NSViews.

Given a view:

import SnapshotTesting
import XCTest

class HomepageTests: XCTestCase {
  func testRender() {
    let size = CGSize(width: 800, height: 600)
    let webView = UIWebView(frame: .init(origin: .zero, size: size))
    webView.loadHTMLString(renderHomepage())

    assertSnapshot(matching: webView)
  }
}

The above will write to an image on disk. If that image ever renders differently in the future, the assertion will fail and produce a diff for inspection.

A screen shot failure.

Related Tools

  • FBSnapshotTestCase 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 front-end with a polished user experience. Several features of this library (diffing, tracking outdated snapshots) were directly influenced.

GitHub