fix(test): stub WebSocket in setupTests so rpcCall fails fast

770's HTTP→read-RPC migration replaced fetch-based agent calls with
rpcCall over WebSocket. setupTests.ts only mocks fetch though, so the
real jsdom WebSocket runs — and jsdom's WebSocket implementation
asynchronously fires its connection-failure error after ~9 seconds
(via internal Timeout._onTimeout). Tests that await component-mount
state (like App.test.tsx > calls getCurrentProject() on mount) hang
on that pending promise and time out at 10s.

This silently broke 1 test on master (App.test.tsx getCurrentProject
on mount) and cascaded into 16 failures in any worktree where the
test file count changed and timing shifted (804, 806).

Fix: replace the global WebSocket constructor with a stub that
immediately fires onerror + onclose on the next microtask. rpcCall
sees the error and rejects synchronously; components catch and continue
rendering with empty state. Tests pass without flake.

Verified locally: vitest run → 349/349 pass.
This commit is contained in:
dave
2026-04-28 17:05:53 +00:00
parent 619bdd9c82
commit 2f6a221f09
+25
View File
@@ -1,6 +1,31 @@
import "@testing-library/jest-dom"; import "@testing-library/jest-dom";
import { beforeEach, vi } from "vitest"; import { beforeEach, vi } from "vitest";
// Default WebSocket stub: every `new WebSocket(...)` immediately fires
// `onerror` + `onclose` on the next microtask. Without this, `rpcCall` from
// `./api/rpc` (added by 770's HTTP→read-RPC migration) opens a real jsdom
// WebSocket that hangs ~9s before firing its connection-failure error,
// making any test that mounts a component calling `listAgents()` time out.
// Tests that need real WS responses should override per-test with
// `vi.stubGlobal("WebSocket", ...)`.
class FailingWebSocket {
onopen: ((ev: Event) => void) | null = null;
onmessage: ((ev: MessageEvent) => void) | null = null;
onerror: ((ev: Event) => void) | null = null;
onclose: ((ev: CloseEvent) => void) | null = null;
readyState = 0;
constructor(_url: string) {
queueMicrotask(() => {
this.readyState = 3;
this.onerror?.(new Event("error"));
this.onclose?.(new CloseEvent("close"));
});
}
send(_data: string) {}
close() {}
}
vi.stubGlobal("WebSocket", FailingWebSocket);
// Provide a default fetch mock so components that call API endpoints on mount // Provide a default fetch mock so components that call API endpoints on mount
// don't throw URL-parse errors in the jsdom test environment. Tests that need // don't throw URL-parse errors in the jsdom test environment. Tests that need
// specific responses should mock the relevant `api.*` method as usual. // specific responses should mock the relevant `api.*` method as usual.