Technique18 juin 20264 min

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

En Bref : L'essentiel à retenir

  • Un test automatisé vérifie la présence d'un attribut, jamais sa pertinence : la majeure partie de la conformité RGAA reste un travail humain.
  • Le bon usage des tests automatisés est la non-régression : ils empêchent un défaut déjà corrigé de revenir, ils ne prouvent pas la conformité.
  • Branchez-les au plus près du code (test unitaire de composant) plutôt qu'en fin de chaîne : un défaut détecté sur un composant est corrigé partout à la fois.
  • Un échec de test signale une anomalie à instruire, pas une non-conformité établie.
JavaScriptTestsWCAGRGAADev

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. Un automate vérifie la présence d'un élément, jamais sa pertinence. Il sait dire qu'une image porte un attribut alt ; il ne sait pas dire que cet alt décrit correctement l'image. Or une part importante des critères RGAA porte précisément sur ce jugement, ce que détaille notre page de couverture des critères. Les tests excellent en revanche 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();
});

Astuce

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.

Questions fréquentes

Les tests automatisés suffisent-ils pour la conformité RGAA ?

Non. Un automate vérifie la présence d'un élément (une alternative textuelle existe, une étiquette est associée) mais pas sa pertinence (cette alternative décrit-elle correctement l'image). Une part importante des 106 critères repose sur ce jugement, qui reste humain. Les tests automatisés servent à défricher et à empêcher les régressions, pas à établir une conformité.

Où placer les tests d'accessibilité dans un projet JavaScript ?

Au plus près du code, dans les tests unitaires de composants. Un défaut détecté sur un composant du design system est corrigé une fois et disparaît partout où ce composant est utilisé. Les tests de bout en bout viennent en complément pour valider les parcours assemblés, mais ils détectent plus tard et coûtent plus cher à maintenir.

Que faire quand un test d'accessibilité échoue ?

Traiter le résultat comme une anomalie à instruire, pas comme une non-conformité prouvée. Certains signalements sont des faux positifs liés au contexte, d'autres révèlent un défaut réel. La vérification manuelle du critère concerné tranche, et c'est elle qui doit décider si le test doit être corrigé ou si c'est le code.

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.