ref(snapshotting): Restructure CI export sidecar schema#259
Merged
Conversation
Restructures the JSON sidecar emitted via SNAPSHOTS_EXPORT_DIR from a flat blob into a nested schema with explicit top-level fields for dashboard filtering and a nested `context` bag for forensic/diagnostic data. Refs EME-1073
Renames and relocates the sidecar's color scheme field. The value reflects the author-declared `.preferredColorScheme(_:)` modifier, not a rendered output, so it belongs under `context` (forensic data) with a name that mirrors the SwiftUI API. Refs EME-1073
… preview Removes the top-level `tags` object. Its `device` field was a duplicate of `context.simulator.device_name`, and its `orientation` field is a per-preview author declaration (from `.previewInterfaceOrientation(_:)` or `#Preview` traits), not a simulator property. Both now live where their provenance points: - `context.preview.orientation` joins the other per-preview author declarations (`display_name`, `preferred_color_scheme`). - `device_name` remains under `context.simulator` as the single source of truth. Refs EME-1073
NicoHinderling
approved these changes
Apr 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Restructures the JSON sidecar emitted via
SNAPSHOTS_EXPORT_DIRfrom a flat blob into a nested schema with explicit top-level fields (display_name,group,diff_threshold) and a nestedcontextobject that groups runtime/environment data and per-preview author declarations.Schema
{ "display_name": "...", // canonical label for UI (author's .previewDisplayName, or derived fallback) "group": "...", // file path (#Preview) or container type display name (PreviewProvider) "diff_threshold": 0.0, // optional, derived from preview precision "context": { "test_name": "...", "accessibility_enabled": false, "simulator": { // optional — drops when no sim env vars "device_name": "iPhone 17 Pro Max", "model_identifier": "iPhone18,2" }, "preview": { "index": 0, "display_name": "...", // optional — raw .previewDisplayName(...) value, absent if author didn't set one "container_type_name": "...", // PreviewProvider type OR mangled PreviewRegistry conformance name "container_display_name": "...", // derived pretty label from type/file name "preferred_color_scheme": "light", // optional — from author's .preferredColorScheme(_:); enum: "light" | "dark" "orientation": "portrait",// from author's .previewInterfaceOrientation(_:) or #Preview trait (default "portrait") "line": 60 // optional — present only for #Preview macro } } }Key design decisions
context.context.previewgroups everything the author declared about this specific preview.display_name,preferred_color_scheme,orientation, andlineall flow from per-preview modifiers or the#Previewmacro invocation site. Sits next to container identity (container_type_name,container_display_name) so each preview record is self-contained.context.simulatoris the runtime environment — sourced purely fromSIMULATOR_DEVICE_NAME/SIMULATOR_MODEL_IDENTIFIERenv vars. Orientation is explicitly not here — despite the simulator being rotated to match during capture, the canonical value is the author's declaration.preferred_color_schememirrors SwiftUI's.preferredColorScheme(_:)modifier. Mapped at the source (SwiftUI.ColorScheme.stringValuenow returnsString?) so@unknown defaultdrops out instead of emitting"unknown".container_type_nameis the type that declared the preview, not the view being previewed. ForPreviewProviderthis is your struct (HackerNews.CommentView_Preview); for#Previewit's a compiler-synthesizedPreviewRegistryconformance (mangled name). A "view-under-test" field would require either fragile SwiftUI reflection or a new preference-key modifier — out of scope here.container_display_nameis a derived pretty label, not author-declared. Doc-commented at the source so future readers don't re-ask.SnapshotContext:previewId(redundant — always"\(index)"),appStoreSnapshot(not emitted anywhere after the refactor),declaredDevice(filtered upstream —PreviewBaseTestalready skips previews whose declared device doesn't match the host sim).Sample sidecars
Four examples covering the full matrix:
PreviewProvidervs#Previewmacro × named vs anonymous × with/withoutpreferred_color_scheme. Samples reflect the current schema; the on-disk fixtures under/private/tmp/snapshots25/iphonewill regenerate to this shape on next export.1.
PreviewProviderwith.previewDisplayName+.preferredColorScheme(.dark)Shows
preferred_color_scheme+orientationnested underpreview, author-setdisplay_name, readablecontainer_type_name(no mangling),indexdisambiguating multiple previews in the same provider.{ "context" : { "accessibility_enabled" : false, "preview" : { "container_display_name" : "Comment View Preview", "container_type_name" : "HackerNews.CommentView_Preview", "display_name" : "Dark mode", "index" : 1, "orientation" : "portrait", "preferred_color_scheme" : "dark" }, "simulator" : { "device_name" : "iPhone 17 Pro Max", "model_identifier" : "iPhone18,2" }, "test_name" : "-[HackerNewsSnapshotTest portrait-Comment View Preview-1-6]" }, "display_name" : "Dark mode", "group" : "Comment View Preview" }2.
PreviewProvider+ForEach(multiple indexed previews, all named)One container, six previews. Each gets a distinct
indexand a per-iteration.previewDisplayName("Indentation \(i)"). Thecontainer_type_nameis shared; the individualdisplay_name+indexidentify the specific snapshot.{ "context" : { "accessibility_enabled" : false, "preview" : { "container_display_name" : "Comment View Indentation Preview", "container_type_name" : "HackerNews.CommentViewIndentation_Preview", "display_name" : "Indentation 0", "index" : 0, "orientation" : "portrait" }, "simulator" : { "device_name" : "iPhone 17 Pro Max", "model_identifier" : "iPhone18,2" }, "test_name" : "-[HackerNewsSnapshotTest portrait-Comment View Indentation Preview-0-8]" }, "display_name" : "Indentation 0", "group" : "Comment View Indentation Preview" }3.
#Previewmacro, anonymousNo
.previewDisplayName—preview.display_nameis absent. Top-leveldisplay_namefalls back to"At line #60".container_type_nameis the mangledPreviewRegistryconformance.container_display_nameis derived from the filename (BookmarksScreen.swift→"Bookmarks Screen").groupis the file path.{ "context" : { "accessibility_enabled" : false, "preview" : { "container_display_name" : "Bookmarks Screen", "container_type_name" : "HackerNews.$s10HackerNews0026BookmarksScreenswift_DsAGgfMX59_0_33_02471A937C398E062128603F3D06A485Ll7PreviewfMf_15PreviewRegistryfMu_", "index" : 0, "line" : 60, "orientation" : "portrait" }, "simulator" : { "device_name" : "iPhone 17 Pro Max", "model_identifier" : "iPhone18,2" }, "test_name" : "-[HackerNewsSnapshotTest portrait-Bookmarks Screen-0-3]" }, "display_name" : "At line #60", "group" : "HackerNews/BookmarksScreen.swift" }4.
#Previewmacro with.previewDisplayNameAll macro-preview fields populated:
preview.display_nameset,linepresent, mangledcontainer_type_name,container_display_namederived from filename.{ "context" : { "accessibility_enabled" : false, "preview" : { "container_display_name" : "Comment Row", "container_type_name" : "HackerNews.$s10HackerNews0021CommentRowswift_IfFDefMX151_0_33_B693E36E869B3E541838B120FF6BB995Ll7PreviewfMf_15PreviewRegistryfMu_", "display_name" : "HTML case 1", "index" : 0, "line" : 152, "orientation" : "portrait" }, "simulator" : { "device_name" : "iPhone 17 Pro Max", "model_identifier" : "iPhone18,2" }, "test_name" : "-[HackerNewsSnapshotTest portrait-Comment Row-0-14]" }, "display_name" : "HTML case 1", "group" : "HackerNews/CommentRow.swift" }Closes EME-1073