name: snapshot-testing-expert description: 'Expert guidance on snapshot testing with swift-snapshot-testing: writing snapshot tests, configuring strategies, device layouts, recording modes, Xcode Cloud CI compatibility, and reviewing snapshot test code. Use when writing new snapshot tests, adding snapshot coverage to features, debugging snapshot failures, reviewing snapshot test code, or configuring CI for snapshots.'
Snapshot Testing (swift-snapshot-testing)
Overview
Use this skill for authoritative guidance on snapshot testing in the Popcorn project using Point-Free's swift-snapshot-testing 1.18+. Covers writing snapshot tests with Swift Testing, configuring image strategies, device layouts, recording modes, Xcode Cloud CI compatibility, and reviewing snapshot test code.
Agent Behavior Contract
- Always use Swift Testing (
@Suite,@Test,import Testing) — never XCTest for snapshot tests. - Always use
verifySnapshot+Issue.record— notassertSnapshot— to support thesnapshotDirectoryparameter for Xcode Cloud CI compatibility. - Always include
snapshotDirectory: Self.snapshotDirectoryin everyverifySnapshotcall — this enables CI resolution fromBundle.module. - Always use
.snapshots(record: .missing)on the@Suite— records only missing snapshots, safe for CI. - Always annotate snapshot test suites with
@MainActor— SwiftUI views require main thread rendering. - Always use
.image(layout: .device(config: .iPhone13Pro))as the default strategy — consistent rendering across environments. - Always wrap views in
NavigationStackwhen testing screens that appear within navigation — matches production context. - Always drive views with a
.preview(viewState:)view model in snapshot tests — snapshots capture visual state, not behavior. - Never force unwrap in snapshot tests — use optional chaining (SwiftLint
force_unwrappingrule). - Preview data must use real TMDb IDs and image URLs — ensures snapshots render authentic content.
First 60 Seconds (Triage Template)
- Clarify the goal: new snapshot test, debugging failure, CI issue, or review.
- Collect minimal facts:
- Which feature/view needs snapshot coverage?
- Is the issue local-only or CI-specific (Xcode Cloud)?
- Is this a new snapshot or a mismatch with an existing reference?
- Branch quickly:
- new snapshot test ->
references/writing-tests.md - CI failure / Xcode Cloud ->
references/xcode-cloud.md - snapshot mismatch ->
references/debugging.md - strategy/layout questions ->
references/strategies.md - review -> verification checklist below
- new snapshot test ->
Common Pitfalls -> Next Best Move
- Snapshot test fails in Xcode Cloud with "No reference found on disk" ->
references/xcode-cloud.md— snapshot images must be bundled as.copyresources and resolved fromBundle.modulein CI. - Using
assertSnapshotinstead ofverifySnapshot->assertSnapshotlackssnapshotDirectoryparameter — switch toverifySnapshot+Issue.recordpattern. - Snapshot renders blank or partially loaded -> ensure preview data includes image URLs; use
timeoutparameter if async loading needed. - Snapshot mismatch after UI change -> delete old snapshot PNG, re-run to record new one, commit the updated PNG.
- Different results on different machines -> use fixed device config (
.iPhone13Pro), not.sizeThatFitswhich varies by host. - Force unwrap lint error on
Bundle.module.resourceURL!-> use optional chaining (resourceURL?). - Missing
Bundle.module-> ensure Package.swift test target declaresresources: [.copy("Views/__Snapshots__")]. - Snapshot test not running in CI -> ensure target is registered in
TestPlans/PopcornSnapshotTests.xctestplan.
Verification Checklist
- Confirm test uses
@Suite(.snapshots(record: .missing))and@MainActor. - Confirm test uses
verifySnapshotwithsnapshotDirectory: Self.snapshotDirectory, notassertSnapshot. - Confirm
snapshotDirectorycomputed property exists — returnsnillocally,Bundle.modulepath in CI. - Confirm Package.swift has
resources: [.copy("Views/__Snapshots__")]on the snapshot test target. - Confirm snapshot PNG is committed to git in
__Snapshots__/{TestTypeName}/{testName}.1.png. - Confirm snapshot test target is registered in
TestPlans/PopcornSnapshotTests.xctestplan. - Confirm preview data uses
static var(notstatic letfor@Modeltypes). - Confirm no force unwraps in test code.
References
references/writing-tests.md— step-by-step guide to writing snapshot testsreferences/strategies.md— image strategies, device configs, layout optionsreferences/xcode-cloud.md— CI compatibility, Bundle.module, resource bundlingreferences/debugging.md— troubleshooting snapshot failures