/** * Notification Store 单元测试 * * 覆盖:addNotification / removeNotification / clearAll / 自动过期清除 */ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { useNotificationStore } from "@/lib/stores/notification-store"; describe("useNotificationStore", () => { beforeEach(() => { // 重置 store 到初始状态 useNotificationStore.setState({ notifications: [] }); vi.useFakeTimers(); }); afterEach(() => { vi.useRealTimers(); }); // ── addNotification ──────────────────────────────────────────────────── describe("addNotification", () => { it("应添加一条通知到队列", () => { const { addNotification } = useNotificationStore.getState(); const id = addNotification({ type: "success", message: "操作成功" }); expect(id).toBeTruthy(); expect(id).toMatch(/^notif-/); const { notifications } = useNotificationStore.getState(); expect(notifications).toHaveLength(1); expect(notifications[0].type).toBe("success"); expect(notifications[0].message).toBe("操作成功"); }); it("应支持不同类型的通知", () => { const { addNotification } = useNotificationStore.getState(); addNotification({ type: "success", message: "成功" }); addNotification({ type: "error", message: "错误" }); addNotification({ type: "warning", message: "警告" }); addNotification({ type: "info", message: "信息" }); const { notifications } = useNotificationStore.getState(); expect(notifications).toHaveLength(4); expect(notifications[0].type).toBe("success"); expect(notifications[1].type).toBe("error"); expect(notifications[2].type).toBe("warning"); expect(notifications[3].type).toBe("info"); }); it("应支持可选标题", () => { const { addNotification } = useNotificationStore.getState(); addNotification({ type: "info", message: "消息", title: "标题" }); const { notifications } = useNotificationStore.getState(); expect(notifications[0].title).toBe("标题"); }); it("默认过期时间应按类型自动设置", () => { const { addNotification } = useNotificationStore.getState(); addNotification({ type: "success", message: "成功" }); addNotification({ type: "error", message: "错误" }); addNotification({ type: "warning", message: "警告" }); addNotification({ type: "info", message: "信息" }); const { notifications } = useNotificationStore.getState(); expect(notifications[0].duration).toBe(3000); // success expect(notifications[1].duration).toBe(5000); // error expect(notifications[2].duration).toBe(4000); // warning expect(notifications[3].duration).toBe(3000); // info }); it("应支持自定义过期时间", () => { const { addNotification } = useNotificationStore.getState(); addNotification({ type: "success", message: "自定义", duration: 10000 }); const { notifications } = useNotificationStore.getState(); expect(notifications[0].duration).toBe(10000); }); it("duration 为 undefined 时应使用默认过期时间", () => { const { addNotification } = useNotificationStore.getState(); // 不传 duration,使用 error 类型的默认值 5000 addNotification({ type: "error", message: "使用默认" }); const { notifications } = useNotificationStore.getState(); expect(notifications[0].duration).toBe(5000); }); it("每条通知应有唯一 ID", () => { const { addNotification } = useNotificationStore.getState(); const id1 = addNotification({ type: "info", message: "第一条" }); const id2 = addNotification({ type: "info", message: "第二条" }); expect(id1).not.toBe(id2); }); }); // ── removeNotification ───────────────────────────────────────────────── describe("removeNotification", () => { it("应移除指定 ID 的通知", () => { const { addNotification, removeNotification } = useNotificationStore.getState(); const id1 = addNotification({ type: "success", message: "保留" }); const id2 = addNotification({ type: "error", message: "移除" }); removeNotification(id2); const { notifications } = useNotificationStore.getState(); expect(notifications).toHaveLength(1); expect(notifications[0].id).toBe(id1); }); it("移除不存在的 ID 不应报错", () => { const { addNotification, removeNotification } = useNotificationStore.getState(); addNotification({ type: "info", message: "测试" }); expect(() => removeNotification("non-existent")).not.toThrow(); const { notifications } = useNotificationStore.getState(); expect(notifications).toHaveLength(1); }); it("移除通知时应清除其定时器", () => { const { addNotification, removeNotification } = useNotificationStore.getState(); const id = addNotification({ type: "success", message: "提前移除" }); removeNotification(id); // 快进超过默认过期时间,不应再触发移除(避免对空列表操作) vi.advanceTimersByTime(5000); const { notifications } = useNotificationStore.getState(); expect(notifications).toHaveLength(0); }); }); // ── 自动过期清除 ─────────────────────────────────────────────────────── describe("自动过期清除", () => { it("到达过期时间后应自动移除通知", () => { const { addNotification } = useNotificationStore.getState(); addNotification({ type: "success", message: "3秒后过期" }); // 快进 3 秒 vi.advanceTimersByTime(3000); const { notifications } = useNotificationStore.getState(); expect(notifications).toHaveLength(0); }); it("不同类型通知在不同时间过期", () => { const { addNotification } = useNotificationStore.getState(); addNotification({ type: "success", message: "3秒" }); addNotification({ type: "error", message: "5秒" }); // 快进 3 秒,success 应被清除 vi.advanceTimersByTime(3000); expect(useNotificationStore.getState().notifications).toHaveLength(1); expect(useNotificationStore.getState().notifications[0].type).toBe( "error" ); // 再快进 2 秒(共 5 秒),error 也应被清除 vi.advanceTimersByTime(2000); expect(useNotificationStore.getState().notifications).toHaveLength(0); }); it("自定义 duration=0 的通知不会自动过期", () => { const { addNotification } = useNotificationStore.getState(); // duration=0 时 setTimeout(cb, 0) 会在下一个事件循环触发 // 但 effectiveDuration !== null 为 true,所以会设置定时器 // 这里测试 duration 传入 0 的行为 addNotification({ type: "error", message: "0 毫秒过期", duration: 0 }); // 0 毫秒定时器应立即触发 vi.advanceTimersByTime(1); const { notifications } = useNotificationStore.getState(); expect(notifications).toHaveLength(0); }); it("自定义 duration 应在指定时间后过期", () => { const { addNotification } = useNotificationStore.getState(); addNotification({ type: "info", message: "1秒过期", duration: 1000 }); vi.advanceTimersByTime(999); expect(useNotificationStore.getState().notifications).toHaveLength(1); vi.advanceTimersByTime(1); expect(useNotificationStore.getState().notifications).toHaveLength(0); }); }); // ── clearAll ──────────────────────────────────────────────────────────── describe("clearAll", () => { it("应清空所有通知", () => { const { addNotification } = useNotificationStore.getState(); addNotification({ type: "success", message: "A" }); addNotification({ type: "error", message: "B" }); addNotification({ type: "warning", message: "C" }); expect(useNotificationStore.getState().notifications).toHaveLength(3); const { clearAll } = useNotificationStore.getState(); clearAll(); expect(useNotificationStore.getState().notifications).toHaveLength(0); }); it("clearAll 后定时器不应再触发", () => { const { addNotification } = useNotificationStore.getState(); addNotification({ type: "success", message: "3秒后过期" }); const { clearAll } = useNotificationStore.getState(); clearAll(); // 快进超过过期时间 vi.advanceTimersByTime(5000); expect(useNotificationStore.getState().notifications).toHaveLength(0); }); }); });