Automated Axe-Core Audits in CI Pipelines

This article explains how modern web development teams integrate axe-core into Continuous Integration (CI) pipelines to automate digital accessibility testing. By embedding axe-core into end-to-end and component testing frameworks, engineering teams can automatically detect Web Content Accessibility Guidelines (WCAG) violations, enforce accessibility standards on pull requests, and prevent regressions before code is merged into production.

Why Use Axe-Core in CI Pipelines

Axe-core is an open-source, automated accessibility testing engine that detects approximately 30% to 57% of WCAG issues automatically with zero false positives by default. Integrating it directly into a CI/CD pipeline shifts accessibility testing left, providing engineers with immediate feedback within pull requests. This automation prevents common issues—such as missing form labels, insufficient color contrast, and invalid ARIA attributes—from ever reaching production environments.

Integration Strategies

Web teams typically adopt one of two primary strategies to run axe-core in automated environments:

  1. End-to-End (E2E) Test Runners: Integrating axe-core with frameworks like Playwright, Cypress, or Puppeteer. This approach evaluates accessibility against dynamic, fully rendered web pages in real browser environments.
  2. Component Testing / Design Systems: Running axe-core within Storybook (via @storybook/addon-a11y or test-runner) or Jest/Vitest (via jest-axe). This evaluates isolated UI components before they are assembled into larger interfaces.

For most web applications, E2E runner integration provides the most realistic coverage because it accounts for live state, routing, and third-party scripts.

Step-by-Step Implementation with Playwright

Modern test suites widely use @axe-core/playwright due to its native browser automation capabilities and speed.

1. Installation

Install Playwright and the official axe-core integration package:

npm install -D @playwright/test @axe-core/playwright

2. Creating an Accessibility Test

Teams write tests that navigate to key user flows, inject axe-core, run the analysis, and assert that zero violations exist.

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

test.describe('Accessibility Audits', () => {
  test('homepage should have no automatically detectable WCAG A or AA violations', async ({ page }) => {
    await page.goto('/');

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

    expect(accessibilityScanResults.violations).toEqual([]);
  });
});

3. Scoping and Rule Configuration

When dealing with legacy applications, failing a build on every violation is often impractical. Teams scope audits and define specific rule enforcement strategies:

  • Include/Exclude Selectors: Run axe on specific DOM containers rather than the whole page using .include('#main-content') or ignore known third-party widgets using .exclude('.third-party-widget').
  • Disable Specific Rules: Suppress specific violations temporarily using .disableRules(['color-contrast']) while technical debt is addressed.
  • Filter by Impact: Configure assertions to only fail builds for critical or serious violations, while logging moderate and minor warnings for future sprints.

Automating in CI Workflows

Once tests are defined, they are executed in the CI workflow (e.g., GitHub Actions, GitLab CI, or Jenkins).

Here is a minimal GitHub Actions configuration:

name: Accessibility Checks

on: [pull_request]

jobs:
  axe-audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Install dependencies
        run: npm ci

      - name: Install Playwright Browsers
        run: npx playwright install --with-deps chromium

      - name: Build and Start Application
        run: |
          npm run build
          npm run start &
          npx wait-on http://localhost:3000

      - name: Run Axe Audits
        run: npx playwright test accessibility.spec.ts

If any violation matching the specified tags or severity thresholds is found, the test runner exits with a non-zero exit code, automatically blocking the pull request from merging.

Reporting and Triaging

Raw terminal logs can be difficult to interpret when complex violations occur. Teams improve visibility by:

  • Generating HTML Reports: Using reporters such as axe-html-reporter to generate visual audit summaries stored as CI build artifacts.
  • Pull Request Comments: Automating bot comments that highlight specific HTML snippets, WCAG criteria failures, and direct remediation links provided by Deque University.
  • Exporting to SARIF: Converting axe outputs to the Static Analysis Results Interchange Format (SARIF) to display warnings natively inside GitHub Code Scanning tabs.

Best Practices

  • Test State Changes: Do not run axe-core only on static page loads. Trigger modal dialogs, dropdowns, and form validation errors, running audits at each dynamic state.
  • Combine with Manual Testing: Automated axe-core tests cover structural and programmatic issues, but cannot assess subjective criteria such as keyboard navigation flow, logical focus order, or screen reader clarity. Automated CI checks must complement, not replace, manual accessibility reviews.