How to Integrate Accessibility Testing into Your CI/CD Pipeline

Manual accessibility audits catch issues, but only at a point in time. By the next sprint, new regressions have appeared. CI/CD integration catches these regressions automatically.

Why Automate Accessibility Testing?

Manual audits are essential because automated tools catch only 30-40% of WCAG issues. But automated testing has a critical role: preventing regressions. When you fix an accessibility issue, you want it to stay fixed. Automated tests in CI/CD ensure that new code doesn't break existing accessibility, developers get immediate feedback on issues, and obvious problems are caught before code review.

Choosing Your Tools

axe-core

The most widely used accessibility testing engine. Powers Deque's tools, Chrome DevTools, and many CI integrations.

Strengths: Zero false positives policy, comprehensive rule set, excellent documentation, and multiple integration options (Jest, Cypress, Playwright).

Limitations: Conservative approach misses some issues to avoid false positives, and requires rendered DOM so it can't test unrendered states.

pa11y

Command-line accessibility testing tool. Good for simple CI integration.

Strengths: Simple CLI interface, CI-friendly output formats, and configurable rule sets.

Limitations: Less comprehensive than axe and fewer integration options.

Lighthouse

Google's web quality tool. Includes accessibility audits alongside performance, SEO, and best practices.

Strengths: Holistic quality reporting, built into Chrome DevTools, and good for stakeholder reporting.

Limitations: Accessibility audits less comprehensive than dedicated tools, and performance overhead higher than axe/pa11y.

Integration Patterns

Pattern 1: Unit Test Integration

Run accessibility checks as part of your component tests.

```javascript // Example with Jest and axe-core import { axe, toHaveNoViolations } from 'jest-axe';

expect.extend(toHaveNoViolations);

test('Button component is accessible', async () => { const { container } = render(); const results = await axe(container); expect(results).toHaveNoViolations(); }); ```

When to use: Component libraries, design systems, reusable UI elements.

Pattern 2: E2E Test Integration

Run accessibility checks during end-to-end tests against real pages.

```javascript // Example with Cypress and cypress-axe describe('Checkout flow', () => { it('has no accessibility violations', () => { cy.visit('/checkout'); cy.injectAxe(); cy.checkA11y();

cy.get('[data-testid="shipping-form"]').within(() => { cy.checkA11y(); }); }); }); ```

When to use: Critical user journeys, forms, interactive features.

Pattern 3: Build Pipeline Stage

Run accessibility checks as a dedicated CI stage.

```yaml

Example GitHub Actions workflow

accessibility: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install dependencies run: npm ci - name: Build run: npm run build - name: Run accessibility tests run: npm run test:a11y ```

When to use: Every PR, pre-deployment gate.

Pattern 4: Scheduled Audits

Run comprehensive accessibility audits on a schedule against production.

```yaml

Run weekly accessibility audit

schedule: - cron: '0 0 0' # Weekly on Sunday ```

When to use: Catch issues from third-party scripts, CMS content changes, dynamic data.

Setting Quality Gates

Strict Mode (Recommended for New Projects)

Fail the build on any accessibility violation.

Pros: Prevents all automated-detectable issues Cons: May slow development initially; requires team buy-in

Warning Mode (Recommended for Legacy Projects)

Report violations but don't fail the build initially. Fail only on new violations.

Pros: Allows gradual improvement; less friction Cons: Existing issues may persist

Threshold Mode

Fail if violations exceed a threshold. Reduce threshold over time.

Pros: Quantifiable progress; manageable for large codebases Cons: Allows some violations; harder to track individual issues

Handling False Positives

Automated tools sometimes flag issues that aren't real problems. Handle them properly:

1. Verify Before Disabling

Always manually verify a reported issue before marking it as false positive. Automated tools are conservative and they're usually right.

2. Disable Specific Rules

Don't disable all accessibility testing. Disable specific rules for specific elements.

```javascript // Disable specific rule for specific element cy.checkA11y({ rules: { 'color-contrast': { enabled: false } } }); ```

3. Document Exceptions

When you disable a rule, document why:

```javascript // Disabled: Text is decorative, not informational // See: https://github.com/your-repo/issues/123 ```

Integrating with Auditi

Auditi's API lets you import CI/CD results into your journey-based audits:

Common Pitfalls

1. Testing Only the Happy Path

2. Ignoring Dynamic Content

Content loaded after initial render needs accessibility testing too. Ensure your tests wait for dynamic content.

3. Over-Relying on Automation

Remember: automated tests catch 30-40% of issues. CI/CD integration supplements manual testing, it doesn't replace it.

4. Not Testing Keyboard Navigation

Automated tools check ARIA and structure. Keyboard navigation flow requires E2E tests that actually tab through the interface.

Getting Started

Start with one tool (axe-core is a good default), add it to one critical journey (your most important user flow), run it on every PR as part of code review, and expand gradually to more journeys and pages over time. Accessibility in CI/CD isn't about catching everything. It's about preventing regressions and building accessibility awareness into your development process.


Built by BetterQA. Auditi is the journey-based accessibility auditing platform for healthcare, fintech, and government organizations.