/** * @fileoverview showToast() display time: a toast with no explicit `duration` uses the * notification preference, and an explicit `duration` (0 = sticky) still wins. */ import { readFileSync } from 'node:fs'; import { resolve } from 'node:path'; import vm from 'node:vm'; import { JSDOM } from 'jsdom'; import { afterEach, describe, expect, it, vi } from 'vitest'; const windows: JSDOM[] = []; function loadApp(notificationManager?: unknown) { const dom = new JSDOM('', { url: 'http://localhost/' }); windows.push(dom); const CodemanApp = function CodemanApp() {} as unknown as { prototype: Record }; const context = vm.createContext({ CodemanApp, document: dom.window.document, requestAnimationFrame: (cb: () => void) => cb(), setTimeout, clearTimeout, console, }); const source = readFileSync(resolve(import.meta.dirname, '../src/web/public/panels-ui.js'), 'utf8'); vm.runInContext(source, context, { filename: 'panels-ui.js' }); const app = new (CodemanApp as unknown as new () => Record)(); app.notificationManager = notificationManager; return app; } afterEach(() => { vi.useRealTimers(); for (const dom of windows.splice(0)) dom.window.close(); }); describe('showToast', () => { it('uses the configured display time when no duration is given', () => { vi.useFakeTimers(); const app = loadApp({ getToastDurationMs: () => 10_000 }); app.showToast('hello'); expect(windows[0].window.document.querySelectorAll('.toast')).toHaveLength(1); vi.advanceTimersByTime(9_000); expect(windows[0].window.document.querySelector('.toast.show')).not.toBeNull(); vi.advanceTimersByTime(1_500); expect(windows[0].window.document.querySelector('.toast.show')).toBeNull(); }); it('falls back to 3s without a notification manager', () => { vi.useFakeTimers(); const app = loadApp(); app.showToast('hello'); vi.advanceTimersByTime(3_100); expect(windows[0].window.document.querySelector('.toast.show')).toBeNull(); }); it('lets an explicit duration of 0 stay until dismissed', () => { vi.useFakeTimers(); const app = loadApp({ getToastDurationMs: () => 1_000 }); app.showToast('sticky', 'error', { duration: 0 }); vi.advanceTimersByTime(60_000); expect(windows[0].window.document.querySelector('.toast.show')).not.toBeNull(); }); });