React Testing Library A11Y
title: "Testing Library and jest-axe" weight: 22 description: "Learn how to test React component accessibility with jest-axe and @testing-library: write assertions for WCAG compliance, test component states, integrate into CI/CD, and catch regressions early." date: 2026-06-28 lastmod: 2026-06-28 tags: [accessibility, react]
Jest-axe integrates axe-core accessibility rules into Jest tests, allowing assertions like `expect(container).toHaveNoViolations()` on rendered React components, catching accessibility regressions automatically in unit tests and CI/CD pipelines.
## What You'll Learn
You will install and configure jest-axe, write accessibility tests for React components, test component states, and integrate tests into CI/CD.
## Why It Matters
Unit testing accessibility catches issues at the component level before they reach integration or E2E tests. A component that passes jest-axe assertions is accessible in isolation, reducing the chance of regressions reaching production.
## Real-World Use
A developer modifies a Button component to add a new variant. The unit test `expect(render(<Button />)).toHaveNoViolations()` fails because the new variant does not have sufficient contrast. The developer fixes the color before committing.
## Jest-axe Testing Flow
```mermaid
flowchart TD
A[Component Renders] --> B[axe-core Scan]
B --> C{Violations?}
C -->|Yes| D[Test Fails]
C -->|No| E[Test Passes]
D --> F[Fix Component]
F --> A
Writing Accessibility Tests
Install jest-axe and write tests that assert accessibility compliance.
npm install --save-dev jest-axe @testing-library/react
import { render } from '@testing-library/react';
import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);
import Button from './Button';
describe('Button accessibility', () => {
it('has no violations in default state', async () => {
const { container } = render(<Button>Click me</Button>);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it('has no violations when disabled', async () => {
const { container } = render(<Button disabled>Click me</Button>);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it('has no violations when loading', async () => {
const { container } = render(<Button loading>Click me</Button>);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});
// Testing interactive components
import { render, fireEvent } from '@testing-library/react';
import { axe } from 'jest-axe';
import Accordion from './Accordion';
describe('Accordion accessibility', () => {
it('has no violations when collapsed', async () => {
const { container } = render(
<Accordion items={[{ title: 'Section', content: 'Content' }]} />
);
expect(await axe(container)).toHaveNoViolations();
});
it('has no violations when expanded', async () => {
const { container, getByText } = render(
<Accordion items={[{ title: 'Section', content: 'Content' }]} />
);
fireEvent.click(getByText('Section'));
expect(await axe(container)).toHaveNoViolations();
});
});
// Testing with custom rules
import { configureAxe } from 'jest-axe';
const axeWithRules = configureAxe({
rules: {
'color-contrast': { enabled: true },
'region': { enabled: false } // Disable region rule for fragments
}
});
test('component with custom rules', async () => {
const { container } = render(<MyComponent />);
const results = await axeWithRules(container);
expect(results).toHaveNoViolations();
});
Common Mistakes
- Not testing all component states (default, hover, focus, disabled, error)
- Using axe incorrectly with container (axe expects the DOM element, not a React component)
- Not configuring rules for project-specific needs
- Ignoring test failures without investigating
- Not integrating accessibility tests into CI/CD
- Testing only happy paths without error states
- Using snapshot tests instead of axe assertions
Practice and Challenge
Practice 1: Install jest-axe and write a test for a Button component. Practice 2: Test a form component in both valid and error states. Practice 3: Test an accordion in collapsed and expanded states. Practice 4: Configure axe rules to exclude known false positives. Practice 5: Integrate jest-axe into a CI/CD pipeline.
Challenge: Create a test suite for a component library with at least 5 components. Each component should be tested in all states (default, hover, focus, active, disabled, error, loading). The test suite should have at least 15 test cases and be configured to run in CI/CD. Include a custom axe configuration that handles project-specific patterns.
FAQ
Mini Project
Create a React component library test suite with jest-axe. Include tests for: Button (default, disabled, loading, icon-only), Input (default, error, disabled, with helper text), Modal (open, with various content), Accordion, and Tabs. Each component should have tests for all states. Configure the test to fail on any violation.
What's Next
eslint-plugin-jsx-a11y covers linting React components for accessibility issues.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro