Did you know that you can automatically test accessibility (a11y) with jest?

Wojciech Stolarski
Published 19 May, 2025

The WCAG (Web Content Accessibility Guidelines) standard is a set of guidelines designed to ensure that digital content is accessible to all users, including people with disabilities. There are several tools that can be used to test for compliance with this standard – one of them is the “jest axe." In this article, we’ll show you how it works, take you through a step-by-step accessibility test, and tell you what to look out for when using it.

More detailed information about what WCAG is, when and how it should be applied, as well as the challenges the future holds in ensuring digital accessibility for users, can be found here.

What is jest-axe?

If a project uses the jest library, it’s easy to add tests to check the WCAG compliance of components.

Jest-axe is an automated accessibility testing tool based on the axe-core engine. It works similarly to code linters (such as ESLint or Stylelint) and detects common problems, although it does not guarantee full compliance with accessibility requirements.

It integrates with the jest library and allows you to analyze the HTML of components for accessibility issues such as:

  • missing alt attributes on images,
  • incorrect ARIA roles,
  • headings with incorrect hierarchy.

It adds the toHaveNoViolations matcher to your tests, enabling easy validation of the analysis results.

Please note!

Jest-axe does not replace a manual accessibility audit. Automated tests are only a support tool and will not catch all problems. A full evaluation should be performed by people with expertise in this area.

What can jest-axe miss?

It’s important to be aware of the limitations of this tool. Jest-axe may not detect, among others:

  • contrast issues,
  • full evaluation of semantic structure,
  • some problems with interactive elements,
  • keyboard navigation issues,
  • contextual issues.

Integration with Angular

To integrate Jest with jest-axe in a project that already uses Jest, follow these steps:

Step 1: Installation

npm install –save-dev jest-axe @types/jest-axe

Step 2: Configuration

In your test setup file, e.g., test-setup.ts, add the following import:

import ‘jest-axe/extend-expect’;

Step 3: Basic component accessibility test

In the test-setup.ts file, you need to import `jest-axe/extend-expect`

Tests

When everything has been configured, the only thing left is to use the tool in your tests. In the test file, add the import import { axe } from 'jest-axe';. Then, by using axe(fixture.nativeElement), an accessibility analysis will be run for the generated HTML of the component. The result of the analysis must be verified using the toHaveNoViolations method, as follows: expect(results).toHaveNoViolations().

Test Cases

For testing purposes, two components have been prepared. The first contains HTML that does not meet accessibility audit requirements, while the second complies with them.

First Scenario

The component contains the following HTML code:

<div class="container">
    <!-- Error: Incorrect heading order (h4 follows h2 without h3) -->
    <h2>Main heading</h2>
    <h4>Recommended accessories</h4>

    <!-- Error: Image without alt attribute -->
    <img src="product.jpg" class="banner-image">

    <!-- Error: Link without content (empty link) -->
    <a href="/home" class="home-link"></a>

    <!-- Error: select element without label -->
    <select>
        <option value="">Choose a topic...</option>
        <option value="question">Question</option>
        <option value="complaint">Complaint</option>
    </select>

    <!-- Error: ARIA attribute with invalid value -->
    <div aria-hidden="falsy">Hidden content</div>
</div>

Test performing the audit:
import {ComponentFixture, TestBed} from '@angular/core/testing';

import {MyComponent} from './my.component';
import {axe} from 'jest-axe';

describe('MyComponent', () => {
    let component: MyComponent;
    let fixture: ComponentFixture<MyComponent>;

    beforeEach(async () => {
        await TestBed.configureTestingModule({
            imports: [MyComponent]
        })
            .compileComponents();

        fixture = TestBed.createComponent(MyComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

    it('should pass accessibility tests', async () => {
        const results = await axe(fixture.nativeElement);
        expect(results).toHaveNoViolations()
    });
});

After running the test, the following error messages were returned:
expect(received).toHaveNoViolations(expected)
Expected the HTML found at $('div[aria-hidden="falsy"]') to have no violations:
<div aria-hidden="falsy">Hidden content</div>
Received:
"ARIA attributes must conform to valid values (aria-valid-attr-value)"
Fix all of the following:
  Invalid ARIA attribute value: aria-hidden="falsy"
You can find more information on this issue here: 
https://dequeuniversity.com/rules/axe/4.10/aria-valid-attr-value?application=axeAPI
────────
...
Received:
"Heading levels should only increase by one (heading-order)"
...
────────
...
Received:
"Images must have alternative text (image-alt)"
...
────────
...
Received:
"Links must have discernible text (link-name)"
...
────────
...
Received:
"Select element must have an accessible name (select-name)"

As you can see, not only error messages, but also suggestions on how to fix each specific issue were returned. The above errors relate to:
  • Incorrect heading order - using an h4 directly after an h2 without an intermediate h3
  • Image without an alt attribute – missing alternative text for the image with the "banner-image" class
  • Link without text content - empty <a> tag with no content or accessibility attributes
  • Select element without a label – a dropdown list lacking an associated label
  • Invalid ARIA attribute value - using "falsy" instead of the valid value "false" for aria-hidden

Second scenario

In this scenario, the component now contains correct, fixed HTML.
<div class="container">
    <!-- Correct heading hierarchy -->
    <h2 id="main-heading">Main heading</h2>
    <h3 id="recommended-heading">Recommended accessories</h3>

    <!-- Added alt attribute to image -->
    <img src="product.jpg" class="banner-image" alt="Product image">

    <!-- Link now contains text -->
    <a href="/home" class="home-link">Home page</a>

    <!-- Select element with proper label -->
    <label for="topic-select">Choose a topic:</label>
    <select id="topic-select" name="topic">
        <option value="">Choose a topic...</option>
        <option value="question">Question</option>
        <option value="complaint">Complaint</option>
    </select>

    <!-- Correct ARIA attribute value -->
    <div aria-hidden="true">Hidden content</div>
</div>

For more information on accessibility testing and detailed usage scenarios with different tools, see our recent article

Summary

Jest-axe easily integrates with Jest and enables the detection of basic accessibility issues in HTML. It also works with popular frameworks such as Angular, React and Vue.

However, it does not provide comprehensive accessibility auditing support.

Therefore, Jest-axe should be used as an additional support tool alongside manual accessibility testing and audits involving people with disabilities, rather than as a replacement for them.

Useful links

jest-axe library repository

  • Trends
  • UX

Authors

Wojciech Stolarski
Regular Fullstack Developer
Regular Fullstack Developer at Consdata since 2022.