import { fireEvent, render, screen } from "@testing-library/react"; import { QueryClientProvider } from "@tanstack/react-query"; import { RouterProvider, createMemoryHistory } from "@tanstack/react-router"; import { AuthProvider, resetAuthProbeForTests } from "@/auth/store"; import { createQueryClient } from "@/lib/queryClient"; import { createAppRouter } from "@/routes"; const NAV_LABELS = [ "Dashboard", "Query Log", "Live", "Clients", "Groups", "Blocklists", "Rules", "Local DNS", "Upstreams", "Lookup", "Diagnostics", "Settings", ]; const RESPONSES: Record = { "/api/stats?period=24h": { period: "24h", since: 0, until: 86400, queries: 0, blocked: 0, cached: 0, clients: 0, avg_response_time_us: null, }, "/api/stats/timeseries?period=24h": { period: "24h", since: 0, until: 86400, bucket_seconds: 1800, buckets: [] }, "/api/health": { status: "ok", disk: { state: "ok", free_bytes: 0, db_bytes: 0, log_bytes: 0, sample_failures: 0 }, upstreams: { available: 1, total: 1 }, queries_dropped: 0, writer_failed: false, refreshes_gated: 0, snapshot_generation: null, diagnostics: { state: "recording", active_warnings: 0, active_errors: 0 }, }, "/api/upstream/health": { upstreams: [], available: 1, total: 1 }, "/api/version": { version: "0.0.0-test", git_commit: "0000000", zig_version: "0.16.0", uptime_seconds: 1 }, }; beforeEach(() => { sessionStorage.clear(); resetAuthProbeForTests(); vi.stubGlobal( "fetch", vi.fn(async (input: RequestInfo | URL) => { const url = String(input); const payload = RESPONSES[url]; if (payload === undefined) return new Response(JSON.stringify({ error: "not stubbed" }), { status: 404 }); return new Response(JSON.stringify(payload), { status: 200, headers: { "content-type": "application/json" }, }); }), ); }); afterEach(() => { vi.unstubAllGlobals(); }); test("shell renders the dashboard route with all nav links", async () => { const queryClient = createQueryClient(); const router = createAppRouter(createMemoryHistory({ initialEntries: ["/"] }), queryClient); render( , ); await screen.findByRole("heading", { name: "Dashboard" }); const nav = screen.getByRole("navigation", { name: "Main" }); expect(nav).toBeTruthy(); for (const label of NAV_LABELS) { expect(screen.getByRole("link", { name: label })).toBeTruthy(); } }); test("mount probe reveals the logout button and a failed logout surfaces inline", async () => { vi.stubGlobal( "fetch", vi.fn(async (input: RequestInfo | URL) => { const url = String(input); if (url === "/api/auth/login") return new Response(JSON.stringify({ error: "password required" }), { status: 401, headers: { "content-type": "application/json" }, }); if (url === "/api/auth/logout") return new Response(JSON.stringify({ error: "rate limited" }), { status: 429, headers: { "content-type": "application/json", "retry-after": "7" }, }); const payload = RESPONSES[url]; if (payload === undefined) return new Response(JSON.stringify({ error: "not stubbed" }), { status: 404 }); return new Response(JSON.stringify(payload), { status: 200, headers: { "content-type": "application/json" }, }); }), ); const queryClient = createQueryClient(); const router = createAppRouter(createMemoryHistory({ initialEntries: ["/"] }), queryClient); render( , ); fireEvent.click(await screen.findByRole("button", { name: "Log out" })); await screen.findByText("Rate limited. Try again in 7s."); expect(screen.getByRole("heading", { name: "Dashboard" })).toBeTruthy(); });