FastAPI + Celery + Next.js + Postgres/Redis app with company monitoring, source collection, LLM-based change analysis, enrichment, and account security (Turnstile, escalating lockout, email verification).
72 lines
2.4 KiB
TypeScript
72 lines
2.4 KiB
TypeScript
import { screen, waitFor, within } from "@testing-library/react";
|
|
import userEvent from "@testing-library/user-event";
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import AlertsPage from "@/app/(app)/alerts/page";
|
|
import { renderWithQueryClient } from "./test-utils";
|
|
|
|
const COMPANIES = [
|
|
{ id: "company-1", name: "Acme Mobility Systems" },
|
|
{ id: "company-2", name: "Globex Corp" },
|
|
];
|
|
|
|
const ALERTS = [
|
|
{
|
|
id: "alert-1",
|
|
company_id: "company-1",
|
|
detected_change_id: "change-1",
|
|
title: "Base plan price increased",
|
|
summary: "Pricing changed.",
|
|
why_it_matters: "Signals margin pressure.",
|
|
severity: "high",
|
|
confidence: 0.82,
|
|
read: false,
|
|
resolved: false,
|
|
created_at: new Date().toISOString(),
|
|
},
|
|
];
|
|
|
|
function mockFetchImplementation() {
|
|
return vi.fn().mockImplementation((url: string) => {
|
|
const path = url.replace("http://localhost:8000", "");
|
|
if (path.startsWith("/api/v1/companies")) {
|
|
return Promise.resolve({ ok: true, status: 200, json: async () => COMPANIES });
|
|
}
|
|
if (path.startsWith("/api/v1/alerts")) {
|
|
return Promise.resolve({ ok: true, status: 200, json: async () => ALERTS });
|
|
}
|
|
return Promise.resolve({ ok: false, status: 404, json: async () => ({ detail: "not found" }) });
|
|
});
|
|
}
|
|
|
|
beforeEach(() => {
|
|
vi.stubGlobal("fetch", mockFetchImplementation());
|
|
});
|
|
|
|
describe("AlertsPage", () => {
|
|
it("renders alerts with the resolved company name", async () => {
|
|
renderWithQueryClient(<AlertsPage />);
|
|
|
|
expect(await screen.findByText("Base plan price increased")).toBeInTheDocument();
|
|
const list = screen.getByRole("list");
|
|
expect(within(list).getByText(/Acme Mobility Systems/)).toBeInTheDocument();
|
|
expect(within(list).getByText("high")).toBeInTheDocument();
|
|
});
|
|
|
|
it("re-fetches with a severity filter when changed", async () => {
|
|
const fetchMock = mockFetchImplementation();
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
const user = userEvent.setup();
|
|
renderWithQueryClient(<AlertsPage />);
|
|
|
|
await screen.findByText("Base plan price increased");
|
|
|
|
await user.click(screen.getByRole("combobox", { name: "Filter by severity" }));
|
|
await user.click(await screen.findByRole("option", { name: "Critical" }));
|
|
|
|
await waitFor(() => {
|
|
const calledUrls = fetchMock.mock.calls.map((call) => call[0] as string);
|
|
expect(calledUrls.some((u) => u.includes("severity=critical"))).toBe(true);
|
|
});
|
|
});
|
|
});
|