• Stars
    star
    1,055
  • Rank 43,416 (Top 0.9 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 6 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Custom Jest matcher for aXe for testing accessibility β™ΏοΈπŸƒ

jest-axe

npm version node Repository CI Status

Custom Jest matcher for axe for testing accessibility

βš οΈβœ‹ This project does not guarantee that what you build is accessible.

The GDS Accessibility team found that only ~30% of issues are found by automated testing.

Tools like axe are similar to code linters such as eslint or stylelint: they can find common issues but cannot guarantee that what you build works for users.

You'll also need to:

Checks that do not work in jest-axe

Color contrast checks do not work in JSDOM so are turned off in jest-axe.

Installation:

npm install --save-dev jest jest-axe jest-environment-jsdom

TypeScript users can install the community maintained types package:

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

Usage:

/**
 * @jest-environment jsdom
 */
const { axe, toHaveNoViolations } = require('jest-axe')

expect.extend(toHaveNoViolations)

it('should demonstrate this matcher`s usage', async () => {
  const render = () => '<img src="#"/>'

  // pass anything that outputs html to axe
  const html = render()

  expect(await axe(html)).toHaveNoViolations()
})

Screenshot of the resulting output from the usage example

Note, you can also require 'jest-axe/extend-expect' which will call expect.extend for you. This is especially helpful when using the jest setupFilesAfterEnv configuration.

Testing React

const React = require('react')
const { render } =  require('react-dom')
const App = require('./app')

const { axe, toHaveNoViolations } = require('jest-axe')
expect.extend(toHaveNoViolations)

it('should demonstrate this matcher`s usage with react', async () => {
  render(<App/>, document.body)
  const results = await axe(document.body)
  expect(results).toHaveNoViolations()
})

Testing React with React Testing Library

const React = require('react')
const App = require('./app')

const { render } = require('@testing-library/react')
const { axe, toHaveNoViolations } = require('jest-axe')
expect.extend(toHaveNoViolations)

it('should demonstrate this matcher`s usage with react testing library', async () => {
  const { container } = render(<App/>)
  const results = await axe(container)
  
  expect(results).toHaveNoViolations()
})

Note: If you're using react testing library <9.0.0 you should be using the cleanup method. This method removes the rendered application from the DOM and ensures a clean HTML Document for further testing.

If you're using React Portals, use the baseElement instead of container:

it('should work with React Portals as well', async () => {
  const { baseElement } = render(<App/>)
  const results = await axe(baseElement)
  
  expect(results).toHaveNoViolations()
})

Testing Vue with Vue Test Utils

const App = require('./App.vue')

const { mount } = require('@vue/test-utils')
const { axe, toHaveNoViolations } = require('jest-axe')
expect.extend(toHaveNoViolations)

it('should demonstrate this matcher`s usage with vue test utils', async () => {
  const wrapper = mount(Image)
  const results = await axe(wrapper.element)

  expect(results).toHaveNoViolations()
})

Testing Vue with Vue Testing Library

const App = require('./app')

const { render } = require('@testing-library/vue')
const { axe, toHaveNoViolations } = require('jest-axe')
expect.extend(toHaveNoViolations)

it('should demonstrate this matcher`s usage with react testing library', async () => {
  const { container } = render(<App/>)
  const results = await axe(container)
  
  expect(results).toHaveNoViolations()
})

Note: If you're using vue testing library <3.0.0 you should be using the cleanup method. This method removes the rendered application from the DOM and ensures a clean HTML Document for further testing.

Testing Angular with Nx

import { ComponentFixture, TestBed } from "@angular/core/testing";
import { axe } from "jest-axe";

import { SomeComponent } from "./some.component";

describe("SomeComponent", () => {
  let fixture: ComponentFixture<SomeComponent>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [SomeComponent],
    });

    fixture = TestBed.createComponent(SomeComponent);
  });

  it("should create", async () => {
    const results = await axe(fixture.nativeElement);
    expect(results).toHaveNoViolations();
  });
});

Note: You may need to extend jest by importing jest-axe/extend-expect at test-setup.ts

Usage with jest.useFakeTimers() or mocking setTimeout

thrown: "Exceeded timeout of 5000 ms for a test. Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."

aXe core does not work when timers (setTimeout) are mocked. When using jest.useFakeTimers() aXe core will timeout often causing failing tests.

We recommend renabling the timers temporarily for aXe:

jest.useRealTimers();
const results = await axe(wrapper.element);
jest.useFakeTimers();

Axe configuration

The axe function allows options to be set with the same options as documented in axe-core:

const { axe, toHaveNoViolations } = require('jest-axe')

expect.extend(toHaveNoViolations)

it('should demonstrate this matcher`s usage with a custom config', async () => {
  const render = () => `
    <div>
      <img src="#"/>
    </div>
  `

  // pass anything that outputs html to axe
  const html = render()

  const results = await axe(html, {
    rules: {
      // for demonstration only, don't disable rules that need fixing.
      'image-alt': { enabled: false }
    }
  })

  expect(results).toHaveNoViolations()
})

Testing isolated components

All page content must be contained by landmarks (region)

When testing with aXe sometimes it assumes you are testing a page. This then results in unexpected violations for landmarks for testing isolation components.

You can disable this behaviour with the region rule:

const { configureAxe } = require('jest-axe')

const axe = configureAxe({
  rules: {
    // disable landmark rules when testing isolated components.
    'region': { enabled: false }
  }
})

Setting global configuration

If you find yourself repeating the same options multiple times, you can export a version of the axe function with defaults set.

Note: You can still pass additional options to this new instance; they will be merged with the defaults.

This could be done in Jest's setup step

// Global helper file (axe-helper.js)
const { configureAxe } = require('jest-axe')

const axe = configureAxe({
  rules: {
    // for demonstration only, don't disable rules that need fixing.
    'image-alt': { enabled: false }
  }
})

module.exports = axe
// Individual test file (test.js)
const { toHaveNoViolations } = require('jest-axe')
const axe = require('./axe-helper.js')

expect.extend(toHaveNoViolations)

it('should demonstrate this matcher`s usage with a default config', async () => {
  const render = () => `
    <div>
      <img src="#"/>
    </div>
  `

  // pass anything that outputs html to axe
  const html = render()

  expect(await axe(html)).toHaveNoViolations()
})

Setting custom rules and checks.

The configuration object passed to configureAxe, accepts a globalOptions property to configure the format of the data used by axe and to add custom checks and rules. The property value is the same as the parameter passed to axe.configure.

// Global helper file (axe-helper.js)
const { configureAxe } = require('jest-axe')

const axe = configureAxe({
  globalOptions: {
    checks: [/* custom checks definitions */]
  },
  // ...
})

module.exports = axe

Setting the level of user impact.

An array which defines which impact level should be considered. This ensures that only violations with a specific impact on the user are considered. The level of impact can be "minor", "moderate", "serious", or "critical".

// Global helper file (axe-helper.js)
const { configureAxe } = require('jest-axe')

const axe = configureAxe({
  impactLevels: ['critical'],
  // ...
})

module.exports = axe

Refer to Developing Axe-core Rules for instructions on how to develop custom rules and checks.

Thanks

  • Jest for the great test runner that allows extending matchers.
  • axe for the wonderful axe-core that makes it so easy to do this.
  • Government Digital Service for making coding in the open the default.
  • jest-image-snapshot for inspiration on README and repo setup

More Repositories

1

getting-started-todo

CSS
26
star
2

github-dependents-api

An API to get the dependents for any Github repository
JavaScript
15
star
3

awesome-govuk-frontend

Curated list of GOV.UK Frontend related projects
15
star
4

design-of-forms

The Design of Forms in Government Departments
CSS
13
star
5

express-webc

WebC Template Engine for ExpressJS
JavaScript
11
star
6

eleventy-plugin-unified

Use the unified ecosystem in Eleventy with remark and rehype.
JavaScript
9
star
7

instagram-archive-viewer

View your main instagram feed and stories to a local website from your data download archive.
JavaScript
8
star
8

website-from-github-wiki

Generate a website from the GitHub Wiki it is linked to
JavaScript
6
star
9

website-from-github-issues

Display GitHub issues in a website.
JavaScript
6
star
10

itsyourbirthdaytoday

JavaScript
5
star
11

convert-html-to-accessible-pdf

Working example of using openhtmltopdf to create an accessible PDF from HTML
HTML
5
star
12

registers.js

Unofficial JavaScript client for the GOV.UK Registers project πŸ“‡πŸ“‹
JavaScript
4
star
13

check-nvmrc

Repository showing how to use a standalone Node.js script to let people know they're on the wrong Node.js version
JavaScript
4
star
14

govuk-api

JavaScript API client for GOV.UK Content and Search APIs.
JavaScript
4
star
15

twitchtetris

Fork of html5tetris on www.twitchtetris.com
JavaScript
3
star
16

nickcolley.co.uk

JavaScript
3
star
17

past

Web framework from the past.
JavaScript
3
star
18

govuk-frontend-sass-compilers

Comparison of building GOV.UK Frontend with different Sass compilers
CSS
2
star
19

drab

boring Preact renderer
JavaScript
2
star
20

ScrollFix

Fixes bouncing on iPad
JavaScript
2
star
21

govuk-frontend-rounded

Rounded corners for GOV.UK Frontend, useful when branding the GOV.UK Design System.
Nunjucks
2
star
22

contrast-checker

Check contrast with the new WCAG 2.1 requirements. Original design by Dave House.
Nunjucks
2
star
23

spicetify-rewind

Reeeeeewiiiind like you're at a boiler room set
JavaScript
2
star
24

hoodie-app-skeleton

HTML
1
star
25

erno

Rubik's Cube Timer
JavaScript
1
star
26

intrinsic-ratio-less

Little less mixin for ratio aware responsive video
CSS
1
star
27

social-image-sharing

JavaScript
1
star
28

e2e

Protractor E2E Boilerplate.
JavaScript
1
star
29

github-projects-fullscreen-compressed

Compresses the columns and UI when in fullscreen mode for GitHub projects to allow for more room.
CSS
1
star
30

do-not-track-third-party-embeds

Glitch backup export
1
star
31

create-mjs

npm init mjs
JavaScript
1
star
32

yourfirstpr-issue-proto

Prototype for automatic issue reviewing
JavaScript
1
star
33

probot-link-checker

Probot that checks markdown files links are not broken
JavaScript
1
star
34

pwc-marquee

JavaScript
1
star
35

sarnie

MORE ENERGY
1
star
36

erno-legacy

Puzzle Timer
JavaScript
1
star
37

eleventy-plugin-accessibility

An Eleventy plugin to check for accessibility issues in HTML using axe.
JavaScript
1
star
38

bubble

Bubble component
1
star
39

next-accessible-typeahead-prototype

Prototyping bringing the accessible-typeahead into React and Next.js
JavaScript
1
star
40

foo

1
star