惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

AI
AI
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
N
News and Events Feed by Topic
O
OpenAI News
W
WeLiveSecurity
S
Secure Thoughts
www.infosecurity-magazine.com
www.infosecurity-magazine.com
H
Heimdal Security Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Schneier on Security
Schneier on Security
Cloudbric
Cloudbric
T
Threatpost
T
Troy Hunt's Blog
T
Tenable Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
V
Vulnerabilities – Threatpost
Google Online Security Blog
Google Online Security Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
The Hacker News
The Hacker News
Know Your Adversary
Know Your Adversary
Forbes - Security
Forbes - Security
Cyberwarzone
Cyberwarzone
C
CXSECURITY Database RSS Feed - CXSecurity.com
P
Privacy & Cybersecurity Law Blog
L
Lohrmann on Cybersecurity
博客园 - 司徒正美
腾讯CDC
博客园 - 三生石上(FineUI控件)
爱范儿
爱范儿
J
Java Code Geeks
Hugging Face - Blog
Hugging Face - Blog
博客园 - 【当耐特】
M
MIT News - Artificial intelligence
T
The Blog of Author Tim Ferriss
MongoDB | Blog
MongoDB | Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
GbyAI
GbyAI
D
Docker
V
Visual Studio Blog
云风的 BLOG
云风的 BLOG
I
InfoQ
WordPress大学
WordPress大学
人人都是产品经理
人人都是产品经理
A
Arctic Wolf
L
LINUX DO - 热门话题
The Cloudflare Blog
雷峰网
雷峰网
Microsoft Azure Blog
Microsoft Azure Blog
小众软件
小众软件

Maxime Heckel's Blog

On Rendering the Sky, Sunsets, and Planets - The Blog of Maxime Heckel Shades of Halftone - The Blog of Maxime Heckel Field Guide to TSL and WebGPU - The Blog of Maxime Heckel On Shaping Light: Real-Time Volumetric Lighting with Post-Processing and Raymarching for the Web - The Blog of Maxime Heckel Speaking at Figma Config 2025 - The Blog of Maxime Heckel Post-Processing Shaders as a Creative Medium - The Blog of Maxime Heckel On Crafting Painterly Shaders - The Blog of Maxime Heckel The Art of Dithering and Retro Shading for the Web - The Blog of Maxime Heckel Moebius-style post-processing and other stylized shaders - The Blog of Maxime Heckel Shining a light on Caustics with Shaders and React Three Fiber - The Blog of Maxime Heckel Real-time dreamy Cloudscapes with Volumetric Raymarching - The Blog of Maxime Heckel Painting with Math: A Gentle Study of Raymarching - The Blog of Maxime Heckel Building a magical AI-powered semantic search from scratch - The Blog of Maxime Heckel Beautiful and mind-bending effects with WebGL Render Targets - The Blog of Maxime Heckel Refraction, dispersion, and other shader light effects - The Blog of Maxime Heckel The magical world of Particles with React Three Fiber and Shaders - The Blog of Maxime Heckel The Study of Shaders with React Three Fiber - The Blog of Maxime Heckel Building a Design System from scratch - The Blog of Maxime Heckel Everything about Framer Motion layout animations - The Blog of Maxime Heckel Building a Vaporwave scene with Three.js - The Blog of Maxime Heckel Cubic Bézier: from math to motion - The Blog of Maxime Heckel First steps with GPT-3 for frontend developers - The Blog of Maxime Heckel Building the perfect GitHub CI workflow for your frontend team - The Blog of Maxime Heckel Migrating to Next.js - The Blog of Maxime Heckel Static Tweets with MDX and Next.js - The Blog of Maxime Heckel Advanced animation patterns with Framer Motion - The Blog of Maxime Heckel Scrollspy demystified - The Blog of Maxime Heckel The Power of Composition with CSS Variables - The Blog of Maxime Heckel My first failed SwiftUI project - The Blog of Maxime Heckel Guide to creating animations that spark joy with Framer Motion - The Blog of Maxime Heckel Using Shortcuts and serverless to build a personal Apple Health API - The Blog of Maxime Heckel SEO mistakes I've made and how I fixed them - The Blog of Maxime Heckel Going native: SwiftUI from the perspective of a React developer - The Blog of Maxime Heckel Build your own preview deployment service - The Blog of Maxime Heckel The little guide to CI/CD for frontend developers - The Blog of Maxime Heckel Immigrating to the US - The Blog of Maxime Heckel The physics behind spring animations - The Blog of Maxime Heckel Generate screenshots of your code with a serverless function - The Blog of Maxime Heckel How to use Framer Motion with Emotion styled-components - The Blog of Maxime Heckel Data Fetching with NextJS: What I learned - The Blog of Maxime Heckel Learning in public - The Blog of Maxime Heckel Fixing the dark mode flash issue on server rendered websites - The Blog of Maxime Heckel How to fix NPM link duplicate dependencies issues - The Blog of Maxime Heckel Running scheduled cross-browser end-to-end tests on Github CI - The Blog of Maxime Heckel How I built my first custom ESLint rule - The Blog of Maxime Heckel React Lazy: a take on preloading views - The Blog of Maxime Heckel Building a GraphQL wrapper for the Docker API - The Blog of Maxime Heckel Switching off the lights - Adding dark mode to your React app - The Blog of Maxime Heckel Getting started with Typescript on Gatsby - The Blog of Maxime Heckel Rebuilding Redux with Hooks and Context - The Blog of Maxime Heckel Asynchronous rendering with React - The Blog of Maxime Heckel Using Flow generics to type generic React components - The Blog of Maxime Heckel How to efficiently type your styled-components with Flow - The Blog of Maxime Heckel How I got started with Kubernetes on GKE - The Blog of Maxime Heckel React sub-components Part 3: Whitelisting sub-components with flow - The Blog of Maxime Heckel React sub-components Part 2: Using the new Context API - The Blog of Maxime Heckel React sub-components - The Blog of Maxime Heckel Running Golang tests with Jest - The Blog of Maxime Heckel No title No title
Automated UI accessibility testing with Cypress - The Blog of Maxime Heckel
Maxime Heckel · 2019-07-09 · via Maxime Heckel's Blog

While writing tests (unit, integration or end to end) is core to my day to day workflow before pushing anything to production, I’ve often forgotten to bring my focus to whether or not what I was building was accessible to everyone. Accessibility or a11y (accessibility has 11 letters between the first and last letter) is nonetheless an essential part of every product development and should get as much if not even more attention than testing. 
Skipping this was a mistake on my end, so I started looking to see if there were any ways I could integrate accessibility tests into my testing pipeline. The aim was similar to writing tests, although here there would be an additional acceptance item, which would be that a given feature or view would have to be compliant with a set of rules. That’s how I discovered cypress-axe, which integrated perfectly with cypress, the end to end testing framework I’m currently using.

In this short post, we’ll see how to setup cypress and cypress-axe and write tests that will make sure your frontend projects follow proper accessibility rules.

Setup

For the purpose of this post, we’ll consider a very simple React app to provide a frontend to run tests against. If you have any apps based on any other favorite framework or library that you wish to use while following this tutorial, you can use them; everything should work the same.
First, we’ll have to install a few dev dependencies:

  • Cypress, the testing framework, if you’re not already using it

  • axe-core, the accessibility engine for automated Web UI testing

  • cypress-axe, the package which will let us use axe-core capabilities within cypress.

  • start-server-and-test, a little helper that we’ll run to start our app, wait for it to be ready, then start cypress to run the test suits.

To get these you can run the following command at the root of your UI project:

1

yarn add -D cypress cypress-axe axe-core start-server-and-test

Now that we have all the tools installed in our project, we’ll have to write some scripts in our package.json to help us run the tests:

package.json excerpt with our test scripts

3

"start": "react-scripts start",

4

"test": "start-server-and test start http://localhost:3000 cy:open",

5

"cy:open": "cypress open",

The code snippet above contains the scripts required to run the tests. We need a start script that can start our app; in my case, it’s react-scripts start since I’ve based this demo on a create-react-app. If you already have a start command no need to change it.
The test script runs start-server-and-test which runs a series of steps. First, it will run the start script, then wait for the [http://localhost:3000](http://localhost:3000) to be available, and finally, once the app is fully started it will run the cy:open which will start the cypress UI and let us run tests.

Writing an accessibility test

Now that cypress and cypress-axe are setup, it’s time to write our first test. First, in cypress/support/index.js, let’s add the following code snippet:

cypress/support/index.js excerpt with cypress-axe

Then, let’s head to the cypress/integration folder and create a accessibility.spec.js. This file will contain the following accessibility test:

Our first accessibility test using cypress-axe

4

values: ['wcag21aa', 'wcag2aa', 'best-practice', 'section508'],

8

context('Accessibility (A11Y)', () => {

9

it('Passes accessibility tests', () => {

10

cy.visit('http://localhost:3000');

12

cy.checkA11y(A11Y_OPTIONS);

The test is contained within the it statement above, and as we can see it contains a few lines which execute the following steps:

  1. we visit our app on whatever URL it is running, in the case of the sample React app: http://localhost:3000

  2. we run injectAxe which injects the axe-core runtime into the page we’re testing.

  3. we run checkA11y with some options which will return any potential accessibility issues on the current page.

Concerning the options passed in the last function, we can see that we’re passing an object with a key runOnly. This object has two fields, type set to tag , and value set to ["section508"]. With these options, we’re telling axe-core to test our page by only running the rules under the section508 accessibility standard which is one of the many accessibility standards for web UIs.
If we choose to call checkA11y without any options, we would run the accessibility tests with all the accessibility rules available.

Now that we’re done writing our first test, it’s time to give it a try!

First accessibility test run

To run the test we wrote above, let’s run yarn test . As explained in the first part, this will start our UI project, and start Cypress once the UI is available.
We should then see the Cypress GUI with a list of tests, one of them being the accessibility test we just wrote.

We can then click on the accessibility.spec.js test which will start the test run and output results.

If like me you ran this test against the create-react-app basic UI you should see a result similar to the following:

Cypress output with one accessibility issues

Cypress output with one accessibility issues

Our test detected one accessibility violation. This output though doesn’t give many details sadly. To know exactly what the issue is, we’ll have to open the chrome console and click on the field labeled with A11Y ERROR!bypass on 1 Node to have more information:

Accessibility violation failure summary for our first cypress test run

Accessibility violation failure summary for our first cypress test run

The output from the console gives us a failure summary with the following message: “Fix any of the following: No valid skip link found Page does not have a header Page does not have a landmark region”. By clicking on the help URL provided by the test output, we can get some documentation on the issue itself, and also a path to fixing it. In this case we simply need to add the following attribute to the main div wrapping our app: role="main".

After the change, running cypress again should result in a passing test:

Successful cypress accessibility test run

Successful cypress accessibility test run

Other examples

Adding extra rules to our accessibility test can potentially surface extra accessibility violation. Let’s add the rule best-practice and see what we get:

The updated version of the options object passed to our accessibility test

4

values: ['section508', 'best-practice'],

We should see two new moderate accessibility violations:

Accessibility test run showcasing two moderate accessibility issues

Accessibility test run showcasing two moderate accessibility issues

As we can see with this example, the more rules add to our accessibility test, the more issues we’re surfacing thus the “accessibility test coverage” we get.
I tried quite a few combinations to see how much issues cypress could surface, and I was quite impressed by the result. For instance, we can try adding a button to the UI with some white label on a cyan background and enable the wcag2aa set of rules in our options. Doing this and running the test will surface color contrast issues as you can see in the screenshot below:

Accessibility test run showcasing one contrast issues on the button with cyan background and white label

Accessibility test run showcasing one contrast issues on the button with cyan background and white label

Conclusion

Adding automated UI accessibility tests has been a game changer in my day to day work. This extra layer of testing can help us reduce the number of accessibility issues present in our projects. I hope that this article will help you set up this kind of testing pipeline on your own projects, or at least help you start the conversation around accessibility in your team if that’s not already the case. The repository featuring the code snippets of this article is available here and should allow you to run the examples showcased with just a few commands.
I spent quite some time to look for other tools that can help any UI developer to build more accessible applications. If you’re interested in learning more, I bundled them in the following Twitter thread:

Don’t hesitate to contact me if you want more details, I may or may not write about the libraries or tools I mentioned in the future.