import React from "react"; import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { describe, it, expect, vi } from "vitest"; import RadioButton from "../../../app/components/RadioButton"; describe("RadioButton Accessibility", () => { it("has proper ARIA attributes", () => { render(); const radioButton = screen.getByRole("radio"); expect(radioButton).toHaveAttribute("role", "radio"); expect(radioButton).toHaveAttribute("aria-checked", "false"); expect(radioButton).toHaveAttribute("tabIndex", "0"); }); it("updates aria-checked when checked state changes", () => { const { rerender } = render( , ); let radioButton = screen.getByRole("radio"); expect(radioButton).toHaveAttribute("aria-checked", "false"); rerender(); radioButton = screen.getByRole("radio"); expect(radioButton).toHaveAttribute("aria-checked", "true"); }); it("associates label with radio button", () => { render(); const radioButton = screen.getByRole("radio"); const labelId = radioButton.getAttribute("aria-labelledby"); expect(labelId).toBeTruthy(); const labelElement = document.getElementById(labelId); expect(labelElement).toHaveTextContent("Accessible Radio"); }); it("uses aria-label when provided", () => { render(); const radioButton = screen.getByRole("radio"); expect(radioButton).toHaveAttribute("aria-label", "Custom Aria Label"); expect(radioButton).not.toHaveAttribute("aria-labelledby"); }); it("prioritizes aria-label over aria-labelledby", () => { render(); const radioButton = screen.getByRole("radio"); expect(radioButton).toHaveAttribute("aria-label", "Hidden Aria Label"); expect(radioButton).not.toHaveAttribute("aria-labelledby"); }); it("is keyboard accessible", async () => { const user = userEvent.setup(); const handleChange = vi.fn(); render(); const radioButton = screen.getByRole("radio"); radioButton.focus(); expect(radioButton).toHaveFocus(); await user.keyboard(" "); expect(handleChange).toHaveBeenCalled(); }); it("handles Enter key activation", async () => { const user = userEvent.setup(); const handleChange = vi.fn(); render(); const radioButton = screen.getByRole("radio"); await user.click(radioButton); // Focus the element first await user.keyboard("Enter"); expect(handleChange).toHaveBeenCalled(); }); it("handles Space key activation", async () => { const user = userEvent.setup(); const handleChange = vi.fn(); render(); const radioButton = screen.getByRole("radio"); radioButton.focus(); await user.keyboard(" "); expect(handleChange).toHaveBeenCalled(); }); it("ignores other keys", async () => { const user = userEvent.setup(); const handleChange = vi.fn(); render(); const radioButton = screen.getByRole("radio"); radioButton.focus(); await user.keyboard("a"); await user.keyboard("Tab"); await user.keyboard("Escape"); expect(handleChange).not.toHaveBeenCalled(); }); it("has proper tab order", () => { render(
, ); const radioButtons = screen.getAllByRole("radio"); radioButtons.forEach((button) => { expect(button).toHaveAttribute("tabIndex", "0"); }); }); it("generates unique IDs for accessibility", () => { render(
, ); const radioButtons = screen.getAllByRole("radio"); const ids = radioButtons.map((button) => button.id); const uniqueIds = new Set(ids); expect(uniqueIds.size).toBe(3); expect(ids.every((id) => id.startsWith("radio-"))).toBe(true); }); it("uses provided ID for accessibility", () => { render(); const radioButton = screen.getByRole("radio"); expect(radioButton).toHaveAttribute("id", "custom-radio-id"); }); it("has accessible name from label", () => { render(); const radioButton = screen.getByRole("radio"); const accessibleName = radioButton.getAttribute("aria-labelledby"); const labelElement = document.getElementById(accessibleName); expect(labelElement).toHaveTextContent("Accessible Name Radio"); }); it("has accessible name from aria-label", () => { render(); const radioButton = screen.getByRole("radio"); expect(radioButton).toHaveAttribute("aria-label", "Aria Label Name"); }); it("maintains focus management", async () => { const handleChange = vi.fn(); const { rerender } = render( , ); const radioButton = screen.getByRole("radio"); radioButton.focus(); expect(radioButton).toHaveFocus(); // Change checked state rerender( , ); // Should still be focusable expect(radioButton).toHaveAttribute("tabIndex", "0"); }); it("has proper role and state", () => { render(); const radioButton = screen.getByRole("radio"); expect(radioButton).toHaveAttribute("role", "radio"); expect(radioButton).toHaveAttribute("aria-checked", "true"); }); it("supports screen reader navigation", () => { render(
, ); const radioButtons = screen.getAllByRole("radio"); // All should be in tab order radioButtons.forEach((button) => { expect(button).toHaveAttribute("tabIndex", "0"); expect(button).toHaveAttribute("role", "radio"); }); }); it("has proper form association", () => { render( , ); const hiddenInput = screen.getByDisplayValue("test-value"); expect(hiddenInput).toHaveAttribute("type", "radio"); expect(hiddenInput).toHaveAttribute("name", "test-radio"); expect(hiddenInput).toHaveAttribute("value", "test-value"); }); });