From 71da72d1a695042be1572c40112fab9abeee7d16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Mon, 9 Mar 2026 14:11:25 +0100 Subject: [PATCH] Fix flaky createBarrier test by using fake timers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'abandons a wait after the timeout expires' test relied on real setTimeout calls with tight margins (~50ms) between barrier timeouts and tick delays. On loaded CI machines, timer coalescing could cause both to fire in the same event loop turn, making the test flaky. Switched all createBarrier tests to jest.useFakeTimers() with advanceTimersByTime() for deterministic timer control, removing the real-timer tick helper entirely. Co-Authored-By: Claude Opus 4.6 Signed-off-by: Fredrik Adelöw Made-with: Cursor --- .../src/processing/TaskPipeline.test.ts | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/plugins/catalog-backend/src/processing/TaskPipeline.test.ts b/plugins/catalog-backend/src/processing/TaskPipeline.test.ts index 43ec118bdb..02a7a2932c 100644 --- a/plugins/catalog-backend/src/processing/TaskPipeline.test.ts +++ b/plugins/catalog-backend/src/processing/TaskPipeline.test.ts @@ -121,8 +121,13 @@ describe('startTaskPipeline', () => { }); describe('createBarrier', () => { - const tick = (millis: number) => - new Promise(resolve => setTimeout(resolve, millis)); + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); it('abandons a wait after the timeout expires', async () => { const abortController = new AbortController(); @@ -132,10 +137,11 @@ describe('createBarrier', () => { const fn1 = jest.fn(); barrier.wait().then(fn1); - await tick(0); + await Promise.resolve(); expect(fn1).not.toHaveBeenCalled(); - await tick(50); + jest.advanceTimersByTime(50); + await Promise.resolve(); expect(fn1).not.toHaveBeenCalled(); // start a new wait mid-way through the timeout @@ -143,14 +149,16 @@ describe('createBarrier', () => { const fn2 = jest.fn(); barrier.wait().then(fn2); - await tick(0); + await Promise.resolve(); expect(fn2).not.toHaveBeenCalled(); - await tick(50); + jest.advanceTimersByTime(50); + await Promise.resolve(); expect(fn1).toHaveBeenCalledTimes(1); expect(fn2).not.toHaveBeenCalled(); - await tick(50); + jest.advanceTimersByTime(50); + await Promise.resolve(); expect(fn1).toHaveBeenCalledTimes(1); expect(fn2).toHaveBeenCalledTimes(1); }); @@ -164,16 +172,16 @@ describe('createBarrier', () => { barrier.wait().then(fn1); // should resolve immediately, not after timeout - await tick(0); + await Promise.resolve(); expect(fn1).not.toHaveBeenCalled(); abortController.abort(); - await tick(0); + await Promise.resolve(); expect(fn1).toHaveBeenCalledTimes(1); // subsequent waits should be immediate no matter what const fn2 = jest.fn(); barrier.wait().then(fn2); - await tick(0); + await Promise.resolve(); expect(fn2).toHaveBeenCalledTimes(1); }); @@ -185,7 +193,8 @@ describe('createBarrier', () => { const fn1 = jest.fn(); barrier.wait().then(fn1); - await tick(50); + jest.advanceTimersByTime(50); + await Promise.resolve(); expect(fn1).not.toHaveBeenCalled(); // start a new wait mid-way through the timeout @@ -193,13 +202,13 @@ describe('createBarrier', () => { const fn2 = jest.fn(); barrier.wait().then(fn2); - await tick(0); + await Promise.resolve(); expect(fn1).not.toHaveBeenCalled(); expect(fn2).not.toHaveBeenCalled(); barrier.release(); - await tick(0); + await Promise.resolve(); expect(fn1).toHaveBeenCalledTimes(1); expect(fn2).toHaveBeenCalledTimes(1); });