Tests that save and assert against reference data

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".

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.

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