test: harden Modal visual regression — realistic content + stable topOffset#1096
Merged
TaprootFreak merged 1 commit intoMay 12, 2026
Merged
Conversation
…ffset, deterministic wait
Three improvements after inspecting the first round of CI-generated
baselines:
1. Decorator (.storybook/preview.tsx)
The previous header surrogate was an empty 64px-tall blue band with
no content; the modalRootRef anchor sat at y=64 but was a zero-size
div, and the screenshots were taken before Modal's ResizeObserver
had updated topOffset, so the fullscreen modal covered the entire
viewport including the simulated header. The decorator now renders
a visible "DFX Services" label inside the header band, places the
modalRootRef anchor as a real positioned div, and matches the
layout shape the app actually uses, so the captured baselines show
the fullscreen modal sitting cleanly below the header.
2. Spec wait (e2e/storybook/modal-visual.spec.ts)
Added an explicit wait for the modal portal (any element with
`.z-50`) to become visible, then two animation frames before the
snapshot. This removes the race between Modal's post-mount
ResizeObserver effect and Playwright's `toHaveScreenshot`, so the
captured `top` style is the final stable value, not the initial 0.
3. Story content (src/components/modal.stories.tsx)
Replaced the placeholder text with realistic content that mirrors
what the deployed app actually puts inside each variant:
- Fullscreen: a KYC-style identity-verification step with a step
indicator, three labeled inputs, a privacy notice and a button
row. Mirrors the layout of KYC, Safe Deposit, Buy/Sell flows.
- Dialog: a transaction-refund confirmation card with a detail
table and Confirm/Cancel buttons. Mirrors the chargeback,
limit-request and recall modals shipped in #1048.
The Default story still renders `<Modal isOpen>` with no `variant`
prop, so the byte-equality between Default and Fullscreen remains the
load-bearing regression signal for the #1048 bug class.
TaprootFreak
added a commit
that referenced
this pull request
May 17, 2026
Six baselines generated by the Linux CI runner after the hardening in #1096 (visible header surrogate, deterministic ResizeObserver wait, realistic story content). Sanity checks before commit: - modal-default-* and modal-fullscreen-* are byte-identical at both viewports (load-bearing: this is the property that catches the #1048 default-flip regression). - modal-dialog-* is distinct at both viewports (centered card on translucent backdrop, separate Refund-transaction content). - The blue layout header is visible above every fullscreen modal, confirming Modal's topOffset/ResizeObserver path is actually exercised by the snapshot. - Inter font is applied (no system fallback). Captured by https://github.com/DFXswiss/services/actions/runs/25752660204
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.
Stacked on top of #1093. Follow-up after inspecting the first CI baseline run from #1095 (now closed): the captured snapshots were technically valid but visually weak — the simulated layout header was hidden, the fullscreen modal covered the full viewport (because the screenshot was taken before `ResizeObserver` updated `topOffset`), and the story content was generic placeholder text.
Three hardening changes
1. Stable `topOffset` in the decorator + visible header
`.storybook/preview.tsx` now renders a real "DFX Services" header band, and the `modalRootRef` anchor is a positioned `
2. Deterministic wait in the spec
The spec now:
This removes the race that caused the previous baselines to show `top: 0` instead of the stabilised `top: 64px`.
3. Realistic story content
`src/components/modal.stories.tsx` swaps the placeholder text for content that mirrors what the deployed app actually renders:
The Default story still renders `` with no `variant`, so the byte-equality between Default and Fullscreen remains the load-bearing regression signal for the #1048 bug class.
Visual sanity check (local, --update-snapshots)
Next steps after merge