shoc-frontend-new/src/test/components/notifications/notification-event-items.test.tsx
Codex Review Integration ae941bc93d feat(notifications): open comment, mention, assignment and uplift items where they happened
Comment and mention items open the work order on the Comments tab with the
comments they were raised for highlighted; a grouped assignment opens the
dispatcher's own open queue; uplift decisions open the work order's uplifts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 13:42:13 -03:00

183 lines
6 KiB
TypeScript

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<typeof import("@/providers/auth-context")>()),
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 <output aria-label="Current location">{`${location.pathname}${location.search}`}</output>;
}
async function openItem(title: RegExp) {
const user = userEvent.setup();
renderWithProviders(
<NotificationSessionProvider>
<NotificationBell />
<LocationProbe />
</NotificationSessionProvider>,
{ 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(
<NotificationSessionProvider>
<NotificationBell />
</NotificationSessionProvider>,
{ 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");
});
});