Align the docs with Sentry Snapshots and replace references to Emerge Tools where applicable (EME-1115)#261
Conversation
Restructure the README so visitors arriving from Sentry docs land on snapshot generation and the TEST_RUNNER_SNAPSHOTS_EXPORT_DIR export flow rather than the preview gallery. Move PreviewGallery, accessibility audits, and PreviewLayoutTest into a later "Additional Features" section, clarify that the exporter writes PNGs + JSON sidecars (no Xcode code-coverage data), trim the env-var tip to the variable Sentry users actually need, and pare back non-essential Emerge branding.
… Sentry docs User-facing rebrand pass for the Sentry Snapshots integration. The SnapshotPreviewsCore public API is left untouched because the legacy Emerge SaaS still binds against it. Renames (breaking API change for adopters): - .emergeAccessibility -> .snapshotAccessibility - .emergeRenderingMode -> .snapshotRenderingMode - .emergeSnapshotPrecision -> .snapshotPrecision - .emergeAppStoreSnapshot -> .snapshotAppStore - .emergeExpansion -> .snapshotExpansion Other changes: - Add RUNNING_FOR_SNAPSHOTS env var as the canonical signal that the app is running inside a snapshot test. EMERGE_IS_RUNNING_FOR_SNAPSHOTS is still set/read as a deprecated alias. - Rewrite the README "Uploading Snapshots to Sentry" section around the documented sentry-cli build snapshots flow, with a complete GitHub Actions example. - Fix stale github.com/EmergeTools/SnapshotPreviews-iOS references in the UnitTestMigration example. - Clean up "emerge" prose in SnapshotPreferences doc comments and the RenderingMode.swift file header. Kept (cross-module ABI with SnapshotPreviewsCore): - EmergeRenderingMode enum (public parameter type) - @objc(EmergeModifierState) / @objc(EmergeModifierFinder) classes (looked up by NSClassFromString from SnapshotPreviewsCore)
Remove the public snapshotPrecision modifier so diffThreshold is the documented way to customize Sentry Snapshot comparison tolerance. Update the README sidecar guidance to describe diffThreshold directly and keep the snapshot modifiers table focused on rendering behavior. Co-Authored-By: OpenAI Codex <codex@openai.com>
| - **`<name>.png`** — the rendered preview image. | ||
| - **`<name>.json`** — metadata sidecar containing `display_name`, `group`, `diff_threshold`, and a `context` block with the test name, simulator info, and preview attributes (orientation, color scheme, source line, etc.). The `context` fields are surfaced on the snapshot's detail page in Sentry's UI. | ||
|
|
||
| You can customize the Sentry Snapshots diff threshold for a specific preview with `.diffThreshold(...)` from the `SnapshotPreferences` product. The exporter writes this value to the sidecar as `diff_threshold`. For example, `.diffThreshold(0.05)` writes `"diff_threshold": 0.05`, allowing up to a 5% difference for that snapshot. |
There was a problem hiding this comment.
In the future we will probably have tags and description. Would we have a similar modifier for those?
Also, is it possible for someone to override the display_name or group if they wanted to?
There was a problem hiding this comment.
I haven't considered overriding the display or group names, not sure if that would be a good idea, as it could cause issues if users don't use unique values, the current solution sets these based on the Preview name, filename and a bunch are and the display name rule is quite complex so that we don't end up with ambiguous display and file names.
| ``` | ||
|
|
||
| Note that there are no test functions; they are automatically added at runtime by `SnapshotTest`. You can return a list of previews from the `snapshotPreviews()` function based on what preview you are trying to locally validate. The snapshots will be added as attachments in Xcode’s test results. | ||
| By default each rendered preview is attached to the XCTest results bundle as a PNG. For CI use, see [Exporting snapshots for Sentry](#exporting-snapshots-for-sentry) below. |
There was a problem hiding this comment.
is there a way to see the local generation?
There was a problem hiding this comment.
Yes you can just run xcodebuild locally I can add that.
| # Uploading Snapshots to Sentry | ||
|
|
||
| The [EmergeTools snapshot testing service](https://docs.emergetools.com/docs/snapshot-testing) generates snapshots and diffs them in the cloud to control for sources of flakiness, store images outside of git, and optimize test performance. `SnapshotTest` is for locally debugging these snapshot tests. You can also use `PreviewLayoutTest` to get code coverage of all previews in your unit test without generating PNGs. This will validate that previews do not crash (such as a missing @EnvironmentObject) but runs faster because it does not render the views to images. | ||
| `SnapshotPreviews` is the recommended iOS feeder for [Sentry Snapshots](https://docs.sentry.io/product/snapshots/). The flow has two steps: `xcodebuild test` writes PNGs + JSON sidecars to a directory, then `sentry-cli build snapshots` uploads that directory. |
| <summary>How does it work?</summary> | ||
|
|
||
| The XCTest dynamically inserts test functions by creating functions using the Objective-C runtime and overriding XCTest’s `testInvocations` function. | ||
| ### 2. Upload to Sentry with `sentry-cli` |
There was a problem hiding this comment.
deserves some mention of fastlane and link to docs in sentry. Possibly we just do
"### 2. Uploading to Sentry
You can use the sentry-cli or fastlane to upload. Below is an example workflow for the sentry-cli, see docs for fastlane."
and keep your same content after that. Alternatively we could just have links to the uploading docs you had here: https://docs.sentry.io/platforms/apple/guides/ios/snapshots/#step-3-integrate-into-ci
There was a problem hiding this comment.
Agreed, we do briefly mention Fastlane but wasn't sure if we wanted to add more, but will do.
| Link your XCTest target to `SnapshottingTests`. | ||
| See Sentry's [iOS Snapshots setup](https://docs.sentry.io/platforms/apple/guides/ios/snapshots/) and [CI integration](https://docs.sentry.io/product/snapshots/integrating-into-ci/) docs for sharding across simulators, base/head SHA pinning, and the Fastlane plugin alternative. | ||
|
|
||
| # Tips |
There was a problem hiding this comment.
I talked with Ryan about creating a "Snapshot best practices" in the docs ala, don't snapshot anything that could have a variable timing, network calls, etc. When we have those in the docs we can link to there, but if anything jumps out iOS/repo specific could put here as well
| # Tips | ||
|
|
||
| ### Unique names | ||
| ### Unique display names |
| | `.snapshotRenderingMode(.coreAnimation)` | The default renderer misses, flakes on, or incorrectly draws a view. | Changes the pixel capture backend. For example, `.coreAnimation` uses the layer tree, `.uiView` uses UIKit hierarchy drawing, and `.window` captures the full window. Different modes can affect blur/materials, maps, animations, and other renderer-sensitive content. | | ||
| | `.snapshotExpansion(false)` | You want to preserve the visible scroll viewport instead of capturing all scroll content. | By default, scroll views are expanded so the snapshot includes their full content. Setting this to `false` keeps the scroll view at its normal visible height. | | ||
|
|
||
| ### Variants |
There was a problem hiding this comment.
not immediately clear that we take snapshots of all the variants
There was a problem hiding this comment.
Ok will revise
| /// | ||
| /// - Note: The actual impact of the precision value may vary depending on the | ||
| /// specific implementation of the emerge snapshot feature. | ||
| public func emergeSnapshotPrecision(_ precision: Float?) -> some View { |
There was a problem hiding this comment.
Seems like this shouldn't be deleted?
There was a problem hiding this comment.
@noahsmartin So I believe it's theoretically safe to remove the legacy modifier because .diffThreshold(...) writes to the same underlying PrecisionPreferenceKey.
The only difference is API semantics:
- old
.emergeSnapshotPrecision(0.95)storedprecision = 0.95 - new
.diffThreshold(0.05)storesprecision = 1 - 0.05 = 0.95
The legacy Emerge Snapshots still receives the same precision value it expects, while Sentry sidecar export inverts it back to diff_threshold. The runtime bridge names and reflected state (EmergeModifierState.precision) are unchanged, so the hosted integration compatibility surface is preserved.
If an Emerge Snapshots customer updates their version of SnapshotPreviews to this version, they will have to update their modifiers to use diffThreshold(_:)and invert the value. It's expected that existing customers won't be updating SnapshotPreviews and we're not onboarding new customers on Emerge.
This is contentious I know, I'm being aggressive here in removing references to emerge, but existing customers can just stay on the current version if they don't want to update their use of the now removed emergeSnapshotPrecision(_:) modifier.
Document how to write rendered snapshots to disk locally without referring to CI export before the Sentry export flow is introduced.\n\nCo-Authored-By: OpenAI Codex <codex@openai.com>
Show the visual diff UI in the Sentry upload section so readers can see the snapshot review experience.\n\nCo-Authored-By: OpenAI Codex <codex@openai.com>
Document that display_name and group are generated, not overrideable, and note that future metadata fields should use explicit SnapshotPreferences modifiers.\n\nCo-Authored-By: OpenAI Codex <codex@openai.com>
Update the Sentry upload section to describe both sentry-cli and Fastlane and link to the Sentry iOS Snapshots CI docs.\n\nCo-Authored-By: OpenAI Codex <codex@openai.com>
Add iOS-specific guidance for deterministic previews to avoid flaky snapshot output from network, timing, animation, locale, and clock dependencies.\n\nCo-Authored-By: OpenAI Codex <codex@openai.com>
Use second-level headings below the README top-level sections so the document hierarchy does not skip from H1 to H3.\n\nCo-Authored-By: OpenAI Codex <codex@openai.com>
Explain that SnapshotTest renders every emitted preview variant and writes each named variant as its own snapshot image and sidecar.\n\nCo-Authored-By: OpenAI Codex <codex@openai.com>

Summary
Repurposes
SnapshotPreviewsso its primary documented use case is generating Xcode preview snapshots for Sentry Snapshots, while keeping the existing preview discovery/rendering architecture intact.The branch updates the public-facing docs and example usage from the legacy Emerge snapshot workflow to the Sentry export/upload flow, renames the user-facing SwiftUI snapshot modifiers to
snapshot*, and removes the redundant precision modifier in favor of the Sentry-orienteddiffThresholdAPI.What changed
https://github.com/EmergeTools/SnapshotPreviews.PreviewGallery.TEST_RUNNER_SNAPSHOTS_EXPORT_DIR/SNAPSHOTS_EXPORT_DIR.sentry-cli build snapshotswith a GitHub Actions example.PreviewGallery, accessibility audits, and preview layout checks are moved under additional features..emergeAccessibility(...)→.snapshotAccessibility(...).emergeRenderingMode(...)→.snapshotRenderingMode(...).emergeAppStoreSnapshot(...)→.snapshotAppStore(...).emergeExpansion(...)→.snapshotExpansion(...)snapshotPrecisionmodifier and documented.diffThreshold(...)as the way to customize Sentry Snapshot comparison tolerance.RUNNING_FOR_SNAPSHOTSas the canonical app-launch environment signal for snapshot runs, while still setting/readingEMERGE_IS_RUNNING_FOR_SNAPSHOTSas a deprecated compatibility alias.SnapshotPreviews-iOSpackage references in the Unit Test Migration example.Compatibility notes
This is a user-facing API cleanup for the Sentry Snapshots integration, but it intentionally does not rename every internal/public symbol that contains
Emerge.Kept intentionally for compatibility:
EmergeRenderingMode, because it is still part of theSnapshotPreviewsCorepublic API surface.EmergeModifierState/EmergeModifierFinder, becauseSnapshotPreviewsCorediscovers them dynamically viaNSClassFromStringacross module boundaries.EMERGE_IS_RUNNING_FOR_SNAPSHOTS, as a deprecated environment-variable alias for existing adopters.Breaking/user-visible changes:
.emerge*SwiftUI modifiers need to migrate to the new.snapshot*names.snapshotPrecisionis removed; use.diffThreshold(...)instead.Validation
Not run locally for this PR description update. The branch changes are primarily documentation, naming, and example updates; CI should continue to cover the package build/test matrix.
Linear EME-1115