Files
ctms/frontend/src/session/desktopNotificationManager.test.ts
T
2026-07-02 15:13:08 +08:00

96 lines
3.5 KiB
TypeScript

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();
});
});