Wie mehrere Browser-Kontexte in Playwright gesteürt, Anwendungsfälle wie Checkout-in-neüm-Tab geprüft und Fenster miteinander synchronisiert werden
Sobald eine Anwendung bewusst einen neuen Tab öffnet, etwa für einen externen Zahlungsdienstleister wie PayPal, oder Zustand über mehrere gleichzeitig geöffnete Fenster hinweg synchron halten muss, reicht das klassische, auf ein einzelnes Fenster beschränkte E2E-Testmodell nicht mehr aus. Cross-Tab- und Multi-Window-Testing verlangt ein bewusstes, explizites Modell mehrerer, gleichzeitig aktiver Browser-Kontexte, das in Playwright deutlich natürlicher unterstützt wird als in Cypress, wo dieselbe Aufgabe historisch nur mit erheblichen Workarounds lösbar war.
Inhaltsverzeichnis
- 1. Warum Multi-Tab-Szenarien besonders schwierig zu testen sind
- 2. Mehrere Browser-Kontexte in Playwright gezielt steürn
- 3. Anwendungsfall: Checkout-in-neüm-Tab zuverlässig prüfen
- 4. Synchronisation zwischen Fenstern zuverlässig testen
- 5. Einschränkungen von Cypress bei Multi-Tab-Szenarien
- 6. Häufige Fallstricke bei Multi-Window-Tests
- 7. Best Practices für die Struktur von Multi-Window-Tests
- 8. Parallele, isolierte Nutzersitzungen mit mehreren BrowserContext-Instanzen testen
- 9. Multi-Window-Testansätze im Überblick
- 10. Zusammenfassung
- 11. FAQ
1. Warum Multi-Tab-Szenarien besonders schwierig zu testen sind
Ein einzelnes Browser-Fenster besitzt einen klar abgegrenzten, linear nachvollziehbaren Zustand: eine Seite ist geladen, ein Nutzer führt eine Aktion aus, die Seite reagiert. Sobald jedoch ein zweites Fenster oder ein zweiter Tab ins Spiel kommt, etwa weil ein Link bewusst mit `target="_blank"` geöffnet wird oder ein externer Zahlungsdienstleister in einem eigenen Fenster läuft, müssen zwei parallel existierende, aber inhaltlich voneinander abhängige Zustände gleichzeitig im Test nachvollzogen werden, was die Testlogik erheblich komplexer macht als ein rein sequenzieller Ablauf.
Diese Komplexität zeigt sich besonders deutlich bei zeitlichen Abhängigkeiten zwischen den Fenstern: Eine Aktion im zweiten Tab, etwa der Abschluss einer PayPal-Zahlung, muss zuverlässig im ersten, ursprünglichen Tab ankommen und dort eine Zustandsänderung auslösen, bevor der Test im ursprünglichen Fenster sinnvoll fortgesetzt werden kann, wobei die genaue zeitliche Reihenfolge dieser Ereignisse zwischen den Fenstern in einem realen Browser nicht immer deterministisch garantiert ist.
2. Mehrere Browser-Kontexte in Playwright gezielt steürn
Playwright modelliert einen neu geöffneten Tab oder ein neues Fenster als eigenständiges `Page`-Objekt innerhalb desselben `BrowserContext`, das über das `popup`-Event des ursprünglichen Page-Objekts zuverlässig eingefangen werden kann, sobald die Anwendung tatsächlich ein neues Fenster öffnet. Dieses saubere, objektorientierte Modell erlaubt es, beide Fenster im selben Testfall unabhängig voneinander anzusprechen, ohne dass der Test manüll zwischen unterschiedlichen Fenster-Handles umschalten muss, wie es in älteren, auf das WebDriver-Protokoll aufsetzenden Werkzeugen noch üblich war.
Für Szenarien, die zusätzlich unterschiedliche, voneinander vollständig isolierte Sitzungen benötigen, etwa das gleichzeitige Testen zweier verschiedener, gleichzeitig eingeloggter Nutzerkonten, bietet Playwright zusätzlich die Möglichkeit, mehrere unabhängige `BrowserContext`-Instanzen parallel zu erzeugen, die sich Cookies, LocalStorage und Session-Zustand grundsätzlich nicht teilen, im Gegensatz zu zwei Tabs innerhalb desselben Kontexts.
import { test, expect } from '@playwright/test';
test('PayPal-Redirect in neüm Tab schließt Checkout im Original-Tab ab', async ({ page, context }) => {
await page.goto('/checkout/payment');
const [popup] = await Promise.all([
context.waitForEvent('page'),
page.getByRole('link', { name: 'Mit PayPal bezahlen' }).click(),
]);
await popup.waitForLoadState();
await popup.getByLabel('E-Mail').fill('kunde@beispiel.de');
await popup.getByRole('button', { name: 'Anmelden und bezahlen' }).click();
await popup.waitForEvent('close');
// Zurück im ursprünglichen Tab: Checkout muss nun abgeschlossen sein
await expect(page.getByText('Bestellung erfolgreich abgeschlossen')).toBeVisible();
});
3. Anwendungsfall: Checkout-in-neüm-Tab zuverlässig prüfen
Ein besonders praxisrelevanter Anwendungsfall für ein Magento-Projekt ist der externe Zahlungs-Redirect, bei dem der eigentliche Checkout-Tab bewusst geöffnet bleibt, während ein zweiter Tab oder ein Popup-Fenster für die Authentifizierung beim Zahlungsdienstleister sorgt. Ein zuverlässiger Test muss dabei nicht nur prüfen, dass der zweite Tab korrekt geöffnet wird und die richtige URL lädt, sondern auch, dass der ursprüngliche Checkout-Tab nach Abschluss der externen Zahlung tatsächlich in den erwarteten, erfolgreichen Endzustand übergeht.
Besondere Vorsicht ist bei Zahlungsdienstleistern geboten, die statt eines echten Popups einen Redirect im selben Tab durchführen und anschließend per Weiterleitung zur Anwendung zurückkehren, da dieses Verhalten für den Test ein grundlegend anderes Muster erfordert als ein tatsächliches Zwei-Fenster-Szenario. Ein sauber geschriebener Test sollte deshalb zürst prüfen, welches der beiden Muster der jeweilige Zahlungsdienstleister tatsächlich verwendet, bevor die Teststrategie festgelegt wird, statt beide Muster unreflektiert gleich zu behandeln.
4. Synchronisation zwischen Fenstern zuverlässig testen
Über den reinen Zahlungs-Redirect hinaus verlangen viele moderne Webanwendungen, dass Zustandsänderungen in einem Tab automatisch in allen anderen, gleichzeitig geöffneten Tabs derselben Anwendung sichtbar werden, etwa wenn ein Produkt in Tab A dem Warenkorb hinzugefügt wird und die Warenkorb-Anzahl in Tab B, ohne manülles Neuladen, automatisch aktualisiert werden soll. Solche Synchronisationen basieren technisch meist auf der BroadcastChannel-API, auf gemeinsam genutztem LocalStorage mit einem Storage-Event-Listener, oder auf regelmässigem Polling gegen das Backend.
Ein zuverlässiger Test für dieses Verhalten öffnet bewusst zwei `Page`-Objekte im selben `BrowserContext`, führt die zustandsändernde Aktion gezielt im ersten Tab aus und wartet anschließend im zweiten Tab explizit auf die erwartete, asynchron eintreffende Änderung, statt eine feste Wartezeit zu verwenden, die je nach tatsächlicher Synchronisationsgeschwindigkeit entweder unnötig lange daürt oder gelegentlich zu kurz bemessen ist und den Test dadurch instabil macht.
test('Warenkorb-Änderung synchronisiert sich zwischen zwei Tabs', async ({ context }) => {
const tabA = await context.newPage();
const tabB = await context.newPage();
await tabA.goto('/produkt/beispiel-artikel');
await tabB.goto('/checkout/cart');
await tabA.getByRole('button', { name: 'In den Warenkorb' }).click();
// explizit auf die asynchrone Synchronisation warten, keine feste Wartezeit
await expect(tabB.getByTestId('cart-count')).toHaveText('1', { timeout: 5000 });
});
5. Einschränkungen von Cypress bei Multi-Tab-Szenarien
Cypress verzichtet aus architektonischen Gründen bewusst auf natives Multi-Tab-Testing, da das gesamte Framework auf der Grundannahme aufbaut, dass ein Test genau ein Fenster kontrolliert, und ein von der Anwendung ausgelöster Tab-Wechsel dieses Grundmodell unterlaufen würde. Wird versucht, `target="_blank"` innerhalb eines Cypress-Tests zu öffnen, blockiert Cypress dies standardmässig oder öffnet die Zielseite stattdessen innerhalb desselben Tabs, was für echte Multi-Window-Assertions ungeeignet ist.
Die gängige Workaround-Strategie in Cypress besteht darin, den externen Zahlungsdienstleister für Testzwecke gezielt zu mocken oder zu stubben, statt den tatsächlichen Tab-Wechsel nachzuvollziehen, wodurch der Test zwar weiterhin innerhalb der architektonischen Grenzen von Cypress funktioniert, aber die tatsächliche Multi-Window-Interaktion nicht mehr wirklich end-to-end prüft. Für Projekte, bei denen echtes Cross-Tab-Verhalten eine zentrale, geschäftskritische Rolle spielt, ist Playwright dieser Einschränkung wegen meist die deutlich besser geeignete Wahl.
6. Häufige Fallstricke bei Multi-Window-Tests
Ein häufiger Fehler ist, nach dem Öffnen eines neuen Tabs sofort mit Interaktionen fortzufahren, ohne explizit auf dessen vollständiges Laden zu warten, etwa über `waitForLoadState()`, wodurch der Test gelegentlich, aber nicht zuverlässig reproduzierbar fehlschlägt, je nachdem wie schnell die externe Seite im jeweiligen Testlauf tatsächlich antwortet.
Ein zweiter, ebenso verbreiteter Fallstrick ist ein versehentlicher, falscher Fokus auf das falsche Fenster, wenn ein Test mehrere `Page`-Objekte gleichzeitig verwaltet, aber eine Interaktion versehentlich gegen das ursprüngliche statt das neu geöffnete Fenster ausführt, was zu verwirrenden, schwer nachvollziehbaren Fehlermeldungen führt, da die aufgerufene Methode formal existiert, aber im falschen Kontext ins Leere läuft. Ein sprechend benannter Variablenname für jedes Page-Objekt, etwa `checkoutTab` und `paymentPopup` statt generischer Namen wie `page2`, reduziert dieses Risiko bereits erheblich.
7. Best Practices für die Struktur von Multi-Window-Tests
Ein gut strukturierter Multi-Window-Test sollte jedes beteiligte Fenster von Beginn an explizit und sprechend benannt referenzieren, alle asynchronen Warteoperationen gezielt auf konkrete, erwartete Zustandsänderungen statt auf feste Zeitspannen ausrichten, und den Zeitpunkt des Fensterwechsels klar durch einen Kommentar oder eine eigene Hilfsfunktion im Testcode kennzeichnen, damit spätere Leserinnen und Leser des Tests sofort erkennen, an welcher Stelle die Interaktion zwischen den Fenstern wechselt.
Für wiederkehrende Multi-Window-Muster, etwa den PayPal-Redirect-Flow, lohnt sich zudem eine gemeinsame, wiederverwendbare Hilfsfunktion, die das Öffnen des Popups, das Ausfüllen der externen Formularfelder und das Warten auf den Fensterabschluss kapselt, statt diesen mehrzeiligen Ablauf in jedem einzelnen Testfall, der eine Zahlung über diesen Anbieter durchführt, redundant zu wiederholen.
8. Parallele, isolierte Nutzersitzungen mit mehreren BrowserContext-Instanzen testen
Neben dem Testen mehrerer Tabs innerhalb derselben Sitzung verlangen manche Szenarien zwei vollständig unabhängige, gleichzeitig aktive Nutzersitzungen, etwa um zu prüfen, dass ein Admin-Nutzer in einem Backend-Fenster eine Bestellung storniert, während derselbe Kunde in einem zweiten, davon vollständig isolierten Fenster gleichzeitig den Bestellstatus im Frontend einsieht. Für dieses Szenario reicht ein einzelner BrowserContext nicht aus, da beide Fenster sonst dieselben Cookies und denselben Session-Zustand teilen würden.
Playwright löst dies durch das Erzeugen zweier unabhängiger BrowserContext-Instanzen innerhalb desselben Testlaufs, wobei jede Instanz ihre eigenen Cookies, ihren eigenen LocalStorage und ihre eigene Session-Identität besitzt, wodurch sich echte Zwei-Nutzer-Szenarien testen lassen, ohne zwei komplett getrennte Testläufe oder gar zwei separate Browser-Installationen betreiben zu müssen.
test('Admin storniert Bestellung, Kunde sieht Statusänderung live', async ({ browser }) => {
const adminContext = await browser.newContext({ storageState: 'admin-session.json' });
const kundenContext = await browser.newContext({ storageState: 'kunden-session.json' });
const adminPage = await adminContext.newPage();
const kundenPage = await kundenContext.newPage();
await kundenPage.goto('/sales/order/view/order_id/1001');
await adminPage.goto('/admin/sales/order/view/order_id/1001');
await adminPage.getByRole('button', { name: 'Bestellung stornieren' }).click();
await kundenPage.reload();
await expect(kundenPage.getByText('Storniert')).toBeVisible();
await adminContext.close();
await kundenContext.close();
});
9. Multi-Window-Testansätze im Überblick
Die folgende Tabelle vergleicht die vorgestellten Ansätze für Cross-Tab- und Multi-Window-Testing.
| Ansatz | Geeignet für | Einschränkung |
|---|---|---|
| Playwright BrowserContext popup-Event | Echte Multi-Tab-Interaktionen | Erfordert sauberes Event-Handling |
| Mehrere BrowserContext-Instanzen | Parallele, isolierte Nutzersitzungen | Höherer Ressourcenverbrauch |
| Cypress mit Mocking des externen Tabs | Cypress-Projekte ohne Playwright | Kein echtes End-to-End-Multi-Window |
| BroadcastChannel-Synchronisationstest | Cross-Tab-Zustandsabgleich | Explizites Warten statt fester Zeitspanne nötig |
Mironsoft
E2E-Teststrategie, CI-Integration und stabile Testsuiten
Testsuiten, die Bugs finden statt nur rot zu blinken?
Wir prüfen bestehende E2E-Testsuiten auf Flakiness, fehlende Testisolation und ineffiziente CI-Laufzeiten und bauen daraus eine Teststrategie, die tatsächlich Vertrauen schafft statt nur Haken zu setzen.
Test-Audit
Flaky Tests, Testpyramide und Coverage-Lücken systematisch aufdecken.
CI-Optimierung
Parallele Ausführung, Retry-Strategien und schnelle Feedback-Zyklen aufbauen.
Cypress/Playwright-Setup
Robuste E2E-Suiten für Magento-Frontends von Grund auf einrichten.
10. Zusammenfassung
Cross-Tab-Testing: Das Wichtigste auf einen Blick
Kernidee
Playwright modelliert neue Tabs als eigenständige Page-Objekte innerhalb desselben BrowserContext.
Wichtigster Anwendungsfall
Externe Zahlungs-Redirects wie PayPal müssen zuverlässig in den ursprünglichen Checkout-Tab zurückwirken.
Hauptfallstrick
Fehlendes explizites Warten auf Fensterladen oder Synchronisation macht Tests instabil.
Cypress-Grenze
Cypress unterstützt echtes Multi-Tab-Testing architektonisch nicht, nur Mocking als Workaround.