From d44045de3105b951f22575ac036266fcb8ae39a3 Mon Sep 17 00:00:00 2001 From: 4gray <4gray@users.noreply.github.com> Date: Sat, 1 Aug 2026 22:00:29 +0200 Subject: [PATCH] test(playlist): fix flaky refresh-preparation worker-event spec (#1331) The spec raced a fixed 160ms sleep against the service's internal rAF + 120ms paint delay that runs before deleteXtreamPlaylistContent is called. Under parallel jest load the sleep could win, asserting before the mocked worker event was ever delivered. Await a deferred resolved by the mock right after it fires onEvent instead, so the assertion is causally ordered after the signal update. Co-authored-by: Claude Fable 5 --- .../lib/playlist-refresh-action.service.spec.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/libs/playlist/shared/ui/src/lib/playlist-refresh-action.service.spec.ts b/libs/playlist/shared/ui/src/lib/playlist-refresh-action.service.spec.ts index b87054a3d..6227ed3e2 100644 --- a/libs/playlist/shared/ui/src/lib/playlist-refresh-action.service.spec.ts +++ b/libs/playlist/shared/ui/src/lib/playlist-refresh-action.service.spec.ts @@ -60,10 +60,6 @@ function createAbortError(): Error { return error; } -async function waitForRefreshPreparationPaint(): Promise { - await new Promise((resolve) => setTimeout(resolve, 160)); -} - function createPlaylistMeta( overrides: Partial = {} ): PlaylistMeta { @@ -559,6 +555,13 @@ describe('PlaylistRefreshActionService', () => { hiddenCategories: []; }>(); let confirmPromise: Promise | undefined; + // The service awaits its internal paint delay (rAF + setTimeout) + // before it calls deleteXtreamPlaylistContent, so a fixed sleep here + // races against real timers under parallel jest load. The mock fires + // onEvent synchronously and the service applies it to the signal + // synchronously, so resolving this deferred inside the mock is a + // deterministic "worker event has been applied" signal. + const workerEventDelivered = createDeferred(); databaseService.deleteXtreamPlaylistContent.mockImplementation( ( @@ -576,6 +579,7 @@ describe('PlaylistRefreshActionService', () => { current: 50, total: 100, }); + workerEventDelivered.resolve(); return refresh.promise; } @@ -587,7 +591,7 @@ describe('PlaylistRefreshActionService', () => { ); service.refresh(item); - await waitForRefreshPreparationPaint(); + await workerEventDelivered.promise; expect(service.refreshPreparation()).toEqual({ playlistId: item._id,