From 2f6a221f09f96c39792a82619bb7f5cb38110397 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 28 Apr 2026 17:05:53 +0000 Subject: [PATCH] fix(test): stub WebSocket in setupTests so rpcCall fails fast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- frontend/src/setupTests.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/frontend/src/setupTests.ts b/frontend/src/setupTests.ts index 1c857b4a..f7d022a8 100644 --- a/frontend/src/setupTests.ts +++ b/frontend/src/setupTests.ts @@ -1,6 +1,31 @@ import "@testing-library/jest-dom"; 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 // don't throw URL-parse errors in the jsdom test environment. Tests that need // specific responses should mock the relevant `api.*` method as usual.