CI-fähige e2e-Tests für Angular mit Cypress und TypeScript in weniger als 60 Minuten
In diesem Artikel soll beschrieben werden, wie Sie End-to-End-Tests für Angular mit Cypress inklusive TypeScript einrichten können. Sie werden Ihre ersten e2e-Tests schreiben und sie als kontinuierliches Integrationssystem mit jedem Update Ihres Repositorys auf einem CircleCI lauffähig machen.
End-to-End-Tests (kurz e2e) sind eine Art von Softwaretests, die das Softwaresystem zusammen mit seiner Integration mit externen Schnittstellen validieren. Der Zweck des End-to-End-Tests ist es, ein vollständiges produktionsähnliches Szenario zu üben.
Quelle: https://www.guru99.com/end-to-end-testing.html.
Überblick
- Was ist Cypress?
- Voraussetzungen
- Einrichten von Cypress
- Schreiben einiger Tests
- Einrichten von Continuous Integration
- Abschluss und Referenzen
Ich habe einen Hintergrund in der Frontend-Entwicklung in Microsofts .NET & WPF und erinnere mich an die Zeiten, in denen wir kostspielige Frameworks evaluierten, um End-to-End-Tests für unsere Projekte zu schreiben. Nach vielen Evaluierungen und Wochen, ja sogar Monaten mit benutzerdefiniertem Glue-Code und der Entwicklung von Testinfrastrukturen auf der Grundlage bestehender Tools haben wir schließlich einige e2e-Tests zum Laufen gebracht. Sie waren spröde, scheiterten oft an manuellen Anpassungen, die wir vornehmen mussten, oder an Problemen mit unzuverlässigen Läufern in der kontinuierlichen Integrationspipeline.
Einige Jahre später, mit Angular und Protractor als Standard für e2e-Tests, basierten wir immer noch auf Seitenobjekten und Selenium Web Driver, und die Tests waren weiterhin ziemlich unzuverlässig. Es wurden keine teuren kommerziellen Frameworks und keine eigene Infrastruktur benötigt. Aber hat es Spaß gemacht, e2e-Tests zu schreiben? Nein.
Allerdings sind wir jetzt im Jahr 2020 und die Zeit ist reif für neue Helden. 🚀
Was ist Cypress?
Cypress verspricht schnelle, einfache und zuverlässige Tests für alles, was in einem Browser läuft. Es basiert nicht auf dem Selenium Web Driver, der Netzwerkverbindungen nutzt, um mit dem Browser zu interagieren. Stattdessen ist Cypress ein Test-Runner, der innerhalb des Browsers neben der Webanwendung läuft und somit direkte Kontrolle über diese hat.
Ohne auf alle Details einzugehen, macht dies Cypress nicht nur schneller und zuverlässiger, sondern öffnet auch die Tür für eine Menge anderer interessanter Funktionen wie
- Zeitreise-Debugging,
- einfaches Snapshotten und Aufzeichnen,
- automatisches Warten.
Zusätzlich zu all diesen Funktionen bietet Cypress eine Entwicklererfahrung (DX), die nahezu konkurrenzlos ist. Haben Sie jemals eine Meldung in den Fehlerprotokollen Ihres fehlgeschlagenen Builds gesehen, die Ihnen genau sagt, was Sie falsch gemacht haben, die Sie auf die richtigen Abhängigkeiten hinweist, die Sie hinzufügen müssen, und die auch auf eine erklärende Dokumentationsseite verweist, die das Problem beschreibt? Genau so fühlt sich Cypress an. Es wurde von Entwicklern für Entwickler entwickelt.
Im Folgenden werden wir Cypress für ein neues Angular-Projekt installieren, das mit der CLI erstellt wurde. Wir werden einige e2e-Tests schreiben und diese abschließend mit einem automatisierten Build-System ausführen. Alle diese Schritte sollten nicht länger als 60 Minuten dauern. Wir versuchen, die Schritte so kurz wie möglich zu halten, indem wir vorhandene Tools wie Angular Schematics, Bibliotheken und allgemeine Vorlagen nutzen.
Voraussetzungen
Dieser Leitfaden geht davon aus, dass Sie ein Standardprojekt für Angular 9 haben. Wenn nicht, können Sie eines erstellen, wie Sie es normalerweise mit der Angular CLI tun würden. Wenn Sie das CLI nicht global installiert haben, können Sie den Befehl npx
verwenden, der es vorübergehend on the fly installiert:
npx @angular/cli new <app-name>
Einrichten von Cypress
Um Cypress zusammen mit TypeScript so schnell wie möglich einzurichten, verwenden wir ein bestehendes Schema, das von BrieBug entwickelt wurde.
Im Stammverzeichnis Ihres Angular-Projekts können Sie das Terminal öffnen und den folgenden Befehl eingeben:
ng add @briebug/cypress-schematic --addCypressTestScripts
Wenn das CLI nicht global installiert ist, ist der ng
Befehl möglicherweise nicht direkt verfügbar. Sie können die Verwendung des lokalen ng
aus dem package.json
erzwingen:
npm run ng -- add @briebug/cypress-schematic # In case 'ng' could not be found
Wir können Protractor sicher entfernen, da es vollständig ersetzt wird. Während der Installation wurden einige Binärdateien heruntergeladen, da Cypress eine mit Electron gebündelte UI als interaktiver Testrunner enthält.
Mit dem Flag --addCypressTestScripts
wurden zwei praktische npm-Skripte hinzugefügt, um die Arbeit mit Cypress komfortabler zu gestalten. Eines, um e2e-Tests headless auszuführen und das andere Skript, um die Tests mit dem Cypress UI-Runner auszuführen:
// package.json scripts "cy:run": "cypress run", "cy:open": "cypress open"
Wenn man eines dieser Skripte standalone ausführen würde, würde der Test fehlschlagen, weil er versucht, nach http://localhost:4200 zu routen, wo im Moment nichts bedient wird. Um dies zu beheben, müssen wir ein zweites Terminal öffnen und unsere Angular-Anwendung vorher mit npm start
bedienen.
Glücklicherweise hat das Schema den e2e
-Befehl so angepasst, dass dies automatisch vom CLI-Builder für Sie erledigt wird. Mit dem folgenden Befehl können Sie die Anwendung bereitstellen und den e2e-Test starten:
npm run e2e
Cypress erkennt, dass wir es zum ersten Mal gestartet haben. Es prüft die Installation und fügt einige erste Beispieldateien hinzu. Nachdem sich die Benutzeroberfläche geöffnet hat, sehen wir einen Test, der bereits für uns erstellt wurde.
Wenn wir den Test auswählen, wird er ausgeführt. Anfänglich wird der Test fehlschlagen, weil wir etwas nicht richtig getestet haben. Wir werden das jetzt beheben.
Schreiben einiger Tests
Als allerersten Schritt, wie von den Cypress Best Practices vorgeschlagen, setzen wir unsere globale baseUrl, so dass wir diese nicht bei jeder Testausführung duplizieren müssen. Fügen Sie der Konfiguration cypress.json
Folgendes hinzu:
// cypress.json{ "baseUrl": "http://localhost:4200"}
Danach schreiben wir unseren allerersten Smoke-Test, der nur überprüft, ob der Standard-App-Titel auf der Angular-Startseite gesetzt ist. Ändern Sie daher den Inhalt des spec.ts
in den folgenden Inhalt:
// spec.tsit('smoke test', () => { cy.visit('/'); cy.contains('cypress-e2e-testing-angular app is running!');});
Der Test beginnt mit dem Routing zu unserer baseUrl und fährt fort, indem er jedes Element abfragt, das den Text cypress-e2e-testing-angular app is running! enthält.
Testing User Flows
Dieser Test sollte bereits funktionieren, aber lassen Sie uns noch ein paar interaktivere Tests schreiben. Da e2e von Natur aus langsamer sind als Unit-Tests, ist es völlig in Ordnung, e2e-Tests zu haben, die den gesamten Benutzerfluss für eine Funktion modellieren.
Zum Beispiel wollen wir prüfen, ob einige Merkmale der Startseite gültig sind: Unsere Seite sollte standardmäßig den Titel und den ng generate
-Text im Terminal enthalten, aber wenn der Benutzer auf die Angular-Material-Schaltfläche klickt, wollen wir sicherstellen, dass der richtige ng add
-Befehl in der Terminalansicht darunter angezeigt wird.
Sie können den Inhalt Ihrer Testdatei wie folgt ersetzen:
// spec.tsdescribe('When Angular starting page is loaded', () => { beforeEach(() => { cy.visit('/'); }); it('has app title, shows proper command by default and reacts on command changes', () => { cy.contains('cypress-e2e-testing-angular'); cy.contains('.terminal', 'ng generate component xyz'); cy.contains('Angular Material').click(); cy.contains('.terminal', 'ng add @angular/material'); });});
Wir haben unsere Testsuite umstrukturiert, indem wir einen describe
-Block hinzugefügt haben, um alle Tests zu erfassen, die beim Laden der Startseite ausgeführt werden. Da wir jedes Mal die baseUrl besuchen, haben wir dies in den beforeEach
-Aufruf verschoben. Schließlich haben wir die grundlegenden Smoke-Tests mit dem Test für die Terminalansicht auf der Startseite kombiniert.
Es ist wichtig zu wissen, dass man die Abfrageergebnisse von Cypress nicht in Variablen speichern, sondern mit Closures arbeiten sollte. Außerdem haben wir Elemente nach CSS-Klassen und Textinhalten ausgewählt, die zu spröde sein können. Es wird empfohlen, data-
-Attribute für die Auswahl von Elementen zu verwenden.
Cypress hat eine Menge großartiger Funktionen und Möglichkeiten. Wir werden nicht auf alle eingehen, denn unser Ziel ist es, uns auf den allerersten Ansatzpunkt zu konzentrieren. Die offizielle Dokumentation ist wirklich gut und deckt alles ab, wie man mit Elementen interagiert.
Wenn Sie diese Testsuite erneut ausführen, sollten Sie sehen, wie die Benutzeroberfläche durch jedes Szenario klickt und alle drei Tests sollten dieses Mal bestehen. ✔✔✔
Einrichten von Continuous Integration
Nun, da unsere Tests lokal laufen, sollten wir eine kleine CI (Continuous Integration) Pipeline starten. Eine gute Möglichkeit, dies vorzubereiten, besteht darin, npm-Skripte zu erstellen und sie so zu kombinieren, dass das Build-System ein einziges Skript als Einstiegspunkt verwenden kann. Mit dieser Methode können Sie die CI-Schritte lokal ausprobieren, bevor Sie sie online stellen. Außerdem sind npm-Skripte ziemlich unabhängig von einem tatsächlichen Build-System.
Bei CI müssen wir unseren Server im Hintergrund starten und darauf warten, dass er unsere Anwendung bündelt, was eine Weile dauern kann. Dann müssen wir den Cypress Test Runner starten, die Tests durchlaufen und den Server herunterfahren, wenn die Tests abgeschlossen sind. Glücklicherweise können wir dies alles mit einem einzigen Dienstprogramm namens start-server-and-test erledigen, wie in den Cypress-Dokumenten beschrieben:
npm install --save-dev start-server-and-test
Nachdem dies installiert ist, verwenden wir den Angular Serve, der sich derzeit hinter npm start
befindet, und kombinieren ihn mit dem Befehl headless cy:run
:
// package.json scripts "start": "ng serve", "cy:run": "cypress run", "e2e:ci": "start-server-and-test start http://localhost:4200 cy:run"
Man könnte natürlich auch einen Produktions-Build oder einen Build im Vorfeld verwenden und die App über einen beliebigen http-Server servieren. Der Übersichtlichkeit halber überlasse ich diese Verbesserungen Ihnen.
Circle CI
Für unser Beispiel haben wir CircleCI gewählt, weil es sich sehr gut in GitHub integriert, dort weit verbreitet ist und ein kostenloses Angebot hat. Sie können aber auch jedes andere CI-System wie Jenkins oder GitLab (mit dem ich die meiste Erfahrung habe) verwenden. Nach der Anmeldung bei CircleCI und der Verbindung zu unserem GitHub-Konto können Sie das Repository auswählen und ein neues Projekt über das Dashboard erstellen.
Um die Pipeline zu konfigurieren, könnten Sie ein config.yml
schreiben, indem Sie eine Vorlage auswählen und sie an Ihre Bedürfnisse anpassen und schließlich das e2e-Skript ausführen. Glücklicherweise verfügt Cypress über fertige Konfigurationen (Orbs genannt) für CircleCI, die bereits die Installation von Abhängigkeiten, Caching und so weiter beinhalten. Bevor wir es verwenden können, müssen wir die Organisationseinstellungen besuchen, um Drittanbieter-Runner zu aktivieren.
# circleci/config.ymlversion: 2.1orbs: # This Orb includes the following: # - checkout current repository # - npm install with caching # - start the server # - wait for the server to respond # - run Cypress tests # - store videos and screenshots as artifacts on CircleCI cypress: cypress-io/cypress@1workflows: build: jobs: - cypress/run: start: npm start wait-on: 'http://localhost:4200' store_artifacts: true
Die Pipeline hat nur eine Aufgabe: Alle e2e-Tests auszuführen. Sie checkt den aktuellen Zweig aus, installiert alle Abhängigkeiten inklusive Caching, startet den Anwendungsserver und führt unsere Tests aus. Zusätzlich werden Videos (standardmäßig aufgezeichnet) und Screenshots (für den Fall, dass die Tests fehlschlagen) als CircleCI Artefakte zur weiteren Überprüfung hochgeladen.*
Fazit
Die Schritte in dieser Anleitung sind eher minimal. Sie können Ihr bestehendes Angular-Projekt verwenden, die Konfiguration Ihrer Cypress-Testsuiten ändern und eine Menge sinnvoller Tests schreiben. Außerdem können Sie npm-Skripte für verschiedene Szenarien und Umgebungen definieren und natürlich Ihre gesamte Build-Pipeline mit Linting, Unit-Tests, Build und sogar Deployment Ihrer Anwendung erweitern. Nichtsdestotrotz soll dies ein erster Schritt sein, der zeigt, wie schnell automatisierte End-to-End-Tests in der heutigen Zeit aufgesetzt werden können.
Warten Sie ab, bis Sie echte Cypress-Tests für Ihre Anwendung schreiben. Sie werden Spaß haben!
Ich hoffe, dass auch Sie einen Nutzen in diesem Artikel finden. Wenn Sie Fragen oder Anmerkungen haben, lassen Sie es mich einfach wissen. Ihr Feedback ist sehr willkommen!
Die Quellen für diese Anleitung finden Sie auf GitHub:
MrCube42 / cypress-e2e-testing-angular
Beispiel für eine Angular 9-App, die Cypress für End-to-End-Tests verwendet.
CypressE2eTestingAngular
Dieses Projekt wurde mit Angular CLI Version 9.0.6 erstellt.
Entwicklungsserver
Für einen Entwicklungsserver ng serve
ausführen. Navigieren Sie zu http://localhost:4200/
. Die Anwendung wird automatisch neu geladen, wenn Sie eine der Quelldateien ändern.
Codegerüst
Starten Sie ng generate component component-name
, um eine neue Komponente zu erzeugen. Sie können auch ng generate directive|pipe|service|class|guard|interface|enum|module
verwenden.
Build
Run ng build
, um das Projekt zu erstellen. Die Build-Artefakte werden im Verzeichnis dist/
gespeichert. Verwenden Sie das Flag --prod
für einen Produktions-Build.
Ausführen von Unit-Tests
Ausführen ng test
, um die Unit-Tests über Karma auszuführen.
Ausführen von End-to-End-Tests
Ausführen npm run e2e
, um die End-to-End-Tests über Cypress auszuführen.
Weitere Hilfe
Um weitere Hilfe zur Angular CLI zu erhalten, verwenden Sie ng help
oder schauen Sie in das Angular CLI README.
Leave a Reply