Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions docs/platforms/apple/guides/ios/snapshots/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
title: Snapshots
sidebar_order: 4800
sidebar_section: features
description: Catch unintended visual changes in your iOS app before they reach users.
beta: true
---

Snapshots helps you catch unintended visual changes in your Apple apps before they reach users. Below are instructions for common approaches for Snapshotting on Apple Platforms. Additional docs Include:

- [Uploading Snapshots](/product/snapshots/uploading-snapshots/) - Platform-agnostic details on how to upload snapshots to Sentry
- [Reviewing Snapshots](/product/snapshots/reviewing-snapshots/) - How to review and approve snapshots in Sentry

## How It Works

1. Add a snapshot testing library to your project
2. Generate images in ci
3. Upload images to Sentry
4. Sentry posts results to your PR

## Generating Snapshot Images

You can use any snapshot testing library that produces image files. We have guides for two popular approaches:

- **[Using SnapshotPreviews](./using-snapshotpreviews/)** (Recommended) — Automatically discovers and renders your Previews as snapshots, with built-in CI export support and metadata.
- **[Using swift-snapshot-testing](./using-swift-snapshot-testing/)** — A popular library from [Point-Free](https://www.pointfree.co/) for snapshot testing any view or view controller.

Any other tool that outputs PNGs or JPEGs also works: see [Upload Structure](/product/snapshots/uploading-snapshots/#upload-structure) for the generic instructions.

## Uploading to Sentry

You can upload snapshots with either `sentry-cli` or the [Sentry Fastlane plugin](https://github.com/getsentry/sentry-fastlane-plugin). See [uploading snapshots](/product/snapshots/uploading-snapshots/) for sentry-cli details.

### Using Fastlane

1. Install the [Sentry Fastlane plugin](https://github.com/getsentry/sentry-fastlane-plugin):

```ruby
bundle exec fastlane add_plugin fastlane-plugin-sentry
```

2. Add an upload lane to your `Fastfile`:

```ruby
desc 'Upload snapshots to Sentry'
lane :upload_snapshots do
sentry_upload_snapshots(
path: 'snapshot-images',
app_id: 'com.example.your-app',
auth_token: ENV['SENTRY_AUTH_TOKEN'],
org_slug: 'your-org',
project_slug: 'your-project'
)
end
```

Adjust `path` based on where your snapshot library writes its output. For swift-snapshot-testing, this would be `YourAppTests/__Snapshots__/YourSnapshotTests`.

3. Call the lane after your test step in CI:

```yaml
- name: Upload snapshots to Sentry
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
run: bundle exec fastlane ios upload_snapshots
```

## Best Practices

- **Pin your simulator device.** Use the same simulator model and OS version across CI runs to avoid spurious diffs caused by rendering differences.
- **Keep snapshot tests isolated.** Use a dedicated test class or test plan for snapshots so you can run them independently with `only-testing`.

## misc todos

- maybe move this into "common"? unsure
- add some pics where relevant?
- some blurb that you can use multiple libraries
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
---
title: Using SnapshotPreviews
sidebar_order: 4810
description: Generate snapshot images from SwiftUI Previews and upload them to Sentry.
---

[SnapshotPreviews](https://github.com/EmergeTools/SnapshotPreviews) automatically discovers Previews in your app and renders them as snapshot images. You don't have to maintain any explicit test code to produce snapshot images. SnapshotPreviews includes a CI export mode that writes PNG files and JSON metadata sidecars directly to a directory you specify, ready for upload to Sentry.

## Generating Images

### 1. Add the Dependency

Add the `SnapshotPreviews` package (v0.12.0 or later) to your project. In your `Package.swift` or via Xcode's package manager:

```
https://github.com/EmergeTools/SnapshotPreviews
```

Link the `SnapshottingTests` library to your **test target**:

```swift
// In Package.swift
.testTarget(
name: "YourAppTests",
dependencies: [
.product(name: "SnapshottingTests", package: "SnapshotPreviews"),
]
)
```

Or in Xcode, add `SnapshottingTests` under your test target's **Frameworks and Libraries**.

### 2. Create a Snapshot Test

Create a new test file that subclasses `SnapshotTest`:

```swift
import SnapshottingTests

class YourAppSnapshotTest: SnapshotTest {
override class func snapshotPreviews() -> [String]? {
// Return nil to snapshot all previews,
// or return an array of preview names to include.
// Regex patterns are also supported.
return nil
}

override class func excludedSnapshotPreviews() -> [String]? {
// Return an array of preview names to exclude, or nil.
return nil
}
}
```

`SnapshotTest` automatically discovers all SwiftUI `#Preview` and `PreviewProvider` declarations in your app and test targets, renders each one, and generates a snapshot image.

### 3. Enable CI Export

Set the `TEST_RUNNER_SNAPSHOTS_EXPORT_DIR` environment variable in your CI environment to specify where snapshot images should be written:

```bash
export TEST_RUNNER_SNAPSHOTS_EXPORT_DIR="$PWD/snapshot-images"
```

When this variable is set, SnapshotPreviews writes PNG images and JSON metadata sidecars to the specified directory.

When running locally without this variable, snapshots are attached to the XCTest results — useful for development but not for Sentry uploads.

### 4. Run the Tests

```bash
xcodebuild test \
-scheme YourScheme \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 16 Pro' \
-only-testing:YourAppTests/YourAppSnapshotTest \
CODE_SIGNING_ALLOWED=NO
```

After tests complete, the export directory contains your snapshot images ready for upload. The SnapshotPreviews library automatically uses (TODO: WHAT GETS PULLED INTO THE METADATA??).

## Integrating into CI

To see a live example you can refer to this repo (TODO: HACKERNEWS LINK MAYBE WE HAVE THIS HIGHER AS WELL). Below is a sample Github Action workflow for uploading snapshots to Sentry:

```yaml {filename:.github/workflows/snapshots.yml}
name: iOS Snapshots

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
snapshots:
runs-on: macos-15

env:
TEST_RUNNER_SNAPSHOTS_EXPORT_DIR: "${{ github.workspace }}/snapshot-images"

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Boot simulator
run: xcrun simctl boot "iPhone 17 Pro" || true

- name: Generate snapshots
run: |
set -o pipefail && xcodebuild test \
-scheme YourScheme \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro' \
-only-testing:YourAppTests/YourAppSnapshotTest \
CODE_SIGNING_ALLOWED=NO \
| xcpretty

- name: Upload snapshots to Sentry
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
run: |
sentry-cli build snapshots --app-id com.example.your-app snapshot-images
```

You can also upload with Fastlane — see [Uploading to Sentry](../#uploading-to-sentry).

## MISC TODOS

- i think we may need to redo the readme on the repo to be more supplementary + more complete reference. i.e. i've sent https://github.com/EmergeTools/SnapshotPreviews/blob/main/Examples/DemoApp/DemoApp/TestViews/PreviewVariants.swift to people frequently, but now that's just a hidden example
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
---
title: Using swift-snapshot-testing
sidebar_order: 4820
description: Generate snapshot images with Point-Free's swift-snapshot-testing and upload them to Sentry.
---

[swift-snapshot-testing](https://github.com/pointfreeco/swift-snapshot-testing) is a popular open-source library from Point-Free that supports snapshot testing for SwiftUI views, UIKit views, and view controllers. Refer to the [repo](https://github.com/pointfreeco/swift-snapshot-testing) for full documentation.

## Generating Images

### 1. Add the Dependency

Add the `swift-snapshot-testing` package to your project:

```
https://github.com/pointfreeco/swift-snapshot-testing
```

Link `SnapshotTesting` to your test target.

### 2. Write Snapshot Tests

Create test cases using `assertSnapshot`:

```swift
import SnapshotTesting
import SwiftUI
import XCTest

@testable import YourApp

final class YourSnapshotTests: XCTestCase {

@MainActor
func testHomeScreen() {
let view = HomeScreen()
let hostingController = UIHostingController(rootView: view)
hostingController.view.frame = UIScreen.main.bounds

assertSnapshot(
of: hostingController,
as: .image(on: .iPhone13Pro),
named: "HomeScreen-iPhone13Pro"
)

assertSnapshot(
of: hostingController,
as: .image(
on: .iPhone13Pro,
traits: .init(userInterfaceStyle: .dark)
),
named: "HomeScreen-iPhone13Pro-DarkMode"
)
}
}
```

Snapshot images are saved to a `__Snapshots__` directory next to your test file, organized by test class name:

```
YourAppTests/__Snapshots__/YourSnapshotTests/
```

This is the directory you'll upload to Sentry.

### 3. Configure Recording for CI

By default, swift-snapshot-testing compares against existing reference images and fails if they don't match. For Sentry, you want CI to always generate fresh images for upload.

Set the `TEST_RUNNER_SNAPSHOT_TESTING_RECORD` environment variable to `all` in your CI environment:

```bash
export TEST_RUNNER_SNAPSHOT_TESTING_RECORD=all
```

This tells the library to record all snapshots. Locally (without this variable), tests default to comparison mode — so developers can still use reference-based diffing during development.

> **Note:** In record mode, swift-snapshot-testing reports every test as a "failure" since it's recording rather than comparing. Use `continue-on-error: true` on your CI test step to ensure the upload step still runs.

### 4. Run the Tests

```bash
xcodebuild test \
-scheme YourScheme \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 16 Pro' \
-only-testing:YourAppTests/YourSnapshotTests \
CODE_SIGNING_ALLOWED=NO
```

After tests complete, the `__Snapshots__/YourSnapshotTests/` directory contains your snapshot images ready for upload. You can optionally add [JSON metadata](/product/snapshots/uploading-snapshots/#json-metadata) alongside the image files to supplement how the image is displayed in Sentry.

## Integrating into CI

Sample Github Action workflow for uploading snapshots to Sentry:

```yaml {filename:.github/workflows/snapshots.yml}
name: iOS Snapshots

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
snapshots:
runs-on: macos-15

env:
TEST_RUNNER_SNAPSHOT_TESTING_RECORD: all

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Boot simulator
run: xcrun simctl boot "iPhone 17 Pro" || true

- name: Generate snapshots
continue-on-error: true
run: |
set -o pipefail && xcodebuild test \
-scheme YourScheme \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro' \
-only-testing:YourAppTests/YourSnapshotTests \
CODE_SIGNING_ALLOWED=NO \
| xcpretty

- name: Upload snapshots to Sentry
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
APP_ID: com.example.your-app
run: |
sentry-cli build snapshots --app-id $APP_ID YourAppTests/__Snapshots__/YourSnapshotTests
```

You can also upload with Fastlane — see [Uploading to Sentry](../#uploading-to-sentry).
Loading