import React from "react"; import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { expect, describe, it, vi } from "vitest"; import { axe, toHaveNoViolations } from "jest-axe"; import ContextMenu from "../../app/components/ContextMenu"; import ContextMenuItem from "../../app/components/ContextMenuItem"; import ContextMenuSection from "../../app/components/ContextMenuSection"; import ContextMenuDivider from "../../app/components/ContextMenuDivider"; expect.extend(toHaveNoViolations); describe("ContextMenu Components Accessibility", () => { describe("ContextMenu Accessibility", () => { it("has no accessibility violations", async () => { const { container } = render( Item 1 Item 2 , ); const results = await axe(container); expect(results).toHaveNoViolations(); }); it("has proper role and structure", () => { render( Item 1 Item 2 , ); const menu = screen.getByRole("menu"); expect(menu).toBeInTheDocument(); const items = screen.getAllByRole("menuitem"); expect(items).toHaveLength(2); }); it("has proper focus management", async () => { render( Item 1 Item 2 , ); const firstItem = screen.getByRole("menuitem", { name: "Item 1" }); expect(firstItem).toHaveAttribute("tabIndex", "0"); expect(firstItem).toBeInTheDocument(); }); }); describe("ContextMenuItem Accessibility", () => { it("has no accessibility violations", async () => { const { container } = render( Test Item , ); const results = await axe(container); expect(results).toHaveNoViolations(); }); it("has proper ARIA attributes", () => { render( Test Item , ); const item = screen.getByRole("menuitem"); expect(item).not.toHaveAttribute("aria-current"); }); it("updates aria-current when selected", () => { render( Test Item , ); const item = screen.getByRole("menuitem"); expect(item).toHaveAttribute("aria-current", "true"); }); it("is keyboard accessible", async () => { const user = userEvent.setup(); const onClick = vi.fn(); render( Test Item , ); const item = screen.getByRole("menuitem"); item.focus(); await user.keyboard("{Enter}"); expect(onClick).toHaveBeenCalled(); }); it("is accessible with Space key", async () => { const user = userEvent.setup(); const onClick = vi.fn(); render( Test Item , ); const item = screen.getByRole("menuitem"); item.focus(); await user.keyboard(" "); expect(onClick).toHaveBeenCalled(); }); it("has proper focus indicators", () => { render( Test Item , ); const item = screen.getByRole("menuitem"); expect(item).toHaveClass( "hover:!bg-[var(--color-surface-default-secondary)]", ); }); it("announces selection state to screen readers", () => { render( Test Item , ); const item = screen.getByRole("menuitem"); expect(item).toHaveAttribute("aria-current", "true"); }); }); describe("ContextMenuSection Accessibility", () => { it("has no accessibility violations", async () => { const { container } = render( Item 1 , ); const results = await axe(container); expect(results).toHaveNoViolations(); }); it("has proper heading structure", () => { render( Item 1 , ); const title = screen.getByText("Test Section"); expect(title).toBeInTheDocument(); }); it("has sufficient color contrast for section title", () => { render( Item 1 , ); const title = screen.getByText("Test Section"); expect(title).toHaveClass("text-[var(--color-content-default-primary)]"); }); }); describe("ContextMenuDivider Accessibility", () => { it("has no accessibility violations", async () => { const { container } = render(); const results = await axe(container); expect(results).toHaveNoViolations(); }); it("has proper semantic structure", () => { render(); const divider = screen.getByRole("separator"); expect(divider).toBeInTheDocument(); }); it("has sufficient visual contrast", () => { render(); const divider = screen.getByRole("separator"); expect(divider).toHaveClass( "border-[var(--color-border-default-tertiary)]", ); }); }); describe("Integrated Menu Accessibility", () => { const TestMenu = () => ( Item 1 Item 2 Item 3 ); it("has no accessibility violations when integrated", async () => { const { container } = render(); const results = await axe(container); expect(results).toHaveNoViolations(); }); it("has proper menu structure", () => { render(); const menu = screen.getByRole("menu"); expect(menu).toBeInTheDocument(); const items = screen.getAllByRole("menuitem"); expect(items).toHaveLength(3); expect(screen.getByText("First Section")).toBeInTheDocument(); expect(screen.getByText("Second Section")).toBeInTheDocument(); }); it("maintains proper focus order", async () => { render(); const items = screen.getAllByRole("menuitem"); expect(items).toHaveLength(3); // Check that all items are focusable items.forEach((item) => { expect(item).toHaveAttribute("tabIndex", "0"); }); }); it("handles keyboard navigation correctly", async () => { const user = userEvent.setup(); const onClick = vi.fn(); render( Item 1 Item 2 , ); const items = screen.getAllByRole("menuitem"); items[0].focus(); await user.keyboard("{Enter}"); expect(onClick).toHaveBeenCalled(); }); }); describe("Color Contrast", () => { it("has sufficient contrast for menu items", () => { render( Test Item , ); const item = screen.getByRole("menuitem"); expect(item).toHaveClass( "text-[var(--color-content-default-brand-primary)]", ); }); it("has sufficient contrast for section titles", () => { render( , ); const title = screen.getByText("Test Section"); expect(title).toHaveClass("text-[var(--color-content-default-primary)]"); }); it("has sufficient contrast for dividers", () => { render( , ); const divider = screen.getByRole("separator"); expect(divider).toHaveClass( "border-[var(--color-border-default-tertiary)]", ); }); }); describe("Screen Reader Support", () => { it("announces menu structure correctly", () => { render( Item 1 Item 2 , ); const menu = screen.getByRole("menu"); expect(menu).toBeInTheDocument(); const items = screen.getAllByRole("menuitem"); expect(items[0]).not.toHaveAttribute("aria-current"); expect(items[1]).toHaveAttribute("aria-current", "true"); }); it("announces selection state changes", async () => { const { rerender } = render( Test Item , ); const item = screen.getByRole("menuitem"); expect(item).not.toHaveAttribute("aria-current"); rerender( Test Item , ); expect(item).toHaveAttribute("aria-current", "true"); }); }); describe("WCAG Compliance", () => { it("meets WCAG 2.1 AA standards", async () => { const { container } = render( Item 1 Item 2 Item 3 , ); const results = await axe(container); expect(results).toHaveNoViolations(); }); it("meets WCAG standards in all states", async () => { const { container } = render( Selected Item Submenu Item Disabled Item , ); const results = await axe(container); expect(results).toHaveNoViolations(); }); }); });