From 693e18bfefe0767a618f7552759157221a8a85ac Mon Sep 17 00:00:00 2001 From: A <258483684+la14-1@users.noreply.github.com> Date: Mon, 23 Feb 2026 20:19:39 -0800 Subject: [PATCH] test: mock node:child_process to fix flaky cmdUpdate timeout (#1831) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "should handle update failure gracefully" test triggered a real execSync("curl -fsSL .../install.sh | bash") via performUpdate() when the mocked remote version differed from the current version. In isolation this completes in ~5s, but under full-suite concurrency (52 files, 1897 tests) network contention caused it to timeout at 58267ms — far exceeding the 5000ms limit. This also violated CLAUDE.md: "no subprocess spawning". Also mock spawn() used by spawnBash() for cmdRun tests, firing the "close" event immediately (exit code 0) so Promise-based callers resolve without hanging. Result: 1897 pass, 0 fail, full suite runs in 3.15s. Agent: test-engineer Co-authored-by: B <6723574+louisgv@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.5 --- .../commands-update-download.test.ts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/cli/src/__tests__/commands-update-download.test.ts b/cli/src/__tests__/commands-update-download.test.ts index 262d5230..a1bbb72e 100644 --- a/cli/src/__tests__/commands-update-download.test.ts +++ b/cli/src/__tests__/commands-update-download.test.ts @@ -52,6 +52,31 @@ mock.module("@clack/prompts", () => ({ isCancel: () => false, })); +// Mock node:child_process to prevent real subprocess calls in tests: +// - execSync: used by performUpdate() to run curl|bash install — without this mock, +// "should handle update failure gracefully" downloads the real install script from +// the network, causing a 58s timeout under full-suite concurrency (CLAUDE.md violation). +// - spawn: used by spawnBash() to run downloaded scripts — mock must fire the "close" +// event immediately (code 0) so Promise-based callers resolve rather than hanging. +mock.module("node:child_process", () => ({ + execSync: mock(() => {}), + execFileSync: mock(() => {}), + spawn: mock(() => { + type Handler = (...args: unknown[]) => void; + const child = { + on: mock((event: string, cb: Handler) => { + if (event === "close") { + queueMicrotask(() => cb(0, null)); + } + return child; + }), + stdout: { on: mock(() => {}) }, + stderr: { on: mock(() => {}) }, + }; + return child; + }), +})); + // Import commands after mock setup const { cmdUpdate, cmdRun } = await import("../commands.js");