Kuma/tests/notifications/notification-actions.test.ts
2026-08-28 18:20:28 +02:00

109 lines
3.5 KiB
TypeScript

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