137 lines
4.1 KiB
TypeScript
137 lines
4.1 KiB
TypeScript
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("");
|
|
});
|
|
});
|