P3.1: iOS goldens @2x + PNG optimizer + Makefile record/verify targets
- SnapshotGalleryTests rendered at displayScale: 2.0 (was native 3.0)
→ 49MB → 15MB (~69% reduction)
- Records via SNAPSHOT_TESTING_RECORD=1 env var (no code edits needed)
- scripts/optimize_goldens.sh runs zopflipng (or pngcrush fallback)
over both iOS and Android golden dirs
- scripts/{record,verify}_snapshots.sh one-command wrappers
- Makefile targets: make {record,verify,optimize}-snapshots
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -25,9 +25,26 @@
|
||||
//
|
||||
// Recording goldens
|
||||
// -----------------
|
||||
// Set `isRecording = true` in `setUp()`, run the target, then flip back to
|
||||
// `false` before committing. CI fails the build if a screen diverges from
|
||||
// its golden by more than the precision threshold.
|
||||
// Preferred: `make record-snapshots` (or `./scripts/record_snapshots.sh
|
||||
// --ios-only`). The script exports `SNAPSHOT_TESTING_RECORD=1` in the
|
||||
// xcodebuild env, deletes the old `__Snapshots__/SnapshotGalleryTests`
|
||||
// directory, runs the target, then invokes the shared PNG optimizer.
|
||||
//
|
||||
// Manual override: set the `SNAPSHOT_TESTING_RECORD` env var to `1` in
|
||||
// the Xcode scheme's Test action (Edit Scheme → Test → Arguments →
|
||||
// Environment Variables) and re-run the test target. CI fails the
|
||||
// build if a screen diverges from its golden by more than the
|
||||
// precision threshold.
|
||||
//
|
||||
// Rendering scale
|
||||
// ---------------
|
||||
// We force `displayScale: 2.0` on every snapshot. The iPhone 15 /
|
||||
// iPhone 13 simulators default to the device's native 3x, which on a
|
||||
// full-screen gradient-heavy SwiftUI view produced 800–1000 KB PNGs
|
||||
// per image. @2x halves the linear dimensions (2.25x fewer pixels) and
|
||||
// is still plenty to catch layout regressions. Combined with
|
||||
// `scripts/optimize_goldens.sh` (zopflipng / pngcrush) this keeps us
|
||||
// under the 150 KB per-image budget enforced by CI.
|
||||
//
|
||||
|
||||
@preconcurrency import SnapshotTesting
|
||||
@@ -39,8 +56,14 @@ import ComposeApp
|
||||
@MainActor
|
||||
final class SnapshotGalleryTests: XCTestCase {
|
||||
|
||||
// Flip to true locally, run the scheme, revert, commit.
|
||||
private static let recordMode: SnapshotTestingConfiguration.Record = .missing
|
||||
// Record mode is driven by the `SNAPSHOT_TESTING_RECORD` env var so
|
||||
// `scripts/record_snapshots.sh` can flip it without mutating this file.
|
||||
// When the var is unset/empty we only write missing goldens (`.missing`)
|
||||
// so local dev runs never silently overwrite committed PNGs.
|
||||
private static var recordMode: SnapshotTestingConfiguration.Record {
|
||||
let env = ProcessInfo.processInfo.environment["SNAPSHOT_TESTING_RECORD"] ?? ""
|
||||
return (env == "1" || env.lowercased() == "true") ? .all : .missing
|
||||
}
|
||||
|
||||
override func invokeTest() {
|
||||
withSnapshotTesting(record: Self.recordMode) {
|
||||
@@ -63,6 +86,12 @@ final class SnapshotGalleryTests: XCTestCase {
|
||||
private static let pixelPrecision: Float = 0.97
|
||||
private static let perceptualPrecision: Float = 0.95
|
||||
|
||||
/// Force @2x rendering regardless of the simulator device's native
|
||||
/// `displayScale`. See the class-level "Rendering scale" comment for
|
||||
/// rationale. 2.0 keeps PNGs under the size budget without sacrificing
|
||||
/// the structural detail our parity gallery cares about.
|
||||
private static let forcedDisplayScale: CGFloat = 2.0
|
||||
|
||||
private func snap<V: View>(
|
||||
_ name: String,
|
||||
file: StaticString = #filePath,
|
||||
@@ -80,7 +109,10 @@ final class SnapshotGalleryTests: XCTestCase {
|
||||
precision: Self.pixelPrecision,
|
||||
perceptualPrecision: Self.perceptualPrecision,
|
||||
layout: .device(config: .iPhone13),
|
||||
traits: .init(userInterfaceStyle: .light)
|
||||
traits: .init(traitsFrom: [
|
||||
UITraitCollection(userInterfaceStyle: .light),
|
||||
UITraitCollection(displayScale: Self.forcedDisplayScale),
|
||||
])
|
||||
),
|
||||
named: "\(name)_light",
|
||||
file: file,
|
||||
@@ -93,7 +125,10 @@ final class SnapshotGalleryTests: XCTestCase {
|
||||
precision: Self.pixelPrecision,
|
||||
perceptualPrecision: Self.perceptualPrecision,
|
||||
layout: .device(config: .iPhone13),
|
||||
traits: .init(userInterfaceStyle: .dark)
|
||||
traits: .init(traitsFrom: [
|
||||
UITraitCollection(userInterfaceStyle: .dark),
|
||||
UITraitCollection(displayScale: Self.forcedDisplayScale),
|
||||
])
|
||||
),
|
||||
named: "\(name)_dark",
|
||||
file: file,
|
||||
|
||||
Reference in New Issue
Block a user