import { screen, waitFor, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { useLocation } from "react-router"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { NotificationBell } from "@/components/notifications/notification-bell"; import { NotificationSessionProvider } from "@/domain/notifications/session/notification-session-provider"; import { renderWithProviders } from "@/test/test-utils"; const apiGet = vi.hoisted(() => vi.fn()); vi.mock("@/api/api", () => ({ apiGet })); vi.mock("@/providers/auth-context", async (importOriginal) => ({ ...(await importOriginal()), useAuthContext: () => ({ user: { id: "dispatcher-me" } }), })); type Target = { kind: "workOrder" | "queue"; workOrderId?: number; tab?: string; queue?: string }; function item( id: string, reason: string, severity: string, title: string, target: Target, extra = {}, ) { return { id, reason, severity, rowType: "dismissable", title, count: 1, triggeredAt: "2026-09-18T12:00:00Z", target, workOrders: [], ...extra, }; } const mention = item("mention-501", "mentions", "High", "Omar Diaz mentioned you on WO #1011", { kind: "workOrder", workOrderId: 11, tab: "comments", }); const comments = item( "comments-12-505", "activity", "Medium", "2 new comments on WO #1012", { kind: "workOrder", workOrderId: 12, tab: "comments" }, { triggeredAt: "2026-09-18T09:30:00Z" }, ); const assignedGroup = item( "new-assigned-group-30", "activity", "Low", "3 new work orders assigned to you", { kind: "queue", queue: "assigned-to-me" }, { count: 3 }, ); const assignedOne = item("new-assigned-40", "activity", "Low", "WO #1040 was assigned to you", { kind: "workOrder", workOrderId: 40, tab: "info", }); const upliftRejected = item( "uplift-rejected-9", "activity", "High", "Your $400.00 uplift on WO #1020 was rejected: “Quote does not match”", { kind: "workOrder", workOrderId: 20, tab: "uplifts" }, ); const feed = { generatedAt: "2026-09-18T16:00:00Z", sections: [ { reason: "mentions", label: "Mentions", severity: "High", count: 1, items: [mention] }, { reason: "activity", label: "Recent activity", severity: "High", count: 6, items: [upliftRejected, comments, assignedOne, assignedGroup], }, ], }; function LocationProbe() { const location = useLocation(); return {`${location.pathname}${location.search}`}; } async function openItem(title: RegExp) { const user = userEvent.setup(); renderWithProviders( , { withAuth: false }, ); await user.click(await screen.findByRole("button", { name: /^Notifications, \d+ unread$/ })); const panel = await screen.findByRole("dialog"); await user.click(within(panel).getByRole("button", { name: title })); await waitFor(() => expect(screen.queryByRole("dialog")).not.toBeInTheDocument()); const location = screen.getByRole("status", { name: "Current location" }).textContent ?? ""; return new URL(location, "http://localhost"); } describe("event notifications in the Notification Center", () => { beforeEach(() => { apiGet.mockReset(); apiGet.mockResolvedValue(feed); }); it("lists mentions, comments, assignments and uplift decisions in their sections", async () => { const user = userEvent.setup(); renderWithProviders( , { withAuth: false }, ); await user.click(await screen.findByRole("button", { name: "Notifications, 5 unread" })); const panel = await screen.findByRole("dialog"); const mentions = within(panel).getByRole("region", { name: "Mentions, 1" }); expect(within(mentions).getByText(mention.title)).toBeInTheDocument(); const activity = within(panel).getByRole("region", { name: "Recent activity, 6" }); for (const row of [upliftRejected, comments, assignedOne, assignedGroup]) { expect(within(activity).getByText(row.title)).toBeInTheDocument(); } }); it("opens a comment item on the Comments tab with the comments to highlight", async () => { const url = await openItem(/2 new comments on WO #1012/); expect(url.pathname).toBe("/workorders"); expect(url.searchParams.get("wo")).toBe("12"); expect(url.searchParams.get("tab")).toBe("comments"); expect(url.searchParams.get("since")).toBe("2026-09-18T09:30:00Z"); expect(url.searchParams.get("focus")).toBe("comments"); }); it("opens a mention on the Comments tab focused on the mentioning comment", async () => { const url = await openItem(/Omar Diaz mentioned you on WO #1011/); expect(url.searchParams.get("wo")).toBe("11"); expect(url.searchParams.get("tab")).toBe("comments"); expect(url.searchParams.get("since")).toBe("2026-09-18T12:00:00Z"); expect(url.searchParams.get("focus")).toBe("mentions"); }); it("opens a grouped assignment as the signed-in dispatcher's open queue", async () => { const url = await openItem(/3 new work orders assigned to you/); expect(url.pathname).toBe("/workorders"); expect(url.searchParams.get("dispatchers")).toBe("dispatcher-me"); expect(url.searchParams.get("dateFrom")).toBe("1970-01-01"); expect(url.searchParams.get("dateTo")).toBe("2099-12-31"); expect(url.searchParams.get("statuses")).toBeTruthy(); expect(url.searchParams.get("wo")).toBeNull(); }); it("opens a single assignment straight on the work order, with no highlight", async () => { const url = await openItem(/WO #1040 was assigned to you/); expect(`${url.pathname}${url.search}`).toBe("/workorders?wo=40&tab=info"); }); it("opens an uplift decision on the work order's uplifts", async () => { const url = await openItem(/uplift on WO #1020 was rejected/); expect(`${url.pathname}${url.search}`).toBe("/workorders?wo=20&tab=uplifts"); }); });