import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import * as React from "react"; import { describe, it, expect, vi, beforeEach } from "vitest"; import { render } from "vitest-browser-react"; // Mock API vi.mock("../../src/lib/api/client", async () => { const actual = await vi.importActual("../../src/lib/api/client"); return { ...actual, apiFetch: vi.fn().mockImplementation((url: string) => { if (url.includes("/setup/status")) { return Promise.resolve( new Response(JSON.stringify({ data: { needsSetup: true, authMode: "passkey" } }), { status: 200, }), ); } if (url.includes("/setup/admin")) { return Promise.resolve( new Response(JSON.stringify({ data: { success: true } }), { status: 200 }), ); } if (url.includes("/setup") && !url.includes("status")) { return Promise.resolve( new Response(JSON.stringify({ data: { success: true } }), { status: 200 }), ); } return Promise.resolve(new Response(JSON.stringify({ data: {} }), { status: 200 })); }), }; }); // Mock WebAuthn so PasskeyRegistration doesn't bail out Object.defineProperty(window, "PublicKeyCredential", { value: function PublicKeyCredential() {}, writable: true, }); // Import after mocks const { SetupWizard } = await import("../../src/components/SetupWizard"); function QueryWrapper({ children }: { children: React.ReactNode }) { const qc = new QueryClient({ defaultOptions: { queries: { retry: false }, mutations: { retry: false } }, }); return {children}; } describe("SetupWizard", () => { beforeEach(() => { vi.clearAllMocks(); }); it("shows site setup step first with title input", async () => { const screen = await render( , ); await expect.element(screen.getByText("Set up your site")).toBeInTheDocument(); await expect.element(screen.getByPlaceholder("My Awesome Blog")).toBeInTheDocument(); }); it("empty title prevents advancing and shows validation error", async () => { const screen = await render( , ); // Wait for setup status to load await expect.element(screen.getByText("Set up your site")).toBeInTheDocument(); // Click Continue without filling title await screen.getByText("Continue →").click(); await expect.element(screen.getByText("Site title is required")).toBeInTheDocument(); // Should still be on site step await expect.element(screen.getByText("Set up your site")).toBeInTheDocument(); }); it("filling title and clicking Next advances to admin step", async () => { const screen = await render( , ); await expect.element(screen.getByText("Set up your site")).toBeInTheDocument(); // Fill in the title await screen.getByPlaceholder("My Awesome Blog").fill("Test Site"); // Click continue await screen.getByText("Continue →").click(); // Should advance to admin step await expect.element(screen.getByText("Create your account")).toBeInTheDocument(); }); it("admin step shows email input", async () => { const screen = await render( , ); await expect.element(screen.getByText("Set up your site")).toBeInTheDocument(); // Fill title and advance await screen.getByPlaceholder("My Awesome Blog").fill("Test Site"); await screen.getByText("Continue →").click(); // Should see email input on admin step await expect.element(screen.getByText("Create your account")).toBeInTheDocument(); await expect.element(screen.getByPlaceholder("you@example.com")).toBeInTheDocument(); }); it("empty email prevents advancing on admin step", async () => { const screen = await render( , ); await expect.element(screen.getByText("Set up your site")).toBeInTheDocument(); // Fill title and advance await screen.getByPlaceholder("My Awesome Blog").fill("Test Site"); await screen.getByText("Continue →").click(); await expect.element(screen.getByText("Create your account")).toBeInTheDocument(); // Click Continue without filling email await screen.getByText("Continue →").click(); // Should show validation error await expect.element(screen.getByText("Email is required")).toBeInTheDocument(); }); it("step indicator shows three steps", async () => { const screen = await render( , ); await expect.element(screen.getByText("Set up your site")).toBeInTheDocument(); // Step indicator labels - use exact matching via role await expect.element(screen.getByText("Account")).toBeInTheDocument(); await expect.element(screen.getByText("Passkey")).toBeInTheDocument(); }); });