Skip to content

ci/test: fix two flaky visual/browser test failures (firefox hang retry + Modal deflake)#2641

Open
mfal wants to merge 2 commits into
mainfrom
claude/visual-regression-flaky-tests-95002b
Open

ci/test: fix two flaky visual/browser test failures (firefox hang retry + Modal deflake)#2641
mfal wants to merge 2 commits into
mainfrom
claude/visual-regression-flaky-tests-95002b

Conversation

@mfal

@mfal mfal commented Jul 14, 2026

Copy link
Copy Markdown
Member

Fixes two unrelated flaky failures found by analyzing the failed GitHub Actions runs.


1. Run scheduled visual tests — firefox intermittently hangs (~15%, 6/40 runs)

Analysis of the failed runs:

  • Not snapshot/pixel regressions — every test that runs passes, zero assertion (×) failures.
  • Failing runs are missing exactly one test-file summary (81 vs. 82 in a green run).
  • The missing file is always a firefox instance (e.g. Switch.browser.test.tsx); webkit always completes.
  • ResizeObserver loop completed with undelivered notifications. is a red herring — appears identically (4×) in passing runs too.

Root cause: firefox intermittently hangs on a single visual test file in headless CI, aborting the run with exit code 1. Same class of browser flakiness for which chromium was already disabled and file parallelism already turned off.

Fix: wrap the Run visual tests step in a retry loop (up to 3 attempts). A hang can't be recovered by vitest's per-test retry (the whole process is killed), so we re-run test:visual in a fresh vitest/browser process. Successful ^build deps come from the nx cache, so retries only re-execute the visual tests. The Slack alert still fires only when all three attempts fail. Expected residual failure rate ≈ 0.15³ ≈ 0.3%.

Note: this is a symptom mitigation, not a root-cause fix for the firefox hang. Verification can only happen on real scheduled runs (2×/day) or a manual workflow_dispatch once on main.

2. Run tests — flaky Modal animation-timing test

Analysis: the recurring Run tests failures were always a single assertion in Modal.browser.test.tsx > useOnClosed is called when the closing animation has finished (expect(element).not.toBeInTheDocument()). It is flaky, not a regression: it passed/failed on unrelated commits (including a pure version-bump commit) and the latest main run was green.

Root cause: the test waited a fixed 550ms (sleep(50) + sleep(500)) for the close animation to finish and the modal to unmount, but the animation lasts --transition--duration--slow = 400ms, leaving only ~150ms for animationend + React state update + unmount. Under CI load that margin is too tight.

Fix: replace the fixed sleep with condition-based waiting (vitest.waitFor, 2s timeout) that polls until the modal has unmounted, removing the race entirely.

Verification: ran the Modal browser test in webkit locally across repeated runs — passes reliably (8 passed).

🤖 Generated with Claude Code

…x hangs

The scheduled visual regression workflow failed on ~15% of runs (6/40).
Investigation of the failed runs showed these are not snapshot/pixel
regressions: every test that runs passes and there are zero assertion
failures. Instead, firefox intermittently *hangs* on a single visual test
file in headless CI (webkit always completes), so exactly one test-file
summary is missing and the run aborts with exit code 1.

A hang cannot be recovered by vitest's per-test `retry` (the process is
killed as a whole, so there is nothing to re-run), so wrap the step in a
retry loop that re-runs `test:visual` in a fresh vitest/browser process
up to three times. Successful `^build` deps come from the nx cache, so
retries only re-execute the visual tests. The Slack alert still fires only
when all three attempts fail.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for ./packages/components/

Status Category Percentage Covered / Total
🔵 Lines 82.77% 298 / 360
🔵 Statements 83.06% 304 / 366
🔵 Functions 88.6% 70 / 79
🔵 Branches 72.25% 138 / 191
File CoverageNo changed files found.
Generated in workflow #5575 for commit 338f054 by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Preview Deployment

Preview environments are ready:

Type URL
docs pr-2641.docs.review.flow-components.de
storybook pr-2641.storybook.review.flow-components.de

Images:

  • docs: ghcr.io/mittwald/flow/docs:pr-2641
  • storybook: ghcr.io/mittwald/flow/storybook:pr-2641

`useOnClosed is called when the closing animation has finished` intermittently
failed in CI (only in the "Run tests" workflow, always this single assertion:
`expect(element).not.toBeInTheDocument()`). It is a timing-dependent flaky test,
not a regression: it passed and failed on unrelated commits (e.g. a version-bump
commit), and the latest main run was green.

Root cause: the test waited a fixed 550ms (sleep(50) + sleep(500)) for the modal
close animation to finish and unmount, but the animation lasts
`--transition--duration--slow` = 400ms, leaving only ~150ms for animationend +
React state update + unmount. Under CI load that margin is too tight and the
modal is still in the document at 550ms.

Replace the fixed sleep with condition-based waiting (`vitest.waitFor`) that
polls until the modal has unmounted (2s timeout), removing the race entirely.

Verified locally in webkit: test passes reliably across repeated runs.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@mfal mfal changed the title ci(visual-tests): retry scheduled visual tests to absorb flaky firefox hangs ci/test: fix two flaky visual/browser test failures (firefox hang retry + Modal deflake) Jul 14, 2026
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