DEV Community

Cover image for Accessibility audits with Playwright, Axe, and GitHub Actions
Jakub Andrzejewski
Jakub Andrzejewski

Posted on

Accessibility audits with Playwright, Axe, and GitHub Actions

I recently given a talk at JS Poland Conference about one of my most favourite topics -> Improving Software Quality by utilising Continuous Integration. We usually use CI to lint the code, run unit tests, or check if our project was build correctly. While certainly important, these things are rather simple and we can use Continuous Integration for much more complex tests.

In this artice, I will focus about using Playwright and Axe builder, triggered automatically in GitHub Actions CI to continuously audit Accessibility of our application.

Playwright and Axe

Enjoy!

🟒 How to use Playwright and Axe in CI?

Running Accessibility tests in Playwright does not differ that much from doing the normal E2E tests.

First, we need to instruct the Playwright to run the localhost application server before running the tests:

import { defineConfig } from '@playwright/test';

export default defineConfig({
  webServer: {
    command: 'npm run start',
    url: 'http://127.0.0.1:3000',
    reuseExistingServer: !process.env.CI,
  },
});
Enter fullscreen mode Exit fullscreen mode

Then, we can start writing our first A11Y test with Playwright:

import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright'; // 1

test.describe('homepage', () => { // 2
  test('should not have any automatically detectable accessibility issues', async ({ page }) => {
    await page.goto('https://your-site.com/'); // 3

    const accessibilityScanResults = await new AxeBuilder({ page }).analyze(); // 4

    expect(accessibilityScanResults.violations).toEqual([]); // 5
  });
});
Enter fullscreen mode Exit fullscreen mode

Let's stop for a minute and explain each of the steps marked with numbers individually:

  1. Imports the @axe-core/playwright package
  2. Uses normal Playwright Test syntax to define a test case
  3. Uses normal Playwright syntax to navigate to the page under test
  4. Awaits AxeBuilder.analyze() to run the accessibility scan against the page
  5. Uses normal Playwright Test assertions to verify that there are no violations in the returned scan results

Apart from using the default preset of Axe, we can also customize it to check for certain WCAG violcations like A or AA like following:

test('should not have any automatically detectable WCAG A or AA violations', async ({ page }) => {
  await page.goto('https://your-site.com/');

  const accessibilityScanResults = await new AxeBuilder({ page })
      .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
      .analyze();

  expect(accessibilityScanResults.violations).toEqual([]);
});
Enter fullscreen mode Exit fullscreen mode

If we run this test locally, we should see similar result:

Local Playwright Accessibility test

If you would like to learn more about accessibility testing in playwright, check out here.

Now finally, the last step is to add the logic of running this test to CI (which we probably already have if we are using Playwright):

name: Playwright Tests
on:
  push:
    branches: main
jobs:
  test:
    //
    - name: Install dependencies
      run: npm ci
    - name: Install Playwright Browsers
      run: npx playwright install --with-deps
    - name: Run Playwright tests
      run: npx playwright test
Enter fullscreen mode Exit fullscreen mode

And that's it! You have now implemented Accessibility audits in your Continuous Integration pipeline. Nicely done!

πŸ“– Learn more

If you would like to learn more about Vue, Nuxt, JavaScript or other useful technologies, checkout VueSchool by clicking this link or by clicking the image below:

Vue School Link

It covers most important concepts while building modern Vue or Nuxt applications that can help you in your daily work or side projects πŸ˜‰

βœ… Summary

Well done! You have just learned how to implement Accessibility audits in your CI Pipeline.

Take care and see you next time!

And happy coding as always πŸ–₯️

Top comments (1)

Collapse
 
bcostaaa01 profile image
Bruno

Pretty interesting article, Jakub! πŸ‘πŸ» I find testing accessibility within Storybook easier, but I believe this is a bit of how it works under the hood there, maybe? It does look quite useful when you don't want to add yet another tool, and configuration effort (I mean with setting up Storybook from scratch if it is not yet being used in the frontend).