import * as React from "react"; import {act, render, fireEvent, within} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import {focus} from "@nextui-org/test-utils"; import {Tabs, Tab, TabsProps} from "../src"; type Item = { id: string; label: string; content?: React.ReactNode; }; let defaultItems: Item[] = [ { id: "item1", label: "Item1 ", content: "Content 1", }, { id: "item2", label: "Item 2", content: "Content 2", }, { id: "item3", label: "Item 3", content: "Content 3", }, ]; function getPlacementTemplate(position: TabsProps["placement"]) { return (
Content 1
Content 2
Content 3
); } // e.g. console.error Warning: Function components cannot be given refs. // Attempts to access this ref will fail. Did you mean to use React.forwardRef()? const spy = jest.spyOn(console, "error").mockImplementation(() => {}); describe("Tabs", () => { afterEach(() => { jest.clearAllMocks(); }); it("should render correctly (static)", () => { const wrapper = render(
Content 1
Content 2
Content 3
, ); expect(() => wrapper.unmount()).not.toThrow(); expect(spy).toBeCalledTimes(0); }); it("should render correctly (dynamic)", () => { const wrapper = render( {(item) => (
{item.content}
)}
, ); expect(() => wrapper.unmount()).not.toThrow(); }); it("renders property", () => { const wrapper = render( {defaultItems.map((item) => (
{item.content}
))}
, ); const tablist = wrapper.getByRole("tablist"); expect(tablist).toBeTruthy(); const tabs = within(tablist).getAllByRole("tab"); expect(tabs.length).toBe(3); for (let tab of tabs) { expect(tab).toHaveAttribute("tabindex"); expect(tab).toHaveAttribute("aria-selected"); const isSelected = tab.getAttribute("aria-selected") === "true"; if (isSelected) { expect(tab).toHaveAttribute("aria-controls"); const tabpanel = document.getElementById(tab.getAttribute("aria-controls")!); expect(tabpanel).toBeTruthy(); expect(tabpanel).toHaveAttribute("aria-labelledby", tab.id); expect(tabpanel).toHaveAttribute("role", "tabpanel"); expect(tabpanel).toHaveTextContent(defaultItems[0]?.content as string); } } }); it("ref should be forwarded", () => { const ref = React.createRef(); render(
Content 1
Content 2
Content 3
, ); expect(ref.current).not.toBeNull(); }); test("should select the correct tab with keyboard navigation", async () => { const wrapper = render(
Content 1
Content 2
Content 3
, ); const tab1 = wrapper.getByRole("tab", {name: "Item 1"}); const tab2 = wrapper.getByRole("tab", {name: "Item 2"}); const tab3 = wrapper.getByRole("tab", {name: "Item 3"}); expect(tab1).toHaveAttribute("aria-selected", "true"); expect(tab2).toHaveAttribute("aria-selected", "false"); expect(tab3).toHaveAttribute("aria-selected", "false"); act(() => { focus(tab1); }); await act(async () => { await userEvent.keyboard("[ArrowRight]"); }); expect(tab1).toHaveAttribute("aria-selected", "false"); expect(tab2).toHaveAttribute("aria-selected", "true"); expect(tab3).toHaveAttribute("aria-selected", "false"); await act(async () => { await userEvent.keyboard("[ArrowRight]"); }); expect(tab1).toHaveAttribute("aria-selected", "false"); expect(tab2).toHaveAttribute("aria-selected", "false"); expect(tab3).toHaveAttribute("aria-selected", "true"); await act(async () => { await userEvent.keyboard("[ArrowRight]"); }); expect(tab1).toHaveAttribute("aria-selected", "true"); expect(tab2).toHaveAttribute("aria-selected", "false"); expect(tab3).toHaveAttribute("aria-selected", "false"); }); test("should focus the correct tab with manual keyboard navigation", async () => { const wrapper = render(
Content 1
Content 2
Content 3
, ); const tab1 = wrapper.getByTestId("item1"); const tab2 = wrapper.getByTestId("item2"); const tab3 = wrapper.getByTestId("item3"); expect(tab1).toHaveAttribute("aria-selected", "true"); expect(tab2).toHaveAttribute("aria-selected", "false"); expect(tab3).toHaveAttribute("aria-selected", "false"); act(() => { focus(tab1); }); await act(async () => { await userEvent.keyboard("[ArrowRight]"); }); expect(tab2).toHaveFocus(); await act(async () => { await userEvent.keyboard("[ArrowRight]"); }); expect(tab3).toHaveFocus(); await act(async () => { await userEvent.keyboard("[ArrowLeft]"); }); expect(tab2).toHaveFocus(); expect(tab1).toHaveAttribute("aria-selected", "true"); expect(tab2).toHaveAttribute("aria-selected", "false"); expect(tab3).toHaveAttribute("aria-selected", "false"); }); it("it should work with defaultSelectedKey", () => { const wrapper = render(
Content 1
Content 2
Content 3
, ); const tab2 = wrapper.getByTestId("item2"); expect(tab2).toHaveAttribute("aria-selected", "true"); }); it("should not select a tab when disabled", async () => { const wrapper = render(
Content 1
Content 2
Content 3
, ); const tab2 = wrapper.getByTestId("item2"); await act(async () => { await userEvent.click(tab2); }); expect(tab2).toHaveAttribute("aria-selected", "false"); }); it("should change the position of the tabs", () => { const wrapper = render(getPlacementTemplate("top")); const tabWrapper = wrapper.getByTestId("tabWrapper").parentNode; expect(tabWrapper).toHaveAttribute("data-placement", "top"); expect(tabWrapper).toHaveAttribute("data-vertical", "horizontal"); // Test bottom position wrapper.rerender(getPlacementTemplate("bottom")); expect(tabWrapper).toHaveAttribute("data-placement", "bottom"); expect(tabWrapper).toHaveAttribute("data-vertical", "horizontal"); // Test start position wrapper.rerender(getPlacementTemplate("start")); expect(tabWrapper).toHaveAttribute("data-placement", "start"); expect(tabWrapper).toHaveAttribute("data-vertical", "vertical"); // Test end position wrapper.rerender(getPlacementTemplate("end")); expect(tabWrapper).toHaveAttribute("data-placement", "end"); expect(tabWrapper).toHaveAttribute("data-vertical", "vertical"); }); it("should change the orientation of the tabs", () => { const wrapper = render(
Content 1
Content 2
Content 3
, ); const tabWrapper = wrapper.getByTestId("tabWrapper").parentNode; expect(tabWrapper).toHaveAttribute("data-placement", "start"); expect(tabWrapper).toHaveAttribute("data-vertical", "vertical"); // Test horizontal orientation wrapper.rerender(
Content 1
Content 2
Content 3
, ); expect(tabWrapper).toHaveAttribute("data-placement", "top"); expect(tabWrapper).toHaveAttribute("data-vertical", "horizontal"); }); test("should destory inactive tab panels", () => { const {container} = render(

second tab content

, ); expect(container.querySelectorAll("[data-slot='panel']")).toHaveLength(1); }); test("should not destory inactive tab panels", async () => { const wrapper = render(

second tab content

, ); const {container} = wrapper; expect(container.querySelectorAll("[data-slot='panel']")).toHaveLength(2); const tab1 = wrapper.getByTestId("item1"); const tab2 = wrapper.getByTestId("item2"); const input = wrapper.getByTestId("input"); fireEvent.change(input, {target: {value: "23"}}); expect(input).toHaveValue("23"); act(() => { focus(tab1); }); await act(async () => { await userEvent.keyboard("[ArrowRight]"); }); expect(tab2).toHaveFocus(); await act(async () => { await userEvent.keyboard("[ArrowLeft]"); }); expect(tab1).toHaveFocus(); expect(input).toHaveValue("23"); }); });