In Teil eins und zwei unserer Serie haben wir lohnenswerte Features wie automatische Waits, Locators und Reporting in der Interaktion der beiden Tools als absolut unproblematisch bewerten können. Auch beim essenziellen Thema Debugging, sowie bei Hooks und Tags beobachten wir eine zufriedenstellende Teamarbeit beider Werkzeuge.

Jetzt wirds brenzlig

Aber nicht überall verläuft die Zusammenarbeit derart harmonisch. Widmen wir uns nun den Knackpunkten unseres Settings und werfen einen Blick genau dorthin, wo die Teamfähigkeit auf eine harte Probe gestellt wird.

Timeout: global

Automatisch setzt Playwright ein Default-Timeout für Aktionen wie .click(), .fill(), .clear() auf 30 Sekunden. Dieser kann individuell an verschiedenen Stellen oder auch global in der playwright.config.ts verändert werden. Da unser Cucumber Runner die Playwright-Config aber nicht ansteuert, setzen wir stattdessen für unseren Cucumber Runner ein eigenes Default-Timeout global von 60 Sekunden, und zwar dort, wo auch unsere Hooks leben:

e2e/src/support/common-steps.ts
setDefaultTimeout(60 * 1000);

Individuell können wir dieses Cucumber-Timeout z.B. auch in den Steps an sich anpassen. So können wir zum Beispiel mit dem timeout-Attribut das Cucumber-Timeout für diesen einen Step von 60 Sekunden auf 5 Sekunden herunterdrehen.

e2e/src/steps/sample.steps.ts
Then('the sample reveals the box of information', {timeout: 5000},async function () {...}

Wo liegt also das Problem? Auch wenn wir ein Cucumber-Timeout global oder in einzelnen Steps definieren und der Playwright Runner nicht genutzt wird, gilt global für alle Aktionen von Playwright weiterhin das Default-Timeout von 30 Sekunden. Dieses können wir global nicht verändern oder sogar ganz ausstellen, da der Ort für solche Änderungen, die playwright.config.ts, schlichtweg nicht angesteuert wird. Das heißt für uns, dass einerseits das von Playwright beachtete Default-Timeout nicht änderbar ist, und andererseits alle individuell eingestellten Timeouts von Cucumber in unserem Setup nur greifen, wenn die gesetzte Zeit kleiner als der Default-Playwright-Timeout ist. Setze ich also meinen Cucumber-Timeout des Steps auf beispielsweise 40000 ms (also 10 Sekunden mehr als das Playwright-Default-Timeout), so bricht der Test nach 30 Sekunden trotzdem durch das Default-Playwright-Timeout ab.

Timeout: individuell

Auch wenn es global keine Lösung für das Playwright-Default-Timeout gibt, existiert ein kleiner Lichtblick: Wir haben die Möglichkeit, zumindest individuelle Timeouts für einzelne Aktionen einzustellen – die dann auch das von Playwright gesetzte Default-Timeout überschreiben. Möchte ich also beispielsweise ein .click() auf ein Element ausführen, was erfahrungsgemäß eine längere Zeit zum Laden benötigt, so kann ich in diesem speziellen Fall ein individuelles Timeout direkt beim Aufruf dieser einzelnen Aktion setzen:

await page.getByText("Suchen").click({timeout: 40000});

Ein ähnliches Verhalten beobachten wir beim Timeout für die Assertion Library expect. Hierfür hat Playwright ein Default-Timeout von nur 5000 ms festgelegt, global änderbar nur in der playwright.config.ts. Dieses lässt sich wieder einfach mit einem Cucumber-Timeout verkürzen, nicht aber verlängern. Aber auch hier haben wir die Möglichkeit, das Playwright-Default-Timeout individuell für eine bestimmte, einzelne expect-Aktion folgendermaßen zu verkürzen oder sogar zu verlängern:

await expect(page.getByTestId('testid'))
.toBeVisible({timeout: 10000});

Individuell ist das zwar für spezielle Fälle eine gute Lösung, dennoch fehlt uns eine einfache Handhabung aller Timeouts an einem einzigen Ort.

Soft Assertions

Bleiben wir noch einen Moment bei den expect-Assertions. Playwright bietet uns diese auch als softAssertion an. Bricht ein Test normalerweise sofort, wenn die Erwartung einer Assertion nicht erfüllt wird, zeigen softAssertions dies erst einmal nur an, lassen aber die nachfolgenden Steps noch weiterlaufen. So kann man beispielsweise mehrere solcher Assertions hintereinander laufen zu lassen. Die Nutzung sieht bei Playwright wie folgt aus:

await expect.soft(page.getByTestId('status')).toHaveText('Success');

Somit bricht der Test an dieser Stelle nicht ab, sondern meldet uns lediglich eine Fehlermeldung. Dies kann bei mehreren gleichberechtigten Checks durchaus die Anzahl an Tests reduzieren. Leider sind die softAssertions aber nur mit dem Playwright Runner nutzbar, sodass wir diese in unserem Setup nicht benutzen können. Ein einfacher Ersatz mit Cucumber ist ebenfalls nicht möglich. Wenn gewünscht, könnte natürlich eine weitere softAssertion Library eingebunden werden, die dann diese Funktion übernimmt.

Snapshots

Zuletzt werfen wir noch einen Blick auf ein visuelles Detail. Playwright bietet einen Snapshot-Match an, das heißt, es werden zwei Momentaufnahmen, wie Fotografien, miteinander verglichen. Dies ermöglicht es, Seiten ohne veränderliche Inhalte schnell und mit wenig Code-Aufwand auf ihre Beständigkeit zu überprüfen. Playwright stellt uns zwei Hilfsmethoden zur Verfügung. Bei der ersten Variante

await expect(page).toHaveScreenshot();

wird im ersten Testdurchlauf automatisch ein Ordner mit dem passenden Snapshot erstellt. Beim wiederholten Aufrufen des Tests wird ein neuer Snapshot mit dem bereits gespeicherten verglichen.

Mit der zweiten Variante

await expect(value).toMatchSnapshot(snapshotName);

ist es möglich, einen speziellen Screenshot, aber auch Werte oder Texte mit einer definierten Referenz zu vergleichen.

Für beide Methoden ist allerdings eine Integration mit dem Playwright Test Runner erforderlich, was zur Folge hat, dass dieser Vergleich mit Hilfe des Cucumber Runners nicht durchgeführt werden kann. Ein visueller Vergleich seitens Cucumber existiert nicht. Der Test Automation Engineer mit seinem geschulten Blick muss also weiterhin diese Aufgabe übernehmen, oder alternativ nach einem zusätzlichen Hilfstool suchen.

Fazit

In den drei Teilen unserer Artikelserie haben wir das Zusammenspiel zwischen dem BDD-Framework Cucumber und dem Automatisierungstool Playwright im Detail und auf unterschiedlichen Stufen untersucht. Abschließend können wir sagen, dass sich die beiden Tools grundsätzlich gut miteinander kombinieren lassen. Die Stärken der jeweiligen Tools werden nicht beschnitten. Im Gegenteil profitieren wir sowohl von Cucumbers User-zentriertem Ansatz, der hervorragenden Verständlichkeit der zu testenden Anforderungen und dem anschaulichen Reporting, als auch von den technischen Raffinessen, der einfachen Bedienbarkeit und transparenten Analyseoptionen von Playwright. Dafür nehmen wir gerne in Kauf, dass wir uns teilweise für eine Variante entscheiden oder zusätzliche Konfigurationen vornehmen müssen. Ein Wermutstropfen um Timeouts, visuelle Vergleiche und soft Assertions bleibt zwar, dennoch ist das Zusammenspiel beider Tools eine geeignete Lösung, Akzeptanztests effizient und schnell durchzuführen.