Skip to content

Commit 0beb200

Browse files
committed
fix(test): clears lingering Kobalte timers after each test
1 parent d618d01 commit 0beb200

File tree

1 file changed

+28
-0
lines changed

1 file changed

+28
-0
lines changed

tests/setup.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { afterEach } from "vitest";
2+
13
// Global test setup: ensure localStorage is available before module imports.
24
// auth.ts reads localStorage at module scope (to initialize the token signal from
35
// persisted value). happy-dom establishes window globals lazily, so this shim
@@ -15,3 +17,29 @@ if (typeof localStorage === "undefined") {
1517
configurable: true,
1618
});
1719
}
20+
21+
// Track all timer IDs created during tests so we can clear them on teardown.
22+
// Kobalte's tooltip/popover primitives set module-level timers via
23+
// window.setTimeout that can fire after happy-dom tears down, causing
24+
// "ReferenceError: window is not defined".
25+
const pendingTimers = new Set<ReturnType<typeof setTimeout>>();
26+
const originalSetTimeout = globalThis.setTimeout;
27+
const originalClearTimeout = globalThis.clearTimeout;
28+
29+
globalThis.setTimeout = ((...args: Parameters<typeof setTimeout>) => {
30+
const id = originalSetTimeout(...args);
31+
pendingTimers.add(id);
32+
return id;
33+
}) as typeof setTimeout;
34+
35+
globalThis.clearTimeout = ((id?: ReturnType<typeof setTimeout>) => {
36+
if (id !== undefined) pendingTimers.delete(id);
37+
originalClearTimeout(id);
38+
}) as typeof clearTimeout;
39+
40+
afterEach(() => {
41+
for (const id of pendingTimers) {
42+
originalClearTimeout(id);
43+
}
44+
pendingTimers.clear();
45+
});

0 commit comments

Comments
 (0)