import { fireEvent, render, screen } from "@testing-library/react"; import { QueryClientProvider } from "@tanstack/react-query"; import { RouterProvider, createMemoryHistory } from "@tanstack/react-router"; import { AuthProvider } from "@/auth/store"; import { createQueryClient } from "@/lib/queryClient"; import { createAppRouter } from "@/routes"; import type { LookupResult } from "@/lib/types"; const BLOCKED: LookupResult = { domain: "ads.example", group_id: 1, local_records: false, forward_zone: null, blocked: true, reason: "blocklist_domain", matched: "ads.example", source_url: "https://lists.test/a", safe_search_rewrite: null, }; let fetchMock: ReturnType; function json(payload: unknown, status = 200): Response { return new Response(JSON.stringify(payload), { status, headers: { "content-type": "application/json" } }); } function createFetchMock() { return vi.fn(async (input: RequestInfo | URL) => { const url = String(input); if (url === "/api/groups") { return json({ groups: [ { id: 1, name: "default", safe_search: false }, { id: 2, name: "kids", safe_search: true }, ], }); } if (url === "/api/lookup?domain=ads.example&group_id=1") return json(BLOCKED); return json({ error: "not stubbed" }, 404); }); } beforeEach(() => { fetchMock = createFetchMock(); vi.stubGlobal("fetch", fetchMock); }); afterEach(() => { vi.unstubAllGlobals(); }); function renderPage() { const queryClient = createQueryClient(); const router = createAppRouter(createMemoryHistory({ initialEntries: ["/lookup"] }), queryClient); render( , ); } function lookupCalls(): string[] { return fetchMock.mock.calls.map(([input]) => String(input)).filter((url) => url.startsWith("/api/lookup")); } test("fetches nothing until submit, then renders the blocked verdict", async () => { renderPage(); await screen.findByRole("heading", { name: "Lookup" }); await screen.findByLabelText("Group"); expect(lookupCalls()).toEqual([]); fireEvent.change(screen.getByLabelText("Domain"), { target: { value: "ads.example" } }); expect(lookupCalls()).toEqual([]); fireEvent.click(screen.getByRole("button", { name: "Look up" })); await screen.findByRole("heading", { name: "Blocked" }); expect(lookupCalls()).toEqual(["/api/lookup?domain=ads.example&group_id=1"]); expect(screen.getByText("blocklist_domain")).toBeTruthy(); const link = screen.getByRole("link", { name: "https://lists.test/a" }) as HTMLAnchorElement; expect(link.href).toBe("https://lists.test/a"); expect(screen.getByText("Queries for this name get a blocked response.")).toBeTruthy(); }); test("defaults the group select to the default group (id 1)", async () => { renderPage(); // A RAC Select names its trigger with the current value and then the label, so // the selected group's name is the only thing the trigger shows. const trigger = await screen.findByRole("button", { name: /Group$/ }); expect(trigger.textContent).toContain("default"); });