From c91775c3e5b9682177cbe07e270b635662a67e04 Mon Sep 17 00:00:00 2001 From: Max Topolsky <30879163+mtopo27@users.noreply.github.com> Date: Thu, 16 Apr 2026 21:52:42 -0400 Subject: [PATCH 1/4] 1:1 notion draft port --- .../apple/guides/ios/snapshots/index.mdx | 350 ++++++++++++++++++ 1 file changed, 350 insertions(+) create mode 100644 docs/platforms/apple/guides/ios/snapshots/index.mdx diff --git a/docs/platforms/apple/guides/ios/snapshots/index.mdx b/docs/platforms/apple/guides/ios/snapshots/index.mdx new file mode 100644 index 00000000000000..57674d3129c31b --- /dev/null +++ b/docs/platforms/apple/guides/ios/snapshots/index.mdx @@ -0,0 +1,350 @@ +--- +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 iOS app before they reach users. Run snapshot tests in your own CI environment, upload the resulting images to Sentry, and let Sentry handle the image diffing, visual review UI, and GitHub check status updates. + +Sentry uses a **bring-your-own-infrastructure** model. You run snapshot tests locally or in CI using your preferred snapshot library, then upload the generated images using the Sentry CLI or Sentry's Fastlane plugin. Sentry doesn't run your tests — it compares the images you upload. + +> **Tip:** Snapshots is most useful when integrated into your CI pipeline. See [Integrating Into CI](#integrating-into-ci) for setup instructions. + +## How It Works + +1. Add a snapshot testing library to your project +2. Write snapshot tests that generate images +3. Run the tests in CI +4. Upload the generated images to Sentry using the Sentry CLI +5. Sentry compares images across builds and surfaces visual diffs + +## Getting Started + +You can use any snapshot testing library that produces image files. Sentry accepts any directory of snapshot images regardless of how they were generated. + +**Recommended:** [SnapshotPreviews](#using-snapshotpreviews-recommended) — Automatically discovers and renders your SwiftUI previews as snapshots, with built-in CI export support and metadata. + +**Alternative:** [swift-snapshot-testing](#using-swift-snapshot-testing) — A popular library from Point-Free for snapshot testing any view or view controller. + +**Other libraries:** Any tool that generates snapshot images works with Sentry. See [Using Other Snapshot Libraries](#using-other-snapshot-libraries). + +### Using SnapshotPreviews (Recommended) + +[SnapshotPreviews](https://github.com/EmergeTools/SnapshotPreviews) automatically discovers SwiftUI previews in your app and renders them as snapshot images. It includes a CI export mode that writes PNG files and JSON metadata sidecars directly to a directory you specify, ready for upload to Sentry. + +#### 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. + +### Using swift-snapshot-testing + +[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. + +#### 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, organised 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. + +#### Using Other Snapshot Libraries + +Sentry's upload mechanism is directory-based — it accepts any directory of snapshot images. This means you can use any snapshot testing tool that generates image files, including: + +- Custom `XCTest` setups that render views to images +- Other open-source snapshot libraries +- Manual screenshot capture workflows + +The requirement is that your workflow produces image files (Only PNGs or JPGs) in a directory that can be uploaded to Sentry. + +## Uploading Snapshots + +Once you've generated snapshot images, upload them to Sentry using the Sentry CLI. + +1. Install the [sentry-cli](https://docs.sentry.io/cli/) +2. [Authenticate the CLI](https://docs.sentry.io/cli/configuration/#to-authenticate-manually) +3. Upload the snapshot directory: + + ```bash + sentry-cli build snapshots --app-id com.example.your-app path/to/snapshot-images + ``` + + Only `--app-id` and the path are required. When running on GitHub Actions, VCS metadata (commit SHAs, branch names, repo) is detected automatically. For other CI providers, you can pass VCS metadata manually using flags like `--head-sha`, `--base-sha`, `--head-ref`, and `--base-ref`. Run `sentry-cli build snapshots --help` for the full list of options. + +4. After a successful upload, verify the snapshots appear in the Sentry UI. + +## Integrating Into CI + +Snapshots works best when integrated into your CI pipeline so every pull request automatically generates and uploads snapshots for visual comparison. + +### GitHub Actions With SnapshotPreviews + +```yaml +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 +``` + +### GitHub Actions With swift-snapshot-testing + +```yaml +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 +``` + +### Using Fastlane + +If your CI already uses Fastlane, you can use the Sentry Fastlane plugin instead of calling the CLI directly. + +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`. +- **Review diffs in Sentry.** After uploading, use Sentry's visual diff UI to review changes and approve or flag regressions before merging. From a22ff0dc9b82479af7c99c93dd2ec69695cccbdc Mon Sep 17 00:00:00 2001 From: Max Topolsky <30879163+mtopo27@users.noreply.github.com> Date: Thu, 16 Apr 2026 22:43:58 -0400 Subject: [PATCH 2/4] reformat to multiple pages --- .../apple/guides/ios/snapshots/index.mdx | 305 +----------------- .../using-snapshotpreviews/index.mdx | 130 ++++++++ .../using-swift-snapshot-testing/index.mdx | 139 ++++++++ 3 files changed, 282 insertions(+), 292 deletions(-) create mode 100644 docs/platforms/apple/guides/ios/snapshots/using-snapshotpreviews/index.mdx create mode 100644 docs/platforms/apple/guides/ios/snapshots/using-swift-snapshot-testing/index.mdx diff --git a/docs/platforms/apple/guides/ios/snapshots/index.mdx b/docs/platforms/apple/guides/ios/snapshots/index.mdx index 57674d3129c31b..92e216b02e7452 100644 --- a/docs/platforms/apple/guides/ios/snapshots/index.mdx +++ b/docs/platforms/apple/guides/ios/snapshots/index.mdx @@ -6,311 +6,33 @@ description: Catch unintended visual changes in your iOS app before they reach u beta: true --- -Snapshots helps you catch unintended visual changes in your iOS app before they reach users. Run snapshot tests in your own CI environment, upload the resulting images to Sentry, and let Sentry handle the image diffing, visual review UI, and GitHub check status updates. +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: -Sentry uses a **bring-your-own-infrastructure** model. You run snapshot tests locally or in CI using your preferred snapshot library, then upload the generated images using the Sentry CLI or Sentry's Fastlane plugin. Sentry doesn't run your tests — it compares the images you upload. - -> **Tip:** Snapshots is most useful when integrated into your CI pipeline. See [Integrating Into CI](#integrating-into-ci) for setup instructions. +- [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. Write snapshot tests that generate images -3. Run the tests in CI -4. Upload the generated images to Sentry using the Sentry CLI -5. Sentry compares images across builds and surfaces visual diffs - -## Getting Started - -You can use any snapshot testing library that produces image files. Sentry accepts any directory of snapshot images regardless of how they were generated. - -**Recommended:** [SnapshotPreviews](#using-snapshotpreviews-recommended) — Automatically discovers and renders your SwiftUI previews as snapshots, with built-in CI export support and metadata. - -**Alternative:** [swift-snapshot-testing](#using-swift-snapshot-testing) — A popular library from Point-Free for snapshot testing any view or view controller. - -**Other libraries:** Any tool that generates snapshot images works with Sentry. See [Using Other Snapshot Libraries](#using-other-snapshot-libraries). - -### Using SnapshotPreviews (Recommended) - -[SnapshotPreviews](https://github.com/EmergeTools/SnapshotPreviews) automatically discovers SwiftUI previews in your app and renders them as snapshot images. It includes a CI export mode that writes PNG files and JSON metadata sidecars directly to a directory you specify, ready for upload to Sentry. - -#### 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. - -### Using swift-snapshot-testing - -[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. - -#### 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 +2. Generate images in ci +3. Upload images to Sentry +4. Sentry posts results to your PR - assertSnapshot( - of: hostingController, - as: .image(on: .iPhone13Pro), - named: "HomeScreen-iPhone13Pro" - ) +## Generating Snapshot Images - assertSnapshot( - of: hostingController, - as: .image( - on: .iPhone13Pro, - traits: .init(userInterfaceStyle: .dark) - ), - named: "HomeScreen-iPhone13Pro-DarkMode" - ) - } -} -``` +You can use any snapshot testing library that produces image files. We have guides for two popular approaches: -Snapshot images are saved to a `__Snapshots__` directory next to your test file, organised by test class name: +- **[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. -``` -YourAppTests/__Snapshots__/YourSnapshotTests/ -``` +Any other tool that outputs PNGs or JPEGs also works: see [Upload Structure](/product/snapshots/uploading-snapshots/#upload-structure) for the generic instructions. -This is the directory you'll upload to Sentry. +## Uploading 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. - -#### Using Other Snapshot Libraries - -Sentry's upload mechanism is directory-based — it accepts any directory of snapshot images. This means you can use any snapshot testing tool that generates image files, including: - -- Custom `XCTest` setups that render views to images -- Other open-source snapshot libraries -- Manual screenshot capture workflows - -The requirement is that your workflow produces image files (Only PNGs or JPGs) in a directory that can be uploaded to Sentry. - -## Uploading Snapshots - -Once you've generated snapshot images, upload them to Sentry using the Sentry CLI. - -1. Install the [sentry-cli](https://docs.sentry.io/cli/) -2. [Authenticate the CLI](https://docs.sentry.io/cli/configuration/#to-authenticate-manually) -3. Upload the snapshot directory: - - ```bash - sentry-cli build snapshots --app-id com.example.your-app path/to/snapshot-images - ``` - - Only `--app-id` and the path are required. When running on GitHub Actions, VCS metadata (commit SHAs, branch names, repo) is detected automatically. For other CI providers, you can pass VCS metadata manually using flags like `--head-sha`, `--base-sha`, `--head-ref`, and `--base-ref`. Run `sentry-cli build snapshots --help` for the full list of options. - -4. After a successful upload, verify the snapshots appear in the Sentry UI. - -## Integrating Into CI - -Snapshots works best when integrated into your CI pipeline so every pull request automatically generates and uploads snapshots for visual comparison. - -### GitHub Actions With SnapshotPreviews - -```yaml -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 -``` - -### GitHub Actions With swift-snapshot-testing - -```yaml -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 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 -If your CI already uses Fastlane, you can use the Sentry Fastlane plugin instead of calling the CLI directly. - 1. Install the [Sentry Fastlane plugin](https://github.com/getsentry/sentry-fastlane-plugin): ```ruby @@ -347,4 +69,3 @@ If your CI already uses Fastlane, you can use the Sentry Fastlane plugin instead - **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`. -- **Review diffs in Sentry.** After uploading, use Sentry's visual diff UI to review changes and approve or flag regressions before merging. diff --git a/docs/platforms/apple/guides/ios/snapshots/using-snapshotpreviews/index.mdx b/docs/platforms/apple/guides/ios/snapshots/using-snapshotpreviews/index.mdx new file mode 100644 index 00000000000000..43edbfc7729690 --- /dev/null +++ b/docs/platforms/apple/guides/ios/snapshots/using-snapshotpreviews/index.mdx @@ -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 diff --git a/docs/platforms/apple/guides/ios/snapshots/using-swift-snapshot-testing/index.mdx b/docs/platforms/apple/guides/ios/snapshots/using-swift-snapshot-testing/index.mdx new file mode 100644 index 00000000000000..e0286ed5034834 --- /dev/null +++ b/docs/platforms/apple/guides/ios/snapshots/using-swift-snapshot-testing/index.mdx @@ -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). From 5ac1babbd838defbaa44a7f20b2e3a31c78cffee Mon Sep 17 00:00:00 2001 From: Max Topolsky <30879163+mtopo27@users.noreply.github.com> Date: Thu, 16 Apr 2026 22:48:10 -0400 Subject: [PATCH 3/4] todos --- docs/platforms/apple/guides/ios/snapshots/index.mdx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/platforms/apple/guides/ios/snapshots/index.mdx b/docs/platforms/apple/guides/ios/snapshots/index.mdx index 92e216b02e7452..1f415c68c52cdc 100644 --- a/docs/platforms/apple/guides/ios/snapshots/index.mdx +++ b/docs/platforms/apple/guides/ios/snapshots/index.mdx @@ -69,3 +69,8 @@ You can upload snapshots with either `sentry-cli` or the [Sentry Fastlane plugin - **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? From e1e1ab385c7bb8fe722fc2b9f7e8b6021119de55 Mon Sep 17 00:00:00 2001 From: Max Topolsky <30879163+mtopo27@users.noreply.github.com> Date: Thu, 16 Apr 2026 22:48:53 -0400 Subject: [PATCH 4/4] another todo --- docs/platforms/apple/guides/ios/snapshots/index.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/platforms/apple/guides/ios/snapshots/index.mdx b/docs/platforms/apple/guides/ios/snapshots/index.mdx index 1f415c68c52cdc..81244ee7577c2f 100644 --- a/docs/platforms/apple/guides/ios/snapshots/index.mdx +++ b/docs/platforms/apple/guides/ios/snapshots/index.mdx @@ -74,3 +74,4 @@ You can upload snapshots with either `sentry-cli` or the [Sentry Fastlane plugin - maybe move this into "common"? unsure - add some pics where relevant? +- some blurb that you can use multiple libraries