import { useRef } from "react"; import { render, screen } from "@testing-library/react"; import { userEvent } from "@testing-library/user-event"; import { useActiveDescendant } from "./useActiveDescendant"; import { CarouselRoot } from "./CarouselRoot"; import { CarouselContent } from "./CarouselContent"; import { CarouselItem } from "./CarouselItem"; const ComponentWrapper = ({ onClick }: { onClick?: () => void }) => { const containerRef = useRef(null); const { handleDescendantFocus, contentProps, addDescendant, focusClassName } = useActiveDescendant(containerRef); return ( { addDescendant({ element: el, id: "test-1-link", parentId: "test-1", }); }} className={focusClassName(`test-1-link`)} > Test 1 { addDescendant({ element: el, id: "test-1-link-2", parentId: "test-1", }); }} className={focusClassName(`test-1-link-2`)} > Test 1.2 ); }; const activeClassname = "wpds-c-cDbbMU"; describe("useActiveDescendant", () => { test("renders visibly into the document", () => { render(); expect(screen.getByText("Test 1")).toBeVisible(); }); test("uses the down arrow to navigate to child elements", async () => { const user = userEvent.setup(); render(); const groups = screen.getAllByRole("group"); const content = groups[1]; await user.tab(); expect(content).toHaveFocus(); expect(content).toHaveAttribute("aria-activedescendant", "test-1"); await user.keyboard("[ArrowDown]"); expect(screen.getByText("Test 1")).toHaveClass(activeClassname); expect(content).toHaveAttribute("aria-activedescendant", "test-1-link"); }); test("uses the up arrow to navigate away from child elements", async () => { const user = userEvent.setup(); render(); await user.tab(); await user.keyboard("[ArrowDown]"); await user.keyboard("[ArrowUp]"); expect(screen.getByText("Test 1")).not.toHaveClass(activeClassname); }); test("uses the up and down arrow to navigate between child elements", async () => { const user = userEvent.setup(); render(); const groups = screen.getAllByRole("group"); const content = groups[1]; await user.tab(); await user.keyboard("[ArrowDown]"); await user.keyboard("[ArrowDown]"); expect(screen.getByText("Test 1.2")).toHaveClass(activeClassname); expect(content).toHaveAttribute("aria-activedescendant", "test-1-link-2"); await user.keyboard("[ArrowUp]"); expect(screen.getByText("Test 1")).toHaveClass(activeClassname); expect(screen.getByText("Test 1.2")).not.toHaveClass(activeClassname); expect(content).toHaveAttribute("aria-activedescendant", "test-1-link"); }); test("removes active child when new parent becomes active", async () => { const user = userEvent.setup(); render(); const groups = screen.getAllByRole("group"); const content = groups[1]; await user.tab(); await user.keyboard("[ArrowDown]"); await user.keyboard("[ArrowRight]"); expect(screen.getByText("Test 1")).not.toHaveClass(activeClassname); expect(content).toHaveAttribute("aria-activedescendant", "test-2"); }); test("removes active child when content loses focus", async () => { const user = userEvent.setup(); render(); await user.tab(); await user.keyboard("[ArrowDown]"); await user.tab(); expect(screen.getByText("Test 1")).not.toHaveClass(activeClassname); }); test("replaces active child when content returns focus", async () => { const user = userEvent.setup(); render(); await user.tab(); await user.keyboard("[ArrowDown]"); await user.tab(); await user.tab(); expect(screen.getByText("Test 1")).toHaveClass(activeClassname); }); test("fires child click event from keyboard interaction", async () => { const user = userEvent.setup(); const handleClick = jest.fn(); render(); await user.tab(); await user.keyboard("[ArrowRight]"); await user.keyboard("[ArrowDown]"); await user.keyboard("[Space]"); await user.keyboard("[Enter]"); expect(handleClick).toHaveBeenCalledTimes(2); }); });