Zum Inhalt springen
Pandus

Barrierefreiheit testen mit Playwright: WCAG-Prüfungen in Ihrer Test-Suite

Aktualisiert am 14. Oktober 2026 · Lesezeit: 7 Min.

Playwright steuert einen echten Browser, und axe-core ist die Open-Source-Regel-Engine hinter den meisten automatischen Barrierefreiheitsprüfungen. Zusammen machen sie aus WCAG-Prüfungen gewöhnliche Tests: Eine Seite, die einen Button ohne Namen oder einen Text mit zu geringem Kontrast bekommt, bricht den Build, bevor sie Kunden erreicht. Dieser Leitfaden zeigt funktionierende Beispiele mit @axe-core/playwright, die Möglichkeiten für React-Komponenten und Storybook, CI-Tipps und die Grenzen, die Sie kennen sollten.

Die Beispiele folgen dem offiziellen Playwright-Leitfaden zu Barrierefreiheitstests und der README von @axe-core/playwright. Dieselbe Engine nutzen wir auch in unserem eigenen Scanner.

Installation

npm install --save-dev @playwright/test @axe-core/playwright

Die Paketversion folgt der Version von axe-core, die darin enthalten ist. Die README weist darauf hin, dass sie nicht semantischer Versionierung folgt. Legen Sie die Version daher fest und aktualisieren Sie sie bewusst: Ein neues axe-Release kann Regeln hinzufügen, die neue Probleme finden.

Ein erster WCAG-Test

import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';

const WCAG_AA = ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'wcag22aa'];

test('home page has no detectable WCAG A/AA violations', async ({ page }) => {
    await page.goto('/');

    const results = await new AxeBuilder({ page }).withTags(WCAG_AA).analyze();

    expect(results.violations).toEqual([]);
});

withTags beschränkt den Lauf auf die Regeln, die mit diesen WCAG-Versionen und -Stufen gekennzeichnet sind. Ohne diese Angabe führt axe auch seine Best-Practice-Regeln aus, die nützlich, aber keine WCAG-Anforderungen sind.

Die Zustände testen, die Menschen wirklich sehen

Eine Seite ist mehr als ihre erste Darstellung. Öffnen Sie zuerst das Menü, die Warenkorb-Schublade oder den Cookie-Dialog und prüfen Sie dann mit include nur diesen Teil:

test('mobile menu is accessible when open', async ({ page }) => {
    await page.goto('/');
    await page.getByRole('button', { name: 'Menu' }).click();

    const results = await new AxeBuilder({ page })
        .include('#navigation-menu')
        .withTags(WCAG_AA)
        .analyze();

    expect(results.violations).toEqual([]);
});

Gute Kandidaten in einem Shop: die Produktseite mit gewählten Optionen, der Warenkorb mit Artikeln, der Checkout mit angezeigten Validierungsfehlern, das Login-Formular des Kundenkontos. Wenn Sie in Ihren Tests getByRole verwenden, ist das schon ein kleiner Barrierefreiheitstest für sich: Findet Playwright den Button nicht über Rolle und Namen, findet ihn ein Screenreader-Nutzer vermutlich auch nicht.

Bekannte Probleme, ohne Tests abzuschalten

Echte Projekte haben Probleme, die Sie heute nicht beheben können, etwa in einem Widget eines Drittanbieters. Die README bietet drei Werkzeuge:

const results = await new AxeBuilder({ page })
    .exclude('#third-party-chat')      // skip an element
    .disableRules(['color-contrast'])  // skip a rule (use rarely)
    .withTags(WCAG_AA)
    .analyze();

Ein besseres Muster aus dem Playwright-Leitfaden ist ein Snapshot von Fingerprints: Sie halten fest, welche Regeln bei welchen Elementen fehlschlagen, und der Test schlägt nur fehl, wenn etwas Neues auftaucht.

const fingerprints = (results) =>
    results.violations.map((v) => ({
        rule: v.id,
        targets: v.nodes.map((n) => n.target),
    }));

expect(fingerprints(results)).toMatchSnapshot();

Zwei Hinweise aus der README: include und exclude nehmen pro Aufruf einen Selektor (verketten Sie sie für mehrere), und ein erneuter Aufruf von withTags, withRules, disableRules oder options überschreibt den früheren Aufruf.

Zuerst bei dem fehlschlagen, was zählt

Ist der Rückstand groß, beginnen Sie mit den schwersten Problemen. Jeder Verstoß hat ein impact von minor, moderate, serious oder critical:

const blocking = results.violations.filter((v) =>
    ['serious', 'critical'].includes(v.impact),
);
expect(blocking).toEqual([]);

Hängen Sie das vollständige Ergebnis an den Bericht an, damit, wer es behebt, jedes Element sieht:

// inside test('…', async ({ page }, testInfo) => { … })
await testInfo.attach('accessibility-scan-results', {
    body: JSON.stringify(results, null, 2),
    contentType: 'application/json',
});

Der Playwright-Leitfaden zeigt außerdem, wie Sie AxeBuilder in einer Test-Fixture kapseln, sodass jeder Test dieselben Tags und Ausschlüsse an einer zentralen Stelle erhält.

React-Komponenten: jest-axe und vitest-axe

Für Komponententests, die in JSDOM rendern, ergänzen jest-axe und vitest-axe einen Matcher toHaveNoViolations:

import { render } from '@testing-library/react';
import { axe } from 'vitest-axe';
import 'vitest-axe/extend-expect';

it('renders an accessible form', async () => {
    const { container } = render(<SignupForm />);
    expect(await axe(container)).toHaveNoViolations();
});

Sie sind schnell und finden fehlende Labels und Namen früh. Zwei Grenzen aus ihren READMEs: jest-axe schaltet Prüfungen des Farbkontrasts ab, weil sie in JSDOM nicht funktionieren, und vitest-axe funktioniert nicht mit der Umgebung happy-dom. Kontrast, Layout, Zoom und Fokus brauchen einen echten Browser, behalten Sie die Playwright-Tests also für ganze Seiten bei.

Storybook

Das Storybook-Addon für Barrierefreiheit führt axe-core für jede Story aus:

npx storybook add @storybook/addon-a11y

Setzen Sie parameters.a11y.test für Stories, die sauber bleiben müssen, auf 'error': Verstöße lassen dann den Test in der Storybook-Oberfläche und in der CI fehlschlagen. 'todo' zeigt sie nur als Warnungen, und 'off' überspringt die automatische Prüfung.

CI-Tipps

  • Führen Sie die Prüfungen in derselben Pipeline aus wie Ihre anderen Tests. Der Playwright-CI-Leitfaden nutzt npm ci, npx playwright install --with-deps und npx playwright test und lädt den Ordner playwright-report/ als Artefakt hoch.
  • Testen Sie eine gebaute, produktionsnahe Seite, keinen Dev-Server mit Debug-Overlays.
  • Wählen Sie eine kurze Liste wichtiger URLs – Startseite, eine Kategorie, ein Produkt, Warenkorb, Checkout, Login, eine Inhaltsseite –, statt bei jedem Commit alles zu crawlen.
  • Halten Sie die axe-Version fest und aktualisieren Sie sie in einem eigenen Pull Request.
  • Verstecken Sie Fehler nicht lange mit disableRules; nehmen Sie lieber exclude für ein einzelnes Element oder das Snapshot-Muster.

Was automatische Tests Ihnen nicht sagen können

In der README von axe-core steht, dass sich im Durchschnitt 57 % der WCAG-Probleme automatisch finden lassen, und der Playwright-Leitfaden stellt genauso klar, dass automatische Tests nicht alle Arten von WCAG-Verstößen erkennen können. Ein leeres Array violations heißt nicht, dass eine Seite WCAG 2.2 AA erfüllt. Sie brauchen weiterhin einen Durchgang mit der Tastatur, eine Prüfung von Zoom und Reflow und einen Test mit dem Screenreader. Diesen Teil beschreibt unser WCAG-Testleitfaden, und die WCAG-2.2-Checkliste kennzeichnet, welche Punkte einen Menschen brauchen.

Wo Pandus ins Spiel kommt

Tests in der CI schützen den Code, den Sie ändern. Sie sehen nicht, was danach auf der Live-Website passiert: ein Theme-Update, eine neue App oder ein neues Plugin, ein Marketing-Banner, eine vom Lieferanten eingefügte Produktbeschreibung. Pandus prüft die Produktionswebsite: jede Seite jede Woche, mit derselben axe-core-Engine in einem echten Browser, und mit einem Bericht, den ein Shop-Inhaber lesen kann.

  • Die API startet Prüfungen und liefert Ergebnisse als JSON, mit Webhooks, wenn eine Prüfung endet oder neue Probleme auftauchen – nützlich nach einem Deployment.
  • Die Browser-Erweiterung prüft eine Seite so, wie Ihr Browser sie anzeigt, einschließlich Staging und Seiten hinter einem Login.
  • Der kostenlose WCAG-Checker prüft eine öffentliche Seite ohne Konto.

Pandus ist eine automatische Prüfung, kein vollständiges Audit und keine Rechtsberatung. Einen Vergleich weiterer Werkzeuge finden Sie unter Tools für Barrierefreiheitstests.

Häufige Fragen

Wie teste ich Barrierefreiheit mit Playwright?

Installieren Sie @axe-core/playwright, öffnen Sie die Seite in einem Playwright-Test, führen Sie new AxeBuilder({ page }).analyze() aus und prüfen Sie, dass das Array violations leer ist. Beschränken Sie den Lauf mit withTags auf WCAG-Regeln, zum Beispiel wcag2a, wcag2aa, wcag21a, wcag21aa und wcag22aa.

Heißt ein bestandener axe-Test, dass die Seite die WCAG erfüllt?

Nein. Automatische Regeln finden nur einen Teil der WCAG-Probleme. Deque, der Hersteller von axe-core, beziffert das im Durchschnitt auf etwa 57 % der Probleme. Tastaturbedienung, sinnvolle Alternativtexte, Fokusreihenfolge und verständliche Fehlermeldungen muss weiterhin ein Mensch beurteilen.

Kann ich stattdessen jest-axe oder vitest-axe verwenden?

Ja, für Komponenten, die in JSDOM gerendert werden. Beide sind schnell, aber jest-axe schaltet die Prüfung des Farbkontrasts ab, weil sie in JSDOM nicht funktioniert. Nutzen Sie Playwright für ganze Seiten in einem echten Browser, wo Kontrast, Layout und Fokus prüfbar sind.

Wie teste ich Storybook-Komponenten auf Barrierefreiheit?

Fügen Sie @storybook/addon-a11y hinzu. Es führt axe-core für jede Story aus; ist parameters.a11y.test auf error gesetzt, lassen Verstöße den Test in der Storybook-Oberfläche und in der CI fehlschlagen.

Sollte der Build bei jedem Verstoß fehlschlagen?

Lassen Sie ihn zunächst nur bei schwerwiegenden und kritischen Problemen fehlschlagen und halten Sie einen Snapshot der bekannten Probleme fest. So brechen neue Probleme den Build, während alte Schritt für Schritt behoben werden. Verschärfen Sie die Regel, sobald der Rückstand abgebaut ist.

Quellen

  • Playwright, Accessibility testing: https://playwright.dev/docs/accessibility-testing
  • Playwright, Setting up CI: https://playwright.dev/docs/ci-intro
  • Deque, @axe-core/playwright README: https://github.com/dequelabs/axe-core-npm/blob/develop/packages/playwright/README.md
  • Deque, axe-core README: https://github.com/dequelabs/axe-core
  • jest-axe README: https://github.com/NickColley/jest-axe
  • vitest-axe README: https://github.com/chaance/vitest-axe
  • Storybook, Accessibility tests: https://storybook.js.org/docs/writing-tests/accessibility-testing