import { describe, it, expect, vi, beforeEach } from "vitest"; vi.mock("@/src/lib/prisma", () => ({ prisma: { notification: { findMany: vi.fn(), count: vi.fn(), updateMany: vi.fn(), }, }, })); vi.mock("@/src/lib/auth/getUser", () => ({ requireAuthWithData: vi.fn(), isManager: (u: { role: string }) => u?.role === "manager", isEmployee: (u: { role: string }) => u?.role === "employee", })); import { prisma } from "@/src/lib/prisma"; import { requireAuthWithData } from "@/src/lib/auth/getUser"; import { getNotifications, markNotificationRead, markAllNotificationsRead, } from "@/src/modules/notifications/actions/notification-actions"; const findMany = vi.mocked(prisma.notification.findMany); const count = vi.mocked(prisma.notification.count); const updateMany = vi.mocked(prisma.notification.updateMany); const requireAuth = vi.mocked(requireAuthWithData); beforeEach(() => { vi.clearAllMocks(); }); describe("getNotifications", () => { it("liefert leeres Ergebnis für die User-Rolle", async () => { requireAuth.mockResolvedValueOnce({ id: "u1", role: "user" } as never); const result = await getNotifications(); expect(result).toEqual({ items: [], unreadCount: 0 }); expect(findMany).not.toHaveBeenCalled(); }); it("liefert leeres Ergebnis wenn keine Session besteht", async () => { requireAuth.mockRejectedValueOnce(new Error("redirect")); const result = await getNotifications(); expect(result).toEqual({ items: [], unreadCount: 0 }); }); it("scoped die Abfrage auf die eigene recipientId und mappt Datumsfelder", async () => { requireAuth.mockResolvedValueOnce({ id: "mgr-1", role: "manager" } as never); const now = new Date("2026-08-28T10:00:00Z"); findMany.mockResolvedValueOnce([ { id: "n1", type: "booking.created", title: "T", body: "B", linkUrl: "/x", readAt: null, createdAt: now, }, ] as never); count.mockResolvedValueOnce(1); const result = await getNotifications(); expect(findMany.mock.calls[0][0]?.where).toEqual({ recipientId: "mgr-1" }); expect(count.mock.calls[0][0]?.where).toEqual({ recipientId: "mgr-1", readAt: null }); expect(result.unreadCount).toBe(1); expect(result.items[0].createdAt).toBe(now.toISOString()); expect(result.items[0].readAt).toBeNull(); }); }); describe("markNotificationRead", () => { it("nimmt die recipientId in die WHERE-Bedingung auf (Ownership)", async () => { requireAuth.mockResolvedValueOnce({ id: "mgr-1", role: "manager" } as never); updateMany.mockResolvedValueOnce({ count: 1 } as never); await markNotificationRead("n1"); expect(updateMany).toHaveBeenCalledWith({ where: { id: "n1", recipientId: "mgr-1", readAt: null }, data: { readAt: expect.any(Date) }, }); }); it("verweigert die User-Rolle", async () => { requireAuth.mockResolvedValueOnce({ id: "u1", role: "user" } as never); const result = await markNotificationRead("n1"); expect(result).toEqual({ success: false }); expect(updateMany).not.toHaveBeenCalled(); }); }); describe("markAllNotificationsRead", () => { it("markiert nur ungelesene der eigenen recipientId", async () => { requireAuth.mockResolvedValueOnce({ id: "emp-9", role: "employee" } as never); updateMany.mockResolvedValueOnce({ count: 3 } as never); await markAllNotificationsRead(); expect(updateMany).toHaveBeenCalledWith({ where: { recipientId: "emp-9", readAt: null }, data: { readAt: expect.any(Date) }, }); }); });