96 lines
3.1 KiB
TypeScript
96 lines
3.1 KiB
TypeScript
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<typeof createFetchMock>;
|
|
|
|
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(
|
|
<AuthProvider>
|
|
<QueryClientProvider client={queryClient}>
|
|
<RouterProvider router={router} />
|
|
</QueryClientProvider>
|
|
</AuthProvider>,
|
|
);
|
|
}
|
|
|
|
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");
|
|
});
|