TL;DR: Wir zeigen, wie eine strukturelle Trennung von UI-Selektoren und Fachlogik beim Einsatz von Playwright aussehen kann, und adaptieren dafür das bewährte Robot Pattern zum Layered Robot Pattern. So kann eine Browser-Automatisierung erfolgen, ohne Angst vor UI-Änderungen haben zu müssen.
Inhalt
- Warum ein Android-Pattern für Playwright relevant ist
- Schneller Einstieg mit Playwright und KI
- Wachsende Effizienz im Projektalltag
- Das Layered Robot Pattern im Detail
- Abgrenzung zu BDD
- Vorteile und Grenzen
- Fazit
Neues Design, kaputte Automatisierung
Wir haben das Robot Pattern in den letzten zwei Jahren in zwei grundlegend verschiedenen Projekten eingesetzt: einmal für Regressionstests einer Android-App mit Jetpack Compose, einmal für die serverseitige Steuerung einer Webanwendung mit Playwright auf AWS Lambda. Dabei hat uns überrascht, wie direkt sich das Pattern von einer Plattform auf die andere übertragen lässt. Der Anlass ist aktuell: KI-Coding-Agenten übernehmen zunehmend die Erstellung und Wartung von Browser-Automatisierung. Ohne klare Strukturvorgaben produzieren sie beliebig aufgebauten Code, der schwer kontrollierbar ist. Ein konsequent eingehaltenes Pattern gibt dem Agenten einen verbindlichen Vertrag. Je disziplinierter das Pattern eingehalten wird, desto verlässlicher wird die KI-Assistenz. Genau das zeigen wir in diesem Artikel.
Ein konkretes Beispiel: Ein Webportal zur Buchung eines Badmintonplatzes einer Sporthalle soll mittels Playwright automatisiert bedient werden. Login, Hallenwahl, Zeitfensterauswahl, Buchungsbestätigung — das sind vier Seiten mit vielleicht zwanzig Selektoren. Was passiert mit einer bestehenden Automatisierung, wenn die Sporthalle ihr Portal umbaut? Neben neuen Farben werden neue IDs vergeben oder evtl. sogar ein ganz anderes UI-Framework verwendet. Die Playwright-Umsetzung ist nicht mehr lauffähig. Nicht, weil sich der Buchungsprozess geändert hat — sondern weil sich die Oberfläche weiterentwickelt hat.
Warum ein Android-Pattern für Playwright relevant ist
Jake Wharton stellte das Robot Pattern 2016 auf der Kotlin Night in San Francisco vor [1]. Sein Vortrag „Testing Robots" adressierte ein konkretes Problem: UI-Tests mit Googles Espresso-Framework, die ohne strukturelle Disziplin schnell unwartbar wurden.
Der Kerngedanke ist simpel: Trenne das Was vom Wie. Ein Robot kapselt alle UI-spezifischen Interaktionen einer Seite — Selektoren, Klicks, Wartezeiten — hinter fachlich benannten Methoden. Der aufrufende Code — ob Testfall oder Automatisierungsworkflow — sieht nur diese Methoden und niemals einen Selektor.
Das klingt nach dem Page Object Model von Martin Fowler [2], und tatsächlich sind beide verwandt. Der Unterschied liegt im Anspruch: Ein Page Object kapselt primär Selektoren und gibt sie als Eigenschaften nach außen.
Ein Robot hingegen kapselt vollständige Aktionen und sorgt dafür, dass der aufrufende Code wie eine fachliche Beschreibung lesbar ist.
Playwright dokumentiert das Page Object Model ausdrücklich als empfohlenes Pattern [4], aber in der Praxis bleibt die Umsetzung oft auf halber Strecke stehen: Selektoren werden gekapselt, aber als öffentliche Locator-Eigenschaften exponiert, anstatt sie hinter fachlichen Methoden zu verbergen.
Unsere Antwort darauf ist das Layered Robot Pattern: eine Drei-Schichten-Architektur, die die Selektor-Isolation des Page Object Models mit der Aktionskapselung des Robot Patterns verbindet und um eine explizite Workflow-Schicht ergänzt.
Schneller Einstieg mit Playwright und KI
Der Aufbau einer Playwright-Automatisierung ist heute kein mehrtägiges Projekt mehr. Mit playwright codegen generiert ein Browser-Recorder automatisch typsicheren Code mit robusten, semantischen Selektoren — ohne manuelle Selektor-Suche. Noch einen Schritt weiter geht Playwright MCP: Ein KI-Agent navigiert selbst durch die Anwendung, inspiziert das DOM und erzeugt daraus direkt eine fertige PageModel-Klasse. Den generierten Code übernimmt anschließend ein KI-Coding-Agent, der daraus eine vollständige Robot-Klasse nach Projektkonventionen erstellt — inklusive korrekter Vererbung und Projektstruktur. Was früher manuelles Refactoring war, dauert heute nur noch Sekunden.
Wachsende Effizienz im Projektalltag
Ein Effekt, der sich erst mit der Zeit zeigt: Je mehr Robots im Codebase existieren, desto wirksamer wird die KI-Assistenz. Mit genug Referenzen erkennt der Agent das Pattern aus dem Kontext und erzeugt zuverlässig neue PageModels, Robots und auch fachliche Workflows. Das Layered Robot Pattern wirkt dabei als struktureller Vertrag: Es gibt dem Agenten klare Regeln für generierten Code. Ohne dieses Pattern würde ein Agent beliebig strukturierten Playwright-Code produzieren.
Das Layered Robot Pattern im Detail
Unabhängig von der Plattform besteht unser Ansatz aus drei klar getrennten Schichten. Wir zeigen sie am Beispiel der bereits erwähnten Badminton-Platzbuchung.
Der BaseRobot: Gemeinsame Basis aller Robots
Alle konkreten Robots erben von einer gemeinsamen Basisklasse. Der BaseRobot abstrahiert Playwrights API — kein konkreter Robot ruft page.fill() oder page.click() direkt auf, sondern nutzt die Methoden der Basisklasse. Das hat zwei Vorteile: Querschnittsaspekte wirken automatisch auf alle Robots. Und das Verhalten aller Interaktionen lässt sich an genau einer Stelle ändern.
Der folgende Code ist vereinfacht dargestellt:
1export abstract class BaseRobot {
2 protected async click(target: Locator): Promise<void> {
3 await target.click();
4 }
5
6 protected async fill(target: Locator, value: string): Promise<void> {
7 await target.fill(value);
8 }
9
10 protected async waitForSelector(target: Locator): Promise<void> {
11 await target.waitFor({ state: 'visible' });
12 }
13}
Die konkrete Robot-Implementierung: Eine Klasse pro Seite
Der Robot kapselt die fachlichen Aktionen einer Seite. Er kennt sein PageModel, nach außen sieht der Workflow nur fachlich benannte Methoden — niemals einen Selektor.
1export class BookingRobot extends BaseRobot {
2 private readonly page: BookingPage;
3
4 constructor(page: Page, artifactDir: string) {
5 super(page, artifactDir);
6 this.page = new BookingPage(page);
7 }
8
9 async selectCourt(court: string): Promise<void> {
10 this.logger.info('Selecting court: %s', court);
11 await this.click(this.page.courtSelect);
12 await this.click(this.page.courtOption(court));
13 }
14
15 async bookSlot(date: string, time: string): Promise<void> {
16 this.logger.info('Booking slot: %s %s', date, time);
17 await this.fill(this.page.dateInput, date);
18 await this.click(this.page.timeSlot(time));
19 await this.click(this.page.confirmButton);
20 }
21}
Was dahinter passiert — welche Dropdown-Variante die Halle benutzt, ob das Datum per Kalender oder Textfeld eingetragen wird —, ist ein Implementierungsdetail, das sich jederzeit ändern kann, ohne den Workflow zu berühren.
Das PageModel: Selektoren von Verhalten trennen
Das PageModel ist eine eigene Klasse pro Seite, die ausschließlich Selektoren hält — keine Methoden, keine Logik. Ein Robot greift auf diese Klasse zu, nach außen ist sie unsichtbar.
1class BookingPage extends BasePageModel {
2 readonly courtSelect: Locator = this.page.getByLabel('Halle');
3 readonly courtOption = (name: string): Locator =>
4 this.page.getByRole('option', { name });
5 readonly dateInput: Locator = this.page.getByLabel('Datum');
6 readonly timeSlot = (time: string): Locator =>
7 this.page.getByRole('button', { name: time });
8 readonly confirmButton: Locator = this.page.getByRole('button', { name: 'Buchen' });
9}
Diese Trennung hat einen konkreten Vorteil: Ändert das Zielportal ein Formular — ein Label wird umbenannt, ein Button bekommt eine neue Rolle —, ist exakt eine Datei betroffen: nur das PageModel. Der Robot und der Workflow bleiben unberührt.
Der Workflow: Geschäftslogik als Code
Auf der obersten Schicht steht der Workflow. Er orchestriert die Robots und liest sich wie eine fachliche Beschreibung des Buchungsprozesses:
1export class BadmintonBookingWorkflow {
2 constructor(private readonly config: BadmintonBookingConfig) {}
3
4 async execute(page: Page, artifactDir: string): Promise<void> {
5 const { court, date, time } = this.config;
6
7 const loginRobot = new LoginRobot(page, artifactDir);
8 await loginRobot.login(this.config.email, this.config.password);
9
10 const homeRobot = new HomeRobot(page, artifactDir);
11 await homeRobot.navigateToBooking();
12
13 const bookingRobot = new BookingRobot(page, artifactDir);
14 await bookingRobot.selectCourt(court);
15 await bookingRobot.bookSlot(date, time);
16
17 const confirmRobot = new ConfirmationRobot(page, artifactDir);
18 await confirmRobot.verifyBookingSuccess();
19 }
20}
Wer diesen Code liest, versteht den fachlichen Buchungsprozess — auch ohne das Portal der Sporthalle je gesehen zu haben.
Abgrenzung zu BDD
Behavior-Driven Development mit Gherkin und Cucumber verfolgt ein ähnliches Ziel: Fachlichkeit lesbar machen. Der entscheidende Unterschied liegt im Overhead: BDD erfordert Feature-Files, Step Definitions und Glue Code — eine zusätzliche Schicht, in der das Mapping zwischen natürlicher Sprache und Code über Cucumber Expressions oder reguläre Ausdrücke erfolgt. Diese Indirektion erschwert Debugging und macht Refactorings fragil: Eine Textänderung im Feature-File bricht Steps, ohne dass die IDE warnt.
Das Robot Pattern kommt mit reinen TypeScript-Klassen aus. Der Workflow-Code ist gleichzeitig Dokumentation und Implementierung — kein separates Format, das synchron gehalten werden muss.
BDD hat seinen Platz, wenn Product Owner und Tester gemeinsam an Spezifikationen arbeiten und natürliche Sprache der gemeinsame Nenner ist. Für technische Automatisierung, bei der Entwickler*innen die primäre Zielgruppe sind, ist das Robot Pattern leichtgewichtiger, typsicher und wartbarer.
Wer BDD trotzdem bevorzugt, kann es jederzeit als Schicht über den Robots aufbauen — die saubere Trennung der Robots macht genau das einfach.
Vorteile und Grenzen
Der offensichtlichste Vorteil ist die Wartbarkeit durch Isolation: UI-Änderungen betreffen nur das betroffene PageModel (BookingPage) und eventuell den zugehörigen Robot (BookingRobot). Der eigentliche Workflow und andere Robots bleiben unangetastet.
Ein Effekt, der sich fast unbemerkt einstellt, ist die Lesbarkeit. Der Workflow-Code liest sich wie eine fachliche Beschreibung. Neue Teammitglieder verstehen den Ablauf, ohne die UI-Details kennen zu müssen.
Gleichzeitig sorgt die Vererbung vom BaseRobot für Konsistenz über alle Robots hinweg. Logging, Wartezeiten, Fehlerbehandlungen — all das wird einmal definiert und wiederverwendet.
Auf der anderen Seite steht die initiale Komplexität. Für einen Ablauf mit drei Klicks ist das Robot Pattern vermutlich Overengineering. Die Abstraktion lohnt sich erst, wenn der Workflow mehr als zwei bis drei Seiten umfasst, wenn mehrere Workflows dieselben Seiten besuchen, oder wenn das Team aus mehr als einer Person besteht. Und auch mit dem Pattern bleibt die Selektor-Abhängigkeit bestehen — das Pattern eliminiert sie nicht, es kapselt sie.
Fazit
Das Layered Robot Pattern ist kein neues Framework und keine Bibliothek. Es ist eine Strukturentscheidung, die sich in drei Regeln zusammenfassen lässt: Ein PageModel pro Seite — ausschließlich Selektoren. Ein Robot pro Seite — ausschließlich fachliche Aktionen, aufbauend auf der gemeinsamen Basisklasse. Workflows rufen nur Robot-Methoden auf.
Diese Regeln stammen aus der Android-Welt, funktionieren aber in jeder UI-Technologie. Die Investition lohnt sich, sobald ein Workflow mehr als eine Seite umfasst — darunter ist der Overhead selten gerechtfertigt. Aber sobald die Komplexität wächst, zahlt sich die klare Trennung zwischen Was und Wie bei jeder UI-Änderung, jedem neuen Teammitglied und jedem Debugging-Einsatz aus.
Was uns im Projektalltag sehr geholfen hat: Playwright zeichnet auf Wunsch Videos jedes Durchlaufs auf — und genau das hat die Fehleranalyse in der Produktion am stärksten beschleunigt. Ein fehlgeschlagener Lauf lässt sich im Video auf den genauen Moment zurückverfolgen, ohne erneutes Ausführen, ohne zusätzliche Logs.
Mit den heutigen Werkzeugen — Playwright MCP und Codegen für die Selektor-Entdeckung, KI-Agents für die Code-Generierung, headed Mode und Video-Aufzeichnung für Debugging und Demos — lässt sich ein Robot-basierter Workflow in Stunden aufbauen. Und je mehr Robots im Projekt existieren, desto effektiver wird die KI-Assistenz: Das Pattern ist der strukturelle Vertrag, den der Agent braucht, um konsistenten Code zu erzeugen.
Wer ein System per Browser automatisiert — ob für Tests oder Prozessautomatisierung —, findet im Robot Pattern eine Strukturierung, die auch nach dem nächsten Redesign noch funktioniert.
Quellen
[1] Jake Wharton, „Testing Robots", Kotlin Night, San Francisco, 17. Mai 2016 — https://jakewharton.com/testing-robots/
[2] Martin Fowler, „PageObject" — https://martinfowler.com/bliki/PageObject.html
[3] Playwright Documentation, „Codegen" — https://playwright.dev/docs/codegen
[4] Playwright Documentation, „Page Object Model" — https://playwright.dev/docs/pom
[5] Playwright MCP — https://github.com/microsoft/playwright-mcp
Weitere Artikel in diesem Themenbereich
Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.
Blog-Autor*innen
Lars Jouon
IT Consultant
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.
Rebecca Jox
Fullstack Developer & 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.