Introducing cypress-axe

3 min read

Custom Cypress commands for testing accessibility in your application.

With cypress-axe you can inject axe-core from Deque Systems into your page under tests in a Cypress test and use it to check the DOM for accessibility violations.

Motivation

Accessibility is important! As developers building things for the web, we have a responsibility to make the content we create and the interactions we build inclusive. Our applications shouldn't exclude people who use assistive technology or accessibility features on their chosen browsing device.

Since starting my current role back in February, I've put a lot of time and energy into increasing our focus on accessibility. In that time, I've looked at quite a few tools to check our applications for accessibility gaps. Many of the auditing tools available are very focused on static content with urls that can be accessed publicly.

Many of the apps I'm concerned with are highly interactive and behind a login, so those tools just weren't going to cut it. I need a tool that makes it easy to interact with a complex application and check for accessibility violations at each point that the rendered DOM changes. This is where Cypress comes in.

What does it do?

This package leverages the custom command offered by Cypress. It adds two commands to the global cy object. The cy.injectAxe() command does exactly what the name implies, it injects the axe-core library into the current page. It needs to be used after cy.visit(<url>) and before a call to the second command, cy.checkA11y(). The cy.checkA11y() command is where the rubber meets the road. It takes the document and passes it to axe.run. The results of running axe-core are checked for violations, and if any exist, they are logged to the Cypress command log and the test fails.

The entire things is just two custom commands and as of now, 36 lines of code. Cypress and axe-core do all the heavy lifting, the commands just wrap up some boilerplate so you can keep your test code nice and clean.

How do I use it?

I'll assume that you either already use Cypress, or you can follow the instructions on the Cypress website to get up and running with Cypress tests. Once you have Cypress installed, you will need to install cypress-axe and axe-core:

npm install --save-dev cypress-axe axe-core

Then you can add the cypress-axe commands by importing the package into the Cypress/support/index.js file.

// Cypress/support/index.js
import 'cypress-axe'

Then you can use it in your tests like:

// Cypress/integration/a11y.spec.js
describe('App', () => {
  beforeEach(() => {
    cy.visit('http://localhost:9000')
    cy.injectAxe() // make sure axe is available on the page
  })

  it('Has no detectable a11y violations on load', () => {
    cy.checkA11y() // fail for a11y violations
  })

  it('Has no a11y violations after button click', () => {
    cy.get('button').click()
    cy.checkA11y() // check after a rerender
  })
})

If a test fails for accessibility violations, those violations will be shown in the command log. Clicking one of those log entries and showing DevTools will provide the details on the violation.

Cypress and DevTools output for passing and failing axe-core audits

Disclaimer!

A tool like axe-core can only do so much. It can't catch every issue, but it will call out many issues with color contrast and markup semantics that should be relatively easy to address. It

Spread the ❤️

Tweet about this library and let's make a11y testing part of every developer's toolkit.