Skip to content

test: harden Modal visual regression — realistic content + stable topOffset#1096

Merged
TaprootFreak merged 1 commit into
test/modal-visual-regressionfrom
test/modal-visual-improvements
May 12, 2026
Merged

test: harden Modal visual regression — realistic content + stable topOffset#1096
TaprootFreak merged 1 commit into
test/modal-visual-regressionfrom
test/modal-visual-improvements

Conversation

@TaprootFreak

Copy link
Copy Markdown
Collaborator

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 `

` (not an empty zero-size element). The fullscreen modal sits cleanly below the header in every baseline — matches how the real app composes the layout.

2. Deterministic wait in the spec

The spec now:

  • waits for the `.z-50` portal element to become visible (Modal has reached its second render after `mounted` flips),
  • awaits `document.fonts.ready`,
  • yields two animation frames so the `ResizeObserver`-driven `top` style update is committed before the snapshot.

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:

  • Fullscreen: KYC-style identity-verification step with step-indicator, three labelled inputs, privacy notice, Cancel + Continue. Mirrors KYC, Safe Deposit, Buy/Sell flows.
  • Dialog: transaction-refund confirmation card with a detail table (Amount, Recipient IBAN, Reference) and Cancel + Confirm refund buttons. Mirrors the chargeback / limit-request / recall modals shipped in feat: compliance improvements (limit request, stop transaction, chargeback) #1048.

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)

Property Result
Default == Fullscreen byte-identical at both viewports
Dialog distinct (different SHA-1) at both viewports
Layout header visible above the fullscreen modal ✅ — blue "DFX Services" band, modal starts at y=64
Dialog backdrop covers the header (matches app behaviour)
Inter font applied (no system fallback)
Realistic content readable (form fields, detail table)

Next steps after merge

  1. This PR merges into `test/modal-visual-regression`.
  2. The parent test: add visual regression coverage for Modal variants #1093 CI re-runs, `Storybook visual regression` produces a fresh, more meaningful set of baseline candidates in `visual-regression-diff.zip`.
  3. A final stacked PR commits those baselines into `e2e/storybook/snapshots/modal-visual.spec.ts/`.
  4. Subsequent test: add visual regression coverage for Modal variants #1093 runs are green → gate is live.

…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 TaprootFreak marked this pull request as ready for review May 12, 2026 17:59
@TaprootFreak TaprootFreak requested a review from davidleomay as a code owner May 12, 2026 17:59
@TaprootFreak TaprootFreak merged commit 5193348 into test/modal-visual-regression May 12, 2026
@TaprootFreak TaprootFreak deleted the test/modal-visual-improvements branch May 12, 2026 17:59
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant