Vorbereitung
Als Testobjekt dient die neue Komponente „Playwright getByRole Demo“ (Abschnitt 9) in meinem Testlab.

Sie enthält ein kleines Formular „Kundenkonto anlegen“ mit:
- einem Eingabefeld E-Mail-Adresse und einer Auswahlliste Land
- zwei Radiobuttons Privatkunde / Geschäftskunde und einer Checkbox Newsletter abonnieren
- einem Link Datenschutzerklärung
- den Buttons Speichern, Speichern als Entwurf und Abbrechen
- einem Statusbereich, der das Ergebnis der letzten Aktion anzeigt
Der gesamte Bereich hat die ID st-getbyrole-demo-2026-container. Wie schon beim Timeout-Beispiel suchen wir alle Elemente innerhalb dieses Containers:
const demo = page.locator('#st-getbyrole-demo-2026-container');
Das zeigt gleich eine wichtige Erkenntnis: getByRole() lässt sich problemlos mit anderen Locators verketten. Der Container wird per ID gefunden, alles darin per Rolle.
Was ist eine Rolle?
Rollen stammen aus der Barrierefreiheit (ARIA). Screenreader und andere Hilfstechnologien lesen eine Webseite nicht als HTML-Code, sondern als Baum aus Rollen und Namen: „Button, Speichern“ oder „Link, Datenschutzerklärung“.
Ein Rollen-Locator besteht deshalb fast immer aus zwei Teilen:
- Rolle: Um welche Art von Element handelt es sich?
- Name (accessible name): Wie heißt das Element? Meistens der sichtbare Text, das zugehörige Label oder ein
aria-label.
Die meisten HTML-Elemente haben ihre Rolle bereits eingebaut. Du musst im Code also nichts ergänzen:
<button> → button
<a href="..."> → link
<input type="text">, <input type="email">, <textarea> → textbox
<input type="checkbox"> → checkbox, <input type="radio"> → radio
<select> → combobox
<h1> bis <h6> → heading
<tr> / <td> → row / cell
Playwright kennt zwar sehr viele Rollen, im Alltag kommst du aber mit dieser kurzen Liste weit.
Beispiel 1: Ein Name passt auf zwei Buttons

Wir wollen auf „Speichern“ klicken mit:
await demo.getByRole('button', { name: 'Speichern' }).click();

Dieser Test schlägt fehl.
Playwright meldet eine strict mode violation: Der Locator passt auf zwei Elemente. Der Grund: Der Name wird standardmäßig als Teilstring ohne Beachtung der Groß-/Kleinschreibung verglichen. „Speichern“ steckt auch in „Speichern als Entwurf“.
Die Lösung ist die Option exact:

Jetzt findet Playwright genau einen Button und der Test besteht.

Merke: Ähnlich benannte Elemente sind der häufigste Grund für Probleme mit getByRole(). Mit exact: true oder einem regulären Ausdruck wie /^Speichern$/ wird der Vergleich eindeutig.
Beispiel 2: Ein Formular nur mit Rollen ausfüllen
Für Formularelemente nutzt Playwright das zugehörige <label> als Namen. Damit lässt sich unser komplettes Formular ohne eine einzige ID ausfüllen:

Achte auf die passende Aktion zur Rolle: fill() für Textfelder, selectOption() für Auswahllisten und check() für Checkboxen und Radiobuttons. check() ist dabei robuster als click(), weil Playwright anschließend prüft, ob das Element wirklich angehakt ist.
Siehe da, der Test besteht:

Beispiel 3: Überschriften, Links und Statusmeldungen
Übrigens: Auch Inhalte, die nicht klickbar sind, lassen sich über Rollen ansprechen:

Zwei Details sind hier interessant:
- Mit
level grenzt du Überschriften auf eine Ebene ein – hier <h3>.
- Der Statusbereich trägt das Attribut
role="status". Weil es auf der Seite nur einen davon gibt, brauchen wir nicht einmal einen Namen.
Beispiel 4: getByRole findet ein sichtbares Element nicht
Jetzt klicken wir auf „Abbrechen“:

Dieser Test schlägt fehl – obwohl „Abbrechen“ auf der Seite deutlich zu sehen ist und wie ein Button aussieht.
Ein Blick in den HTML-Code verrät den Grund: „Abbrechen“ ist kein <button>, sondern ein <div> mit einem Klick-Handler.

Optisch ein Button, technisch keiner. Für Playwright – und für einen Screenreader – existiert hier kein Button, sodass der Test fehlschlägt.

Du erinnerst dich vllt. an den Action-Timeout aus dem letzten Beitrag: Ein höherer Timeout hilft auch hier nicht. Es gibt zwei Wege:
- Besser: Das Entwicklungsteam ersetzt das
<div> durch einen echten <button>. Damit ist der Test grün und die Seite gleichzeitig barrierefreier.
- Übergangslösung: Im Test auf einen anderen Locator ausweichen, z. B.
demo.getByText('Abbrechen', { exact: true }).
Merke: Wenn getByRole() ein sichtbares Element nicht findet, hast du oft nicht nur ein Testproblem, sondern einen echten Barrierefreiheits-Fehler entdeckt.
Wann getByRole nicht die beste Wahl ist
getByRole() sollte deine erste Wahl sein, aber nicht deine einzige:
- Wechselnde Texte: Zeigt ein Button den aktuell gewählten Wert an (z. B. „Hell“ oder „Dunkel“), bindest du den Locator an Testdaten. Ändert sich der Wert, bricht der Test. Hier ist eine stabile ID oder ein
data-testid besser.
- Icons ohne Namen: Ein Icon-Button ohne Text und ohne
aria-label hat keinen Namen. Auch das ist ein Hinweis für das Entwicklungsteam.
- Versteckte Elemente: Standardmäßig berücksichtigt
getByRole() nur Elemente, die im Accessibility-Baum sichtbar sind.
Tipps: Rolle und Namen schnell herausfinden
- Playwright Codegen / Inspector: Mit
npx playwright codegen und der Funktion „Pick locator“ schlägt dir Playwright für ein Element automatisch einen Locator vor – meistens bereits mit getByRole().
- Browser-DevTools: In Chrome zeigt der Bereich „Accessibility“ im Elements-Tab für jedes Element Rolle und Namen an.
Fazit
Mit getByRole() beschreibst du Elemente nicht über ihren technischen Aufbau, sondern über ihre Bedeutung für den Nutzer. Das macht deine Tests lesbarer und unempfindlicher gegenüber Änderungen an CSS-Klassen oder Seitenstruktur.
Die Beispiele aus dem Testlab zeigen aber auch: Ganz ohne Nachdenken geht es nicht. Ähnlich benannte Elemente brauchen einen exakten Vergleich, und nicht jedes Element, das wie ein Button aussieht, ist auch einer. Gerade diese Fälle sind wertvoll, denn sie decken oft Schwächen in der Barrierefreiheit der Anwendung auf.
Weiterführende Links