Automate App Store screenshots via XCUITests
Replace preview-based screenshot rendering with simulator XCUITests driven by shooter.sh (per-language locale + status bar overrides, xcparse extraction). Add batteries-list accessibility identifier and update CLAUDE.md screenshot docs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
68
CLAUDE.md
68
CLAUDE.md
@@ -113,37 +113,61 @@ PDF exports use `UIGraphicsPDFRenderer` with A4 portrait format. The pattern is:
|
||||
- **ShareSheet** triggered via `@State` item binding in the parent view.
|
||||
- **Toolbar button** (not inline content) for the export action.
|
||||
|
||||
## Screenshots & Previews
|
||||
## Screenshots
|
||||
|
||||
Screenshot previews for all major views live in `Cable/ScreenshotPreviews.swift`. This file contains wrapper views and realistic sample data so screenshots include full app chrome (NavigationBar, TabBar).
|
||||
App Store screenshots are generated via XCUITests running on simulators, automated by `shooter.sh`.
|
||||
|
||||
### How to render screenshots
|
||||
### Running screenshots
|
||||
|
||||
1. Use `mcp__xcode__RenderPreview` with `sourceFilePath: "Cable/ScreenshotPreviews.swift"` and `previewDefinitionIndexInFile` (0–44, grouped by view × 5 languages).
|
||||
2. Output goes to `Shots/Screenshots/`.
|
||||
```bash
|
||||
./shooter.sh # reads ./screenshot.config
|
||||
./shooter.sh other.config # explicit config file
|
||||
VERBOSE=1 ./shooter.sh # full logs on failure
|
||||
PARALLEL=0 ./shooter.sh # sequential mode
|
||||
```
|
||||
|
||||
### Preview index mapping
|
||||
Requires `xcparse`: `brew install chargepoint/xcparse/xcparse`.
|
||||
|
||||
Previews are grouped in blocks of 5 (EN, DE, ES, FR, NL):
|
||||
- 0–4: Overview tab
|
||||
- 5–9: Components tab
|
||||
- 10–14: Batteries tab
|
||||
- 15–19: Chargers tab
|
||||
- 20–24: Systems list
|
||||
- 25–29: Parts Library
|
||||
- 30–34: Load editor (CalculatorView)
|
||||
- 35–39: Battery editor
|
||||
- 40–44: Charger editor
|
||||
### How it works
|
||||
|
||||
### Key patterns for preview-friendly views
|
||||
1. `shooter.sh` reads `screenshot.config` for scheme, bundle ID, devices, and languages.
|
||||
2. Builds once with `build-for-testing`, then runs `test-without-building` per language.
|
||||
3. Per language run: erases simulator, sets locale via `simctl spawn ... defaults write`, suppresses system notifications (DND, Apple Intelligence), overrides status bar (9:41, full battery).
|
||||
4. `xcparse` extracts screenshot attachments from `.xcresult` bundles into `Shots/Screenshots/{device-slug}/{lang}/`.
|
||||
5. Devices run in parallel (languages sequential per device — same simulator).
|
||||
|
||||
- **LoadsView** accepts an `initialTab` parameter (`LoadsView.ComponentTab`) to control which tab is shown. Wrap in `NavigationStack` to get the navigation bar.
|
||||
- **ComponentLibraryView** accepts an optional `viewModel` parameter via `init(viewModel:onSelect:)`. Use `ComponentLibraryViewModel(previewItems:)` to inject mock data and avoid network dependency.
|
||||
- All preview wrappers inject `.modelContainer(container)` (in-memory) and `.environmentObject(UnitSystemSettings())`.
|
||||
### Test structure
|
||||
|
||||
### Localization limitation
|
||||
- **Test target**: `CableUITestsScreenshot` (scheme: `CableScreenshots`, test plan: `CableScreenshots.xctestplan`)
|
||||
- **Test file**: `CableUITestsScreenshot/CableUITestsScreenshot.swift`
|
||||
- **Sample data**: `UITestSampleData.swift` — seeded via `--uitest-sample-data` launch argument, cleared via `--uitest-reset-data`
|
||||
|
||||
`.environment(\.locale, Locale(identifier: "xx"))` does **not** affect `String(localized:defaultValue:)` — those resolve from the app bundle, not the SwiftUI environment. All preview screenshots render in the system language. For multi-language screenshots, use UI tests with `-AppleLanguages` launch arguments or change the Xcode scheme language.
|
||||
### Screenshot inventory
|
||||
|
||||
| # | Name | Source |
|
||||
|---|------|--------|
|
||||
| 01 | OnboardingSystemsView | Empty state after reset |
|
||||
| 02 | OnboardingSystemView | New system overview |
|
||||
| 03 | LoadEditorView | CalculatorView for new load |
|
||||
| 04 | ComponentSelectorView | Component library (network) |
|
||||
| 05 | SystemsWithSampleData | Systems list with sample data |
|
||||
| 06 | AdventureVanOverview | Overview tab |
|
||||
| 07 | AdventureVanLoads | Components tab |
|
||||
| 08 | BillOfMaterials | System BOM sheet |
|
||||
| 09 | AdventureVanCalculator | Load calculator |
|
||||
| 10 | AdventureVanBatteries | Batteries tab |
|
||||
| 11 | BatteryEditor | Battery editor |
|
||||
| 12 | AdventureVanChargers | Chargers tab |
|
||||
| 13 | ChargerEditor | Charger editor |
|
||||
|
||||
### Accessibility identifiers for UI tests
|
||||
|
||||
Key identifiers used by the screenshot tests: `create-system-button`, `systems-list`, `system-overview`, `overview-tab`, `components-tab`, `batteries-tab`, `chargers-tab`, `loads-list`, `batteries-list`, `chargers-list`, `system-bom-button`, `system-bom-close-button`, `library-view-close-button`, `create-component-button`, `select-component-button`.
|
||||
|
||||
### Preview-friendly view inits
|
||||
|
||||
- **LoadsView** accepts `initialTab` (`LoadsView.ComponentTab`) to control which tab is shown.
|
||||
- **ComponentLibraryView** accepts an optional `viewModel` via `init(viewModel:onSelect:)`. Use `ComponentLibraryViewModel(previewItems:)` to bypass network.
|
||||
|
||||
## Model Definitions
|
||||
|
||||
|
||||
Reference in New Issue
Block a user