
Playwright: Moderne Browser-Tests für Websites
Playwright ist ein modernes Tool für automatisierte Browser-Tests. Es hilft dabei, echte Nutzerinteraktionen im Browser zu testen: Seiten öffnen, Buttons klicken, Formulare ausfüllen, Logins prüfen oder komplette Checkout-Prozesse absichern.
Nachdem wir in unserem letzten Beitrag gezeigt haben, wie wir mit Codeception automatisierte Browser-Tests in PHP schreiben, schauen wir uns diesmal Playwright an. Playwright ist für uns besonders spannend, weil es viele Funktionen direkt mitbringt, die bei modernen End-to-End-Tests wichtig sind: automatische Wartezeiten, Tests in mehreren Browsern, parallele Ausführung, Screenshots, Videos und einen sehr hilfreichen Trace Viewer.
Wir nutzen Playwright aktuell noch nicht so lange und umfangreich wie Codeception. Dieser Beitrag ist deshalb kein Erfahrungsbericht aus vielen Jahren Projektpraxis, sondern eine fachliche Einordnung: Seit wann ist Playwright relevant? Welche Vorteile bietet es? Wie gelingt die Installation? Und welche Best Practices solltest du von Anfang an beachten?
Seit wann ist Playwright relevant?
Playwright wurde von Microsoft entwickelt und ist seit 2020 verfügbar. Die ersten 0.x-Versionen erschienen Anfang 2020, Playwright 1.0 folgte im Mai 2020. Seitdem wurde das Tool kontinuierlich weiterentwickelt und gehört heute zu den wichtigsten Werkzeugen für moderne End-to-End-Tests im Browser.
Besonders relevant wurde Playwright, weil sich Webanwendungen in den letzten Jahren stark verändert haben. Viele Websites laden Inhalte dynamisch nach, arbeiten mit JavaScript-Frameworks, komplexen Formularen, Cookie-Bannern, externen APIs und interaktiven Komponenten. Klassische Tests stoßen dabei schnell an Grenzen, wenn sie zu früh klicken, auf noch nicht geladene Elemente zugreifen oder nur einen einzelnen Browser abdecken.
Playwright setzt genau hier an: Es wurde für moderne Webanwendungen entwickelt und bringt viele Komfortfunktionen direkt mit.
Was ist Playwright?
Playwright ist ein Open-Source-Framework für Web Testing und Browser-Automation. Mit Playwright lassen sich Tests für Chromium, Firefox und WebKit mit einer einheitlichen API schreiben. Der Playwright Test Runner ist speziell für End-to-End-Tests gedacht und bringt unter anderem Browser-Isolation, Auto-Waiting und web-first Assertions mit.
Ein einfacher Playwright-Test sieht zum Beispiel so aus:
import { test, expect } from '@playwright/test';
test('Kontaktformular ist erreichbar', async ({ page }) => {
await page.goto('/kontakt');
await expect(page.getByRole('heading', { name: 'Kontakt' })).toBeVisible();
await expect(page.getByLabel('E-Mail')).toBeVisible();
});Der Test öffnet die Kontaktseite und prüft, ob die Überschrift und das E-Mail-Feld sichtbar sind. Solche Tests können lokal, in CI/CD-Prozessen oder in Container-Setups ausgeführt werden.
Welche Vorteile bietet Playwright?
Playwright wartet automatisch auf Elemente
Ein großer Vorteil von Playwright ist das automatische Warten. Bevor Playwright eine Aktion ausführt, prüft es, ob ein Element wirklich sichtbar, stabil, aktiviert und bereit für die Interaktion ist. Die Playwright-Dokumentation nennt diese Prüfungen „Actionability Checks“. Erst wenn die Bedingungen erfüllt sind, wird zum Beispiel geklickt.
Das reduziert typische Timing-Probleme. Statt überall feste Wartezeiten einzubauen, kannst du dich stärker auf echte Zustände konzentrieren:
await page.getByRole('button', { name: 'Absenden' }).click();
await expect(page.getByText('Vielen Dank')).toBeVisible();Natürlich macht Auto-Waiting Tests nicht automatisch perfekt. Wenn eine Anwendung instabil lädt, externe Dienste hängen oder ein Selektor schlecht gewählt ist, können Tests weiterhin fehlschlagen. Aber Playwright nimmt dir viele klassische Warteprobleme ab.
Playwright testet mehrere Browser
Playwright kann Tests in Chromium, Firefox und WebKit ausführen. Damit lassen sich Unterschiede zwischen Browser-Engines früh erkennen. Gerade WebKit ist interessant, weil es näher an Safari liegt und damit für iOS-/macOS-Nutzerinnen und Nutzer relevant ist.
In der Konfiguration kannst du mehrere Projekte definieren:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],
});Für viele Projekte reicht es am Anfang, nur mit Chromium zu starten. Später können Firefox und WebKit ergänzt werden, wenn die Tests stabil laufen.
Playwright bringt starke Debugging-Werkzeuge mit
Ein wichtiger Unterschied zu vielen älteren Setups ist das Debugging. Playwright bringt mit dem Trace Viewer ein Werkzeug mit, mit dem sich Testläufe nachträglich analysieren lassen. Du kannst unter anderem die Timeline, DOM-Snapshots, Aktionen, Network Requests und Screenshots betrachten.
Das ist besonders hilfreich, wenn Tests in der CI fehlschlagen, lokal aber funktionieren. Statt nur eine Fehlermeldung zu sehen, kannst du nachvollziehen, was der Browser tatsächlich gemacht hat.
In der Konfiguration lässt sich Tracing zum Beispiel so aktivieren:
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
});Damit werden Traces, Screenshots und Videos vor allem dann erzeugt, wenn sie wirklich gebraucht werden.
Playwright führt Tests parallel aus
Playwright Test kann Tests parallel ausführen. Dafür nutzt es mehrere Worker-Prozesse. Das ist besonders interessant, wenn eine Testsuite wächst und nicht mehr alle Tests nacheinander laufen sollen.
Für kleine Projekte ist das noch nicht entscheidend. Bei größeren Websites, Shops oder Webanwendungen kann Parallelisierung aber viel Zeit sparen – besonders in CI/CD-Pipelines.
Playwright hat gute Selektoren
Playwright empfiehlt nutzernahe Selektoren. Statt fragile CSS-Klassen wie .btn-primary:nth-child(2) zu verwenden, kannst du Elemente über Rollen, Labels oder sichtbaren Text auswählen:
await page.getByRole('button', { name: 'Absenden' }).click();
await page.getByLabel('E-Mail').fill('max@example.de');
await expect(page.getByText('Vielen Dank')).toBeVisible();Das hat zwei Vorteile: Die Tests lesen sich verständlicher und sie orientieren sich stärker daran, wie Nutzerinnen, Nutzer und assistive Technologien eine Seite wahrnehmen.
Playwright installieren
Playwright lässt sich in einem Node.js-Projekt sehr schnell einrichten. Die offizielle Installation läuft über:
npm init playwright@latest
Alternativ kann Playwright in einem bestehenden Projekt manuell installiert werden:
npm i -D @playwright/test npx playwright install
Die offizielle Playwright-Dokumentation nennt genau diese Installationswege.
Falls du nach der Installation den Hinweis bekommst, dass Abhängigkeiten und Bibliotheken fehlen, dann kannst du folgendes Kommando ausführen:
npx playwright@latest install-deps
Beim Setup fragt Playwright typischerweise ab, ob TypeScript oder JavaScript verwendet werden soll, wo die Tests liegen sollen und ob ein GitHub-Actions-Workflow angelegt werden soll.
Eine typische Struktur sieht danach ungefähr so aus:
playwright.config.ts tests/ example.spec.ts package.json
Playwright mit DDEV nutzen
Auch in DDEV-Projekten unterscheidet sich die Installation von Playwright grundsätzlich nicht von anderen Setups, da Playwright über Node.js installiert und ausgeführt wird. Wichtig ist vor allem, dass die Tests gegen die richtige DDEV-URL laufen.
Die Basis-URL kannst du in der playwright.config.ts hinterlegen:
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
baseURL: process.env.PLAYWRIGHT_BASE_URL || 'https://myproject.ddev.site',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
});Die Test-URL kann dann über eine .env-Variable oder über den CI-Prozess gesetzt werden:
PLAYWRIGHT_BASE_URL=https://myproject.ddev.site
Wichtig: Lokale Projekt-URLs sollten möglichst nicht fest in Git versioniert werden. Für Teams ist es sauberer, mit Umgebungsvariablen zu arbeiten.
Beispiel: Kontaktformular mit Playwright testen
Ein einfacher Test für ein Kontaktformular könnte so aussehen:
import { test, expect } from '@playwright/test';
test('Kontaktformular kann abgeschickt werden', async ({ page }) => {
await page.goto('/kontakt');
await page.getByLabel('Name').fill('Max Mustermann');
await page.getByLabel('E-Mail').fill('max@example.de');
await page.getByLabel('Nachricht').fill('Das ist eine Testnachricht.');
await page.getByRole('button', { name: 'Absenden' }).click();
await expect(page.getByText('Vielen Dank')).toBeVisible();
});Der Test ist bewusst einfach gehalten. In echten Projekten kommen oft weitere Aspekte hinzu: Pflichtfelder, Validierungsfehler, Spam-Schutz, Cookie-Banner, Ajax-Verhalten oder mehrsprachige Formularvarianten.
Playwright Tests ausführen
Alle Tests lassen sich über die Konsole starten:
npx playwright test
Ein einzelner Test kann über den Dateipfad gestartet werden:
npx playwright test tests/contact.spec.ts
Für eine sichtbare Browser-Ausführung eignet sich:
npx playwright test --headed
Der UI Mode hilft beim Entwickeln und Debuggen:
npx playwright test --ui
Den HTML-Report öffnest du mit:
npx playwright show-report
Dein Browser öffnet sich und du siehst eine Auflistung aller Tests.

Bei fehlgeschlagenen Tests kannst du in den Trace Viewer wechseln und so jeden Schritt direkt im Browser nachvollziehen.

Playwright in PhpStorm starten
Playwright-Tests lassen sich nicht nur über die Konsole ausführen, sondern auch direkt in PhpStorm starten. Das ist besonders praktisch, wenn du einzelne Tests während der Entwicklung schnell prüfen möchtest.
Voraussetzung ist, dass Node.js im Projekt korrekt eingerichtet ist und Playwright wie oben beschrieben installiert wurde.
Anschließend erkennt PhpStorm Playwright-Tests in der Regel direkt in den Testdateien. Du kannst einen Test dann über das Run-Symbol neben dem Test oder über das Kontextmenü starten.
Playwright Best Practices
Nutze nutzernahe Selektoren
Bevor du CSS-Klassen verwendest, prüfe, ob ein Element über Rolle, Label oder Text erreichbar ist:
await page.getByRole('button', { name: 'Speichern' }).click();
await page.getByLabel('E-Mail').fill('max@example.de');Das macht Tests robuster und verständlicher. Außerdem fallen Probleme mit Labels oder Buttons schneller auf.
Vermeide feste Wartezeiten
Feste Wartezeiten machen Tests langsam und oft trotzdem instabil:
await page.waitForTimeout(3000);
Besser ist es, auf sichtbare Zustände zu warten:
await expect(page.getByText('Vielen Dank')).toBeVisible();Oder auf ein bestimmtes Element:
await expect(page.locator('.success-message')).toBeVisible();Nutze Konstanten und Page Objects gezielt
Bei Playwright müssen nicht alle Selektoren als Konstanten ausgelagert werden. Oft sind semantische Locator direkt im Test gut lesbar:
await page.getByRole('button', { name: 'Absenden' }).click();
await page.getByLabel('E-Mail').fill('max@example.de');Sinnvoll sind Konstanten vor allem für URLs, erwartete Texte, Testdaten oder technische Selektoren, die mehrfach verwendet werden:
const URL_CONTACT = '/kontakt'; const SUCCESS_MESSAGE = 'Vielen Dank';
Wenn Tests größer werden, können Page Objects helfen, wiederkehrende Abläufe sauber zu kapseln. So bleibt der eigentliche Test kurz und verständlich.
Halte Tests klein und verständlich
Ein Test sollte möglichst ein klares Szenario prüfen. Statt einen riesigen Test zu schreiben, der Login, Suche, Formular, Warenkorb und Logout kombiniert, sind mehrere kleinere Tests oft besser wartbar.
Gut:
- Login funktioniert
- Kontaktformular kann abgeschickt werden
- Suchfilter zeigt passende Ergebnisse
- Checkout erreicht Bestellübersicht
Schlecht:
- Kompletter Website-Test mit allen Funktionen
Verwende Testdaten bewusst
Tests sollten nicht von zufälligen Live-Daten abhängen. Wenn ein Test nur funktioniert, solange ein bestimmter Datensatz existiert, wird er schnell instabil.
Besser ist es, stabile Testdaten zu verwenden oder Daten gezielt vor dem Test anzulegen.
Speichere Zugangsdaten nicht im Repository
Logins und Zugangsdaten gehören nicht in Git. Nutze Umgebungsvariablen:
TEST_USER=max@example.de TEST_PASS=secret
Im Test:
await page.getByLabel('E-Mail').fill(process.env.TEST_USER || '');
await page.getByLabel('Passwort').fill(process.env.TEST_PASS || '');Aktiviere Trace, Screenshots und Videos gezielt
Für lokale Tests brauchst du nicht immer Videos. Für fehlgeschlagene CI-Läufe sind sie aber sehr hilfreich.
export default defineConfig({
use: {
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
});Starte mit wenigen kritischen Tests
Gerade wenn Playwright neu eingeführt wird, sollte nicht sofort die komplette Website automatisiert werden. Sinnvoller ist ein kleiner, stabiler Einstieg:
- Kontaktformular
- Login
- Cookie-Banner
- zentrale Suche
- Checkout oder Anfrageprozess
So zeigt sich schnell, ob Setup, Selektoren, Daten und CI-Prozess funktionieren.
Playwright oder Codeception?
Wir nutzen in vielen Projekten aktuell Codeception für Browser-Tests. Das hat weiterhin gute Gründe: Codeception passt sehr gut in PHP-Projekte, Tests können in PHP geschrieben werden und das WebDriver-Modul ermöglicht Tests in echten Browsern über das W3C-WebDriver-Protokoll.
Playwright bringt dagegen einige Vorteile mit, die vor allem bei modernen Browser-Tests spannend sind:
| Thema | Codeception | Playwright |
|---|---|---|
| Sprache | PHP | TypeScript/JavaScript |
| Browser-Steuerung | WebDriver/Selenium | Playwright-eigene Browser-Automation |
| Auto-Waiting | möglich, aber stärker manuell geprägt | sehr stark integriert |
| Debugging | Screenshots, Reports, WebDriver-Logs | Trace Viewer, Screenshots, Videos, HTML-Report |
| Cross-Browser | möglich über WebDriver | Chromium, Firefox, WebKit direkt integriert |
| Parallelisierung | möglich, aber zusätzlicher Aufwand | direkt im Test Runner vorgesehen |
| Team-Fit | stark für PHP-Teams | stark für Frontend-/JS-/TS-Teams |
Für uns bedeutet das: Codeception bleibt für bestehende PHP-Projekte weiterhin sinnvoll. Playwright ist aber ein sehr spannender Kandidat für neue Projekte, frontendlastige Anwendungen oder Setups, bei denen Debugging, Parallelisierung und Cross-Browser-Tests besonders wichtig sind.
Und was ist mit Cypress?
Cypress ist ebenfalls ein bekanntes Tool für End-to-End-Tests. Es bietet gute Entwicklerwerkzeuge und setzt ebenfalls auf Mechanismen, um dynamische Anwendungen besser testbar zu machen. Die Cypress-Dokumentation beschreibt zum Beispiel Retry-ability als Kernfunktion, mit der Commands, Queries und Assertions wiederholt werden können, um Tests stabiler zu machen.
Trotzdem sehen wir Cypress für unsere aktuelle Situation nicht als ersten Kandidaten. Ein Grund ist unser PHP-Schwerpunkt. Wenn wir aus dem PHP-Umfeld heraus in ein JavaScript-/TypeScript-Testsetup wechseln, sollte der Mehrwert deutlich sein. Bei Playwright sehen wir diesen Mehrwert aktuell stärker: vor allem durch den integrierten Cross-Browser-Ansatz, den Trace Viewer, die Parallelisierung und die sehr aktive Weiterentwicklung.
Auch die npm-Download-Zahlen zeigen, dass Playwright in den letzten Jahren stark an Bedeutung gewonnen hat. Solche Zahlen sind kein vollständiger Marktanteil, weil Tools wie Selenium auch in anderen Ökosystemen stark genutzt werden. Sie zeigen aber deutlich, dass Playwright im JavaScript-/TypeScript-Umfeld aktuell sehr präsent ist.

Quelle: https://npmtrends.com/cypress-vs-playwright-vs-selenium-webdriver
Das heißt nicht, dass Cypress schlecht ist. Für viele Frontend-Teams kann Cypress sehr gut passen. Für uns wirkt Playwright im Moment aber wie der spannendere nächste Schritt.
Video: Einstieg in Playwright
In diesem Video bekommst du einen ersten Eindruck davon, wie Playwright eingerichtet wird und wie ein einfacher Browser-Test aussieht.
Dieses Video wird über eine externe Plattform (YouTube) gehostet. Das Laden bedarf der Zustimmung unserer Datenschutzbestimmungen.
Fazit: Playwright ist ein starker Kandidat für moderne Browser-Tests
Playwright ist seit 2020 relevant und hat sich seitdem zu einem der wichtigsten Tools für moderne End-to-End-Tests entwickelt. Besonders stark ist Playwright bei automatischem Warten, Cross-Browser-Tests, Debugging mit Trace Viewer, paralleler Ausführung und nutzerorientierten Selektoren.
Für uns ersetzt Playwright Codeception nicht automatisch. Codeception passt weiterhin sehr gut zu PHP-Projekten und zu Teams, die Browser-Tests im gewohnten PHP-Ökosystem schreiben möchten. Playwright ist aber ein sehr interessanter Kandidat für neue Projekte, moderne Frontends und Testsuiten, die stärker auf Debugging, Parallelisierung und Cross-Browser-Sicherheit setzen.
Auch Barrierefreiheit spielt beim Testen eine wichtige Rolle. Playwright kann durch Locator wie getByRole() oder getByLabel() dabei helfen, zugängliche Strukturen bewusster zu nutzen. Automatisierte Tests ersetzen aber keine vollständige Barrierefreiheitsprüfung. Wenn du tiefer einsteigen möchtest, lies auch unseren Beitrag zum Barrierefreiheit-Testen.
Ebenso bleibt visuelle Qualität ein wichtiger Teil der Qualitätssicherung. Wenn du Layout-Veränderungen automatisch erkennen möchtest, empfehlen wir dir zusätzlich unseren Beitrag zu BackstopJS und visuellen Regressionstests.
Wir schauen uns Playwright in den nächsten Projekten weiter an und sind gespannt, wie sich das Tool in unserem Alltag bewährt. Hast du bereits Erfahrungen mit Playwright, Codeception oder Cypress gesammelt? Schreib uns gerne in die Kommentare, welches Tool du nutzt und welche Best Practices sich bei dir bewährt haben.
- https://playwright.dev/
- https://playwright.dev/docs/intro
- https://playwright.dev/docs/actionability
- https://playwright.dev/docs/trace-viewer
- https://www.jetbrains.com/help/phpstorm/playwright.html
- https://docs.cypress.io/app/core-concepts/retry-ability
- https://npmtrends.com/cypress-vs-playwright-vs-selenium-webdriver
- https://chatgpt.com/