diff --git a/tests/memory-leak.test.ts b/tests/memory-leak.test.ts index 535b034..1a22614 100644 --- a/tests/memory-leak.test.ts +++ b/tests/memory-leak.test.ts @@ -16,18 +16,21 @@ import { VideoPlaybackModel } from "../src/track-lab/model/VideoPlaybackModel.js import { PlaybackControlsNode } from "../src/track-lab/view/PlaybackControlsNode.js"; /** - * Force garbage collection with multiple passes. When `earlyExitRef` is supplied - * the loop bails as soon as the object is confirmed collected. The setTimeout(0) - * yield after a live deref() avoids the WeakRef macrotask-liveness pin. + * Force garbage collection with multiple passes. When `earlyExitRefs` is supplied + * the loop bails as soon as every referenced object is confirmed collected. The + * setTimeout(0) yield after a live deref() avoids the WeakRef macrotask-liveness pin. + * Without early-exit refs the loop always runs all passes, which on a slow `gc()` + * can exceed the Vitest testTimeout — always pass refs when you have them. */ -async function forceGC(earlyExitRef?: WeakRef): Promise { +async function forceGC(earlyExitRefs?: WeakRef | readonly WeakRef[]): Promise { + const refs = earlyExitRefs === undefined ? [] : Array.isArray(earlyExitRefs) ? earlyExitRefs : [earlyExitRefs]; for (let i = 0; i < 15; i++) { globalThis.gc?.(); await new Promise((r) => setTimeout(r, 50)); - if (earlyExitRef !== undefined && earlyExitRef.deref() === undefined) { + if (refs.length > 0 && refs.every((ref) => ref.deref() === undefined)) { return; } - if (earlyExitRef !== undefined) { + if (refs.length > 0) { await new Promise((r) => setTimeout(r, 0)); } } @@ -151,7 +154,7 @@ describe("Memory leak regression", () => { for (let i = 0; i < 10; i++) { refs.push(createAndDisposeGraphControlsPanel()); } - await forceGC(); + await forceGC(refs); const survivors = refs.filter((r) => r.deref() !== undefined).length; expect(survivors).toBe(0); });