import { resolve } from "node:path";
import { describe, expect, it, vi } from "vitest";
import { render, fireEvent } from "@testing-library/preact";
import { Tabs } from "./Tabs.js";
const sampleTabs = [
{ id: "one", label: "Tab One", content:
Content One
},
{ id: "two", label: "Tab Two", content: Content Two
},
{ id: "three", label: "Tab Three", content: Content Three
},
];
describe("Tabs", () => {
it("renders a tablist whose selected tab is the only one in the tab order and whose panel is the only one shown", () => {
const { getAllByRole, getByRole } = render( {}} />);
expect(getByRole("tablist")).toBeTruthy();
const tabs = getAllByRole("tab");
expect(tabs.map((t) => t.getAttribute("aria-selected"))).toEqual(["false", "true", "false"]);
expect(tabs.map((t) => t.tabIndex)).toEqual([-1, 0, -1]);
const panels = getAllByRole("tabpanel", { hidden: true });
expect(panels.map((p) => p.hidden)).toEqual([true, false, true]);
});
it("wires each panel to its tab with ids that do not collide across two sets", () => {
const { container } = render(
{}} />
{}} />
,
);
const tabs = Array.from(container.querySelectorAll('[role="tab"]'));
const ids = tabs.map((t) => t.id);
expect(new Set(ids).size).toBe(ids.length);
for (const tab of tabs) {
const panel = container.querySelector(`#${CSS.escape(tab.getAttribute("aria-controls") as string)}`);
expect(panel?.getAttribute("aria-labelledby")).toBe(tab.id);
}
});
it("clicking a tab calls onChange with its id", () => {
const onChange = vi.fn();
const { getAllByRole } = render();
fireEvent.click(getAllByRole("tab")[1]);
expect(onChange).toHaveBeenCalledWith("two");
});
it("owns the selection when uncontrolled: the first tab, or defaultActiveTab, then whatever is clicked", () => {
const { getAllByRole } = render();
const tabs = getAllByRole("tab");
expect(tabs[2]).toHaveAttribute("aria-selected", "true");
fireEvent.click(tabs[0]);
expect(tabs[0]).toHaveAttribute("aria-selected", "true");
expect(tabs[2]).toHaveAttribute("aria-selected", "false");
const first = render();
expect(first.getAllByRole("tab")[0]).toHaveAttribute("aria-selected", "true");
});
it("the arrows, Home and End select and focus, wrapping at the ends", () => {
const onChange = vi.fn();
const { getAllByRole } = render();
const tabs = getAllByRole("tab");
fireEvent.keyDown(tabs[0], { key: "ArrowRight" });
expect(onChange).toHaveBeenLastCalledWith("two");
expect(document.activeElement).toBe(tabs[1]);
fireEvent.keyDown(tabs[0], { key: "ArrowLeft" });
expect(onChange).toHaveBeenLastCalledWith("three");
fireEvent.keyDown(tabs[0], { key: "End" });
expect(onChange).toHaveBeenLastCalledWith("three");
fireEvent.keyDown(tabs[0], { key: "Home" });
expect(onChange).toHaveBeenLastCalledWith("one");
});
it("with manual activation the arrows move focus only, and Enter or Space (a click) selects", () => {
const onChange = vi.fn();
const { getAllByRole } = render();
const tabs = getAllByRole("tab");
fireEvent.keyDown(tabs[0], { key: "ArrowRight" });
expect(document.activeElement).toBe(tabs[1]);
expect(onChange).not.toHaveBeenCalled();
fireEvent.keyDown(tabs[1], { key: "ArrowRight" });
expect(document.activeElement).toBe(tabs[2]);
fireEvent.click(tabs[2]);
expect(onChange).toHaveBeenCalledWith("three");
});
it("the instrument variant is a class on the root", () => {
const { container } = render();
expect(container.querySelector(".strand-tabs.strand-tabs--instrument")).toBeTruthy();
});
});
import { snapshotFixtures } from "../../test/snapshot.js";
import { snapshotStylesheet } from "../../test/stylesheet.js";
import { fixtures } from "./Tabs.fixtures.js";
snapshotFixtures(Tabs, fixtures);
snapshotStylesheet(resolve(__dirname, "./Tabs.css"));