From e47af77c5a9e43524243833a054e61a5ffbd246e Mon Sep 17 00:00:00 2001 From: Vance Ingalls Date: Mon, 13 Jul 2026 21:26:53 +0000 Subject: [PATCH] test(cli): stabilize flaky install-lock wait-notice test with fake timers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adopt the fake-timer pattern the sibling "recovers when a crashed reclaimer leaves both lock directories" test in the same file already uses. Without fake timers, if the dynamic `import("./manager.js")` beat between `installFsMocks({ initialMtimeMs: Date.now() })` and the `withInstallLock` call exceeds `staleMs` (50 ms on a busy shared runner with `vi.resetModules()` per beforeEach), the new immediate-stale short-circuit added in #2328 fires on iteration 1, breaks out before `waitedMs` reaches `waitNoticeMs=20`, and no "Waiting for another hyperframes process" warn ever emits — the assertion at `manager.test.ts:428` (`expected false to be true`) then fails. Under fake timers, `Date.now()` is frozen at the mtime seed, so the lock stays non-stale across the dynamic import and the wait-notice branch observes real polling; `vi.advanceTimersByTimeAsync(staleMs + pollMs * 5)` then drives the loop past both the wait-notice threshold and the stale deadline so the reclaim + acquisition still resolves. Test-only change; no production-code diff. Verified 27/27 in `packages/cli/src/browser/manager.test.ts` under `vitest run`. --- packages/cli/src/browser/manager.test.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/browser/manager.test.ts b/packages/cli/src/browser/manager.test.ts index d0f46af023..893252e3a3 100644 --- a/packages/cli/src/browser/manager.test.ts +++ b/packages/cli/src/browser/manager.test.ts @@ -411,6 +411,12 @@ describe("findBrowser — cache resolution", () => { }); it("withInstallLock reports progress while waiting instead of staying silent", async () => { + // Fake timers freeze Date.now() so the lock mtime stays non-stale across + // the dynamic import that follows — without them, a slow import beat could + // push wall-clock past staleMs before `withInstallLock` even starts polling, + // firing the immediate-stale short-circuit and skipping the wait-notice + // branch this test exists to observe. + vi.useFakeTimers(); const paths = installFsMocks({ existing: new Set([CACHE_ROOT, HF_LOCK]), initialMtimeMs: Date.now(), @@ -418,8 +424,17 @@ describe("findBrowser — cache resolution", () => { const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {}); const { withInstallLock } = await import("./manager.js"); - await withInstallLock(async () => "done", { ...TEST_LOCK_TIMINGS, waitNoticeMs: 20 }); + const acquisition = withInstallLock(async () => "done", { + ...TEST_LOCK_TIMINGS, + waitNoticeMs: 20, + }); + + // Advance past waitNoticeMs (fires the "Waiting for…" warn), then past + // staleMs (lets `reclaimStaleInstallLock` clear the held lock so the + // acquisition resolves). + await vi.advanceTimersByTimeAsync(TEST_LOCK_TIMINGS.staleMs + TEST_LOCK_TIMINGS.pollMs * 5); + await expect(acquisition).resolves.toBe("done"); expect(paths.has(HF_LOCK)).toBe(false); expect( warnSpy.mock.calls.some(([msg]) =>