Un même bouton, un même champ de formulaire, un même composant d’onglets : testés vingt fois, par vingt équipes différentes, avec vingt niveaux d’exigence différents, ou testés une seule fois à la source, avec un niveau de confiance identique pour tout le monde ensuite. Ce constat, posé par l’équipe plateforme d’un grand groupe médias possédant vingt produits web indépendants construits sur le même design system Gutenberg, a motivé la refonte complète de leur dispositif de tests d’accessibilité.
Avant cette refonte, chaque équipe produit exécutait, ou n’exécutait pas, ses propres vérifications d’accessibilité sur son site final. Résultat : un même bug d’accessibilité présent dans le composant source se retrouvait dupliqué sur quinze sites différents, découvert quinze fois séparément, corrigé quinze fois séparément dans le pire des cas, ou jamais dans le meilleur.
Le principe : déplacer le test au plus près du composant
La question à trancher était simple à énoncer et complexe à mettre en œuvre : où exécuter les tests d’accessibilité pour qu’une correction profite immédiatement à tous les produits qui consomment le composant concerné ? La réponse retenue a été de placer l’essentiel de la couverture de test au niveau du dépôt du design system lui-même, pas au niveau de chaque site qui l’utilise.
Ce billet ne traite pas la gouvernance du design system en tant que telle (qui décide des évolutions, comment les équipes proposent des composants) : il se concentre exclusivement sur l’architecture technique des tests d’accessibilité mutualisés.
L’arborescence retenue

Le dépôt du design system a été réorganisé pour isoler clairement trois niveaux de responsabilité : les composants eux-mêmes, leurs tests d’accessibilité génériques, et un kit de conformité que chaque équipe produit peut consommer sans le réécrire.
design-system/
├── components/
│ ├── Bouton/
│ │ ├── Bouton.php
│ │ ├── Bouton.stories.js
│ │ └── Bouton.a11y.test.js
│ ├── ChampFormulaire/
│ │ ├── ChampFormulaire.php
│ │ ├── ChampFormulaire.stories.js
│ │ └── ChampFormulaire.a11y.test.js
│ └── Onglets/
│ ├── Onglets.php
│ ├── Onglets.stories.js
│ └── Onglets.a11y.test.js
├── a11y-kit/
│ ├── regles-communes.js (config axe-core partagée)
│ ├── playwright.a11y.config.js
│ └── rapport-html.js
└── pipelines/
└── ci-a11y.yml
Chaque composant embarque son propre test d’accessibilité, écrit une seule fois par l’équipe plateforme, exécuté via Storybook et l’addon a11y en développement, puis rejoué en CI via Playwright et axe-core sur le rendu final du composant isolé.
Le référentiel de règles commun
Le point le plus délicat n’a pas été technique mais organisationnel : obtenir un accord entre vingt équipes sur un même niveau d’exigence. Certaines équipes voulaient bloquer sur toute anomalie, d’autres préféraient ne bloquer que sur les anomalies critiques et laisser les anomalies mineures en simple avertissement. Le compromis retenu a pris la forme d’un fichier de configuration axe-core unique, versionné dans le dépôt central, que chaque pipeline produit importe sans le modifier localement :
// a11y-kit/regles-communes.js
module.exports = {
rules: {
'color-contrast': { enabled: true },
'label': { enabled: true },
'aria-required-attr': { enabled: true },
'nested-interactive': { enabled: true },
},
resultTypes: ['violations'],
reporter: 'v2',
};
Toute évolution de ce fichier passe par une revue de l’équipe plateforme, jamais par une équipe produit isolée. Cette contrainte a été discutée âprement au démarrage, puis largement acceptée une fois la première régression bloquée en amont plutôt que découverte en production.
Le pipeline central et sa propagation aux vingt produits
Le pipeline de CI du design system exécute la suite de tests d’accessibilité à chaque proposition de modification d’un composant. Si un composant régresse, la publication d’une nouvelle version est bloquée avant même qu’un produit ne puisse la consommer. Chaque produit, de son côté, ne rejoue qu’un sous-ensemble de tests d’intégration propres à son usage spécifique du composant (par exemple, un composant d’onglets utilisé dans un contexte de navigation principale versus un contexte de filtre secondaire).
| Niveau | Ce qui est testé | Fréquence |
|---|---|---|
| Design system | Chaque composant isolé, tous les états ARIA | À chaque pull request sur le composant |
| Produit | Intégration du composant dans son contexte réel | À chaque pull request sur le produit |
| Global | Échantillon de pages critiques sur les vingt produits | Hebdomadaire |
Un gain qui dépasse le seul temps de test
Le bénéfice le plus visible n’a pas été la réduction du temps de test, réelle mais secondaire, mais la disparition progressive des débats entre équipes sur ce qui constitue une anomalie ou non. Le référentiel commun a mis fin à des discussions récurrentes où chaque équipe défendait son propre niveau de tolérance, souvent par manque de temps plutôt que par désaccord de fond.
Notre verdict
Mutualiser les tests d’accessibilité au niveau des composants d’un design system, plutôt qu’au niveau de chaque site final, change fondamentalement l’échelle du problème : une correction profite immédiatement à tous les produits qui consomment le composant, et une régression est bloquée à la source plutôt que découverte site par site, parfois plusieurs mois plus tard.