Technique18 juin 20269 min

Tester l'accessibilité JavaScript : Outils et méthodes 2026

En Bref : L'essentiel à retenir

  • Les tests automatisés détectent environ 30 à 40% des problèmes d'accessibilité WCAG - le reste nécessite des tests manuels.
  • axe-core est la référence pour les tests JavaScript avec zéro faux positifs et une intégration dans tous les frameworks.
  • Intégrez les tests d'accessibilité dans votre pipeline CI/CD pour détecter les regressions avant la mise en production.
  • Combinez toujours tests automatisés et tests manuels avec lecteurs d'écran pour une couverture complète.
JavaScriptTestingaxe-coreautomatisationWCAGRGAACI/CD

Les applications JavaScript modernes (React, Vue, Angular) présentent des défis spécifiques en matière d'accessibilité : contenu dynamique, gestion du focus, composants interactifs complexes. Heureusement, l'écosystème de tests s'est considérablement enrichi pour répondre à ces enjeux.

Les limites des tests automatisés

Avant de plonger dans les outils, une mise en garde importante : les tests automatisés ne détectent que 30 à 40% des problèmes d'accessibilité. Ils excellent pour identifier :

  • Les images sans attribut alt
  • Les contrastes insuffisants
  • Les formulaires sans labels
  • Les structures de titres incorrectes
  • Les liens vides

Mais ils ne peuvent pas évaluer :

  • La pertinence d'un texte alternatif
  • La cohérence de l'ordre de lecture
  • L'expérience réelle avec un lecteur d'écran
  • La compréhensibilité du contenu

axe-core : la référence du marché

Développé par Deque, axe-core est le moteur de test d'accessibilité le plus utilisé. Il alimente de nombreux outils (Lighthouse, axe DevTools, Pa11y) et s'intègre dans tous les environnements JavaScript.

Installation

CODE
npm install axe-core --save-dev

Utilisation basique

CODE
import axe from 'axe-core';

// analyser toute la page
axe.run(document).then(results => {
  if (results.violations.length) {
    console.error('Problèmes d\'accessibilité détectés :', results.violations);
  }
});

Configuration avancée

CODE
axe.run(document, {
  runOnly: {
    type: 'tag',
    values: ['wcag2a', 'wcag2aa', 'wcag21aa']
  },
  rules: {
    'color-contrast': { enabled: true },
    'region': { enabled: false } // désactiver une règle spécifique
  }
}).then(results => {
  // traiter les résultats
});

Intégration avec les frameworks de test

Jest + React Testing Library

CODE
import { render } from '@testing-library/react';
import { axe, toHaveNoViolations } from 'jest-axe';
import MonComposant from './MonComposant';

expect.extend(toHaveNoViolations);

describe('MonComposant', () => {
  it('ne doit pas avoir de violations d\'accessibilité', async () => {
    const { container } = render(<MonComposant />);
    const results = await axe(container);
    expect(results).toHaveNoViolations();
  });
});

Cypress avec cypress-axe

CODE
// cypress/support/commands.js
import 'cypress-axe';

// Dans vos tests
describe('Page d\'accueil', () => {
  it('doit être accessible', () => {
    cy.visit('/');
    cy.injectAxe();
    cy.checkA11y();
  });

  it('doit être accessible après interaction', () => {
    cy.visit('/');
    cy.injectAxe();
    cy.get('[data-cy=menu-toggle]').click();
    cy.checkA11y('.menu-ouvert');
  });
});

Playwright

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

test('accessibilité de la page', async ({ page }) => {
  await page.goto('/');

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

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

Tester le contenu dynamique

Les applications SPA nécessitent des tests spécifiques pour le contenu chargé dynamiquement.

Attendre le rendu

CODE
// Avec Cypress
cy.visit('/dashboard');
cy.get('[data-cy=data-loaded]').should('be.visible');
cy.injectAxe();
cy.checkA11y();

Tester les états interactifs

CODE
// Tester un modal
it('le modal doit être accessible', async () => {
  render(<App />);

  // état initial
  const { container: closedContainer } = render(<App />);
  expect(await axe(closedContainer)).toHaveNoViolations();

  // Ouvrir le modal
  fireEvent.click(screen.getByText('Ouvrir'));

  // Tester avec le modal ouvert
  expect(await axe(document.body)).toHaveNoViolations();
});

[!TIP] Consultez notre article sur l'accessibilité des SPA React et Vue pour des conseils spécifiques sur la gestion du focus.

Intégration CI/CD

L'objectif ultime est d'intégrer les tests d'accessibilité dans votre pipeline d'intégration continue.

GitHub Actions

CODE
name: Tests d'accessibilité

on: [push, pull_request]

jobs:
  a11y:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      - run: npm ci
      - run: npm run build
      - run: npm run test:a11y

Configuration package.json

CODE
{
  "scripts": {
    "test:a11y": "jest --testPathPattern=a11y",
    "test:a11y:ci": "cypress run --spec 'cypress/e2e/accessibility/**'"
  }
}

Outils complémentaires

Lighthouse CI

CODE
npm install -g @lhci/cli

lhci autorun --collect.url=http://localhost:3000 \
  --assert.assertions.categories:accessibility=error

Pa11y

CODE
const pa11y = require('pa11y');

async function testPages() {
  const urls = ['/', '/contact', '/produits'];

  for (const url of urls) {
    const results = await pa11y(`http://localhost:3000${url}`);
    console.log(`${url}: ${results.issues.length} problèmes`);
  }
}

ESLint pour JSX

CODE
npm install eslint-plugin-jsx-a11y --save-dev
CODE
// .eslintrc.js
module.exports = {
  plugins: ['jsx-a11y'],
  extends: ['plugin:jsx-a11y/recommended']
};

[!NOTE] Le plugin eslint-plugin-jsx-a11y détecte les problèmes d'accessibilité directement dans votre éditeur, avant même l'exécution du code.

Bonnes pratiques

1. Tester à chaque étape

  • Développement : ESLint + tests unitaires
  • Pull Request : Tests Cypress/Playwright en CI
  • Staging : Audit complet avec RGAA Checker
  • Production : Monitoring continu

2. Ne pas désactiver les tests qui échouent

CODE
// MAUVAISE PRATIQUE
it.skip('accessibilité du formulaire', async () => { ... });

// BONNE PRATIQUE : corriger le problème ou documenter l'exception
it('accessibilité du formulaire', async () => {
  const results = await axe(container, {
    rules: {
      // Exception documentée : le composant tiers X n'est pas conforme
      'specific-rule': { enabled: false }
    }
  });
  expect(results).toHaveNoViolations();
});

3. Catégoriser les violations

CODE
const results = await axe(document);

const critical = results.violations.filter(v => v.impact === 'critical');
const serious = results.violations.filter(v => v.impact === 'serious');

// Échouer uniquement sur les violations critiques en CI
expect(critical).toHaveLength(0);

// Logger les autres pour correction ultérieure
if (serious.length) {
  console.warn('Violations sérieuses à corriger :', serious);
}

Conclusion

Les tests automatisés d'accessibilité JavaScript sont un filet de sécurité indispensable, mais ils ne remplacent pas les tests manuels. Combinez axe-core dans vos tests unitaires, Cypress ou Playwright pour les tests E2E, et complétez par des audits réguliers avec des outils comme RGAA Checker.

Pour une couverture complète, consultez notre guide des tests utilisateurs et notre comparatif des lecteurs d'écran.

Votre site est-il conforme ?

Ne prenez pas de risques avec l'accessibilité. Lancez un audit complet de votre site en quelques minutes et obtenez un rapport détaillé des corrections à apporter.