import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; const getSubscriptionMock = vi.hoisted(() => vi.fn()); const claimNotificationsMock = vi.hoisted(() => vi.fn()); const acknowledgeNotificationsMock = vi.hoisted(() => vi.fn()); const getTokenMock = vi.hoisted(() => vi.fn()); const getPermissionMock = vi.hoisted(() => vi.fn()); const showNotificationMock = vi.hoisted(() => vi.fn()); vi.mock("../api/desktopNotifications", () => ({ getDesktopNotificationSubscription: getSubscriptionMock, claimDesktopNotifications: claimNotificationsMock, acknowledgeDesktopNotifications: acknowledgeNotificationsMock, })); vi.mock("../utils/auth", () => ({ getToken: getTokenMock, })); vi.mock("../runtime", () => ({ getNotificationPermission: getPermissionMock, isTauriRuntime: () => true, showSystemNotification: showNotificationMock, })); describe("desktop notification manager", () => { beforeEach(() => { vi.useFakeTimers(); getTokenMock.mockReturnValue("session-token"); getPermissionMock.mockResolvedValue("granted"); getSubscriptionMock.mockResolvedValue({ data: { enabled: true } }); claimNotificationsMock.mockResolvedValue({ data: { claim_token: "claim-token", items: [ { id: "notification-1" }, { id: "notification-2" }, ], }, }); acknowledgeNotificationsMock.mockResolvedValue({ data: {} }); showNotificationMock.mockResolvedValue(true); }); afterEach(async () => { const { stopDesktopNotificationManager } = await import("./desktopNotificationManager"); stopDesktopNotificationManager(); vi.clearAllTimers(); vi.useRealTimers(); vi.resetModules(); vi.clearAllMocks(); }); it("acknowledges displayed notifications and leaves failed deliveries for retry", async () => { showNotificationMock .mockResolvedValueOnce(true) .mockRejectedValueOnce(new Error("notification failed")); const { initDesktopNotificationManager, triggerDesktopNotificationPoll } = await import("./desktopNotificationManager"); initDesktopNotificationManager(); triggerDesktopNotificationPoll(); await vi.runOnlyPendingTimersAsync(); expect(showNotificationMock).toHaveBeenCalledTimes(2); expect(acknowledgeNotificationsMock).toHaveBeenCalledWith("claim-token", ["notification-1"]); expect(acknowledgeNotificationsMock).toHaveBeenCalledTimes(1); }); it("does not acknowledge notifications when the system dispatch does not happen", async () => { showNotificationMock .mockResolvedValueOnce(false) .mockResolvedValueOnce(true); const { initDesktopNotificationManager, triggerDesktopNotificationPoll } = await import("./desktopNotificationManager"); initDesktopNotificationManager(); triggerDesktopNotificationPoll(); await vi.runOnlyPendingTimersAsync(); expect(showNotificationMock).toHaveBeenCalledTimes(2); expect(acknowledgeNotificationsMock).toHaveBeenCalledWith("claim-token", ["notification-2"]); expect(acknowledgeNotificationsMock).toHaveBeenCalledTimes(1); }); it("does not claim notifications before operating system permission is granted", async () => { getPermissionMock.mockResolvedValue("prompt"); const { initDesktopNotificationManager, triggerDesktopNotificationPoll } = await import("./desktopNotificationManager"); initDesktopNotificationManager(); triggerDesktopNotificationPoll(); await vi.runOnlyPendingTimersAsync(); expect(claimNotificationsMock).not.toHaveBeenCalled(); expect(acknowledgeNotificationsMock).not.toHaveBeenCalled(); }); });