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.
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
npm install axe-core --save-dev
Utilisation basique
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
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
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
// 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
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
// Avec Cypress
cy.visit('/dashboard');
cy.get('[data-cy=data-loaded]').should('be.visible');
cy.injectAxe();
cy.checkA11y();
Tester les états interactifs
// 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
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
{
"scripts": {
"test:a11y": "jest --testPathPattern=a11y",
"test:a11y:ci": "cypress run --spec 'cypress/e2e/accessibility/**'"
}
}
Outils complémentaires
Lighthouse CI
npm install -g @lhci/cli
lhci autorun --collect.url=http://localhost:3000 \
--assert.assertions.categories:accessibility=error
Pa11y
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
npm install eslint-plugin-jsx-a11y --save-dev
// .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
// 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
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.
Guides RGAA associés
Pour aller plus loin sur les sujets abordés dans cet article, consultez nos fiches techniques :
Chaque champ de formulaire doit avoir une étiquette (label) qui lui est liée explicitement.
Chaque image porteuse d'information doit avoir une alternative textuelle pertinente via l'attribut alt. Les images décoratives doivent avoir un attribut alt vide.
Le contraste entre la couleur du texte et la couleur de son arrière-plan doit être suffisamment élevé (4.5:1 pour le texte normal, 3:1 pour le grand texte).
Articles similaires
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.