test(goldens): switch default locale to de + handbook gap coverage (stacked on #541)#562
Merged
TaprootFreak merged 6 commits intoMay 25, 2026
Conversation
Switches wrapForGolden's default Locale from 'en' to 'de' so the Goldens match the German UI that the Maestro handbook captures with de_CH simulator locale. This unblocks unifying handbook screenshots and golden baselines — without the switch the handbook would lose German strings. Adds three new gap-coverage tests for handbook pages without a Golden: - create_wallet revealed state (handbook 05-seed-revealed) - settings_seed revealed state (handbook 19-settings-seed-revealed) - SettingsConfirmLogoutWalletSheet modal (handbook 24-settings-delete-wallet) The temporary golden-bootstrap workflow regenerates all baselines on the dfx01 self-hosted runner and uploads them as an artifact. It will be removed in the same PR once the new baselines are committed.
Outputs of golden-bootstrap.yaml on dfx01 run 26343749115:
- 56 existing baselines regenerated in German (the en → de switch
re-renders every screen the locale switch touched, which is
effectively all of them — only icons/empty-state graphics
survived byte-identical from before)
- 3 new baselines for the handbook gap-coverage tests:
create_wallet_page_revealed
settings_seed_page_revealed
settings_confirm_logout_wallet_sheet_default
Spot-checked vs docs/handbook/screenshots/ on de_CH Maestro flows —
the rendered German strings match (Wallet-Sicherung, Hier tippen um
anzuzeigen, …). The 12 recovery words on the revealed Golden display
in the same 2-column grid as the handbook screenshot.
Removes .github/workflows/golden-bootstrap.yaml — it was only needed
to populate this run's baseline artifact.
Material's global ThemeData(fontFamily: 'Open Sans') does NOT propagate through WidgetStatePropertyAll<TextStyle> overrides — Material applies the override 1:1 with no theme-merge fallback. So filledButtonTheme and textButtonTheme's textStyle, which inherited from RealUnitTextStyle.body (no fontFamily) plus copyWith(fontWeight: w600), resolved to Flutter's default font. In headless flutter_test the default is Ahem, which renders every glyph as a filled rectangle — hence the AppFilledButton / AppTextButton labels appearing as horizontal white boxes (one box per word, wrap-aware) in the visual-regression baselines. On real iOS the system font fallback hides the bug, but the buttons still don't render in Open Sans there. Adds fontFamily: RealUnitTextStyle.fontFamily to both button-theme textStyles. Baselines will be regenerated on dfx01 via the temporary golden-bootstrap workflow (re-introduced in this commit, removed once the new baselines are committed).
bd23abd to
81db267
Compare
Outputs of golden-bootstrap.yaml on dfx01 run 26344455196. The previous baselines (commit e738f07) rendered the AppFilledButton/AppTextButton labels as Ahem boxes because the button-textStyle override in lib/styles/themes.dart dropped the Open Sans fontFamily. After the theme fix (81db267 → adds explicit fontFamily on filledButtonTheme/textButtonTheme.textStyle) every button label now renders correctly — verified by spot-check against create_wallet_page_default.png ('Ich habe es gesichert' visible in Open Sans w600 instead of 4 white rectangles). Removes .github/workflows/golden-bootstrap.yaml — done with its second-and-final run for this PR.
This was referenced May 23, 2026
TaprootFreak
added a commit
that referenced
this pull request
May 25, 2026
…ed on #568) (#570) ## Summary Stacked on #568. Phase 1 of the Maestro → Goldens handbook unification plan: the 26 PNGs at `handbook.realunit.app/screenshots/` now come from the same Golden baselines the visual-regression CI verifies on every PR. ## Why - **Single source of truth**: one pixel-checked baseline per handbook page. A UI regression that breaks a Golden also breaks the handbook image before either ships. - **Determinism**: dfx01's headless Skia/Open Sans rendering is byte-stable across CI runs. Maestro's iOS-simulator screenshots drifted on Apple Silicon + iOS 26 driver hangs (mobile-dev-inc/Maestro#3137). - **Cycle time**: the handbook image rebuilds when Goldens change, in seconds — no 30-minute Maestro suite to refresh a page. ## What changed - **`scripts/assemble-handbook-screenshots.sh`** — explicit `handbook-name → golden-path` mapping for all 26 pages (see PR #568 for the audit that built this table). Copies and renames Goldens into a flat output directory the Dockerfile then consumes. Fails loudly if a Golden goes missing. - **`Dockerfile.handbook`** — multi-stage build. Stage 1 (alpine + bash) runs the assembly script. Stage 2 (nginx) copies the assembled screenshots over the legacy `docs/handbook/screenshots/` tree, preserving output paths so the handbook HTML `<img>` links work unchanged. - **`.github/workflows/handbook-build-check.yaml`** — new PR-only validation. Runs the assembly script independently (cheap check before docker spins up), builds the image, starts the container, hits `/healthz`, verifies the auth gate returns 401 on `/de/`, and probes `/screenshots/{01,11,26}.png` to prove the assembled files land on disk. Does **not** push to Docker Hub and does **not** deploy. The develop-push `handbook-deploy.yaml` retains sole ownership of DEV → PRD rollout. ## Out of scope - The legacy `docs/handbook/screenshots/` tree is left in place; the COPY in Dockerfile.handbook overlays it with the assembled output, so the legacy PNGs are harmless. **Phase 2** (Maestro pipeline retirement) decides whether to delete the directory + flow YAMLs. - DEV deploy verification — happens after merge to develop (the deploy pipeline does that automatically). ## Test plan - [ ] `Handbook Build Check` CI green on the PR (docker build + container smoke) - [ ] `Visual Regression` job green on the PR (parallel — no Golden changes here, should pass trivially) - [ ] After merge to develop: `handbook-deploy.yaml` builds the image, DEV-deploy succeeds, `https://dev-handbook.realunit.app/de/` shows the Goldens-sourced screenshots (spot-check 3 pages: welcome, dashboard, terms) - [ ] PRD deploy follows DEV-green, same spot-check on prod URL ## Pre-conditions for merge The stack below this PR must merge in order: #541 → #562 → #568 → this. Each subsequent merge re-targets the PR base automatically.
… (#568) ## Summary Stacked on #562. Closes the 6 remaining handbook→Golden mapping gaps: | # | Handbook page | Golden added | Notes | |---|---|---|---| | 03 | software-wallet-terms | `welcome_page_second_step` | `@visibleForTesting initialShowSecondStep` ctor param | | 09 | pin-confirm | `setup_pin_page_confirming` | `SetupPinMode.confirm` state | | 10 | biometric-prompt | `biometric_prompt_sheet_default` | Flutter `EnableBiometricBottomSheet` — **NOT** an iOS system sheet (Maestro YAML comment misleading) | | 11 | dashboard | `home_page_loaded` | `DashboardView` with mocked price chart | | 17 | settings-backup-pin | `verify_pin_page_seed_backup` | i18n-driven subtitle, no lib refactor | | 26 | terms | `legal_document_page_terms_loaded` | `@visibleForTesting initialMarkdownContent` ctor param | After this PR, the handbook can switch to Golden-sourced screenshots (Phase 1) without leaving any page unmapped. ## Lib refactors Two minimal refactors, both `@visibleForTesting`, both with the production default unchanged: - `lib/screens/welcome/welcome_page.dart` — adds `initialShowSecondStep` (default `false`) - `lib/screens/legal/subpages/legal_document_page.dart` — adds `initialMarkdownContent` (null → unchanged `_loadMarkdown()` path) Driving the second-step / loaded-state via tap + pumpAndSettle was tried first but is fragile in alchemist's hook chain. ## Bootstrap workflow `.github/workflows/golden-bootstrap.yaml` is re-introduced temporarily, push-triggered on this branch. Generates baselines on dfx01, removed once committed. ## Test plan - [ ] Bootstrap workflow completes green on dfx01 - [ ] Baselines downloaded + committed - [ ] Bootstrap workflow removed - [ ] `Visual Regression` job green on final commit - [ ] Spot-check each of the 6 new baselines visually matches its handbook counterpart
# Conflicts: # test/goldens/screens/settings_tax_report/goldens/macos/settings_tax_report_page_default.png # test/goldens/screens/transaction_history/goldens/macos/transaction_history_page_default.png
453ace2
into
feat/visual-regression-pilot
5 of 6 checks passed
TaprootFreak
added a commit
that referenced
this pull request
May 25, 2026
…in de Both PNGs were inherited from pilot's pre-#562 en-locale snapshots during the #562 conflict merge — they were the only goldens not re-rendered in the locale switch, so Visual Regression flagged them (1.94% / 0.40% diff) once the screens started rendering in de. Regenerated on dfx01 against the current de-locale + deterministic-clock setup so both pipelines (de-locale switch + determinism fix) line up.
TaprootFreak
added a commit
that referenced
this pull request
May 26, 2026
Collection PR for follow-ups identified during the #541 review session. Held as a **Draft** while commits accumulate; flipped to ready + merged at the end. ### Likely contents (subject to scope decisions) - `lib/styles/text_styles.dart` — hardcode `fontFamily` directly in `_Body.base/.sm/.xs` + `_Header.h1/.h2/.h4` (root-cause for the latent `appBarTheme.titleTextStyle` Ahem-rendering bug; supersedes the per-theme `copyWith(fontFamily: …)` pin added in #562) - `test/integration/wallet_creation_bitbox_test.dart:194-195` — drop the tautological `appStore.wallet = created; verify(...).called(1);` or replace with a real contract pin - `test/integration/connect_bitbox_flow_test.dart:249,285` — align wall-clock `Future.delayed(fastObserverInterval * 4)` with the `fakeAsync`+`async.elapse` pattern used in `bitbox_reconnect_recovery_test.dart` - `test/goldens/screens/legal/legal_document_golden_test.dart` — replace inline `_termsMarkdownStub` (1:1 copy of production terms) with a synthetic markdown fixture under `test/fixtures/` - Investigate why the dfx01 runner produces ±10–50 byte encoder drift on unrelated golden PNGs during baseline refresh (Skia version pin, build cache, font cache) ### Out of scope - Anything that should go to a dedicated PR (e.g. a real new feature) - #325 release develop → main ### Notes Empty seed commit kept in history so the PR existed before the first real change landed. --------- Co-authored-by: Blume1977 <jana.ruettimann@dfx.swiss> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Stacked on #541 (which is itself the merge bus for #552). Two changes that together unblock unifying the Maestro handbook screenshots with the Golden baselines (see plan at
~/Documents/Claude/realunit-handbook-unification-plan.md):wrapForGoldendefaulted toLocale('en'), so all 59 current Goldens render in English. The Maestro handbook pins the simulator tode_CHand captures German UI — the two pipelines cannot share images while they speak different languages.create_wallet_page_revealed— handbook 05-seed-revealed (state variant ofstate.hideSeed=false)settings_seed_page_revealed— handbook 19-settings-seed-revealed (showSeed=true)settings_confirm_logout_wallet_sheet_default— handbook 24-settings-delete-wallet (modal in initial unchecked state)Mapping audit (Phase 0)
Verified against
.maestro/handbook/*.yaml:verify_pin_page, needs context-aware test setup)legal_document_page_defaultLocalAuthentication, not rendered by Flutter — Skia cannot reproduce it. Will be discussed before Phase 1 (Dockerfile.handbook switch).BackdropFilter validation
The existing
settings_seed_page_defaultGolden already proves that Flutter's headless Skia rendersBackdropFiltercorrectly (the blur is visible, not the historic XCUITest-black-PNG issue). Same applies to the new revealed/hidden state variants and thecreate_wallet_view'sSeedBlurCard.Bootstrap workflow
.github/workflows/golden-bootstrap.yamlis re-introduced temporarily, triggered by push to this branch. It runsflutter test test/goldens --update-goldenson therealunit-appself-hosted dfx01 runner and uploads the regenerated PNGs asgolden-baselines. I download the artifact, commit the baselines intotest/goldens/screens/**/goldens/macos/, then delete the bootstrap workflow file in a follow-up commit — same pattern as the pilot PR.Test plan
golden-bootstrapworkflow run completes green on dfx01golden-bootstrap.yamlremovedVisual Regressionjob in pull-request.yaml green on final commit10-biometric-promptand17-settings-backup-pinbefore promoting to ready-for-reviewOut of scope
Dockerfile.handbookswitch fromdocs/handbook/screenshots/totest/goldens/(Phase 1 of the unification plan)