Files
storkit/frontend/src/components/selection/SelectionScreen.test.tsx

137 lines
4.1 KiB
TypeScript
Raw Normal View History

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> = {},
): SelectionScreenProps {
return {
knownProjects: [],
onOpenProject: vi.fn(),
onForgetProject: vi.fn(),
pathInput: "",
homeDir: null,
onPathInputChange: vi.fn(),
onPathInputKeyDown: vi.fn() as (
event: KeyboardEvent<HTMLInputElement>,
) => 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(<SelectionScreen {...makeProps()} />);
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(
<SelectionScreen
{...makeProps({ knownProjects: ["/Users/test/project"] })}
/>,
);
expect(screen.getByText("Recent projects")).toBeInTheDocument();
});
it("does not render recent projects list when knownProjects is empty", () => {
render(<SelectionScreen {...makeProps({ knownProjects: [] })} />);
expect(screen.queryByText("Recent projects")).not.toBeInTheDocument();
});
it("calls onOpenProject when Open Project button is clicked", () => {
const onOpenProject = vi.fn();
render(
<SelectionScreen
{...makeProps({ pathInput: "/my/path", onOpenProject })}
/>,
);
fireEvent.click(screen.getByText("Open Project"));
expect(onOpenProject).toHaveBeenCalledWith("/my/path");
});
it("shows Opening... text and disables buttons when isOpening is true", () => {
render(<SelectionScreen {...makeProps({ isOpening: true })} />);
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(
<SelectionScreen {...makeProps({ completionError: "Path not found" })} />,
);
expect(screen.getByText("Path not found")).toBeInTheDocument();
});
it("does not display error div when completionError is null", () => {
const { container } = render(<SelectionScreen {...makeProps()} />);
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(
<SelectionScreen
{...makeProps({
homeDir: "/Users/test",
onPathInputChange,
onCloseSuggestions,
})}
/>,
);
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(
<SelectionScreen
{...makeProps({
homeDir: "/Users/test/",
onPathInputChange,
onCloseSuggestions,
})}
/>,
);
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(
<SelectionScreen {...makeProps({ homeDir: null, onPathInputChange })} />,
);
fireEvent.click(screen.getByText("New Project"));
expect(onPathInputChange).toHaveBeenCalledWith("");
});
});