Deutsch
  • test
  • e2e test
  • integrationstest
  • entwicklung
  • produktivität
  • jest
  • puppeteer

Ein schneller Leitfaden zum Schreiben von End-to-End-Tests mit jest-puppeteer

Dieser Artikel bietet einen schnellen Leitfaden zum effizienten Schreiben von End-to-End-Tests mit jest-puppeteer, wobei der Fokus auf dem Setup-Prozess, häufig verwendeten APIs und praktischen Test-Szenarien anhand eines simplen To-do-App-Beispiels liegt.

Yijun
Yijun
Developer

Als Teil unseres Engagements für die Qualität von Logto und kontinuierliche Verbesserungen setzen wir jest-puppeteer für automatisierte End-to-End-Tests ein. Dadurch können wir die Entwicklung von Logto ohne Unterbrechungen schnell vorantreiben.

In diesem Artikel teilen wir unsere Erfahrungen mit dem Schreiben effizienter jest-puppeteer Testskripts anhand eines simplen To-Do App Beispiels. Unser Ziel ist es, Ihnen zu helfen, schnell mit dem Schreiben von jest-puppeteer Testcode für Ihre eigenen Projekte zu beginnen.

Einführung in End-to-End-Tests mit jest-puppeteer

End-to-End-Tests sind eine Möglichkeit, sicherzustellen, dass Ihre Anwendung aus Sicht des Benutzers korrekt funktioniert. Um dies zu erreichen, nutzen wir zwei wesentliche Werkzeuge: Jest und Puppeteer.

Jest ist ein beliebtes JavaScript-Test-Framework, das eine benutzerfreundliche API zum Schreiben von Tests und Assertions bietet. Es wird häufig für Unit- und Integrationstests verwendet.

Puppeteer ist eine von dem Chrome-Team entwickelte Node.js-Bibliothek, die eine High-Level-API für die Steuerung von Headless-Chrome- oder Chromium-Browsern bietet. Dies macht es zu einer idealen Wahl für die Automatisierung von Browserinteraktionen in End-to-End-Tests.

jest-puppeteer ist ein Jest-Prerender, der End-to-End-Tests mit Puppeteer ermöglicht. Es bietet eine unkomplizierte API zum Starten neuer Browserinstanzen und zur Interaktion mit Webseiten über diese.

Nun, da Sie ein grundlegendes Verständnis der wesentlichen Werkzeuge haben, vertiefen wir uns in das Einrichten Ihrer Testumgebung.

Einrichten Ihrer Testumgebung

Das Einrichten Ihrer Testumgebung für End-to-End-Tests mit jest-puppeteer ist ein einfacher Prozess, der aus drei Hauptschritten besteht:

  1. Installieren Sie Abhängigkeiten

Öffnen Sie in Ihrem Projekt (oder erstellen Sie ein neues Projekt) das Terminal und führen Sie aus:

Gehen Sie dann zu den node_modules/puppeteer und installieren Sie Chromium (das für Puppeteer benötigt wird):

  1. Konfigurieren Sie Jest

Als nächstes müssen Sie Jest so konfigurieren, dass es nahtlos mit Puppeteer zusammenarbeitet.

Erstellen Sie eine Jest-Konfigurationsdatei (z. B. jest.config.js) im Stammverzeichnis Ihres Projekts, falls Sie noch keine haben. Geben Sie in dieser Konfigurationsdatei jest-puppeteer als Voreinstellung an:

Sie können bei Bedarf auch andere Jest-Einstellungen in dieser Datei anpassen. Weitere Informationen zur Anpassung von Jest-Konfigurationen finden Sie in der Jest-Konfiguration.

  1. Schreiben Sie Ihre Tests

Erstellen Sie Testdateien in Ihrem Projekt, üblicherweise mit der Erweiterung .test.js. Jest wird diese Testdateien automatisch entdecken und ausführen.

Hier ist ein Beispiel aus dem Jest-Doc:

Führen Sie dann den Befehl aus, um den Test zu starten:

Wenn Sie diesen drei Schritten folgen, haben Sie eine gut konfigurierte Testumgebung für die Durchführung von End-to-End-Tests mit jest-puppeteer.

Bitte beachten Sie jedoch, dass dies nur ein einfaches Beispiel ist. Für detailliertere Informationen zur Umgebungskonfiguration, verweisen wir auf die entsprechende Dokumentation:

Häufig verwendete APIs

In den folgenden Schritten werden wir uns auf APIs verlassen, die von Jest, Puppeteer und jest-puppeteer bereitgestellt werden, um uns bei unseren Tests zu unterstützen.

Jest bietet hauptsächlich APIs zum Organisieren von Tests und zum Behaupten von erwarteten Ergebnissen. Sie können die spezifischen Details in der Dokumentation nachlesen.

Die APIs von Puppeteer sind hauptsächlich zur Interaktion mit Browsern entwickelt worden, und ihre Unterstützung für Tests ist möglicherweise nicht so einfach. Sie können die Puppeteer-Dokumentation zu Rate ziehen, um die Funktionalitäten zu verstehen, die sie bietet. In unseren anschließenden Testbeispielen werden wir einige gängige Anwendungsfälle behandeln.

Da die APIs von Puppeteer ursprünglich nicht für Tests konzipiert waren, kann das Schreiben von Tests damit herausfordernd sein. Um den Prozess des Schreibens von Puppeteer-Tests zu vereinfachen, beinhaltet jest-puppeteer eine eingebettete Bibliothek namens expect-puppeteer. Sie bietet eine Reihe von knappen und benutzerfreundlichen APIs. Die Bibliothek wird in ihrer Dokumentation detailliert vorgestellt, die verschiedene hilfreiche Features einführt, wie in den folgenden Beispielen gezeigt:

In den folgenden Beispielen kombinieren wir die APIs, die von diesen Bibliotheken bereitgestellt werden, um unsere Testszenarien zu vervollständigen.

Nun ist es an der Zeit, zu lernen, wie man Testcode mit unserer simplen To-do-App schreibt.

Die einfache To-do-App

Angenommen, wir haben eine einfache To-do-App, die unter http://localhost:3000 läuft, der Haupt-HTML-Code für diese App lautet wie folgt:

Bei der Durchführung von End-to-End-Tests streben wir an, die folgenden Szenarien abzudecken:

  1. Wenn wir auf die URL der App zugreifen, sollten die App und ihre Daten korrekt laden.
  2. Der Prüfknopf des Elements sollte anklickbar sein.
  3. Das Anklicken eines externen Links innerhalb der Elementnotizen sollte den Link in einem neuen Tab öffnen.
  4. Es sollte möglich sein, über das Formular ein Element hinzuzufügen.

Später werden wir Testcode schreiben, um diese Szenarien zu validieren.

Erwarte, dass die App und ihre Daten geladen wurden

Wir gehen davon aus, dass die App erfolgreich geladen hat, wenn die folgenden Bedingungen erfüllt sind:

  1. Ein Element mit der ID "app" sollte auf der Seite existieren, nachdem auf die URL der App zugegriffen wurde.
  2. Die Daten innerhalb der App sollten korrekt gerendert werden.

Daher haben wir den folgenden Testcode geschrieben:

In dem Code:

  • page.goto entspricht dem Eingeben von "http://localhost:3000" im Browser, was es Ihnen ermöglicht, zu jeder URL zu navigieren.
  • page.waitForSelector wird verwendet, um auf ein spezifisches CSS-Selektor zu warten, das ein bestimmtes Element entspricht, mit einer standardmäßigen Wartezeit von 30 Sekunden.
  • expect(page).toMatchElement stammt aus der expect-puppeteer-Bibliothek, Es ist ähnlich wie page.waitForSelector, unterstützt aber auch die Übereinstimmung des Textes innerhalb eines Elements. Darüber hinaus beträgt die Standard-Zeitüberschreitung für toMatchElement nur 500ms.

Auf den ersten Blick mag es perfekt erscheinen, aber beim Ausführen dieses Tests und beim Bereitstellen in einer CI-Umgebung scheitert es gelegentlich nach mehreren Ausführungen. Die Fehlermeldung deutet darauf hin:

Basierend auf der Fehlerinformation und der Tatsache, dass dieser Test die meiste Zeit erfolgreich ist, können wir schlussfolgern, dass die von der App angeforderten Daten möglicherweise nicht immer innerhalb der ersten 500ms nach dem Laden der App zurückkehren. Daher möchten wir auf das Laden der Daten warten, bevor wir die Behauptung aufstellen.

Üblicherweise gibt es zwei gängige Ansätze, um dies zu erreichen:

  1. Erhöhen Sie die Wartezeit für die Behauptung

Aus der Fehlermeldung können wir entnehmen, dass die standardmäßige Wartezeit für toMatchElement auf 500ms festgelegt ist. Wir können die Wartezeit erhöhen, indem wir die timeout-Option der Funktion hinzufügen, wie in diesem Beispiel:

Dieser Ansatz kann das Auftreten von fehlgeschlagenen Tests bis zu einem gewissen Grad reduzieren, löst das Problem aber nicht vollständig, da wir nicht genau wissen, wie viel Zeit für das Abrufen der Daten benötigt wird.

Daher verwenden wir diesen Ansatz nur, wenn wir uns über die erforderliche Wartezeit sicher sind, wie in Szenarien wie "Ein Tooltip erscheint, nachdem man über ein Element für mehr als 2 Sekunden geschwebt hat.”

  1. Warten Sie auf den Abschluss der Netzwerkanfrage, bevor Sie eine Behauptung aufstellen

Dies ist der richtige Ansatz. Obwohl wir möglicherweise nicht wissen, wie lang die Datenanfrage dauern wird, ist es immer eine sichere Wahl, auf das Beenden der Netzwerkanfrage zu warten. An diesem Punkt können wir page.waitForNavigation({ waitUntil: 'networkidle0' }) verwenden, um auf das Beenden der Netzwerkanfragen zu warten:

So können wir, bevor wir die Behauptung für die App und ihre geladenen Daten durchführen, sicherstellen, dass unsere Netzwerkanfragen bereits abgeschlossen sind. Dies gewährleistet, dass der Test konsequent die richtigen Ergebnisse liefert.

Erwarte, dass ein spezieller Button angeklickt wird

Als nächstes testen wir die Funktion des Anklickens des Prüfknopfes innerhalb eines Elements.

In der Beispiel-App haben wir festgestellt, dass alle Elemente dieselbe Struktur teilen. Ihre Prüfknöpfe haben den CSS-Selektor li[class$=item] > button, und der Text des Knopfes ist immer "Prüfen". Das bedeutet, dass wir nicht direkt spezifizieren können, welchen Prüfknopf des Elements wir anklicken sollen. Daher benötigen wir eine neue Lösung.

Angenommen, wir möchten den Prüfknopf des Elements "Logto start-Dokumentation lesen" anklicken. Wir können dies in zwei Schritte unterteilen:

  1. Zunächst eine Referenz zu diesem speziellen Element erhalten.
  2. Dann klicken Sie auf den Prüfknopf, der sich innerhalb dieses Elements befindet.

Wie im Code gezeigt, verwenden wir die Funktion toMatchElement, um das Element mit dem itemName auf "Logto start-Dokumentation lesen" abzugleichen. Dann verwenden wir die readDocItem Referenz, um den Knopf mit dem Textinhalt 'Prüfen' unterhalb davon zu klicken.

Es ist wichtig zu beachten, dass bei der Beschaffung der readDocItem, der verwendete CSS-Selektor li[class$=item]:has(div[class$=itemName]) ist. Dieser Selektor passt zum Wurzelelement li des Elements, nicht zum itemName darin, denn wir beabsichtigen, später den button unter dem li-Tag anzuklicken.

Die Verwendung von expect(readDocItem).toClick ähnelt toMatchElement. Im Beispielcode geben wir { text: 'Prüfen' } weiter, um den textContent des Knopfes weiter abzugleichen. Je nach Bedarf können Sie jedoch wählen, ob Sie den Textinhalt des Knopfes abgleichen wollen oder nicht.

Als nächstes wollen wir testen, ob wir einen externen Link in einem neuen Tab öffnen können, wenn wir darauf innerhalb der Elementnotizen klicken.

In der Beispiel-App haben wir festgestellt, dass das Element "Logto start-Dokumentation lesen" einen externen Link zur Logto-Dokumentation innerhalb seiner Notizen hat. Hier ist unser Testcode:

In dem Code nutzen wir toClick um auf den Link innerhalb der itemNotes zu klicken.

Anschließend verwenden wir browser.waitForTarget, um einen neu geöffneten Tab mit der URL "https://docs.logto.io/docs/tutorials/get-started." zu erfassen.

Nachdem wir den Tab erhalten haben, verwenden wir target.page(), um eine Instanz der Logto doc Seite zu bekommen und weiter zu überprüfen, ob die Seite geladen wurde.

Vergessen Sie nicht, die neu geöffnete Seite nach Beendigung unseres Tests zu schließen.

Erwarte, dass ein Element aus dem Formular erstellt wird

Jetzt wollen wir die Funktion des Hinzufügens eines Elements testen.

Wir müssen den Namen des Elements und die Notizen des Elements in das Formular eintragen, auf den Button "Hinzufügen" klicken und prüfen, ob der von uns hinzugefügte Inhalt in der Liste erscheint:

Sie werden bemerken, dass wir die Funktion expect(page).toFill(inputSelector, content) verwenden, um den Formularinhalt auszufüllen. Diese Funktion ersetzt alle Inhalte in der Eingabe durch den content.

Wenn Sie einige Zeichen zur Eingabe hinzufügen möchten, ohne den vorhandenen Inhalt zu ersetzen, können Sie page.type(selector, content) verwenden, um den gewünschten Inhalt direkt in die Eingabe einzufügen.

Wenn wir jedoch viele Felder in unserem Formular ausfüllen müssen, ist es nicht praktisch, toFill mehrmals aufzurufen. In diesem Fall können wir den folgenden Ansatz verwenden, um alle Inhalte auf einmal auszufüllen:

Der bereitgestellte Objektschlüssel ist das name-Attribut des Eingabeelements.

Zusammenfassung

Wir haben ein einfaches Beispiel behandelt, um gängige Testanforderungen und entsprechende Codierschreibtechniken bei der Verwendung von jest-puppeteer für End-to-End-Tests vorzustellen. Wir hoffen, dass es Ihnen helfen kann, die Grundlagen des Schreibens von jest-puppeteer Testcode schnell zu erlernen.