English | 日本語
Snapshot testing for SwiftUI: name the states you care about, and every device × theme × locale × text size combination is captured for you.
- Declarative macros.
@SnapshotSuite,@Snapshot,@ComponentSnapshot— a function returns a View, and that is the whole test. - Matrix capture. Three devices, light and dark,
enandjaby default. iPadOS 26 window widths and accessibility text sizes are opt-in axes, so adding them never invalidates images you already recorded. - Views and components are separate. Full-screen views use the matrix; design-system components use the theme axis alone.
- Any theme system.
ThemeApplicableconnects the theme axis to whatever actually drives appearance in your app, so snapshots exercise the same path the app does. - Browsable output. Every run writes a
manifest.jsonbeside the images; those aggregate into a catalog and a self-contained HTML gallery with filters, search, and light/dark comparison.
import SwiftUI
import Testing
import VisualTesting
@SnapshotSuite("SettingsView")
@MainActor
struct SettingsViewSnapshots {
@Snapshot
func loaded() -> some View {
SettingsView()
}
@Test func snapshots() {
for snapshotCase in Self.__snapshotCases { snapshotCase.run() }
}
}That single function records twelve reference images at
__Snapshots__/SettingsView/{device}/loaded.{theme}_{locale}.png.
The runner test is hand-written on purpose: a macro cannot expand @Test without corrupting
swift-testing's test records, so @SnapshotSuite only collects the cases. Omitting the runner is a
compile error that names the exact line to add.
Getting Started and the full API reference cover component snapshots, custom theme systems, changing the matrix, recording reference images, and generating the HTML gallery.
dependencies: [
.package(url: "https://github.com/no-problem-dev/swift-visual-testing.git", from: "3.0.0")
].testTarget(
name: "YourTests",
dependencies: [
.product(name: "VisualTesting", package: "swift-visual-testing")
]
)See CONTRIBUTING.md.
MIT — see LICENSE.