2026-03-31 21:42:28 +07:00

139 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { fireEvent, render, screen } from "@solidjs/testing-library";
import { createSignal } from "solid-js";
import { describe, expect, it, vi } from "vitest";
import { Combobox } from "../../../src/components/combobox/index";
describe("Combobox roles", () => {
it("input has role=combobox", () => {
render(() => (
<Combobox items={["a", "b"]}>
<Combobox.Input />
<Combobox.Content>
<Combobox.Item value="a">A</Combobox.Item>
<Combobox.Item value="b">B</Combobox.Item>
</Combobox.Content>
</Combobox>
));
expect(screen.getByRole("combobox")).toBeTruthy();
});
it("content has role=listbox when open", () => {
render(() => (
<Combobox items={["a", "b"]} defaultOpen>
<Combobox.Input />
<Combobox.Content>
<Combobox.Item value="a">A</Combobox.Item>
<Combobox.Item value="b">B</Combobox.Item>
</Combobox.Content>
</Combobox>
));
expect(screen.getByRole("listbox")).toBeTruthy();
});
});
describe("Combobox input", () => {
it("typing opens content", () => {
const onInput = vi.fn();
render(() => (
<Combobox items={["a", "b"]} onInputChange={onInput}>
<Combobox.Input />
<Combobox.Content>
<Combobox.Item value="a">A</Combobox.Item>
<Combobox.Item value="b">B</Combobox.Item>
</Combobox.Content>
</Combobox>
));
fireEvent.input(screen.getByRole("combobox"), { target: { value: "a" } });
expect(onInput).toHaveBeenCalled();
});
it("controlled value works", () => {
render(() => (
<Combobox items={["a", "b"]} value="a" onValueChange={() => {}}>
<Combobox.Input />
<Combobox.Content>
<Combobox.Item value="a">A</Combobox.Item>
<Combobox.Item value="b">B</Combobox.Item>
</Combobox.Content>
</Combobox>
));
expect(screen.getByRole("combobox")).toBeTruthy();
});
});
describe("Combobox keyboard", () => {
it("ArrowDown highlights first item", () => {
render(() => (
<Combobox items={["a", "b"]} defaultOpen>
<Combobox.Input />
<Combobox.Content>
<Combobox.Item value="a">A</Combobox.Item>
<Combobox.Item value="b">B</Combobox.Item>
</Combobox.Content>
</Combobox>
));
fireEvent.keyDown(screen.getByRole("combobox"), { key: "ArrowDown" });
const options = screen.getAllByRole("option");
expect(options[0].getAttribute("data-highlighted")).toBe("");
});
it("Enter selects highlighted item", () => {
const onChange = vi.fn();
render(() => (
<Combobox items={["a", "b"]} defaultOpen onValueChange={onChange}>
<Combobox.Input />
<Combobox.Content>
<Combobox.Item value="a">A</Combobox.Item>
<Combobox.Item value="b">B</Combobox.Item>
</Combobox.Content>
</Combobox>
));
fireEvent.keyDown(screen.getByRole("combobox"), { key: "ArrowDown" });
fireEvent.keyDown(screen.getByRole("combobox"), { key: "Enter" });
expect(onChange).toHaveBeenCalledWith("a");
});
it("Escape closes", () => {
render(() => (
<Combobox items={["a", "b"]} defaultOpen>
<Combobox.Input />
<Combobox.Content>
<Combobox.Item value="a">A</Combobox.Item>
</Combobox.Content>
</Combobox>
));
fireEvent.keyDown(screen.getByRole("combobox"), { key: "Escape" });
expect(screen.queryByRole("listbox")).toBeNull();
});
});
describe("Combobox empty and custom", () => {
it("Empty message shown when no items", () => {
render(() => (
<Combobox items={[]} defaultOpen>
<Combobox.Input />
<Combobox.Content>
<Combobox.Empty>No results</Combobox.Empty>
</Combobox.Content>
</Combobox>
));
expect(screen.getByText("No results")).toBeTruthy();
});
it("allowCustomValue works", () => {
const onChange = vi.fn();
render(() => (
<Combobox items={[]} defaultOpen allowCustomValue onValueChange={onChange}>
<Combobox.Input />
<Combobox.Content>
<Combobox.Empty>No results</Combobox.Empty>
</Combobox.Content>
</Combobox>
));
const input = screen.getByRole("combobox") as HTMLInputElement;
fireEvent.input(input, { target: { value: "custom" } });
fireEvent.keyDown(input, { key: "Enter" });
expect(onChange).toHaveBeenCalledWith("custom");
});
});