import { fireEvent, render, screen } from "@testing-library/react"; import type { KeyboardEvent } from "react"; import { describe, expect, it, vi } from "vitest"; import type { SelectionScreenProps } from "./SelectionScreen"; import { SelectionScreen } from "./SelectionScreen"; function makeProps( overrides: Partial = {}, ): SelectionScreenProps { return { knownProjects: [], onOpenProject: vi.fn(), onForgetProject: vi.fn(), pathInput: "", homeDir: null, onPathInputChange: vi.fn(), onPathInputKeyDown: vi.fn() as ( event: KeyboardEvent, ) => void, isOpening: false, suggestionTail: "", matchList: [], selectedMatch: -1, onSelectMatch: vi.fn(), onAcceptMatch: vi.fn(), onCloseSuggestions: vi.fn(), completionError: null, currentPartial: "", ...overrides, }; } describe("SelectionScreen", () => { it("renders the title and description", () => { render(); expect(screen.getByText("StorkIt")).toBeInTheDocument(); expect( screen.getByText("Paste or complete a project path to start."), ).toBeInTheDocument(); }); it("renders recent projects list when knownProjects is non-empty", () => { render( , ); expect(screen.getByText("Recent projects")).toBeInTheDocument(); }); it("does not render recent projects list when knownProjects is empty", () => { render(); expect(screen.queryByText("Recent projects")).not.toBeInTheDocument(); }); it("calls onOpenProject when Open Project button is clicked", () => { const onOpenProject = vi.fn(); render( , ); fireEvent.click(screen.getByText("Open Project")); expect(onOpenProject).toHaveBeenCalledWith("/my/path"); }); it("shows Opening... text and disables buttons when isOpening is true", () => { render(); expect(screen.getByText("Opening...")).toBeInTheDocument(); const buttons = screen.getAllByRole("button"); for (const button of buttons) { if ( button.textContent === "Opening..." || button.textContent === "New Project" ) { expect(button).toBeDisabled(); } } }); it("displays completion error when completionError is provided", () => { render( , ); expect(screen.getByText("Path not found")).toBeInTheDocument(); }); it("does not display error div when completionError is null", () => { const { container } = render(); const errorDiv = container.querySelector('[style*="color: red"]'); expect(errorDiv).toBeNull(); }); it("New Project button calls onPathInputChange with homeDir (trailing slash appended)", () => { const onPathInputChange = vi.fn(); const onCloseSuggestions = vi.fn(); render( , ); fireEvent.click(screen.getByText("New Project")); expect(onPathInputChange).toHaveBeenCalledWith("/Users/test/"); expect(onCloseSuggestions).toHaveBeenCalled(); }); it("New Project button uses homeDir as-is when it already ends with /", () => { const onPathInputChange = vi.fn(); const onCloseSuggestions = vi.fn(); render( , ); fireEvent.click(screen.getByText("New Project")); expect(onPathInputChange).toHaveBeenCalledWith("/Users/test/"); expect(onCloseSuggestions).toHaveBeenCalled(); }); it("New Project button uses empty string when homeDir is null", () => { const onPathInputChange = vi.fn(); render( , ); fireEvent.click(screen.getByText("New Project")); expect(onPathInputChange).toHaveBeenCalledWith(""); }); });