import { describe, expect, it } from "vitest"; import { AUTO_DISMISS_MS, MAX_TOASTS, createToastStore } from "./toastStore"; function fakeTimers() { let next = 1; const pending = new Map void; ms: number }>(); return { setTimer: (fn: () => void, ms: number) => { const id = next++; pending.set(id, { fn, ms }); return id; }, clearTimer: (id: unknown) => void pending.delete(id as number), fireAll: () => [...pending.entries()].forEach(([id, t]) => (pending.delete(id), t.fn())), pending, }; } describe("toast store", () => { it("auto-dismisses non-error toasts after the delay", () => { const timers = fakeTimers(); const store = createToastStore(timers); store.add("success", "Saved"); store.add("info", "FYI"); expect([...timers.pending.values()].map((t) => t.ms)).toEqual([AUTO_DISMISS_MS, AUTO_DISMISS_MS]); timers.fireAll(); expect(store.getSnapshot()).toHaveLength(0); }); it("keeps errors until they are closed", () => { const timers = fakeTimers(); const store = createToastStore(timers); const id = store.add("error", "Failed", "details"); expect(timers.pending.size).toBe(0); timers.fireAll(); expect(store.getSnapshot()).toEqual([{ id, kind: "error", title: "Failed", subtitle: "details" }]); store.dismiss(id); expect(store.getSnapshot()).toHaveLength(0); }); it("dismiss cancels the timer and is idempotent", () => { const timers = fakeTimers(); const store = createToastStore(timers); const id = store.add("success", "x"); store.dismiss(id); expect(timers.pending.size).toBe(0); store.dismiss(id); expect(store.getSnapshot()).toHaveLength(0); }); it("notifies subscribers with a new snapshot reference per change", () => { const store = createToastStore(fakeTimers()); let calls = 0; const off = store.subscribe(() => calls++); const before = store.getSnapshot(); store.add("info", "a"); expect(calls).toBe(1); expect(store.getSnapshot()).not.toBe(before); const same = store.getSnapshot(); store.dismiss(999); expect(calls).toBe(1); expect(store.getSnapshot()).toBe(same); off(); store.add("info", "b"); expect(calls).toBe(1); }); it("caps the stack and drops the oldest first, cancelling its timer", () => { const timers = fakeTimers(); const store = createToastStore(timers); for (let i = 0; i < MAX_TOASTS + 2; i++) store.add("success", `t${i}`); const titles = store.getSnapshot().map((t) => t.title); expect(titles).toHaveLength(MAX_TOASTS); expect(titles[0]).toBe("t2"); expect(timers.pending.size).toBe(MAX_TOASTS); }); it("clear empties the stack and cancels timers", () => { const timers = fakeTimers(); const store = createToastStore(timers); store.add("success", "a"); store.add("error", "b"); store.clear(); expect(store.getSnapshot()).toHaveLength(0); expect(timers.pending.size).toBe(0); }); });