import React from "react"; import { render, screen, fireEvent } from "@testing-library/react"; import { expect, test, describe, vi } from "vitest"; import { axe, toHaveNoViolations } from "jest-axe"; import Input from "../../app/components/Input"; expect.extend(toHaveNoViolations); describe("Input Component Accessibility", () => { test("has no accessibility violations", async () => { const { container } = render(); const results = await axe(container); expect(results).toHaveNoViolations(); }); test("has no accessibility violations when disabled", async () => { const { container } = render(); const results = await axe(container); expect(results).toHaveNoViolations(); }); test("has no accessibility violations when in error state", async () => { const { container } = render(); const results = await axe(container); expect(results).toHaveNoViolations(); }); test("has no accessibility violations with horizontal label", async () => { const { container } = render( ); const results = await axe(container); expect(results).toHaveNoViolations(); }); test("associates label with input correctly", () => { render(); const input = screen.getByLabelText("Test input"); expect(input).toBeInTheDocument(); expect(input).toHaveAttribute("type", "text"); }); test("maintains label association with custom ID", () => { render(); const input = screen.getByLabelText("Test input"); expect(input).toHaveAttribute("id", "custom-input"); }); test("supports keyboard navigation", () => { render(); const input = screen.getByRole("textbox"); // Input should be focusable input.focus(); expect(input).toHaveFocus(); }); test("supports keyboard activation", () => { const handleChange = vi.fn(); render(); const input = screen.getByRole("textbox"); // Type in the input fireEvent.change(input, { target: { value: "test" } }); expect(handleChange).toHaveBeenCalled(); }); test("supports Enter key activation", () => { const handleChange = vi.fn(); render(); const input = screen.getByRole("textbox"); // Focus the input first input.focus(); expect(input).toHaveFocus(); fireEvent.keyDown(input, { key: "Enter" }); // Input should still be focused and ready for typing expect(input).toHaveFocus(); }); test("supports Space key activation", () => { const handleChange = vi.fn(); render(); const input = screen.getByRole("textbox"); // Focus the input first input.focus(); expect(input).toHaveFocus(); fireEvent.keyDown(input, { key: " " }); // Input should still be focused and ready for typing expect(input).toHaveFocus(); }); test("supports Tab navigation", () => { render(
); const firstInput = screen.getByLabelText("First input"); const secondInput = screen.getByLabelText("Second input"); firstInput.focus(); expect(firstInput).toHaveFocus(); // Use userEvent for more realistic tab navigation fireEvent.keyDown(firstInput, { key: "Tab", code: "Tab" }); // Note: In a real browser, Tab would move focus, but in tests we need to simulate it secondInput.focus(); expect(secondInput).toHaveFocus(); }); test("supports Shift+Tab navigation", () => { render(
); const firstInput = screen.getByLabelText("First input"); const secondInput = screen.getByLabelText("Second input"); secondInput.focus(); expect(secondInput).toHaveFocus(); // Use userEvent for more realistic tab navigation fireEvent.keyDown(secondInput, { key: "Tab", shiftKey: true, code: "Tab" }); // Note: In a real browser, Shift+Tab would move focus, but in tests we need to simulate it firstInput.focus(); expect(firstInput).toHaveFocus(); }); test("handles disabled state accessibility", () => { render(); const input = screen.getByRole("textbox"); expect(input).toBeDisabled(); expect(input).toHaveAttribute("disabled"); }); test("handles error state accessibility", () => { render(); const input = screen.getByRole("textbox"); // Error state should still be accessible expect(input).toBeInTheDocument(); expect(input).not.toBeDisabled(); }); test("supports different input types", () => { const { rerender } = render(); let input = screen.getByRole("textbox"); expect(input).toHaveAttribute("type", "email"); rerender(); // Password inputs don't have textbox role, they have textbox role only for text inputs input = screen.getByLabelText("Password"); expect(input).toHaveAttribute("type", "password"); rerender(); input = screen.getByRole("spinbutton"); expect(input).toHaveAttribute("type", "number"); }); test("supports placeholder accessibility", () => { render(); const input = screen.getByPlaceholderText("Enter your name"); expect(input).toBeInTheDocument(); }); test("supports value accessibility", () => { render(); const input = screen.getByDisplayValue("test value"); expect(input).toBeInTheDocument(); }); test("maintains focus management", () => { const handleFocus = vi.fn(); const handleBlur = vi.fn(); render( ); const input = screen.getByRole("textbox"); fireEvent.focus(input); expect(handleFocus).toHaveBeenCalled(); // Focus the input to ensure it has focus input.focus(); expect(input).toHaveFocus(); fireEvent.blur(input); expect(handleBlur).toHaveBeenCalled(); // Manually blur the input to ensure it loses focus input.blur(); expect(input).not.toHaveFocus(); }); test("supports form association", () => { render(
); const input = screen.getByRole("textbox"); expect(input).toHaveAttribute("name", "test-field"); }); test("supports ARIA attributes", () => { render( ); const input = screen.getByRole("textbox"); expect(input).toHaveAttribute("aria-describedby", "help-text"); expect(input).toHaveAttribute("aria-required", "true"); }); test("supports custom ARIA labels", () => { render(); const input = screen.getByLabelText("Custom input label"); expect(input).toBeInTheDocument(); }); test("handles multiple inputs without conflicts", () => { render(
); const firstInput = screen.getByLabelText("First input"); const secondInput = screen.getByLabelText("Second input"); const thirdInput = screen.getByLabelText("Third input"); expect(firstInput).toBeInTheDocument(); expect(secondInput).toBeInTheDocument(); expect(thirdInput).toBeInTheDocument(); // Each should have unique IDs expect(firstInput.id).not.toBe(secondInput.id); expect(secondInput.id).not.toBe(thirdInput.id); expect(firstInput.id).not.toBe(thirdInput.id); }); test("supports screen reader navigation", () => { render(); const input = screen.getByRole("textbox"); const label = screen.getByText("Test input"); // Label should be associated with input expect(label).toHaveAttribute("for", input.id); }); test("handles dynamic label changes", () => { const { rerender } = render(); expect(screen.getByText("Original label")).toBeInTheDocument(); rerender(); expect(screen.getByText("Updated label")).toBeInTheDocument(); expect(screen.queryByText("Original label")).not.toBeInTheDocument(); }); test("supports controlled input behavior", () => { const handleChange = vi.fn(); render(); const input = screen.getByDisplayValue("controlled value"); fireEvent.change(input, { target: { value: "new value" } }); expect(handleChange).toHaveBeenCalled(); }); });