Présentation

Des tests d’accessibilité qui vous disent ce qu’ils ne peuvent pas vous dire.

Tests d’accessibilité déterministes pour Playwright, Cypress, Puppeteer, Selenium, WebdriverIO, Jest/Vitest et vos pipelines de CI.

@surea11y/core est un moteur de tests d’accessibilité que vous exécutez dans votre propre suite de tests, dans votre pipeline de CI ou en ligne de commande.

Ce qui le distingue, c’est ce qu’il fait des cas que les tests automatisés ne peuvent pas trancher. Il implémente le format ouvert du W3C, Accessibility Conformance Testing (ACT) Rules Format, et il est vérifié sur le corpus de tests publié par ACT plutôt que jugé uniquement à l’aune de ses propres tests. Il rapporte ce qu’il trouve, ce qu’il ne trouve pas et, chose rare, ce dont il n’est pas certain, de sorte que ses résultats sont vérifiables plutôt que rassurants.

Sure, c’est la certitude sur ce que l’on sait, et l’honnêteté sur ce que l’on ne sait pas. Il vous dit ce qu’il ne peut pas vous dire.

145 règles d’accessibilité · 60 règles ACT du W3C vérifiées sur les cas de test du W3C · 957 cas de référence · résultats déterministes · incertitude explicite

enginev1.14.1licenseMPL-2.0

Voir les nouveautés de la dernière version

Pas un produit unique

surea11y est une famille de paquets qui partagent un même moteur, et non un outil unique avec une seule commande d’installation. Installez celui qui correspond à votre façon de tester actuelle, avec @surea11y/core, le moteur qu’il exécute. Installez core seul pour exécuter le moteur sur un DOM dont vous disposez déjà, ou pour bâtir votre propre outil dessus :

Je veux…Installer
Ajouter des vérifications d’accessibilité aux tests Playwright@surea11y/playwright + @surea11y/core
…Puppeteer@surea11y/puppeteer + @surea11y/core
…Selenium@surea11y/selenium + @surea11y/core
…Cypress@surea11y/cypress + @surea11y/core
…WebdriverIO@surea11y/webdriverio + @surea11y/core
Vérifier l’accessibilité dans des tests unitaires ou de composants Jest/Vitest@surea11y/test-matchers + @surea11y/core
Analyser des pages depuis un terminal ou un pipeline de CI, en HTML statique ou dans Chromium@surea11y/cli
Vérifier EN 301 549, la norme européenne, avec n’importe lequel des précédents@surea11y/pack-en301549 + @surea11y/core
Vérifier mes propres règles, profils ou norme, publics ou internesUn pack à moi : voir Écrire un pack
Exécuter le moteur sur un DOM dont je dispose déjà@surea11y/core
Créer mon propre outil sur le moteur : une CLI, une extension, un tableau de bord, un générateur de rapports@surea11y/core

Voir Premiers pas pour l’installation et l’utilisation de chaque binding. Si vous construisez un outil, BUILDING_ON_CORE.md (sur GitHub, en anglais) présente le contrat stable, l’exécution des analyses, le choix des vérifications et la façon de présenter les résultats sans leur faire dire plus qu’ils ne disent.

Pour un premier aperçu sans suite de tests, chargez le bundle autonome dans une page et analysez-la depuis la console du navigateur : await a11ycore.run() analyse la page, a11ycore.table(result) liste les résultats, a11ycore.highlight(result) les encadre dans la page et await a11ycore.openReport(result) ouvre le rapport HTML. INTEGRATION.md (sur GitHub, en anglais) liste les autres fonctions, comme a11ycore.inspect('headings') pour les titres, les landmarks, les noms ou l’ordre de focus d’une page.

En quoi ses résultats diffèrent

Chaque règle prend une décision déterministe, à partir d’un vocabulaire fixe de quatre résultats, et non selon la structure violations/passes/incomplete/inapplicable qu’utilisent d’autres outils de test d’accessibilité répandus :

  • fail (fail) : une violation démontrable à partir du DOM. Réservé aux cas objectifs et normatifs.
  • pass (pass) : la condition précise de cette règle est remplie. Cela ne signifie pas que la page est accessible.
  • can't tell (cantTell) : une personne doit trancher, et le résultat indique ce qui était ambigu.
  • n/a (notApplicable) : la condition préalable de la règle n’est pas présente.

cantTell est la raison d’être du projet. Un moteur qui écarte discrètement ce qu’il ne peut pas déterminer produit un rapport plus court et une fausse impression de couverture. Voir Résultats et rapports pour la structure complète du résultat, et Conformité pour la façon dont les résultats individuels s’agrègent en un verdict WCAG, y compris la façon dont une version WCAG cible (2.0/2.1/2.2) est déterminée et appliquée.

Un cantTell ne vous laisse pas seul face à une question. Chacun de ceux que renvoie une règle de core indique comment y répondre : quelques étapes à partir de l’élément qu’il désigne, et ce que vous verrez s’il réussit et s’il échoue, dans la langue de l’analyse. Quand la page fournit des indices, le résultat penche en plus vers pass ou fail, avec les faits qu’il a lus, sa raison et ce qui pourrait le rendre faux. Chaque penchant est compté sur les cas de test ACT du W3C et, une fois compté sur au moins cinq cas, il indique combien de fois il a vu juste ; d’ici là, il ne porte aucun chiffre, jamais une estimation. Le résultat reste cantTell : un penchant ordonne les questions, et c’est toujours une personne qui y répond. Voir Comment vérifier et Penchants dans le Schéma de sortie, et LEANS.md (sur GitHub, en anglais) pour ce qui vaut un penchant à un résultat et la confiance à lui accorder.

Le rapport HTML présente les questions dans l’ordre où une personne les examine : « Échec probable : à confirmer », « Réussite probable : à confirmer » et « À examiner par une personne ». Chaque carte a ses étapes « Comment vérifier », et celles des deux premiers groupes disent pourquoi elles penchent. En CI, les rapports JUnit et SARIF peuvent aussi bloquer le build sur les résultats qui penchent vers l’échec, option désactivée par défaut, et une baseline peut accepter ceux qu’une page a déjà, si bien que seuls les nouveaux font échouer le build. Voir Rapport HTML et Baseline / allowlist, ou ouvrez un exemple de rapport sur une petite page de paiement.

Un pass qui est passé de justesse le dit. Les règles qui mesurent une valeur par rapport à un seuil (contraste, taille de cible, espacement du texte) signalent une margin quand la réussite la plus juste s’est approchée de la limite : l’élément qui s’en est le plus approché tout en la respectant. Un texte à 4,52:1 pour un minimum de 4,5:1 passe, et la marge le montre : vous pouvez le corriger avant qu’un petit changement n’en fasse un fail. Voir le Schéma de sortie.

Nommez la norme, et le moteur choisit les règles. { wcag: { version: '2.2', level: 'AA' } } exécute les règles des critères A et AA de WCAG 2.2, selon le niveau de chaque critère dans cette version, et bestPractices: true ajoute les vérifications que WCAG n’exige pas. Une norme au-delà de WCAG, comme une norme nationale ou la politique propre à votre organisation, prend la forme d’un pack : ses règles, ses profils et les points de sa liste de contrôle s’exécutent à côté de celles de core et apparaissent dans chaque rapport. Voir Options du moteur et Packs.

Nommez des vérifications plutôt qu’une norme, et le résultat indique toujours les critères WCAG qu’elles concernent. Une analyse qui n’exécute que link-name-present signale aussi 2.4.4 et 4.1.2, plus le critère AAA 2.4.9 si l’analyse ne fixe pas de niveau, et un critère dont l’analyse a laissé de côté les autres vérifications ressort en cantTell (« Vérifié en partie » dans le rapport HTML), pas en pass. wcagLevel: 'AA' fixe le niveau des critères qu’une analyse signale, et les rapports JUnit, SARIF et EARL le suivent : un build AA n’échoue pas sur un critère AAA.

Aucun critère WCAG n’est déclaré réussi sur la foi de règles qui n’en vérifient qu’une partie. Un critère ne réussit que si ses règles vérifient tout ce qu’il demande, et aucun n’est encore vérifié aussi complètement : quand toutes les règles d’un critère réussissent, le critère ressort en cantTell. Les parties que vérifient les règles sont respectées, et une personne vérifie le reste. Un rapport sans échec le dit aussi sous son titre : aucune règle n’a échoué, ce qui ne signifie pas que la page est conforme. Déclarer ces critères réussis, ce serait donner la fausse impression de couverture que ce moteur est conçu pour éviter. Voir Correspondance de conformité WCAG.

Les composants web sont jugés sur ce qu’ils exposent. Un élément personnalisé qui se donne un nom, des états ou un rôle par ElementInternals est vérifié sur ces valeurs quand le moteur peut les lire, et fait l’objet d’une question quand il ne le peut pas. Pour les exécutions de test et d’audit, internalsHookScript() est un script facultatif qui permet à l’analyse de lire les internals qu’un composant garde privés : ces éléments réussissent ou échouent au lieu de ressortir en cantTell. INTEGRATION.md (sur GitHub) montre comment l’installer avant les scripts de la page.

Les règles atteignent trois critères qu’aucune règle ne couvrait : 3.3.1 « Identification des erreurs » (un champ marqué invalide dont le message d’erreur manque, est masqué ou ne lui est pas associé), 4.1.3 « Messages d’état » (une région live que les technologies d’assistance ne peuvent pas atteindre) et 1.4.5 « Texte sous forme d’image » (du texte dessiné dans une image qui pourrait être du vrai texte). Les trois posent une question au lieu d’échouer. Les règles du clavier lisent les gestionnaires d’événements dans le balisage ; avec listenerHookScript(), un autre script facultatif installé avant ceux de la page, elles jugent aussi les écouteurs ajoutés par script : un role="button" dans l’ordre de tabulation avec un écouteur de clic et aucun écouteur de touche là où ses touches pourraient en atteindre un (sur lui, à l’intérieur, sur ses ancêtres, sur un shadow root qui le contient, le document ou la fenêtre), ni d’écouteur de focus qui pourrait en ajouter un, échoue, car Entrée et Espace ne font rien. INTEGRATION.md (sur GitHub) montre comment l’installer, ainsi que son équivalent pour les messages d’état, le hook des régions live.

Dans un navigateur, le contraste est mesuré tel que la page est dessinée : le texte d’une page sans arrière-plan propre, sur le canevas que peint le navigateur, clair ou sombre ; le texte généré par ::before, ::after et les marqueurs de liste ; et un <select> fermé. Ces cas étaient auparavant ignorés ou faisaient l’objet d’une question. Le texte dessiné uniquement par un contour ou une ombre échoue désormais là où chaque couleur dans laquelle il est dessiné est sous le ratio. Un caractère isolé qui tient lieu du nom d’un contrôle, comme le « X » d’un bouton nommé « Fermer », fait l’objet d’une question au lieu d’un échec : savoir s’il s’agit d’une icône ou d’une lettre demande une personne.

Vérifié sur le corpus ACT

Le moteur comprend 145 règles. Celles qui ont un équivalent dans les W3C ACT Rules sont exécutées sur les cas de test que le W3C publie pour elles, ceux que note la liste des implémentations du W3C : 957 exemples répartis sur 60 règles ACT. Le moteur ne renvoie fail sur aucun des exemples qu’ACT marque comme réussis ou inapplicables ; il ne produit donc aucun faux positif sur ce corpus. C’est un résultat sur ces exemples, pas une garantie pour toute page ; quand le moteur ne peut pas trancher un cas, il renvoie cantTell, ce qu’ACT permet à une implémentation automatisée.

Cela vaut dans les deux environnements où le moteur s’exécute : dans jsdom, comme avec test-matchers et la CLI par défaut, et dans Chromium, comme avec les bindings de navigateur, chaque cas de test étant chargé comme une vraie page, scripts et feuilles de style liées compris. Vingt-deux exemples qu’ACT marque en échec ne sont pas signalés dans jsdom, et 18 dans Chromium. Ce sont pour la plupart des questions de jugement, comme savoir si un titre décrit le contenu qui le suit ; les quatre que le navigateur détecte demandent les scripts ou les feuilles de style de la page, que jsdom n’exécute pas. Voir ACT_RULE_MAPPING.md pour chacun d’eux, avec le raisonnement.

Deux rapports d’implémentation EARL consignent le résultat de chacun de ces cas, réussites et résultats inapplicables compris : une règle restée muette parce que rien ne s’appliquait se distingue ainsi d’une règle qui n’est pas implémentée du tout. SureA11y est exécuté dans jsdom, et SureA11y in a browser dans Chromium. Voir Rapport EARL pour le format.

Principes clés

  • Exécution déterministe. Une même page, rendue dans les mêmes conditions et analysée avec les mêmes options, reçoit les mêmes décisions. Les temps, horodatages et détails d’environnement du résultat peuvent tout de même varier d’une exécution à l’autre. Les animations et transitions en cours sont figées pendant l’analyse, si bien qu’un fondu en cours ne change pas ce que mesurent les règles.
  • Prudent par conception. Les règles de core réservent fail aux violations objectives et normatives, pour que les fausses alertes restent rares.
  • Traçabilité vers les normes. Les règles sont associées au critère de succès WCAG applicable chaque fois que c’est pertinent.
  • Sortie stable et lisible par machine. Les identifiants de règle restent les mêmes quelle que soit la langue.
  • Indépendant du framework. S’exécute dans jsdom ou dans n’importe quel framework d’automatisation de navigateur.
  • Extensible. Ajoutez des règles personnalisées, enregistrez des politiques et filtrez les analyses par ID de règle, tag ou version WCAG.
  • Rapports localisés. Les messages lisibles par un humain peuvent être traduits sans toucher aux données lisibles par machine ; en, fr, de, es et ja sont fournis aujourd’hui.

Philosophie

Automatiser ce qui peut être déterminé objectivement. Ne jamais prétendre automatiser ce qui ne peut pas l’être.

Certaines exigences des WCAG peuvent être vérifiées avec une certitude totale. D’autres demandent un jugement humain, une connaissance du contexte ou une évaluation de l’utilisabilité. Un score unique ou un verdict réussi/échoué gomme cette différence ; surea11y la rapporte. C’est pour cela que cantTell et notApplicable existent en tant que résultats, et cela détermine chaque règle du moteur.

Ce que surea11y ne détectera pas

Être explicite sur les limites de l’automatisation fait partie de la même philosophie. Par exemple, surea11y ne pourra pas :

  • confirmer qu’un texte alternatif a du sens, seulement qu’il est présent (un attribut alt valant "image123.png" passe la vérification objective, et fait l’objet d’une question, penchant vers l’échec, en tant que nom de fichier) ;
  • juger si un choix de contraste de couleurs est esthétiquement approprié, seulement s’il atteint le rapport de contraste applicable ;
  • déterminer si un message d’erreur explique réellement le problème, car cela dépend d’une logique de validation qu’une analyse statique ne voit pas ;
  • détecter un piège au clavier ou un contenu rogné à un zoom de 400 %, car les deux exigent de simuler une véritable interaction utilisateur dans le temps, et pas seulement de lire le DOM à un instant donné.

Certaines vérifications implémentées renvoient cantTell quand une personne doit trancher. D’autres aspects, dont les pièges au clavier et la redistribution au zoom, ne sont pas du tout vérifiés par le moteur et demandent des tests à part : aucun cantTell ne les remplace, donc un résultat qui n’en contient pas ne signifie pas qu’ils ont été couverts. Voir Limites connues pour la liste complète.

À propos du projet

surea11y est un projet open source indépendant, développé de manière ouverte.

@surea11y/core et tous les paquets d’intégration sont publiés sur npm. Les tickets, les discussions et les modifications se font publiquement sur GitHub, et les contributions sont bienvenues. Voir CONTRIBUTING.md pour les règles de contribution.