import { render, screen } from "@testing-library/react"; import { createMemoryRouter, RouterProvider } from "react-router"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { routes } from "./routes"; // Flags come from the Unleash SDK; tests control them directly. const flagsOn = vi.hoisted(() => new Set()); vi.mock("@unleash/proxy-client-react", () => ({ FlagProvider: ({ children }: { children: React.ReactNode }) => children, useFlag: (name: string) => flagsOn.has(name), useVariant: () => ({ name: "disabled", enabled: false }), })); function renderAt(path: string) { const router = createMemoryRouter(routes, { initialEntries: [path] }); return render(); } beforeEach(() => { flagsOn.clear(); window.__APP_CONFIG__ = { API_BASE_URL: "/api", APP_NAME: "test-app" }; }); afterEach(() => { vi.unstubAllGlobals(); }); describe("app", () => { it("library lists published stories and links to play", async () => { vi.stubGlobal( "fetch", vi.fn( async () => new Response( JSON.stringify({ stories: [ { id: "s1", title: "Cave", description: "Dark", nodeCount: 3, published: true, }, ], }), ), ), ); renderAt("/"); expect( await screen.findByRole("heading", { name: "Cave" }), ).toBeInTheDocument(); expect( screen.getAllByRole("link", { name: "Play" }).at(-1)!, ).toHaveAttribute("href", "/play/s1"); }); it("library shows a builder prompt when empty", async () => { vi.stubGlobal( "fetch", vi.fn(async () => new Response(JSON.stringify({ stories: [] }))), ); renderAt("/"); expect( await screen.findByText(/No published stories yet/), ).toBeInTheDocument(); }); it("status fetches / and /readyz under API_BASE_URL and renders the JSON", async () => { const fetchMock = vi.fn(async (url: string) => { const body = url === "/api/readyz" ? { status: "ready" } : { service: "svc" }; return new Response(JSON.stringify(body), { status: 200 }); }); vi.stubGlobal("fetch", fetchMock); renderAt("/status"); expect(await screen.findByText(/GET \/readyz/)).toBeInTheDocument(); expect(screen.getByText(/"status": "ready"/)).toBeInTheDocument(); expect(screen.getByText(/"service": "svc"/)).toBeInTheDocument(); // Layout also asks /auth/me who is signed in; that's not what's under test. expect( fetchMock.mock.calls.map((c) => c[0]).filter((u) => u !== "/api/auth/me"), ).toEqual(["/api/", "/api/readyz"]); }); it("status shows the error page when the backend is unreachable", async () => { vi.stubGlobal( "fetch", vi.fn(async () => { throw new Error("network down"); }), ); renderAt("/status"); expect(await screen.findByRole("alert")).toHaveTextContent("network down"); }); });