test: mock node:child_process to fix flaky cmdUpdate timeout (#1831)

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 <noreply@anthropic.com>
This commit is contained in:
A 2026-02-23 20:19:39 -08:00 committed by GitHub
parent afde749d68
commit 693e18bfef
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -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");