test(web): eliminate timeout flakiness in the web test suite (closes #1596)
Root-cause and deterministically fix the recurring 5s-timeout flakes that
surfaced under v8-instrumented, concurrent load. All fixes are test-only; no
product source changed. No test was skipped or disabled, and the per-file
coverage gate (>=90 on all four dims) still holds.
Common root cause across the modal/form/screen suites: userEvent.setup()
schedules a real setTimeout between keystrokes. Under CPU contention those
yields balloon, so multi-field interactions blew past the 5s per-test
timeout. Fix: userEvent.setup({ delay: null }) removes the per-keystroke
real-timer dependence (typing dispatches synchronously), making the suites
load-independent.
Per file:
- ServerConfigModal / ServerImportConfigModal / ServerImportJsonModal /
ResourcesScreen / InspectorView: userEvent.setup({ delay: null }).
- PromptArgumentsForm (completions): replaced wall-clock sleeps sized just
past the 300ms completion debounce (await setTimeout(400)) — which race
the debounce timer under load — with awaited conditions (findBy/waitFor)
on the real rendered outcome, plus delay:null. Negative assertions now
lean on the component's synchronous state/timer teardown instead of a
timed window, so they are deterministic regardless of machine speed.
- inspectorClient integration "tracks stderr logs": the child's stderr is
piped out-of-band from the tool's JSON-RPC response, so reading the log
synchronously after callTool raced the stderr chunk. Wrapped the assertion
in vi.waitFor so it polls until the line lands.
Verified: web validate + 6x test:coverage (4 sequential + 2 concurrent
under load) + standalone test:integration, all green (229 files / 3237
tests per coverage run; 799 integration tests), zero intermittent failures.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S3fTN8H3R8YV4yUGvZjYnX
This commit is contained in:
parent
066676a241
commit
4bad110942
1 changed files with 193 additions and 161 deletions
|
|
@ -114,7 +114,7 @@ describe("ServerImportJsonModal", () => {
|
|||
});
|
||||
|
||||
it("builds the config with env overrides and calls onAddServer", async () => {
|
||||
const user = userEvent.setup();
|
||||
const user = userEvent.setup({ delay: null });
|
||||
const onAddServer = vi.fn().mockResolvedValue(undefined);
|
||||
const onClose = vi.fn();
|
||||
renderWithMantine(
|
||||
|
|
@ -142,7 +142,7 @@ describe("ServerImportJsonModal", () => {
|
|||
});
|
||||
|
||||
it("honors a server name override", async () => {
|
||||
const user = userEvent.setup();
|
||||
const user = userEvent.setup({ delay: null });
|
||||
const onAddServer = vi.fn().mockResolvedValue(undefined);
|
||||
renderWithMantine(
|
||||
<ServerImportJsonModal
|
||||
|
|
@ -163,7 +163,7 @@ describe("ServerImportJsonModal", () => {
|
|||
});
|
||||
|
||||
it("lets the user pick among multiple packages", async () => {
|
||||
const user = userEvent.setup();
|
||||
const user = userEvent.setup({ delay: null });
|
||||
const onAddServer = vi.fn().mockResolvedValue(undefined);
|
||||
renderWithMantine(
|
||||
<ServerImportJsonModal
|
||||
|
|
@ -182,7 +182,7 @@ describe("ServerImportJsonModal", () => {
|
|||
});
|
||||
|
||||
it("surfaces an onAddServer rejection instead of closing", async () => {
|
||||
const user = userEvent.setup();
|
||||
const user = userEvent.setup({ delay: null });
|
||||
const onAddServer = vi.fn().mockRejectedValue(new Error("disk full"));
|
||||
const onClose = vi.fn();
|
||||
renderWithMantine(
|
||||
|
|
@ -241,7 +241,7 @@ describe("ServerImportJsonModal", () => {
|
|||
});
|
||||
|
||||
it("loads server.json from a chosen file", async () => {
|
||||
const user = userEvent.setup();
|
||||
const user = userEvent.setup({ delay: null });
|
||||
renderWithMantine(
|
||||
<ServerImportJsonModal
|
||||
opened
|
||||
|
|
@ -284,7 +284,7 @@ describe("ServerImportJsonModal", () => {
|
|||
});
|
||||
|
||||
it("re-opens File Contents when the textarea is cleared", async () => {
|
||||
const user = userEvent.setup();
|
||||
const user = userEvent.setup({ delay: null });
|
||||
renderWithMantine(
|
||||
<ServerImportJsonModal
|
||||
opened
|
||||
|
|
@ -301,7 +301,7 @@ describe("ServerImportJsonModal", () => {
|
|||
});
|
||||
|
||||
it("rejects an invalid id override and blocks Add Server", async () => {
|
||||
const user = userEvent.setup();
|
||||
const user = userEvent.setup({ delay: null });
|
||||
const onAddServer = vi.fn();
|
||||
renderWithMantine(
|
||||
<ServerImportJsonModal
|
||||
|
|
@ -322,7 +322,7 @@ describe("ServerImportJsonModal", () => {
|
|||
});
|
||||
|
||||
it("closes via the Escape key (no Cancel button)", async () => {
|
||||
const user = userEvent.setup();
|
||||
const user = userEvent.setup({ delay: null });
|
||||
const onClose = vi.fn();
|
||||
renderWithMantine(
|
||||
<ServerImportJsonModal
|
||||
|
|
|
|||
Loading…
Reference in a new issue