1.000-Fuß-Übersicht über das Schreiben von Cypress-Tests #frontend@twiliosendgrid
Veröffentlicht: 2020-10-03Bei Twilio SendGrid haben wir Hunderte von End-to-End (E2E)-Tests für Cypress geschrieben und schreiben weitere, wenn neue Funktionen für verschiedene Webanwendungen und Teams veröffentlicht werden. Diese Tests decken den gesamten Stack ab und verifizieren, dass die häufigsten Anwendungsfälle, die ein Kunde durchlaufen würde, immer noch funktionieren, nachdem neue Codeänderungen in unseren Anwendungen vorgenommen wurden.
Wenn Sie zunächst einen Schritt zurücktreten und mehr darüber lesen möchten, wie man über E2E-Tests im Allgemeinen nachdenkt, können Sie sich gerne diesen Blogbeitrag ansehen und darauf zurückkommen, sobald Sie bereit sind. Dieser Blogbeitrag erfordert nicht, dass Sie ein Experte für E2E-Tests sind, aber er hilft, in die richtige Stimmung zu kommen, da Sie sehen werden, warum wir in unseren Tests auf eine bestimmte Weise vorgegangen sind. Wenn Sie nach einem schrittweisen Tutorial suchen, das Sie in Cypress-Tests einführt, empfehlen wir Ihnen, sich die Cypress-Dokumentation anzusehen . In diesem Blogbeitrag gehen wir davon aus, dass Sie vielleicht schon viele Cypress-Tests gesehen oder geschrieben haben und neugierig sind, wie andere Cypress-Tests für ihre eigenen Anwendungen schreiben.
Nachdem Sie viele Cypress-Tests geschrieben haben, werden Sie bemerken, dass Sie ähnliche Cypress-Funktionen, Behauptungen und Muster verwenden, um das zu erreichen, was Sie brauchen. Wir zeigen Ihnen die häufigsten Teile und Strategien, die wir mit Cypress verwendet oder zuvor durchgeführt haben, um Tests für separate Umgebungen wie Entwicklung oder Staging zu schreiben. Wir hoffen, dass dieser 1.000-Fuß-Überblick darüber, wie wir Cypress-Tests schreiben, Ihnen Ideen zum Vergleich mit Ihren eigenen gibt und Ihnen hilft, Ihre Herangehensweise an Cypress-Tests zu verbessern.
Umriss:
- Zusammenfassung der Cypress-API
- Interaktion mit Elementen
- Behauptung auf Elementen
- Umgang mit APIs und Diensten
- Erstellen von HTTP-Anfragen mit cy.request(…)
- Wiederverwendbare Plugins mit cy.task() erstellen
- Verspotten von Netzwerkanfragen mit cy.server() und cy.route()
- Benutzerdefinierte Befehle
- Über Seitenobjekte
- Die Entscheidung, clientseitigen Code nicht mit window.Cypress-Prüfungen auszuführen
- Umgang mit iframes
- Standardisierung über Testumgebungen hinweg
Zusammenfassung der Cypress-API
Beginnen wir damit, die Teile durchzugehen, die wir am häufigsten mit der Cypress-API verwendet haben.
Auswählen von Elementen
Es gibt viele Möglichkeiten, DOM-Elemente auszuwählen, aber Sie können das meiste, was Sie tun müssen, mit diesen Cypress-Befehlen erreichen, und Sie können normalerweise weitere Aktionen und Assertionen nach diesen verketten.
- Abrufen von Elementen basierend auf einem CSS-Selektor mit
cy.get(“[data-hook='someSelector']”)
odercy.find(“.selector”)
. - Auswählen von Elementen basierend auf Text wie
cy.contains(“someText”)
oder Abrufen eines Elements mit einem bestimmten Selektor, der Text enthält, wiecy.contains(“.selector”, “someText”)
. - Ein übergeordnetes Element dazu bringen, „innerhalb“ zu suchen, sodass alle Ihre zukünftigen Abfragen auf die untergeordneten Elemente des übergeordneten Elements ausgerichtet sind, z. B.
cy.get(“.selector”).within(() => { cy.get(“.child”) })
. - Eine Liste von Elementen finden und „jedes“ durchsehen, um weitere Abfragen und Behauptungen wie
cy.get(“tr”).each(($tableRow) => { cy.wrap($tableRow).find('td').eq(1).should(“contain”, “someText” })
. - Manchmal sind Elemente möglicherweise nicht auf der Seite sichtbar, daher müssen Sie das Element zuerst in die Ansicht scrollen, z. B.
cy.get(“.buttonFarBelow”).scrollIntoView()
. - Manchmal benötigen Sie eine längere Zeitüberschreitung als die standardmäßige Befehlszeitüberschreitung, sodass Sie optional ein
{ timeout: timeoutInMs }
wiecy.get(“.someElement”, { timeout: 10000 })
hinzufügen können.
Interaktion mit Elementen
Dies sind die am häufigsten verwendeten Interaktionen, die in unseren Cypress-Tests gefunden wurden. Gelegentlich müssen Sie eine Eigenschaft { force: true }
in diese Funktionsaufrufe einfügen, um einige Überprüfungen mit den Elementen zu umgehen. Dies tritt häufig auf, wenn ein Element auf irgendeine Weise abgedeckt oder von einer externen Bibliothek abgeleitet ist, über die Sie hinsichtlich der Darstellung von Elementen nicht viel Kontrolle haben.
- Wir müssen auf viele Dinge wie Schaltflächen in Modalen, Tabellen und dergleichen klicken, also machen wir Dinge wie
cy.get(“.button”).click()
. - Formulare sind überall in unseren Webanwendungen vorhanden, um Benutzerdaten und andere Datenfelder auszufüllen. Wir geben diese Eingaben mit
cy.get(“input”).type(“somekeyboardtyping”)
und müssen möglicherweise einige Standardwerte von Eingaben löschen, indem wir sie zuerst wiecy.get(“input”).clear().type(“somenewinput”)
. Es gibt auch coole Möglichkeiten, andere Tasten wie{enter}
für die Eingabetaste einzugeben, wenn Siecy.get(“input”).type(“text{enter}”)
. - Wir können mit ausgewählten Optionen wie
cy.get(“select”).select(“value”)
und Checkboxen wiecy.get(“.checkbox”).check()
.
Behauptung auf Elementen
Dies sind die typischen Behauptungen, die Sie in Ihren Cypress-Tests verwenden können, um festzustellen, ob Dinge mit dem richtigen Inhalt auf der Seite vorhanden sind.
- Um zu überprüfen, ob Dinge auf der Seite angezeigt werden oder nicht, können Sie zwischen
cy.get(“.selector”).should(“be.visible”)
undcy.get(“.selector”).should(“not.be.visible”)
. - Um festzustellen, ob irgendwo im Markup DOM-Elemente vorhanden sind, und wenn es Ihnen nicht unbedingt wichtig ist, ob die Elemente sichtbar sind, können Sie
cy.get(“.element”).should(“exist”)
odercy.get(“.element”).should(“not.exist”)
. - Um zu sehen, ob ein Element Text enthält oder nicht, können Sie zwischen
cy.get(“button”).should(“contain”, “someText”)
undcy.get(“button”).should(“not.contain”, “someText”)
. - Um zu überprüfen, ob eine Eingabe oder Schaltfläche deaktiviert oder aktiviert ist, können Sie Folgendes bestätigen:
cy.get(“button”).should(“be.disabled”)
. - Um festzustellen, ob etwas überprüft wird, können Sie Folgendes testen:
cy.get(“.checkbox”).should(“be.checked”)
. - Sie können sich normalerweise auf greifbarere Text- und Sichtbarkeitsprüfungen verlassen, aber manchmal müssen Sie sich auf Klassenprüfungen wie
cy.get(“element”).should(“have.class”, “class-name”)
. Es gibt auch andere ähnliche Möglichkeiten, Attribute mit.should(“have.attr”, “attribute”)
zu testen. - Es ist oft nützlich, Behauptungen wie
cy.get(“div”).should(“be.visible”).and(“contain”, “text”)
zu verketten.
Umgang mit APIs und Diensten
Wenn Sie mit Ihren eigenen APIs und Diensten im Zusammenhang mit E-Mail arbeiten, können Sie cy.request(...)
verwenden, um HTTP-Anforderungen an Ihre Back-End-Endpunkte mit Authentifizierungsheadern zu senden. Eine weitere Alternative besteht darin, dass Sie cy.task(...)
Plugins erstellen können, die von jeder Spezifikationsdatei aufgerufen werden können, um andere Funktionen abzudecken, die am besten in einem Node-Server mit anderen Bibliotheken gehandhabt werden können, z Abgleich von E-Mails oder mehr Kontrolle über die Antworten und Abfragen bestimmter API-Aufrufe, bevor einige Werte für die zu verwendenden Tests zurückgegeben werden.
Erstellen von HTTP-Anfragen mit cy.request(…)
Sie können cy.request()
verwenden, um HTTP-Anforderungen an Ihre Backend-API zu senden, um Daten einzurichten oder zu entfernen, bevor Ihre Testfälle ausgeführt werden. Normalerweise übergeben Sie die Endpunkt-URL, die HTTP-Methode wie „GET“ oder „POST“, Header und manchmal einen Anfragetext, der an die Backend-API gesendet wird. Sie können dies dann mit einem .then((response) => { })
, um über Eigenschaften wie „status“ und „body“ Zugriff auf die Netzwerkantwort zu erhalten. Ein Beispiel für einen Aufruf von cy.request()
wird hier demonstriert.
Manchmal ist es Ihnen egal, ob cy.request(...)
während der Bereinigung vor einem Testlauf mit einem 4xx- oder 5xx-Statuscode fehlschlägt oder nicht. Ein Szenario, in dem Sie den fehlgeschlagenen Statuscode ignorieren können, ist, wenn Ihr Test eine GET-Anforderung sendet, um zu überprüfen, ob ein Element noch vorhanden ist und bereits gelöscht wurde. Das Element ist möglicherweise bereits bereinigt und die GET-Anforderung schlägt mit dem Statuscode 404 nicht gefunden fehl. In diesem Fall würden Sie eine andere Option von failOnStatusCode: false
, damit Ihre Cypress-Tests nicht fehlschlagen, bevor Sie die Testschritte überhaupt ausgeführt haben.
Wiederverwendbare Plugins mit cy.task() erstellen
Wenn wir mehr Flexibilität und Kontrolle über eine wiederverwendbare Funktion haben möchten, um mit einem anderen Dienst wie einem E-Mail-Posteingangsanbieter über einen Node-Server zu kommunizieren (wir werden dieses Beispiel in einem späteren Blogbeitrag behandeln), stellen wir gerne unsere eigene zusätzliche Funktionalität und benutzerdefinierte Antworten auf API-Aufrufe, die wir verketten und in unseren Cypress-Tests anwenden können. Oder wir führen gerne einen anderen Code auf einem Node-Server aus – oft bauen wir dafür ein cy.task()
-Plug-In auf. Wir erstellen Plugin-Funktionen in Moduldateien und importieren sie in plugins/index.ts
, wo wir die Aufgaben-Plugins mit den Argumenten definieren, die wir zum Ausführen der Funktionen benötigen, wie unten gezeigt.
Diese Plug-ins können mit einem cy.task(“pluginName”, { ...args })
überall in Ihren Spezifikationsdateien aufgerufen werden, und Sie können erwarten, dass dieselbe Funktionalität ausgeführt wird. Wenn Sie dagegen cy.request()
verwendet haben, haben Sie weniger Wiederverwendbarkeit, es sei denn, Sie haben diese Aufrufe selbst in Seitenobjekte oder Hilfsdateien verpackt, die überall importiert werden können.
Eine weitere Einschränkung besteht darin, dass Sie die üblichen Cypress-Befehle innerhalb dieser Funktionen wie Cypress.env(“apiHost”)
oder cy.getCookie('auth_token')
nicht aufrufen können, da der Plugin-Aufgabencode auf einem Node-Server ausgeführt werden soll. Sie übergeben Dinge wie die Zeichenfolge des Authentifizierungstokens oder den Backend-API-Host an das Argumentobjekt Ihrer Plug-in-Funktion, zusätzlich zu Dingen, die für den Anforderungstext erforderlich sind, wenn er mit Ihrer Backend-API kommunizieren muss.
Verspotten von Netzwerkanfragen mit cy.server() und cy.route()
Für Cypress-Tests, die Daten erfordern, die schwer zu reproduzieren sind (wie Variationen wichtiger UI-Zustände auf einer Seite oder der Umgang mit langsameren API-Aufrufen), ist eine zu berücksichtigende Cypress-Funktion das Stubben der Netzwerkanforderungen. Dies funktioniert gut mit auf XmlHttpRequest (XHR) basierenden Anforderungen, wenn Sie Vanilla XMLHttpRequest, die axios-Bibliothek oder jQuery AJAX verwenden. Sie würden dann cy.server()
und cy.route()
verwenden, um nach Routen zu lauschen, um Antworten für jeden gewünschten Status zu simulieren. Hier ist ein Beispiel:
Ein weiterer Anwendungsfall ist die gemeinsame Verwendung von cy.server()
, cy.route()
und cy.wait()
, um zuzuhören und zu warten, bis Netzwerkanforderungen abgeschlossen sind, bevor die nächsten Schritte ausgeführt werden. Normalerweise signalisiert nach dem Laden einer Seite oder dem Ausführen einer Aktion auf der Seite ein intuitiver visueller Hinweis, dass etwas abgeschlossen oder bereit ist, dass wir es bestätigen und bearbeiten können. In den Fällen, in denen Sie keinen solchen sichtbaren Hinweis haben, können Sie explizit warten, bis ein API-Aufruf so beendet wird.
Ein großes Problem ist, wenn Sie fetch für Netzwerkanfragen verwenden, können Sie die Netzwerkanfragen nicht verspotten oder darauf warten, dass sie auf die gleiche Weise beendet werden. Sie benötigen eine Problemumgehung, indem Sie das normale window.fetch
durch ein XHR-Polyfill ersetzen und einige Einrichtungs- und Bereinigungsschritte ausführen, bevor Ihre Tests wie in diesen Problemen beschrieben ausgeführt werden . Ab Cypress 4.9.0 gibt es auch eine experimentalFetchPolyfill
-Eigenschaft, die für Sie funktionieren könnte, aber insgesamt suchen wir immer noch nach besseren Methoden, um Netzwerk-Stubbing über die Abruf- und XHR-Nutzung in unseren Anwendungen hinweg zu handhaben, ohne dass Dinge kaputt gehen. Ab Cypress 5.1.0 gibt es eine vielversprechende neue cy.route2()
Funktion (siehe die Cypress -Dokumentation ) für experimentelles Netzwerk-Stubbing von sowohl XHR- als auch Abrufanfragen, also planen wir, unsere Cypress-Version zu aktualisieren und damit zu experimentieren, um zu sehen, ob es löst unsere Probleme.
Benutzerdefinierte Befehle
Ähnlich wie bei Bibliotheken wie WebdriverIO können Sie globale benutzerdefinierte Befehle erstellen, die wiederverwendet und in Ihren Spezifikationsdateien verkettet werden können, z. B. einen benutzerdefinierten Befehl zum Verarbeiten von Anmeldungen über die API, bevor Ihre Testfälle ausgeführt werden. Sobald Sie sie in einer Datei wie support/commands.ts
entwickelt haben, können Sie auf Funktionen wie cy.customCommand()
oder cy.login()
. Das Schreiben eines benutzerdefinierten Befehls zum Anmelden sieht so aus.
Über Seitenobjekte
Ein Seitenobjekt ist ein Wrapper um Selektoren und Funktionen, die Ihnen helfen, mit einer Seite zu interagieren. Sie müssen keine Seitenobjekte erstellen, um Ihre Tests zu schreiben, aber es ist gut, über Möglichkeiten nachzudenken, wie Sie Änderungen an der Benutzeroberfläche kapseln können. Sie möchten sich das Leben erleichtern, indem Sie Dinge gruppieren, um zu vermeiden, dass Selektoren und Interaktionen in mehreren Dateien anstatt an einem Ort aktualisiert werden.
Sie können eine „Seiten“-Basisklasse mit allgemeiner Funktionalität wie open()
definieren, damit geerbte Seitenklassen gemeinsam genutzt und erweitert werden können. Abgeleitete Seitenklassen definieren ihre eigenen Getter-Funktionen für Selektoren und andere Hilfsfunktionen, während sie die Funktionalität der Basisklassen durch Aufrufe wie super.open()
, wie hier gezeigt.
Die Entscheidung, clientseitigen Code nicht mit window.Cypress-Prüfungen auszuführen
Wenn wir Flows mit automatisch heruntergeladenen Dateien wie CSV getestet haben, haben die Downloads unsere Cypress-Tests oft unterbrochen, indem sie den Testlauf eingefroren haben. Als Kompromiss wollten wir hauptsächlich testen, ob der Benutzer den richtigen Erfolgsstatus für einen Download erreichen und die Datei in unserem Testlauf nicht wirklich herunterladen kann, indem wir eine window.Cypress
Prüfung hinzufügen.
Während Cypress-Testläufen wird dem Browser eine window.Cypress
Eigenschaft hinzugefügt. In Ihrem clientseitigen Code können Sie prüfen, ob es keine Cypress-Eigenschaft für das Fensterobjekt gibt, und dann den Download wie gewohnt durchführen. Wenn es jedoch in einem Cypress-Test ausgeführt wird, laden Sie die Datei nicht wirklich herunter. Wir nutzten auch die Überprüfung der window.Cypress
Eigenschaft für unsere A/B-Experimente, die in unserer Web-App ausgeführt werden. Wir wollten nicht mehr Unschärfe und nicht deterministisches Verhalten aus A/B-Experimenten hinzufügen, die möglicherweise unterschiedliche Erfahrungen für unsere Testbenutzer zeigen, also haben wir zuerst überprüft, ob die Eigenschaft nicht vorhanden ist, bevor wir die unten hervorgehobene Experimentlogik ausführen.
Umgang mit iframes
Der Umgang mit Iframes kann bei Cypress schwierig sein, da es keine integrierte Iframe-Unterstützung gibt. Es gibt ein laufendes [Problem] ( https://github.com/cypress-io/cypress/issues/136 ), das mit Problemumgehungen gefüllt ist, um einzelne Iframes und verschachtelte Iframes zu handhaben, die je nach Ihrer aktuellen Version von Cypress möglicherweise funktionieren oder nicht oder das Iframe, mit dem Sie interagieren möchten. Für unseren Anwendungsfall brauchten wir eine Möglichkeit, mit Zuora-Abrechnungs-Iframes in unserer Staging-Umgebung umzugehen, um die E-Mail-API- und Marketingkampagnen-API-Upgrade-Flows zu überprüfen. Unsere Tests umfassen das Ausfüllen von Beispielrechnungsinformationen, bevor ein Upgrade auf ein neues Angebot in unserer App abgeschlossen wird.
Wir haben einen benutzerdefinierten Befehl cy.iframe(iframeSelector)
erstellt, um den Umgang mit Iframes zu kapseln. Das Übergeben eines Selektors an den Iframe überprüft dann den Inhalt des Iframes, bis er nicht mehr leer ist, und gibt dann den Inhalt des Körpers zurück, damit er mit weiteren Cypress-Befehlen verkettet werden kann, wie unten gezeigt:
Wenn Sie mit TypeScript arbeiten, können Sie Ihren benutzerdefinierten iframe-Befehl wie folgt in Ihre index.d.ts
-Datei eingeben:
Um den Abrechnungsteil unserer Tests durchzuführen, haben wir den benutzerdefinierten iframe-Befehl verwendet, um den Textinhalt des Zuora-iframes abzurufen, und dann die Elemente innerhalb des iframes ausgewählt und ihre Werte direkt geändert. Wir hatten zuvor Probleme mit der Verwendung von cy.find(...).type(...)
und anderen Alternativen, die nicht funktionierten, aber zum Glück haben wir eine Problemumgehung gefunden, indem wir die Werte der Eingaben geändert und direkt mit dem Aufrufbefehl ausgewählt haben, dh cy.get(selector).invoke('val', 'some value')
. Sie benötigen außerdem ”chromeWebSecurity”: false
in Ihrer cypress.json
Konfigurationsdatei, damit Sie Cross-Origin-Fehler umgehen können. Nachfolgend finden Sie ein Beispiel-Snippet für die Verwendung mit Füller-Selektoren:
Standardisierung über Testumgebungen hinweg
Nachdem wir Tests mit Cypress unter Verwendung der gebräuchlichsten Behauptungen, Funktionen und Ansätze geschrieben haben, die zuvor hervorgehoben wurden, können wir die Tests ausführen und sie in einer Umgebung bestehen lassen. Dies ist ein großartiger erster Schritt, aber wir haben mehrere Umgebungen, um neuen Code bereitzustellen und unsere Änderungen zu testen. Jede Umgebung hat ihre eigenen Datenbanken, Server und Benutzer, aber unsere Cypress-Tests sollten nur einmal geschrieben werden, damit sie mit den gleichen allgemeinen Schritten funktionieren.
Um Cypress-Tests in mehreren Testumgebungen wie Entwicklung, Tests und Staging durchzuführen, bevor wir unsere Änderungen schließlich in der Produktion bereitstellen, müssen wir die Fähigkeit von Cypress nutzen, Umgebungsvariablen hinzuzufügen und Konfigurationswerte zu ändern, um diese Anwendungsfälle zu unterstützen.
So führen Sie Ihre Tests mit verschiedenen Frontend-Umgebungen durch :
Sie müssen den „baseUrl“ -Wert, auf den über Cypress.config(“baseUrl”)
zugegriffen wird, ändern, um diesen URLs wie https://staging.app.com oder https://testing.app.com zu entsprechen . Dadurch wird die Basis-URL für alle Ihre cy.visit(...)
Aufrufe geändert, an die ihre Pfade angehängt werden. Es gibt mehrere Möglichkeiten, dies festzulegen, z. B. das Festlegen CYPRESS_BASE_URL=<frontend_url>
vor dem Ausführen Ihres Cypress-Befehls oder das Festlegen --config baseUrl=<frontend_url>
.
So führen Sie Ihre Tests in verschiedenen Back-End-Umgebungen aus :
Sie müssen den API-Hostnamen wie https://staging.api.com oder https://testing.api.com kennen , um ihn in einer Umgebungsvariablen wie „apiHost“ festzulegen und über Aufrufe wie Cypress.env(“apiHost”)
. Diese werden für Ihre cy.request(...)
Aufrufe verwendet, um HTTP-Anforderungen an bestimmte Pfade wie „<apiHost>/some/endpoint“ zu senden, oder als weiteres Argument an Ihre cy.task(...)
Funktionsaufrufe weitergegeben -Eigenschaft, um zu wissen, auf welches Backend zugegriffen werden soll. Diese authentifizierten Aufrufe müssten auch das Authentifizierungstoken kennen, das Sie höchstwahrscheinlich in localStorage oder ein Cookie über cy.getCookie(“auth_token”)
. Stellen Sie sicher, dass dieses Authentifizierungstoken schließlich als Teil des „Authorization“-Headers oder auf andere Weise als Teil Ihrer Anfrage übergeben wird. Es gibt eine Vielzahl von Möglichkeiten, diese Umgebungsvariablen festzulegen, z. B. direkt in der Datei cypress.json
oder in --env
-Befehlszeilenoptionen, wo Sie in der Cypress-Dokumentation darauf verweisen können .
Um sich bei verschiedenen Benutzern anzumelden oder unterschiedliche Metadaten zu verwenden:
Nun, da Sie wissen, wie Sie mit mehreren Front-End-URLs und Back-End-API-Hosts umgehen, wie gehen Sie mit der Anmeldung bei verschiedenen Benutzern um? Wie verwenden Sie unterschiedliche Metadaten basierend auf der Umgebung, z. B. Dinge im Zusammenhang mit Domänen, API-Schlüsseln und anderen Ressourcen, die wahrscheinlich in Testumgebungen eindeutig sind?
Beginnen wir damit, eine weitere Umgebungsvariable namens „testEnv“ mit möglichen Werten für „testing“ und „staging“ zu erstellen, damit Sie auf diese Weise feststellen können, welche Benutzer und Metadaten der Umgebung im Test angewendet werden sollen. Mit der Umgebungsvariable „testEnv“ können Sie dies auf verschiedene Weise angehen.
Sie können separate „staging.json“, „testing.json“ und andere Umgebungs-JSON-Dateien im Ordner „ fixtures
“ erstellen und sie importieren, damit Sie sie basierend auf dem „testEnv“-Wert wie cy.fixture(`${testEnv}.json`).then(...)
. Allerdings kann man die JSON-Dateien nicht gut abtippen und es gibt viel mehr Spielraum für Fehler in der Syntax und beim Ausschreiben aller pro Test erforderlichen Eigenschaften. Die JSON-Dateien sind auch weiter vom Testcode entfernt, sodass Sie beim Bearbeiten der Tests mindestens zwei Dateien verwalten müssten. Ähnliche Wartungsprobleme würden auftreten, wenn alle Umgebungstestdaten in Umgebungsvariablen direkt in Ihrer cypress.json
würden und es zu viele gäbe, um sie über eine Vielzahl von Tests hinweg zu verwalten.
Eine alternative Option besteht darin, ein Testvorrichtungsobjekt innerhalb der Spezifikationsdatei mit Eigenschaften zu erstellen, die auf Tests oder Staging basieren, um die Benutzer- und Metadaten dieses Tests für eine bestimmte Umgebung zu laden. Da es sich um Objekte handelt, können Sie auch einen besseren generischen TypeScript-Typ um Testvorrichtungsobjekte für alle Ihre Spezifikationsdateien herum definieren, um sie wiederzuverwenden und die Metadatentypen zu definieren. Sie würden Cypress.env(“testEnv”)
, um zu sehen, mit welcher Testumgebung Sie arbeiten, und diesen Wert verwenden, um die Testvorrichtung der entsprechenden Umgebung aus dem gesamten Testvorrichtungsobjekt zu extrahieren und diese Werte in Ihrem Test zu verwenden. Die allgemeine Idee des Objekts „Test Fixtures“ ist im Code-Snippet darunter zusammengefasst.
Die gemeinsame Anwendung des Cypress-Konfigurationswerts „baseUrl“, der Backend-Umgebungsvariable „apiHost“ und der Umgebungsvariable „testEnv“ ermöglicht es uns, Cypress-Tests zu haben, die für mehrere Umgebungen funktionieren, ohne mehrere Bedingungen oder separate Logikflüsse hinzuzufügen, wie unten gezeigt.
Lassen Sie uns einen Schritt zurückgehen, um zu sehen, wie Sie sogar Ihre eigenen Cypress-Befehle erstellen können, um npm zu durchlaufen. Ähnliche Konzepte können auf Garn, Makefile und andere Skripte angewendet werden, die Sie möglicherweise für Ihre Anwendung verwenden. Möglicherweise möchten Sie Variationen von „Öffnen“- und „Ausführen“-Befehlen definieren, um sie mit dem „Öffnen“ der GUI von Cypress und „Ausführen“ im Headless-Modus für verschiedene Frontend- und Backend-Umgebungen in Ihrer package.json
. Sie können auch mehrere JSON-Dateien für die Konfiguration jeder Umgebung einrichten, aber der Einfachheit halber sehen Sie die Befehle mit den Optionen und Werten inline.
Sie werden in den package.json
Skripten feststellen, dass Ihre Frontend-„baseUrl“ von „http://localhost:9001“ für den lokalen Start Ihrer App bis zur bereitgestellten Anwendungs-URL wie „ https://staging.app“ reicht. de “. Sie können die Backend-Variablen „apiHost“ und „testEnv“ festlegen, um Anfragen an einen Backend-Endpunkt zu stellen und ein bestimmtes Testvorrichtungsobjekt zu laden. Sie können auch spezielle „cicd“-Befehle erstellen, wenn Sie Ihre Tests in einem Docker-Container mit dem Aufzeichnungsschlüssel ausführen müssen.
Ein paar Mitbringsel
Wenn es darum geht, Elemente auszuwählen, mit Elementen zu interagieren und Aussagen über Elemente auf der Seite zu machen, können Sie ziemlich weit kommen, indem Sie viele Cypress-Tests mit einer kleinen Liste von Cypress-Befehlen wie cy.get()
, cy.contains()
. .click()
, .type()
, .should('be.visible')
.
Es gibt auch Möglichkeiten, HTTP-Anfragen an eine Backend-API mit cy.request()
zu stellen, beliebigen Code in einem Node-Server mit cy.task()
auszuführen und Netzwerkanfragen mit cy.server()
und cy.route()
. Sie können sogar Ihren eigenen benutzerdefinierten Befehl wie cy.login()
erstellen, der Ihnen hilft, sich über die API bei einem Benutzer anzumelden. All diese Dinge helfen dabei, einen Benutzer auf den richtigen Ausgangspunkt zurückzusetzen, bevor die Tests ausgeführt werden. Packen Sie diese Selektoren und Funktionen zusammen in eine Datei, und Sie haben wiederverwendbare Seitenobjekte zur Verwendung in Ihren Spezifikationen erstellt.
Um Ihnen beim Schreiben von Tests zu helfen, die in mehr als einer Umgebung bestehen, nutzen Sie Umgebungsvariablen und Objekte, die umgebungsspezifische Metadaten enthalten.
Dies hilft Ihnen, verschiedene Benutzergruppen mit separaten Datenressourcen in Ihren Cypress-Spezifikationen auszuführen. Separate Cypress npm-Befehle wie npm run cypress:open:staging
in Ihrer package.json
laden die richtigen Umgebungsvariablenwerte und führen die Tests für die Umgebung aus, für die Sie sich entschieden haben.
Dies schließt unseren 1000-Fuß-Überblick über das Schreiben von Cypress-Tests ab. Wir hoffen, dass Ihnen dies praktische Beispiele und Muster geliefert hat, die Sie in Ihren eigenen Cypress-Tests anwenden und verbessern können.
Möchten Sie mehr über Cypress-Tests erfahren? Sehen Sie sich die folgenden Ressourcen an:
- Was beim Schreiben von E2E-Tests zu beachten ist
- Schreiben Sie alle Dinge in Ihre Cypress-Tests
- Umgang mit E-Mail-Flows in Cypress-Tests
- Ideen zum Konfigurieren, Organisieren und Konsolidieren Ihrer Cypress-Tests
- Integration von Cypress-Tests mit Docker, Buildkite und CICD