From 70ba24bfe1ddc274365e15c6094bb934c83a8e54 Mon Sep 17 00:00:00 2001 From: Maurice Date: Tue, 21 Apr 2026 22:18:54 +0200 Subject: [PATCH] fix(test): cancel Navbar theme-transition timer on unmount The dark-mode toggle kicked off a 360ms setTimeout that removed a CSS class via 'document.documentElement'. In vitest the document was torn down before the timer fired, triggering an unhandled ReferenceError that flipped the whole run to a non-zero exit even though every test passed. Track the handle in a ref and clearTimeout on unmount (and before scheduling a new one). --- client/src/components/Layout/Navbar.tsx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/client/src/components/Layout/Navbar.tsx b/client/src/components/Layout/Navbar.tsx index a8ec8f5c..36d543c1 100644 --- a/client/src/components/Layout/Navbar.tsx +++ b/client/src/components/Layout/Navbar.tsx @@ -61,11 +61,25 @@ export default function Navbar({ tripTitle, tripId, onBack, showBack, onShare }: navigate('/login', { state: { noRedirect: true } }) } + // Keep track of the pending theme-transition cleanup so we can cancel it + // on unmount. Without this the timer fires after jsdom teardown in unit + // tests (document is gone) and triggers an unhandled ReferenceError that + // trips vitest's exit code. + const themeTransitionTimer = useRef(null) + useEffect(() => () => { + if (themeTransitionTimer.current !== null) { + window.clearTimeout(themeTransitionTimer.current) + themeTransitionTimer.current = null + } + }, []) + const toggleDarkMode = () => { document.documentElement.classList.add('trek-theme-transitioning') updateSetting('dark_mode', dark ? 'light' : 'dark').catch(() => {}) - window.setTimeout(() => { + if (themeTransitionTimer.current !== null) window.clearTimeout(themeTransitionTimer.current) + themeTransitionTimer.current = window.setTimeout(() => { document.documentElement.classList.remove('trek-theme-transitioning') + themeTransitionTimer.current = null }, 360) }