Snapshot testing
Skill almasumdev/awesome-mobile-testing-agent-skills/.github/skills/ui/snapshot-testing
Expert guidance on snapshot / golden image testing across mobile stacks — Paparazzi (Android), swift-snapshot-testing (iOS), golden_toolkit (Flutter), and RN snapshot tests. Use when asked to lock down UI visuals or catch unintended rendering regressions.From its SKILL.md
npx -y skills add almasumdev/awesome-mobile-testing-agent-skills --skill snapshot-testingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
5.2 KB, ~1.2k tokens by cl100k_base, as published. Nobody here has run it
Snapshot Testing
Instructions
Snapshot tests render a UI component to a file (image or serialized tree) and fail if the next render differs. They excel at catching unintended visual regressions. They fail badly when used as a substitute for logic tests or when goldens are mass-regenerated without review.
1. Host-Rendered vs Device-Rendered
Always prefer host-rendered snapshot libraries — they run on the JVM / host Swift / host Dart and produce deterministic images without emulator skew.
- Android — Paparazzi (JVM) or Roborazzi (Robolectric + rendering). Avoid screenshotting via instrumentation unless you need a true-device render for a specific bug.
- iOS — swift-snapshot-testing runs on simulator but can be pinned to a specific simulator model/OS to stay deterministic.
- Flutter —
flutter test --update-goldenswithmatchesGoldenFile, optionally viagolden_toolkitoralchemistfor multi-config runs. Renders off-device on host. - React Native —
react-test-renderer+jest'stoMatchSnapshotfor serialized trees; for pixel images use@storybook/test-runner+ Chromatic orreact-native-owl(device-based, slower).
2. Android — Paparazzi (Compose)
class CheckoutButtonScreenshot {
@get:Rule val paparazzi = Paparazzi(
deviceConfig = DeviceConfig.PIXEL_5,
theme = "android:Theme.Material.Light.NoActionBar",
)
@Test fun default() = paparazzi.snapshot {
AppTheme { CheckoutButton(state = Idle, onClick = {}) }
}
@Test fun loading() = paparazzi.snapshot {
AppTheme { CheckoutButton(state = Loading, onClick = {}) }
}
}
Goldens land under src/test/snapshots/images/. Commit them. Review diffs as code.
3. iOS — swift-snapshot-testing
final class CheckoutButtonSnapshotTests: XCTestCase {
func test_default_lightMode() {
let view = CheckoutButtonView(state: .idle)
assertSnapshot(of: view, as: .image(traits: .init(userInterfaceStyle: .light)))
}
func test_default_darkMode() {
let view = CheckoutButtonView(state: .idle)
assertSnapshot(of: view, as: .image(traits: .init(userInterfaceStyle: .dark)))
}
}
Pin the simulator in CI (platform=iOS Simulator,name=iPhone 15,OS=17.5); different iOS versions render font metrics differently.
4. Flutter — goldens with golden_toolkit
void main() {
testGoldens('CheckoutButton states', (tester) async {
final builder = DeviceBuilder()
..overrideDevicesForAllScenarios(devices: [Device.phone])
..addScenario(widget: const CheckoutButton(state: ButtonState.idle), name: 'idle')
..addScenario(widget: const CheckoutButton(state: ButtonState.loading), name: 'loading');
await tester.pumpDeviceBuilder(builder);
await screenMatchesGolden(tester, 'checkout_button_states');
});
}
Run flutter test --update-goldens locally to regenerate. In CI, run without the flag and fail on diff.
5. React Native — Component Tree Snapshot
import { render } from '@testing-library/react-native';
test('CheckoutButton renders in idle state', () => {
const { toJSON } = render(<CheckoutButton state="idle" />);
expect(toJSON()).toMatchSnapshot();
});
Tree snapshots catch structural drift. For pixel-accurate RN visuals, use Storybook + Chromatic or an image-diff tool; toMatchSnapshot alone will not catch style regressions.
6. Determinism Rules
- Pin the theme, locale, and density. Render both light and dark explicitly.
- Pin fonts. Embed the app's fonts in the test configuration; never rely on a system font the CI image may update.
- Freeze animation and time. Use
pump()/waitForIdle()/ explicit animation-skipping. - Avoid network and images. Inject a fake image loader that produces a deterministic placeholder.
7. Reviewing Golden Diffs
- PRs that touch goldens must show the image diff in review (most CI UIs render PNGs).
- Do not click "update all" without inspecting each diff.
- If a platform upgrade (e.g., new iOS) changes many goldens, update them in a separate PR tagged
chore(goldens)so logic changes do not hide behind visual churn.
8. What Snapshot Testing Does NOT Cover
- Accessibility — use accessibility tests.
- Behavior — a button can render correctly and still navigate nowhere.
- Data correctness — a list can render beautifully with the wrong items.
9. Checklist
- Snapshots run on host (JVM / simulator pinned / Dart VM / Node), not on arbitrary emulators.
- Theme, locale, density, and fonts are pinned.
- Animations and image loading are deterministic.
- Goldens are committed and reviewed as code; no mass auto-approval.
- Light and dark modes are both snapshotted.
- Platform-upgrade golden churn lives in its own PR.
- Snapshot tests complement, not replace, logic and accessibility tests.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.