Skip to content

Flaky web test: ServerImportJsonModal debounce guard fails under a full parallel run #2250

Description

@cliffhall

The web unit test ServerImportJsonModalguards against a live edit made before the debounce re-validates fails intermittently inside a full npm run local:gate, and passes every time in isolation.

Evidence

Observed across four gate runs on the same branch (#2245, whose diff touches zero files under clients/ — only .claude/, AGENTS.md, docs/ and scripts/ — so it cannot be the cause):

gate run stage machine result
1 quiet clean, exit 0
2 coverage load 50–126 failed, 24 945 ms for the file
3 coverage load ~150 a different test failed (ServerSettingsModal › SEP-2350), 90 787 ms
4 validate quiet-ish (load ~18–40) failed again, 11 275 ms for the file / 1 567 ms for the test

In isolation it is stable: 6/6 runs pass, ~11 s each.

npx vitest run --project=unit \
  src/components/groups/ServerImportJsonModal/ServerImportJsonModal.test.tsx

Run 4 is the one that matters. I had initially attributed runs 2 and 3 to machine contention — another process had the box at load 100+ — but run 4 failed on a quiet machine, in the validate stage rather than coverage, with the test itself taking only 1.6 s. Contention alone does not explain that, so the honest read is a real timing race that parallelism makes more likely, not merely a slow machine.

Why it is worth fixing rather than tolerating

local:gate promises that a green local run means CI passes. A test that fails ~50% of full runs and 0% of isolated ones inverts that: it makes the gate a coin flip and trains people to re-run rather than read a red result — the same "channel nobody fails on" failure that Lint has no warning tier exists to prevent.

Where to look

clients/web/src/components/groups/ServerImportJsonModal/ServerImportJsonModal.test.tsx. The name says debounce, so the likely shapes are a real-timer wait racing a fake-timer advance, or an assertion that depends on a setTimeout landing before a React flush. ServerSettingsModalmaps the OAuth insufficient-scope policy into settings (SEP-2350) failed the same way once and may share a root cause; check both before assuming they are independent.

Acceptance

  • The test passes deterministically inside a full npm run local:gate, not only in isolation — demonstrated over several consecutive runs.
  • The fix removes the race rather than widening a timeout, or says explicitly why a timeout is the right lever here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingv2Issues and PRs for v2

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions