Skip to content

Align the docs with Sentry Snapshots and replace references to Emerge Tools where applicable (EME-1115)#261

Merged
cameroncooke merged 10 commits into
getsentry:mainfrom
cameroncooke:main
May 14, 2026
Merged

Align the docs with Sentry Snapshots and replace references to Emerge Tools where applicable (EME-1115)#261
cameroncooke merged 10 commits into
getsentry:mainfrom
cameroncooke:main

Conversation

@cameroncooke
Copy link
Copy Markdown
Contributor

@cameroncooke cameroncooke commented May 13, 2026

Summary

Repurposes SnapshotPreviews so 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-oriented diffThreshold API.

What changed

  • Reworked the README around the Sentry Snapshots workflow:
    • Installation now points at https://github.com/EmergeTools/SnapshotPreviews.
    • Snapshot generation is the lead use case instead of PreviewGallery.
    • CI export is documented via TEST_RUNNER_SNAPSHOTS_EXPORT_DIR / SNAPSHOTS_EXPORT_DIR.
    • Exported artifacts are described as PNG files plus JSON sidecars containing display name, group, diff threshold, simulator/test context, and preview metadata.
    • Upload instructions now use sentry-cli build snapshots with a GitHub Actions example.
    • PreviewGallery, accessibility audits, and preview layout checks are moved under additional features.
  • Renamed user-facing snapshot preference modifiers from Emerge-branded names to Snapshot-branded names:
    • .emergeAccessibility(...).snapshotAccessibility(...)
    • .emergeRenderingMode(...).snapshotRenderingMode(...)
    • .emergeAppStoreSnapshot(...).snapshotAppStore(...)
    • .emergeExpansion(...).snapshotExpansion(...)
  • Removed the public snapshotPrecision modifier and documented .diffThreshold(...) as the way to customize Sentry Snapshot comparison tolerance.
  • Added RUNNING_FOR_SNAPSHOTS as the canonical app-launch environment signal for snapshot runs, while still setting/reading EMERGE_IS_RUNNING_FOR_SNAPSHOTS as a deprecated compatibility alias.
  • Updated demo/example code to use the new modifier names and diff-threshold guidance.
  • Fixed stale SnapshotPreviews-iOS package 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 the SnapshotPreviewsCore public API surface.
  • EmergeModifierState / EmergeModifierFinder, because SnapshotPreviewsCore discovers them dynamically via NSClassFromString across module boundaries.
  • EMERGE_IS_RUNNING_FOR_SNAPSHOTS, as a deprecated environment-variable alias for existing adopters.

Breaking/user-visible changes:

  • Existing users of the old .emerge* SwiftUI modifiers need to migrate to the new .snapshot* names.
  • snapshotPrecision is 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

claude and others added 3 commits May 13, 2026 15:08
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>
@cameroncooke cameroncooke changed the title Align the docs with Sentry Snapshots and replace references to Emerge Tools where applicable Align the docs with Sentry Snapshots and replace references to Emerge Tools where applicable (EME-1115) May 13, 2026
Comment thread README.md Outdated
- **`<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.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread README.md Outdated
```

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.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a way to see the local generation?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you can just run xcodebuild locally I can add that.

Comment thread README.md
# 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.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's add a pic of the ux below, can use this but ideally it would be a more iOS-y diff

Image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

Comment thread README.md Outdated
<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`
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, we do briefly mention Fastlane but wasn't sure if we wanted to add more, but will do.

Comment thread README.md
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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread README.md Outdated
# Tips

### Unique names
### Unique display names
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: H3 after an h1

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good spot

Comment thread README.md Outdated
| `.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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not immediately clear that we take snapshots of all the variants

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this shouldn't be deleted?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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) stored precision = 0.95
  • new .diffThreshold(0.05) stores precision = 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>
@cameroncooke cameroncooke merged commit d42446f into getsentry:main May 14, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants