Machen wir uns nichts vor - eine Website barrierefrei zu gestalten ist nicht trivial. Das Thema ist hochkomplex, und muss von allen Seiten mitgedacht werden. Und so ist es leider auch beim Testen: ein großer Teil muss manuell getestet werden, weil die automatisierten Tests bis jetzt nicht in der Lage sind, alles abzudecken. Aber trotzdem können wir Einiges tun, um unsere Testabdeckung in Bezug auf Barrierefreiheit zu optimieren.
Automatische Prüfung
Es gibt einige Tools für die automatische Prüfung auf Barrierefreiheit. Sie orientieren sich an den anerkannten Standards, den Web Content Accessibility Guidelines (WCAG).
Die Effizienz der Tools ist umstritten. Im Allgemeinen wird angenommen, dass diese Tools nur 20-30% der Verstöße gegen die WCAG erkennen können. Immer wieder gibt es auch Untersuchungen, so wie diese von Adrian Roselli, die auf eine noch geringere Erfolgsquote kommen. Auf der anderen Seite gibt es Hersteller, die eine weit höhere Abdeckung angeben. So wie Deque mit seiner Testing-Engine axe-core. Der Hersteller behauptet hier, dass die durchschnittliche Abdeckung 57% beträgt. Für diese Berechnung wurde aber schlicht eine andere Metrik angewandt – nachzulesen in diesem Blogpost von Deque.
Trotzdem sind automatisierte Tests ein sinnvolles Tool, um die Barrierefreiheit einer Website abzusichern. Testing-Engines wie Axe-core sind in vielen Tools verbaut, auch in Entwicklertools zum Testen von Frontend-Anwendungen, wie zum Beispiel jest oder cypress. Am Beispiel von playwright-axe schauen wir uns die Benutzung an.
Automatische Prüfung mit @axe-core/playwright
Wie der Name schon impliziert, ist @axe-core/playwright eine Bibliothek, die die axe-core Testing-Engine in das End-to-End-Testing Framework Playwright einbindet. Die Installation erfolgt dabei einfach über npm.
npm install --save-dev @axe-core/playwright
Nach der Installation können wir axe in Tests verwenden. Es läuft dabei grundsätzlich so ab, dass wir zuerst die Seite vollständig laden, und sie danach mit der Testing-Engine analysieren. Der Test ist bestanden, wenn es keine Regelverstöße gibt.
1await page.goto("/"); 2const accessibilityScanResults = await new AxeBuilder({ page }).analyze(); 3expect(accessibilityScanResults.violations).toEqual([]);
Axe kann auch nur auf einen Teil der Seite angewendet werden. Weiterhin können wir Elemente oder Regeln explizit ausnehmen. So können wir auch Seiten testen, bei denen noch Baustellen im Bezug auf Barrierefreiheit bekannt sind. Weiter Infos dazu findet ihr auf der Seite von Playwright.
Die Regeln von axe beziehen sich auf verschiedene Erfolgskriterien von WCAG 2.0 bis 2.2. Bis auf wenige Ausnahmen sind dabei nur die Konformitätslevel A und AA abgedeckt. Zusätzlich gibt es Regeln für Best Practices und experimentelle Regeln. Alle Regeln können individuell ein- und ausgeschaltet werden. Hier findet ihr eine Komplettübersicht.
Alleine ein Blick auf diese Übersicht macht aber klar, dass längst nicht alle Erfolgskriterien abgedeckt sind. Selbst wenn sie abgedeckt sind, gibt es keine Garantie, dass die ein Regel alle Verstöße gegen ein Kriterium erkennen kann. Automatische Überprüfungen sollten also nur als Baseline angesehen werden.
Tests für Keyboardnavigation
Normalerweise klicken wir uns in automatisierten Tests durch das Interface. Eine Reihe wichtiger Erfolgskriterien der WCAG legt aber fest, dass die Website auch mit dem Keyboard benutzt werden kann. Deswegen ist es sinnvoll, auch entsprechende Tests in die E2E-Testsuite mit aufzunehmen.
Schauen wir uns dazu ein Beispiel mit Playwright an. Playwright exponiert das Keyboard über die Property keyboard in der page. Mit
1await page.keyboard.press("Tab");
kann zum Beispiel das nächste Element in der Tabreihenfolge angesteuert werden. Danach sollte überprüft werden, ob das richtige Element fokussiert ist. Das fokussierte Element kann über den Selektor „*:focus-visible“ ausgewählt werden:
1await expect(page.locator("*:focus-visible")).toContainText("Homepage");
Auf diese Art und Weise kann überprüft werden, ob alle Elemente angesteuert werden können, und zwar auch in der richtigen Reihenfolge.
In Cypress ist das Ganze ein bisschen komplizierter. Stand heute (Juni 2024) gibt es in Cypress keine Möglichkeit, den Tab-Key auszulösen. Der Grund ist wohl, dass Cypress emulierte Events verwendet statt der nativen Browser Events. Siehe dazu das entsprechende Github-Issue.
Ein Workaround ist das Plugin cypress-real-events, mit dem richtige Browser-Events ausgelöst werden können. Mit dieser Unterstützung sieht der Testcode für die Keyboardnavigation so aus:
1cy.get("nav a").first().focus(); 2cy.realPress("Tab"); 3cy.focused().should("contain.text", "All");
Ein wichtiger Punkt beim Testen ist, dass wir initial - aus Sicht von Cypress - keinen Fokus in der Seite haben. Damit die Tab-Navigation funktioniert, muss erst ein Element mit Cypress fokussiert werden (Zeile 1). Sobald wir einmal den Fokus haben, funktioniert es aber wie erwartet – jedoch leider nur in Chrome. Andere Browser werden von dem Plugin nicht unterstützt. Die Unterstützung für Tab-Navigation ist in Cypress also ausbaufähig.
Tests auf semantische Namen
Alle interaktiven Komponenten des Interfaces brauchen einen Namen, der programmatisch erkannt werden kann (WCAG Erfolgskriterium 4.1.2). Das ist ein Kriterium, das relativ leicht automatisiert getestet werden kann.
Playwright unterstützt uns dabei: Die Assertion toHaveAccessibleName ist neu in Playwright 1.44 und liefert den Namen, unter dem ein Element im Accessibility Tree sichtbar ist. Damit können wir die Assertion aus dem obigen Beispiel wie folgt umschreiben:
1await expect(page.locator("*:focus-visible")).toHaveAccessibleName("Homepage");
Der Accessibility Tree wird vom Browser auf Basis des DOM-Trees erstellt und ist die semantische Repräsentation einer Seite. Für Screenreader, Spracherkennungssoftware und andere assistive Technologien ist er eine wichtige Informationsquelle. Der accessible Name eines Elements wird abgeleitet von sichtbaren oder unsichtbaren Labeln. Ein sichtbares Label für ein Formularfeld ist zum Beispiel Text in einem label-Tag, dass mit dem Formularfeld verknüpft ist. Ein Beispiel für ein unsichtbares Label ist der Wert des alt-Attributs eines Bildes.
Mit der Nutzung dieser Assertion, und der ähnlich gestrickten Assertion toHaveAccessibleDescription können wir sicherstellen, dass wir semantisch korrekte Namen vergeben.
Die Nutzer von Cypress müssen etwas mehr Aufwand betreiben, und sich bei jedem Element genauer überlegen, wie der accessible Name zustande kommt. Je nachdem wird das label-Tag, oder das entspreche Attributs eines Elements überprüft. Allerdings gibt es in Cypress keine Möglichkeit zu testen, dass dies auch tatsächlich der accessible Name ist, der im Accessibility Tree auftaucht.
Tests von semantischen Rollen
Das oben erwähnte Erfolgskriterium 4.1.2 der WCAG legt auch fest, dass semantische Rollen programmatisch erkannt werden müssen. Die Rollen können implizit sein (zum Beispiel ist h1 implizit eine Überschrift Ebene 1), oder explizit vergeben werden mit dem role-Attribut. Die Korrektheit einer semantische Rolle können wir in E2E-Tests recht einfach überprüfen, indem wir unsere Elemente anhand ihrer Rolle auswählen.
In Playwright funktionier das mit dem Locator getByRole. Damit kann man Elemente anhand ihrer Rolle auswählen, und auch nach accessible Name oder Zustand filtern.
1await expect(page.getByRole("heading", { level: 1 })).toContainText("Welcome");
2await page.getByRole("link", { name: "Homepage" });
3await page.getByRole("button", { disabled: false });
Für Formularfelder kann der Locator getByLabel verwendet werden. Damit werden Felder anhand ihres semantischen Labels selektiert.
1await page.getByLabel("Search");
Für die Benutzer von Cypress führt der Weg über die Testing Library. Die Testing Library ist eine Sammlung von Testing Utilities für verschiedene Test Frameworks. Ein Grundprinzip ist das Auswählen von Elementen über die semantische Rolle. Deswegen können mit der Cypress Testing Library Elemente analog zu Playwright über findByRole bzw. findByLabelText ausgewählt werden.
1cy.findByRole("heading", { level: 1 }).should("contain.text", "Welcome");
2cy.findByLabelText("Search");
Zusammenfassung
Wir haben viele Instrumente an der Hand, um die Barrierefreiheit einer Website automatisiert zu testen. Die Standard Testing-Engines der einschlägigen Hersteller sind ein wichtiger Baustein, aber können uns nur eine Basis bieten. Durch gezieltes Einbauen von semantischen Selektoren und Keyboardtests können wir unsere Frontend-Tests in dieser Hinsicht weiter verbessern. Manuelles Testen kann dadurch aber nicht komplett ersetzt werden.
Weitere Beiträge
von Anna Maier
Dein Job bei codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
Weitere Artikel in diesem Themenbereich
Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Blog-Autor*in
Anna Maier
Senior IT-Consultant
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.