2026-04-23 Vitest Ubuntu Research Note
2026-04-23 Vitest Ubuntu Research Note
Section titled “2026-04-23 Vitest Ubuntu Research Note”Symptoms
Section titled “Symptoms”Hang #1: Vitest unit suite stalls on Ubuntu
Section titled “Hang #1: Vitest unit suite stalls on Ubuntu”Observed in GitHub Actions run 24803637727 after:
✓ src/components/WizardReviewStep.test.tsx (1 test) 78msThe job then sat idle until the 20-minute timeout. The Ubuntu job log later showed orphaned vitest worker processes and esbuild still alive when GitHub Actions cleaned the job up.
Run URL:
https://github.com/brownjuly2003-code/ab-test-research-designer/actions/runs/24803637727
Hang #2: Playwright click timeout on Ubuntu
Section titled “Hang #2: Playwright click timeout on Ubuntu”Observed in GitHub Actions run 24811054759:
Error: locator.click: Test timeout of 45000ms exceeded.The failing step was not a generic early click. The failed locator was:
app/frontend/src/test/e2e-smoke.spec.ts:52await page.getByRole("button", { name: "Export Markdown" }).click();Run URL:
https://github.com/brownjuly2003-code/ab-test-research-designer/actions/runs/24811054759
Sources Consulted
Section titled “Sources Consulted”- Local version checks from
app/frontend/package.jsonon April 23, 2026:vitest@^3.2.4jsdom@^28.1.0vitest-axe@^0.1.0@playwright/test@^1.58.2
- Vitest issue
#835(jsdom loading issue if threads false):https://github.com/vitest-dev/vitest/issues/835 - Vitest issue
#8133(Terminating Worker Thread error since Vitest 3.2.0):https://github.com/vitest-dev/vitest/issues/8133 - Vitest
v1.6.0release notes:https://github.com/vitest-dev/vitest/releases/tag/v1.6.0 - GitHub Actions runner image release
Ubuntu 24.04 (20260420):https://github.com/actions/runner-images/releases/tag/ubuntu24/20260420.95 - Playwright actionability docs:
https://playwright.dev/docs/actionability - Playwright issue
#12193(Weird issues with unreliable test results, passes and fails arbitrarily):https://github.com/microsoft/playwright/issues/12193
Hypothesis For Hang #1 (Vitest Unit) With Evidence
Section titled “Hypothesis For Hang #1 (Vitest Unit) With Evidence”Final diagnosis
Section titled “Final diagnosis”The Ubuntu hang was not caused by vitest-axe, jsdom, Node 22, or the Ubuntu 24.04 runner image directly.
The concrete root cause was a render loop in app/frontend/src/components/SidebarPanel.tsx:
compareCandidateswas recomputed as a fresh array on every render.- A
useEffectdepended on that fresh array. - The effect always called
setSelectedComparisonProjectIds(current.filter(...)). - Even when
currentwas already[],current.filter(...)returned a new empty array reference. - React treated that as a state change and re-rendered again.
- Under Vitest/jsdom
act(...), the first render ofSidebarPanelnever settled on Linux, so the worker looked like a deadlock.
Evidence chain
Section titled “Evidence chain”- The full Ubuntu suite previously appeared to stop after
WizardReviewStep.test.tsx, but a local Linux reproduction narrowed the unfinished files to:src/App.test.tsxsrc/test/a11y-api-keys.test.tsxsrc/test/a11y-sidebar.test.tsx
- A minimal Linux probe that only imported
SidebarPanelcompleted quickly. - A minimal Linux probe that only rendered
SidebarPanelwithoutaxestill hung. - A staged probe printed
STAGE: before renderand then hung insiderenderIntoDocument(<SidebarPanel />), beforeflushEffects()and beforeunmount(). - A temporary patch in the Linux container that stopped the
selectedComparisonProjectIdseffect from writing the same selection again immediately removed the hang. - After that temporary patch:
a11y-sidebar.test.tsxran to completion and surfaced real accessibility failures instead of hanging.a11y-api-keys.test.tsxpassed.App.test.tsxran to completion and surfaced one separate stale-UI regression instead of hanging.- the full Linux
npm run test:unitcompleted green.
Why the upstream/tooling hypotheses were rejected
Section titled “Why the upstream/tooling hypotheses were rejected”pool: "threads"vspool: "forks"was tested on isolated Linux runs and both still hung before the local code fix.- The Ubuntu runner image changed on April 21, 2026, but the same hang reproduced in a local Linux Playwright container, so the runner image was not sufficient to explain it.
- The task brief mentioned Vitest
1.x, but the current repo was already onvitest 3.2.4, so the1.xrelease notes were informative background, not a direct match.
Hypothesis For Hang #2 (Playwright Click) With Evidence
Section titled “Hypothesis For Hang #2 (Playwright Click) With Evidence”Final diagnosis
Section titled “Final diagnosis”The Playwright failure was a stale smoke test, not a backend-readiness race.
SensitivityOverview.tsx now puts report export actions inside a hidden menu:
- the visible control is
Export Export MarkdownandExport HTMLlive inside#report-export-menu- the menu is hidden until
exportMenuOpenbecomestrue
The smoke spec still clicked Export Markdown and Export HTML directly without opening the menu first.
Evidence chain
Section titled “Evidence chain”- The failing GH Actions line was the direct click on
Export Markdown, after the app had already:- loaded successfully
- finished analysis
- rendered
Deterministic experiment design
- The current component code in
SensitivityOverview.tsxshows:- a dedicated
Exportbutton - submenu buttons hidden behind
display: exportMenuOpen ? "grid" : "none"
- a dedicated
- After updating the smoke spec to:
- click
Export - wait for
Export Markdown/Export HTMLto become visible - then click the submenu entry
the Playwright smoke run passed locally through
scripts/run_frontend_e2e.py.
- click
Proposed Fix Path For Each, Ranked By Confidence
Section titled “Proposed Fix Path For Each, Ranked By Confidence”Hang #1 (Vitest unit)
Section titled “Hang #1 (Vitest unit)”- High confidence: make the
SidebarPanelcomparison-selection effect idempotent and stop using invalid listbox semantics that surfaced once the hang was removed. - Medium confidence: restore the per-project
Comparebutton that the store logic still supported but the sidebar UI no longer rendered. - Low confidence / not needed: change Vitest pool settings or pin different Vitest versions.
Hang #2 (Playwright click)
Section titled “Hang #2 (Playwright click)”- High confidence: update
e2e-smoke.spec.tsto open theExportmenu first and assert submenu visibility before clicking. - Low confidence / not needed: alter backend startup timing in
run_frontend_e2e.py. - Low confidence / not needed: change Chromium flags or headless settings.
Rejected Options And Why
Section titled “Rejected Options And Why”vitest-axequarantine or test deletion: rejected because the render loop reproduced withoutaxe.- Global Vitest pool/config changes: rejected because isolated Linux runs still hung in both
threadsandforksbefore the local component fix. - Blaming Node 22 or Ubuntu 24.04 image alone: rejected because the same render loop reproduced in a local Linux container.
- Playwright readiness sleeps: rejected because the failing click happened after analysis output was already visible.
- Re-disabling frontend unit tests on Ubuntu: rejected because the root cause was local and fixable.