cypress-axe
This package provides three simple Cypress commands to help test your applications for accessibility issues using axe-core.
Install and configure
Add as a dev dependency:
npm i -D cypress-axe-commands
Install peer dependencies:
npm i -D cypress
NOTE: axe-core is now bundled and doesn't need to be installed as a peer dependency
Include the commands
Update Cypress/support/index.js
file to include the cypress-axe-commands commands by adding:
import 'cypress-axe-commands'
Add a task to log the messages to the terminal when the cypress executes the spec files
Example - configuring log task
Commands
cy.injectAxe
This will inject the axe-core
runtime into the page under test. You must run this after a call to cy.visit()
and before you run the checkA11y
command.
You run this command with cy.injectAxe()
either in your test, or in a beforeEach
, as long as the visit
comes first.
beforeEach(() => {
cy.visit('http://localhost:9000')
cy.injectAxe()
})
cy.configureAxe
Purpose
To configure the format of the data used by aXe. This can be used to add new rules, which must be registered with the library to execute.
Description
User specifies the format of the JSON structure passed to the callback of axe.run
Link - aXe Docs: axe.configure
it('Has no detectable a11y violations on load (custom configuration)', () => {
cy.configureAxe({
branding: {
brand: String,
application: String
},
reporter: 'option',
checks: [Object],
rules: [Object],
locale: Object
})
cy.checkA11y()
})
cy.checkA11y
This will run axe against the document at the point in which it is called. This means you can call this after interacting with your page and uncover accessibility issues introduced as a result of rendering in response to user actions.
Parameters on cy.checkA11y (axe.run)
context (optional)
Defines the scope of the analysis - the part of the DOM that you would like to analyze. This will typically be the document or a specific selector such as class name, ID, selector, etc.
options (optional)
Set of options passed into rules or checks, temporarily modifying them. This contrasts with axe.configure, which is more permanent.
The keys consist of those accepted by axe.run
's options argument as well as a custom includedImpacts
key.
The includedImpacts
key is an array of strings that map to impact
levels in violations. Specifying this array will only include violations where the impact matches one of the included values. Possible impact values are "minor", "moderate", "serious", or "critical".
Filtering based on impact in combination with the skipFailures
argument allows you to introduce cypress-axe-commands
into tests for a legacy application without failing in CI before you have an opportunity to address accessibility issues. Ideally, you would steadily move towards stricter testing as you address issues.
violationCallback (optional)
Allows you to define a callback that receives the violations for custom side-effects, such as adding custom output to the terminal.
NOTE: This respects the includedImpacts
filter and will only execute with violations that are included.
skipFailures (optional, defaults to false)
Disables assertions based on violations and only logs violations to the console output. This enabled you to see violations while allowing your tests to pass. This should be used as a temporary measure while you address accessibility violations.
Reference : https://github.com/avanslaars/cypress-axe/issues/17
Examples
Basic usage
it('Has no detectable a11y violations on load', () => {
cy.checkA11y()
})
it('Has no detectable a11y violations on load (with custom parameters)', () => {
cy.checkA11y('.example-class', {
runOnly: {
type: 'tag',
values: ['wcag2a']
}
})
})
it('Has no detectable a11y violations on load (filtering to only include critical impact violations)', () => {
cy.checkA11y(null, {
includedImpacts: ['critical']
})
})
it('Has no a11y violations after button click', () => {
cy.get('button').click()
cy.checkA11y()
})
Using the violationCallback argument
The violation callback parameter accepts a function and allows you to add custom behavior when violations are found.
This example adds custom logging to the terminal running Cypress, using cy.task
and the violationCallback
argument for cy.checkA11y
In Cypress plugins file
This registers a log
task as seen in the Cypress docs for cy.task as well as a table
task for sending tabular data to the terminal.
module.exports = (on, config) => {
on('task', {
log(message) {
console.log(message)
return null
},
table(message) {
console.table(message)
return null
}
})
}
In your spec file
Then we create a function that uses our tasks and pass it as the validationCallback
argument to cy.checkA11y
function terminalLog(violations) {
cy.task(
'log',
`${violations.length} accessibility violation${
violations.length === 1 ? '' : 's'
} ${violations.length === 1 ? 'was' : 'were'} detected`
)
const violationData = violations.map(
({ id, impact, description, nodes }) => ({
id,
impact,
description,
nodes: nodes.length
})
)
cy.task('table', violationData)
}
it('Logs violations to the terminal', () => {
cy.checkA11y(null, null, terminalLog)
})
This custom logging behavior results in terminal output like this:
Standard Output
When accessibility violations are detected, your test will fail and an entry titled "A11Y ERROR!" will be added to the command log for each type of violation found (they will be above the failed assertion). Clicking on those will reveal more specifics about the error in the DevTools console.
Contributors
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!