Locator Assertions vs. Generic Assertions in Playwright

Playwright kennt zwei Arten von Assertions: Generic Assertions und Locator Assertions. Sie sehen sich auf den ersten Blick zum Verwechseln ähnlich, verhalten sich aber grundlegend anders – und dieser Unterschied entscheidet oft darüber, ob ein Test stabil läuft oder zufällig scheitert.

In dieser Woche möchte ich dir den Unterschied an einem Beispiel zeigen, und auch dafür habe ich wieder ein eigenes Beispiel in meinem Testlab vorbereitet, siehe Abschnitt 6.

Vorbereitung

Als Testobjekt dient die folgende kleine Komponente aus dem Testlab. Sie enthält eine feste Überschrift und zwei Buttons, die eine Artikelliste nachladen – ähnlich wie eine Seite, die ihre Inhalte von einer API holt. Nach dem Klick erscheint zunächst kurz der Text „Lade Artikel …”, und erst danach die eigentliche Liste:

Die beiden Buttons unterscheiden sich nur in der Ladezeit:

  • Artikel laden: Die Liste erscheint nach etwa einer Sekunde
  • Artikel langsam laden: Die Liste erscheint erst nach etwa sechs Sekunden

Den zweiten Button brauchen wir erst am Ende, um zu zeigen, wie lange Playwright eigentlich wartet.

Die zwei Arten von Assertions

Der Unterschied lässt sich in zwei Sätzen zusammenfassen:

  • Generic Assertion: Man übergibt expect() einen Wert, der bereits vorliegt, und vergleicht ihn mit dem erwarteten Ergebnis. Es gibt keine Wartezeit, und es wird kein await vor expect benötigt.
  • Locator Assertion: Man übergibt expect() einen Locator. Playwright fragt das Element selbstständig ab und wartet, bis der erwartete Zustand eintritt. Deshalb ist hier ein await nötig.

Der Unterschied steckt also nicht in expect selbst, sondern in der Methode dahinter: toEqual(), toBe()oder toContain() sind Generic Assertions, toHaveText() oder toContainText() sind Locator Assertions.

Beispiel 1: Ein statischer Text

Zunächst prüfen wir die feste Überschrift der Komponente. Dafür legen wir einen Locator an:

Variante mit Generic Assertion: Zuerst wird der Text aus dem Element ausgelesen, anschließend wird der ausgelesene Wert verglichen:

Variante mit Locator Assertion: Hier übergeben wir direkt den Locator und prüfen mit toHaveText:

Beide Tests laufen durch. Die Locator Assertion ist dabei kompakter: eine Zeile statt zwei.

Wie erkennt man, welche Art man gerade verwendet? In Visual Studio Code genügt es, mit der Maus über die Methode nach expect zu fahren. Der Tooltip zeigt an, ob es sich um eine generic assertion oder eine locator assertion handelt.

Beispiel 2: Dynamisch geladene Inhalte

Bei statischem Text sehen wir keinen Unterschied. Interessant wird es bei Inhalten, die erst nachgeladen werden. Wir klicken auf „Artikel laden” und prüfen, ob der Artikel „Flaky Tests vermeiden” in der Liste auftaucht.

Variante mit Generic Assertion:

Dieser Test schlägt fehl – und die Fehlermeldung ist auf den ersten Blick überraschend:

Woher kommt der Text „Lade Artikel …”? Das ist der Zustand der Seite direkt nach dem Klick. textContent() wartet zwar darauf, dass das Element existiert, aber nicht darauf, dass es einen bestimmten Inhalt hat. Es liefert einfach den Text, der im Moment des Aufrufs auf der Seite steht. Die Liste wird erst eine Sekunde später geladen – da ist die Prüfung längst gelaufen und fehlgeschlagen.

Variante mit Locator Assertion:

Dieser Test besteht.

Hier fragt Playwright das Element immer wieder ab, bis der erwartete Text erscheint. Die Liste wird nach einer Sekunde geladen, die Assertion wartet geduldig – und besteht.

Genau darin liegt der zweite große Vorteil der Locator Assertions neben der kompakteren Schreibweise: Sie warten automatisch auf den erwarteten Zustand und machen Tests dadurch deutlich stabiler gegenüber Ladezeiten.

Wie lange wartet eine Locator Assertion?

Standardmäßig fünf Sekunden. Das Zeitlimit gilt speziell für Assertions und ist unabhängig von den übrigen Timeouts. Tritt der erwartete Zustand innerhalb dieser Zeit nicht ein, schlägt der Test fehl.

Das lässt sich mit dem zweiten Button im Testlab ausprobieren, dessen Liste erst nach zehn Sekunden erscheint:

Der Test scheitert nach fünf Sekunden mit einer Timeout-Meldung, denn die Liste braucht einen Moment länger als die Assertion zu warten bereit ist.

Für einzelne Assertions lässt sich das Zeitlimit direkt anpassen:

Jetzt wartet Playwright bis zu elf Sekunden, und der Test besteht.

Soll das Limit für alle Assertions im Projekt gelten, kann es in der playwright.config.js übrigens gesetzt werden, mit:

expect: {
  timeout: 11000,
},

Wann sind Generic Assertions trotzdem sinnvoll?

Generic Assertions sind nicht „falsch”. Sie passen immer dann, wenn der Wert bereits feststeht und nichts mehr nachgeladen werden muss, zum Beispiel bei:

  • dem Ergebnis einer Berechnung oder einer eigenen Hilfsfunktion
  • bereits ausgelesenen Daten, etwa der Antwort eines API-Aufrufs
  • Werten aus Testdaten oder Konfigurationsdateien

Sobald die Prüfung aber das ansieht, was gerade im Browser angezeigt wird, sind Locator Assertions die bessere Wahl.

Hinweis: Wenn du mehr über Playwright Assertions erfahren willst, empfehle ich Dir diesen Beitrag.

Fazit

Der Unterschied zwischen den beiden Assertion-Arten ist klein in der Schreibweise, aber groß in der Wirkung:

  • Generic Assertions vergleichen einen Wert, der schon vorliegt, und warten nicht.
  • Locator Assertions fragen das Element ab, warten bis zum Timeout auf den erwarteten Zustand und brauchen ein await.

Für alles, was auf einer Webseite sichtbar ist und sich durch Ladezeiten verändern kann, gilt deshalb als Faustregel: Locator Assertions verwenden. Sie sind kompakter und machen Tests deutlich stabiler. Und nicht vergessen: Ohne await wartet der Test nicht auf die Prüfung, und die Assertion kann ungeprüft durchrutschen.

Weiterführende Links

Über mich

Dieser Beitrag wurde veröffentlicht .