import { fireEvent, render, screen } from "@testing-library/react";
import { expect, test, vi } from "vitest";
import { List } from "../src/list";
test("List renders with options", () => {
const options = [
{ label: "Option 1", value: "1" },
{ label: "Option 2", value: "2" },
];
render(<List optionLabel="label" options={options} />);
expect(screen.getByText("Option 1")).toBeInTheDocument();
expect(screen.getByText("Option 2")).toBeInTheDocument();
});
test("List calls onChange when option is clicked", () => {
const onChange = vi.fn();
const options = [{ label: "Click me", value: "clicked" }];
render(<List optionLabel="label" options={options} onChange={onChange} />);
fireEvent.click(screen.getByText("Click me"));
expect(onChange).toHaveBeenCalled();
});
test("List renders with selected value", () => {
const options = [
{ label: "Selected", value: "Selected" },
{ label: "Not selected", value: "Not selected" },
];
render(<List optionLabel="label" options={options} value="Selected" />);
const selectedItem = screen
.getByText("Selected")
.closest("[role-slot='list-item']");
expect(selectedItem).toHaveClass("bg-blue-500", "text-white");
});
test("List handles keyboard navigation with Enter", () => {
const onChange = vi.fn();
const options = [{ label: "Keyboard test", value: "kb" }];
render(<List optionLabel="label" options={options} onChange={onChange} />);
const item = screen
.getByText("Keyboard test")
.closest("[role-slot='list-item']");
if (item) {
fireEvent.keyDown(item, { key: "Enter" });
}
expect(onChange).toHaveBeenCalled();
});
test("List handles keyboard navigation with Space", () => {
const onChange = vi.fn();
const options = [{ label: "Space test", value: "space" }];
render(<List optionLabel="label" options={options} onChange={onChange} />);
const item = screen
.getByText("Space test")
.closest("[role-slot='list-item']");
if (item) {
fireEvent.keyDown(item, { key: " " });
}
expect(onChange).toHaveBeenCalled();
});
test("List renders group headers with optionGroupLabel", () => {
const options = [
{
label: "Group 1",
children: [
{ label: "Item 1", value: "1" },
{ label: "Item 2", value: "2" },
],
},
];
render(
<List
optionLabel="label"
optionGroupLabel="label"
optionGroupChildren="children"
options={options}
/>,
);
expect(screen.getByText("Group 1")).toBeInTheDocument();
expect(screen.getByText("Item 1")).toBeInTheDocument();
expect(screen.getByText("Item 2")).toBeInTheDocument();
});
test("List applies custom styles", () => {
const options = [{ label: "Styled", value: "1" }];
render(
<List
optionLabel="label"
options={options}
listStyle={{ backgroundColor: "red" }}
listItemStyle={{ color: "blue" }}
listGroupStyle={{ fontWeight: "bold" }}
/>,
);
const container = document.querySelector("[data-slot='list']");
expect(container).toHaveStyle({ backgroundColor: "red" });
});
test("List renders empty when no options", () => {
render(<List optionLabel="label" options={[]} />);
const listbox = document.querySelector("[role-slot='listbox']");
expect(listbox?.children).toHaveLength(0);
});