Setting up Cypress with axe for accessibility
After reading Nikita Poltoratsky's article Angular a11y: 11 tips on how to make your apps more accessible and a chat in the InDepth group, it came to my mind that I should be testing my blog for accessibility.
I've written an article before about accessibility, where I had my first encountering with axe. Now a big year later, axe has grown, and so has Cypress. In this article, we'll see how easy it's to combine the two and test your website for accessibility by integrating the axe methods as Cypress commands.
Axe helps you to test the accessibility of your site. They have a range of tools in their arsenal: a browser extension, an application, a CLI, and libraries for different testing libraries. If you're getting into accessibility testing, axe will quickly pop up as the standard. What I also like about the tooling, is that most tools share the same API.
Axe is open source. It returns zero false positives (bugs notwithstanding). It's designed to work on all modern browsers and with whatever tools, frameworks, libraries and environments you use today. It's actively supported by Deque Systems, a major accessibility vendor. It integrates with your existing functional/acceptance automated tests. It automatically determines which rules to run based on the evaluation context. Axe supports in-memory fixtures, static fixtures, integration tests and iframes of infinite depth. Axe is highly configurable.
I'm assuming Cypress is already installed, so the only dependencies we have to install are
After that the installation is complete, add the commands to the
Now, the axe commands are available on the
cy object and we're ready to use axe in our tests.
The first step is to inject axe.
To inject axe, simply invoke the
This must be done after the page is loaded.
After axes is injected, we can check the page's accessibility with the
This command will make the test fail when it uncovers accessibility issues.
By default, it will scan the whole page but it also can be configured to run against a specific element, or to exclude some elements.
For example, I use this method to exclude a specific button (which I should fix...) with a CSS selector. It's also possible to pass DOM Nodes, by using the
checkA11y command also accepts a second argument, to set options. I think most of these options will remain untouched for most of the time, except for the
runOnly properties. With it, you can enable or disable certain rules, or a standardized set of rules (as tags).
The last command that is available, is
For more advanced use cases, this command is used to define custom rules or to modify existing checks and rules.
With it, the default reporting can be changed, as well as the locale for the output messages.
When we put everything together, the simplest test case looks as follows. After a page navigation, inject axe, and lastly, check the accessibility of the page.
When Cypress runs, it will throw and log an
AssertionError when the page isn't accessible.
Just like most of the Cypress errors, it's possible to click on the accessibility error, which prints out more information in the console window of the DevTools. The log includes the rule id, the impact, the impacted nodes, and a url to get more information about the violation, including certain fixes.
When it doesn't spot violations, you will end up with a green test.
For small static sites you can manually test each page this way, but I don't want to add a new test for each article that I write. To automate the process, I created a Cypress task to read the website's sitemap to iterate over all my pages.
To make sure the website is also accessible on smaller devices, I use Cypress's
cy.viewport command to set the size of the screen. The viewport command accepts a width and height as argument, or a preset.
In my test, I create an array of different viewports and iterate over them.
My blog has a light theme and a dark theme. To determine which theme to use, it looks at the user's preferences to set its theme. Because the different color schemes I wanted to test both themes, especially for the contrast.
To know which theme to render, I use the
prefers-color-scheme CSS media feature. In a Cypress test, this can be stubbed during the
I ended up with the following code to test the accessibility of my blog, and I'm happy with it. It did find some accessibility issues, but it also found missing and duplicate header links.
Everyone, including myself, benefits from these tests. And let's be honest, if you're already using Cypress these tests can be set up quickly, with minimal effort. With it, you gain a website that is more accessible and with fewer issues.
This gives the following result when a page doesn't make the accessibility test.
When all violations and issues are fixed, the tests in test run turn green.
Did you notice that Cypress added support for Firefox and more 🤩? See the Introduction post of Cypress 4.0 for more info.
Please consider supporting me if have you enjoyed this post and found it useful: