import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { SetupWizardModal } from "../SetupWizardModal";
// Mock the API
const mockRegisterProject = vi.fn();
vi.mock("../api", () => ({
registerProject: (...args: unknown[]) => mockRegisterProject(...args),
}));
// Mock lucide-react icons
vi.mock("lucide-react", () => ({
X: () => ×,
Loader2: () => ⟳,
FolderPlus: () => 📁,
CheckCircle: () => ✓,
}));
const noop = () => {};
describe("SetupWizardModal", () => {
beforeEach(() => {
vi.clearAllMocks();
localStorage.clear();
});
it("renders the wizard with manual step by default", async () => {
render(
);
// Should show welcome/manual screen
expect(await screen.findByText("Welcome to kb")).toBeDefined();
// Should show manual entry form
expect(screen.getByLabelText("Project Path")).toBeDefined();
expect(screen.getByLabelText("Project Name")).toBeDefined();
expect(screen.getByLabelText("Isolation Mode")).toBeDefined();
});
it("allows entering project details in manual step", async () => {
render(
);
const pathInput = await screen.findByLabelText("Project Path");
fireEvent.change(pathInput, { target: { value: "/path/to/project" } });
expect(pathInput).toHaveValue("/path/to/project");
});
it("calls onClose when close button is clicked", async () => {
const onClose = vi.fn();
render(
);
const closeButton = await screen.findByLabelText("Close wizard");
fireEvent.click(closeButton);
expect(onClose).toHaveBeenCalled();
});
it("disables register button when form is incomplete", async () => {
render(
);
// Wait for form to render
await screen.findByLabelText("Project Path");
const registerButton = screen.getByRole("button", { name: /register project/i });
expect(registerButton).toBeDisabled();
// Fill only path
fireEvent.change(screen.getByLabelText("Project Path"), {
target: { value: "/path/to/project" },
});
// Button should still be disabled
expect(registerButton).toBeDisabled();
});
it("enables register button when form is complete", async () => {
render(
);
// Wait for form to render
await screen.findByLabelText("Project Path");
// Fill the form
fireEvent.change(screen.getByLabelText("Project Path"), {
target: { value: "/path/to/project" },
});
fireEvent.change(screen.getByLabelText("Project Name"), {
target: { value: "test-project" },
});
// Wait for button to be enabled
const registerButton = screen.getByRole("button", { name: /register project/i });
await waitFor(() => expect(registerButton).not.toBeDisabled());
});
it("has isolation mode selector with correct options", async () => {
render(
);
const select = await screen.findByLabelText("Isolation Mode") as HTMLSelectElement;
expect(select.value).toBe("in-process");
// Check options exist
const options = Array.from(select.options);
expect(options.some(opt => opt.value === "in-process")).toBe(true);
expect(options.some(opt => opt.value === "child-process")).toBe(true);
});
it("shows form hint for project path", async () => {
render(
);
expect(await screen.findByText("Absolute path to your project directory")).toBeDefined();
});
it("has correct isolation mode default value", async () => {
render(
);
const select = await screen.findByLabelText("Isolation Mode") as HTMLSelectElement;
expect(select.value).toBe("in-process");
});
});