Files
community-rule/tests/accessibility/Input.a11y.test.jsx
T
adilallo c4a631a5d8
CI Pipeline / test (20) (pull_request) Successful in 2m55s
CI Pipeline / test (18) (pull_request) Successful in 3m32s
CI Pipeline / e2e (webkit) (pull_request) Has been cancelled
CI Pipeline / visual-regression (pull_request) Has been cancelled
CI Pipeline / performance (pull_request) Has been cancelled
CI Pipeline / storybook (pull_request) Has been cancelled
CI Pipeline / lint (pull_request) Has been cancelled
CI Pipeline / build (pull_request) Has been cancelled
CI Pipeline / e2e (chromium) (pull_request) Has been cancelled
CI Pipeline / e2e (firefox) (pull_request) Has been cancelled
Cleanup code and tests
2025-10-14 17:34:05 -06:00

287 lines
9.1 KiB
React

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(<Input label="Test input" />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
test("has no accessibility violations when disabled", async () => {
const { container } = render(<Input label="Test input" disabled={true} />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
test("has no accessibility violations when in error state", async () => {
const { container } = render(<Input label="Test input" error={true} />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
test("has no accessibility violations with horizontal label", async () => {
const { container } = render(
<Input label="Test input" labelVariant="horizontal" />,
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
test("associates label with input correctly", () => {
render(<Input label="Test input" />);
const input = screen.getByLabelText("Test input");
expect(input).toBeInTheDocument();
expect(input).toHaveAttribute("type", "text");
});
test("maintains label association with custom ID", () => {
render(<Input id="custom-input" label="Test input" />);
const input = screen.getByLabelText("Test input");
expect(input).toHaveAttribute("id", "custom-input");
});
test("supports keyboard navigation", () => {
render(<Input label="Test input" />);
const input = screen.getByRole("textbox");
// Input should be focusable
input.focus();
expect(input).toHaveFocus();
});
test("supports keyboard activation", () => {
const handleChange = vi.fn();
render(<Input label="Test input" onChange={handleChange} />);
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(<Input label="Test input" onChange={handleChange} />);
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(<Input label="Test input" onChange={handleChange} />);
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(
<div>
<Input label="First input" />
<Input label="Second input" />
</div>,
);
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(
<div>
<Input label="First input" />
<Input label="Second input" />
</div>,
);
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(<Input label="Test input" disabled={true} />);
const input = screen.getByRole("textbox");
expect(input).toBeDisabled();
expect(input).toHaveAttribute("disabled");
});
test("handles error state accessibility", () => {
render(<Input label="Test input" error={true} />);
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(<Input type="email" label="Email" />);
let input = screen.getByRole("textbox");
expect(input).toHaveAttribute("type", "email");
rerender(<Input type="password" label="Password" />);
// 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 type="number" label="Number" />);
input = screen.getByRole("spinbutton");
expect(input).toHaveAttribute("type", "number");
});
test("supports placeholder accessibility", () => {
render(<Input placeholder="Enter your name" />);
const input = screen.getByPlaceholderText("Enter your name");
expect(input).toBeInTheDocument();
});
test("supports value accessibility", () => {
render(<Input value="test value" />);
const input = screen.getByDisplayValue("test value");
expect(input).toBeInTheDocument();
});
test("maintains focus management", () => {
const handleFocus = vi.fn();
const handleBlur = vi.fn();
render(
<Input label="Test input" onFocus={handleFocus} onBlur={handleBlur} />,
);
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(
<form>
<Input name="test-field" label="Test input" />
</form>,
);
const input = screen.getByRole("textbox");
expect(input).toHaveAttribute("name", "test-field");
});
test("supports ARIA attributes", () => {
render(
<Input
label="Test input"
aria-describedby="help-text"
aria-required="true"
/>,
);
const input = screen.getByRole("textbox");
expect(input).toHaveAttribute("aria-describedby", "help-text");
expect(input).toHaveAttribute("aria-required", "true");
});
test("supports custom ARIA labels", () => {
render(<Input aria-label="Custom input label" />);
const input = screen.getByLabelText("Custom input label");
expect(input).toBeInTheDocument();
});
test("handles multiple inputs without conflicts", () => {
render(
<div>
<Input label="First input" />
<Input label="Second input" />
<Input label="Third input" />
</div>,
);
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(<Input label="Test input" />);
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(<Input label="Original label" />);
expect(screen.getByText("Original label")).toBeInTheDocument();
rerender(<Input label="Updated label" />);
expect(screen.getByText("Updated label")).toBeInTheDocument();
expect(screen.queryByText("Original label")).not.toBeInTheDocument();
});
test("supports controlled input behavior", () => {
const handleChange = vi.fn();
render(<Input value="controlled value" onChange={handleChange} />);
const input = screen.getByDisplayValue("controlled value");
fireEvent.change(input, { target: { value: "new value" } });
expect(handleChange).toHaveBeenCalled();
});
});