From 082f7577c23e5e7d1575292f1ab16b718dcb3b57 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sat, 5 Sep 2026 13:40:16 +0200 Subject: [PATCH] fix(coding-agent): make footer debounce tests deterministic --- .../test/footer-data-provider.test.ts | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/packages/coding-agent/test/footer-data-provider.test.ts b/packages/coding-agent/test/footer-data-provider.test.ts index 4ad9a23a1..4fead8218 100644 --- a/packages/coding-agent/test/footer-data-provider.test.ts +++ b/packages/coding-agent/test/footer-data-provider.test.ts @@ -77,6 +77,12 @@ function createReftableWorktree(tempDir: string): WorktreeFixture { return { worktreeDir, reftableDir }; } +function emitReftableChange(provider: FooterDataProvider): void { + const { reftableWatcher } = provider as unknown as { reftableWatcher: FSWatcher | null }; + expect(reftableWatcher).not.toBeNull(); + reftableWatcher?.emit("change", "change", "tables.list"); +} + async function waitFor(condition: () => boolean, timeoutMs = 3000): Promise { const startedAt = Date.now(); while (!condition()) { @@ -167,8 +173,10 @@ describe("FooterDataProvider reftable branch detection", () => { } }); + // Drive debounce behavior explicitly; native fs.watch delivery can race watcher startup. it("does not notify listeners when reftable updates keep the same branch", async () => { - const { worktreeDir, reftableDir } = createReftableWorktree(tempDir); + vi.useFakeTimers(); + const { worktreeDir } = createReftableWorktree(tempDir); process.chdir(worktreeDir); const provider = new FooterDataProvider(worktreeDir); @@ -178,8 +186,8 @@ describe("FooterDataProvider reftable branch detection", () => { const onBranchChange = vi.fn(); provider.onBranchChange(onBranchChange); - writeFileSync(join(reftableDir, "tables.list"), "1\n"); - await waitFor(() => vi.mocked(execFile).mock.calls.length === 1); + emitReftableChange(provider); + await vi.advanceTimersByTimeAsync(501); expect(vi.mocked(execFile)).toHaveBeenCalledTimes(1); expect(vi.mocked(spawnSync)).not.toHaveBeenCalled(); @@ -187,11 +195,13 @@ describe("FooterDataProvider reftable branch detection", () => { expect(onBranchChange).not.toHaveBeenCalled(); } finally { provider.dispose(); + vi.useRealTimers(); } }); it("debounces rapid reftable updates into a single async refresh", async () => { - const { worktreeDir, reftableDir } = createReftableWorktree(tempDir); + vi.useFakeTimers(); + const { worktreeDir } = createReftableWorktree(tempDir); process.chdir(worktreeDir); const provider = new FooterDataProvider(worktreeDir); @@ -199,15 +209,18 @@ describe("FooterDataProvider reftable branch detection", () => { expect(provider.getGitBranch()).toBe("main"); vi.mocked(execFile).mockClear(); - writeFileSync(join(reftableDir, "tables.list"), "1\n"); - writeFileSync(join(reftableDir, "tables.list"), "2\n"); - writeFileSync(join(reftableDir, "tables.list"), "3\n"); - await waitFor(() => vi.mocked(execFile).mock.calls.length === 1); - await new Promise((resolve) => setTimeout(resolve, 650)); - + emitReftableChange(provider); + emitReftableChange(provider); + emitReftableChange(provider); + await vi.advanceTimersByTimeAsync(499); + expect(vi.mocked(execFile)).not.toHaveBeenCalled(); + await vi.advanceTimersByTimeAsync(2); + expect(vi.mocked(execFile)).toHaveBeenCalledTimes(1); + await vi.advanceTimersByTimeAsync(650); expect(vi.mocked(execFile)).toHaveBeenCalledTimes(1); } finally { provider.dispose(); + vi.useRealTimers(); } });