import { createPointerEvent, installPointerEvent } from "@kobalte/tests";
import { fireEvent, render, within } from "@solidjs/testing-library";
import { vi } from "vitest";
import userEvent from "@testing-library/user-event";
import * as ToggleGroup from ".";
describe("ToggleGroup", () => {
const user = userEvent.setup({ delay: null });
beforeEach(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.clearAllMocks();
vi.clearAllTimers();
});
afterAll(() => {
vi.restoreAllMocks();
});
installPointerEvent();
it("can have a default value", async () => {
const onChangeSpy = vi.fn();
const { getByRole, getAllByTestId, getByText } = render(() => (
Dogs
Cats
Dragons
));
const toggleGroup = getByRole("group");
const buttons = getAllByTestId("item") as HTMLButtonElement[];
expect(toggleGroup).toBeTruthy();
expect(buttons.length).toBe(3);
expect(onChangeSpy).not.toHaveBeenCalled();
expect(buttons[0]).toHaveAttribute("aria-pressed", "false");
expect(buttons[1]).toHaveAttribute("aria-pressed", "true");
expect(buttons[2]).toHaveAttribute("aria-pressed", "false");
const dragons = getByText("Dragons");
fireEvent.click(dragons);
await Promise.resolve();
expect(onChangeSpy).toHaveBeenCalledTimes(1);
expect(onChangeSpy).toHaveBeenCalledWith("dragons");
expect(buttons[0]).toHaveAttribute("aria-pressed", "false");
expect(buttons[1]).toHaveAttribute("aria-pressed", "false");
expect(buttons[2]).toHaveAttribute("aria-pressed", "true");
});
it("allows user to change toggle item via left/right arrow keys with horizontal group", async () => {
const { getByRole } = render(() => (
Dogs
Cats
Dragons
));
const toggleGroup = getByRole("group");
const toggles = within(toggleGroup).getAllByTestId("item");
const selectedItem = toggles[0];
expect(toggleGroup).toHaveAttribute("data-orientation", "horizontal");
expect(selectedItem).toHaveAttribute("tabindex", "-1");
selectedItem.focus();
fireEvent.keyDown(selectedItem, {
key: "ArrowRight",
code: 39,
charCode: 39,
});
await Promise.resolve();
const nextSelectedItem = toggles[1];
expect(nextSelectedItem).toHaveAttribute("tabindex", "0");
fireEvent.keyDown(nextSelectedItem, {
key: "ArrowLeft",
code: 37,
charCode: 37,
});
await Promise.resolve();
expect(selectedItem).toHaveAttribute("tabindex", "0");
/** Doesn't change selection because its horizontal group. */
fireEvent.keyDown(selectedItem, { key: "ArrowUp", code: 38, charCode: 38 });
await Promise.resolve();
expect(selectedItem).toHaveAttribute("tabindex", "0");
fireEvent.keyDown(selectedItem, {
key: "ArrowDown",
code: 40,
charCode: 40,
});
await Promise.resolve();
expect(selectedItem).toHaveAttribute("tabindex", "0");
});
it("allows user to change toggle item via up/down arrow keys with vertical group", async () => {
const { getByRole } = render(() => (
Dogs
Cats
Dragons
));
const toggleGroup = getByRole("group");
const toggles = within(toggleGroup).getAllByTestId("item");
const selectedItem = toggles[0];
expect(toggleGroup).toHaveAttribute("data-orientation", "vertical");
expect(selectedItem).toHaveAttribute("tabindex", "-1");
selectedItem.focus();
fireEvent.keyDown(selectedItem, {
key: "ArrowDown",
code: 40,
charCode: 40,
});
await Promise.resolve();
const nextSelectedItem = toggles[1];
expect(nextSelectedItem).toHaveAttribute("tabindex", "0");
fireEvent.keyDown(selectedItem, {
key: "ArrowUp",
code: 38,
charCode: 38,
});
await Promise.resolve();
expect(selectedItem).toHaveAttribute("tabindex", "0");
/** Doesn't change selection because its vertical group. */
fireEvent.keyDown(selectedItem, {
key: "ArrowRight",
code: 39,
charCode: 39,
});
await Promise.resolve();
expect(selectedItem).toHaveAttribute("tabindex", "0");
fireEvent.keyDown(nextSelectedItem, {
key: "ArrowLeft",
code: 37,
charCode: 37,
});
await Promise.resolve();
expect(selectedItem).toHaveAttribute("tabindex", "0");
});
it("select last item via end key / select first item via home key", async () => {
const { getByRole } = render(() => (
Dogs
Cats
Dragons
));
const toggleGroup = getByRole("group");
const toggles = within(toggleGroup).getAllByTestId("item");
const firstItem = toggles[0];
firstItem.focus();
expect(toggleGroup).toHaveAttribute("data-orientation", "horizontal");
expect(firstItem).toHaveAttribute("tabindex", "0");
fireEvent.keyDown(firstItem, { key: "End", code: 35, charCode: 35 });
await Promise.resolve();
const lastItem = toggles[toggles.length - 1];
expect(lastItem).toHaveAttribute("tabindex", "0");
fireEvent.keyDown(lastItem, { key: "Home", code: 36, charCode: 36 });
await Promise.resolve();
expect(firstItem).toHaveAttribute("tabindex", "0");
});
it("supports using click to change state", async () => {
const { getByRole } = render(() => (
Dogs
Cats
Dragons
));
const toggleGroup = getByRole("group");
const toggles = within(toggleGroup).getAllByTestId("item");
const [firstItem, secondItem] = toggles;
expect(firstItem).toHaveAttribute("aria-pressed", "false");
fireEvent(
secondItem,
createPointerEvent("pointerdown", { pointerId: 1, pointerType: "mouse" }),
);
await Promise.resolve();
expect(secondItem).toHaveAttribute("aria-pressed", "true");
fireEvent(
firstItem,
createPointerEvent("pointerdown", { pointerId: 1, pointerType: "mouse" }),
);
await Promise.resolve();
expect(firstItem).toHaveAttribute("aria-pressed", "true");
expect(secondItem).toHaveAttribute("aria-pressed", "false");
});
it("multi-select", async () => {
const { getByRole } = render(() => (
Dogs
Cats
Dragons
));
const toggleGroup = getByRole("group");
const toggles = within(toggleGroup).getAllByTestId("item");
const [firstItem, secondItem] = toggles;
expect(firstItem).toHaveAttribute("aria-pressed", "false");
fireEvent(
secondItem,
createPointerEvent("pointerdown", { pointerId: 1, pointerType: "mouse" }),
);
await Promise.resolve();
fireEvent(
firstItem,
createPointerEvent("pointerdown", { pointerId: 1, pointerType: "mouse" }),
);
await Promise.resolve();
expect(firstItem).toHaveAttribute("aria-pressed", "true");
expect(secondItem).toHaveAttribute("aria-pressed", "true");
});
it.skipIf(process.env.GITHUB_ACTIONS)(
"should focus the selected item when tabbing in for the first time",
async () => {
const { getByRole } = render(() => (
Dogs
Cats
Dragons
));
await user.tab();
const toggleGroup = getByRole("group");
const toggles = within(toggleGroup).getAllByTestId("item");
expect(document.activeElement).toBe(toggles[2]);
},
);
it.skipIf(process.env.GITHUB_ACTIONS)(
"should not focus if group is disabled",
async () => {
const { getByTestId } = render(() => (
<>
Dogs
Cats
Dragons
>
));
await user.tab();
const button = getByTestId("focus-btn");
expect(document.activeElement).toBe(button);
},
);
it.skipIf(process.env.GITHUB_ACTIONS)(
"disabled item should be be pressed",
async () => {
const onValueChangeSpy = vi.fn();
const { getByRole } = render(() => (
Dogs
Cats
Dragons
));
await user.tab();
const toggleGroup = getByRole("group");
const toggles = within(toggleGroup).getAllByTestId("item");
expect(document.activeElement).toBe(toggles[0]);
await user.click(toggles[1]);
expect(onValueChangeSpy).not.toBeCalled();
},
);
});