import { render } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { MemoryRouter } from "react-router"; import { vi } from "vitest"; import type { Book, Genre, User } from "../api"; import { AppRoutes } from "../App"; import { AuthProvider } from "../auth/AuthContext"; export const alice: User = { id: 1, username: "alice" }; export const genres: Genre[] = [ { id: 3, name: "Fantasy" }, { id: 5, name: "Science Fiction" }, ]; export const dune: Book = { id: 7, title: "Dune", author: "Frank Herbert", genre: { id: 5, name: "Science Fiction" }, total_pages: 380, current_page: 142, status: "reading", created_at: "2026-10-01T10:00:00+00:00", updated_at: "2026-10-01T10:00:00+00:00", }; type Reply = [status: number, body?: unknown]; type Handler = (request: { body: unknown; url: URL }) => Reply; export type Call = { method: string; path: string; body: unknown }; export function mockApi(routes: Record): Call[] { const calls: Call[] = []; vi.stubGlobal( "fetch", vi.fn(async (input: string, init: RequestInit = {}) => { const url = new URL(input, "http://localhost"); const method = init.method ?? "GET"; const body = typeof init.body === "string" ? JSON.parse(init.body) : undefined; calls.push({ method, path: url.pathname + url.search, body }); const handler = routes[`${method} ${url.pathname}`]; const [status, data] = handler ? handler({ body, url }) : [500, { error: `No mock for ${method} ${url.pathname}` }]; return new Response(status === 204 ? null : JSON.stringify(data), { status, headers: { "Content-Type": "application/json" }, }); }), ); return calls; } export function signedIn(routes: Record = {}): Call[] { return mockApi({ "GET /api/auth/me": () => [200, alice], "GET /api/genres": () => [200, genres], ...routes, }); } export function renderApp(url: string) { const user = userEvent.setup(); render( , ); return user; }