Verwendung mit Playwright

Playwright ist ein browserübergreifendes Framework für End-to-End-Tests von Microsoft, das echte Chromium-, Firefox- und WebKit-Engines aus Node.js heraus steuert. surea11y wird über das Binding @surea11y/playwright eingebunden.

$ npm install @surea11y/core @surea11y/playwright playwright
$ npx playwright install chromium

Der zweite Befehl ist wichtig — jeder Test startet einen echten Browser, und npm install allein lädt ihn nicht herunter.

const { chromium } = require('playwright');
const { A11yCoreBuilder } = require('@surea11y/playwright');
 
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com/');
 
const results = await new A11yCoreBuilder({ page })
.include('#main') // optional -- call multiple times for multi-region scans
.exclude('.cookie-banner') // optional
.withWcag('2.2', 'AA') // the rules for WCAG 2.2's A and AA criteria
.disableRules(['meta-refresh-no-exceptions'])
.analyze();
 
console.log(results.checksResults.filter(r => r.outcome === 'fail'));
await browser.close();

.withWcag(version, level) wählt nach Konformitätsziel aus: die Regeln für die Erfolgskriterien der Stufen A und AA von WCAG 2.2, nach der Stufe, die jedes Kriterium in dieser Version hat. .withBestPractices() fügt die Regeln hinzu, die kein WCAG-Erfolgskriterium prüfen, etwa region; allein ausgeführt, laufen nur diese.

.withPacks() registriert vor dem Scan ein Pack in der Seite, und .options({ profile }) wählt sein Profil. Ein Pack, das nicht läuft, wird als Scan-Lücke 'pack-skipped' gemeldet, sodass ein Test, der getScanGaps(results) prüft, fehlschlägt, statt ohne das Pack zu bestehen.

Funktioniert mit allen drei Playwright-Engines, nicht nur mit Chromium — überprüft mit echten Läufen in Firefox und WebKit.

Web Components. Eine Komponente, die ihre ElementInternals in einem privaten Feld hält und sich darüber einen Namen, ihre Zustände oder eine Rolle gibt, lässt sich von keinem Skript der Seite auslesen. Standardmäßig stellt der Scan zu einer solchen Komponente eine Frage (cantTell), statt sie zu beurteilen, und eine Rolle, die nur so gesetzt ist, wird gar nicht geprüft. Wenn Sie eine Komponentenbibliothek bauen oder testen, installieren Sie den optionalen Internals-Hook des Bindings, bevor die eigenen Skripte der Seite laufen, und diese Komponenten werden wie jedes andere Bedienelement beurteilt:

const context = await browser.newContext();
await A11yCoreBuilder.installInternalsHook(context); // before any page navigates
const page = await context.newPage();
await page.goto('https://example.com/');

Rufen Sie ihn vor page.goto() auf, auf der Seite oder auf ihrem Browser-Kontext. Er läuft über addInitScript(), sodass ein Aufruf jeden Frame und jede Navigation abdeckt, für die Seite oder für jede Seite, die der Kontext öffnet, in Chromium, Firefox und WebKit. Mit @playwright/test rufen Sie ihn in einem beforeEach auf der Fixture context auf.

Der Hook ist für Test- und Audit-Läufe gedacht: Er legt das, was er aufzeichnet, dort ab, wo jedes Skript der Seite es lesen kann, deshalb ist er optional. Ohne ihn meldet der Scan einmal, wenn er zu solchen Komponenten Fragen gestellt hat. Der Abschnitt der README zum Internals-Hook enthält die Details.

Klick-Handler und Live-Regionen. Seit core 1.14 gibt es zwei weitere optionale Hooks. Die meisten Seiten fügen ihre Klick-Handler per Skript hinzu, wo kein Skript der Seite sie danach auflisten kann. Der Scan sieht daher nicht, dass ein <div role="button"> mit einem Klick-Listener per Tastatur nichts tut; mit dem Listener-Hook ergibt ein solcher Button fail (CLICK_HANDLER_NO_KEY_LISTENER). Der Live-Region-Hook zeichnet auf, was die Live-Regionen der Seite erhalten: Der Scan stellt dann eine Frage zu einer Statusmeldung, die schon mit ihrem Text eingefügt wurde und die Screenreader oft nicht ansagen, und announcements() gibt zurück, was die Seite zur Ansage bereitgestellt hat, damit ein Test prüfen kann, ob eine Aktion den Nutzenden etwas mitgeteilt hat. Installieren Sie sie, bevor die eigenen Skripte der Seite laufen, wie den Internals-Hook:

const context = await browser.newContext();
await A11yCoreBuilder.installListenerHook(context); // before any page navigates
await A11yCoreBuilder.installLiveRegionHook(context);
const page = await context.newPage();
await page.goto('https://example.com/settings');
await page.getByRole('button', { name: 'Save' }).click();
 
const said = await A11yCoreBuilder.announcements(page);
// [{ text: 'Saved', politeness: 'polite', ..., selector: '#status' }]

Beide werden wie der Internals-Hook installiert, auf der Seite oder ihrem Browser-Kontext, bevor sie navigiert. Mit @playwright/test installieren Sie sie in einem beforeEach auf der Fixture context.

Wie der Internals-Hook sind beide für Test- und Audit-Läufe gedacht: Jedes Skript der Seite kann lesen, was sie aufzeichnen. announcements() ist das, was die Seite zur Ansage bereitgestellt hat, nicht das, was ein Screenreader gesagt hat, und ohne den Live-Region-Hook null. Fehlt einer der beiden Hooks, meldet getScanNotes(), wenn Befunde, die er entschieden hätte, ohne ihn beurteilt wurden. Die Abschnitte der README zum Listener-Hook und zum Live-Region-Hook enthalten die Details.

Dunkler Modus, Smartphone-Breiten und eine Schwelle nach Schweregrad. .conditions([{ colorScheme: 'dark' }, { width: 320 }]) scannt die Seite so, wie sie ist, und dann erneut unter jeder Bedingung, und gibt ein einziges Ergebnis zurück: Das Ergebnis einer Regel ist ihr schlechtestes über alle Scans, und jeder Befund nennt die Bedingungen, unter denen er auftrat. Jede Bedingung ist ein vollständiger Scan, und .frames(true) lässt sich noch nicht damit kombinieren. Das funktioniert in Chromium, Firefox und WebKit. getGatingFailures(results, { failOnSeverity: 'serious' }) gibt die fehlschlagenden Regeln ab diesem Schweregrad zurück, sodass ein Test zuerst bei schwerwiegenden und kritischen Problemen blockiert, während der Rest weiter gemeldet wird; formatFailures() nimmt dieselbe Option.

Fragen mit Tendenz und Prüfschritten. Seit core 1.14 kann ein cantTell-Befund zu fail oder pass tendieren, mit Begründung, und er enthält howToCheck: die Schritte, mit denen eine Person ihn beantwortet. formatFailures() listet die wahrscheinlich nicht erfüllten Fragen direkt nach den Fehlschlägen und gibt mit { howToCheck: true } die Schritte aus. Soll ein Test auch bei wahrscheinlichen Fehlschlägen scheitern, nehmen Sie leaningFailures(results) aus core in die Schwelle auf.

A11yCoreBuilder hat außerdem .wcagLevel(), das die gemeldeten Kriterien auf eine WCAG-Stufe begrenzt, ohne zu ändern, welche Regeln laufen; .includeMode('or'), das die Regeln eines Tags plus die Regeln ausführt, die Sie nennen; .plannedChecks() und .plannedCriteria(), die auflisten, was ein Scan prüfen wird, bevor er läuft, damit eine Auswahl, die nichts ausführt, nicht als Scan ohne Befunde durchgeht; .logger(), das Warnungen zu Scan-Lücken an Ihr eigenes Log schickt; .fetchStyleSheets(false), das .analyze() davon abhält, Stylesheets anderer Origins, die die Seite selbst nicht lesen kann, für die Regeln abzurufen, die das CSS lesen; und getScanNotes(results), das angibt, wie die Seite gescannt wurde. Die README des Bindings beschreibt jede davon.

Siehe auch ein lauffähiges Beispiel im Repository des Pakets.

Als Nächstes: festlegen, welche Regeln laufen, den Scan in die CI einbinden und das vollständige Ergebnisschema ansehen.