5.6 E2E-Tests
Mit Testframeworks wie Vitest können Sie theoretisch alle Ebenen der Testpyramide abdecken. Am besten eignet sich diese Klasse von Frameworks für die Formulierung von Unit- und Integrationstests. Für die Ende-zu-Ende-Tests (E2E-Tests) existieren separate Frameworks wie Selenium, Cypress oder Playwright, die sich darauf spezialisiert haben, Ihnen das Implementieren von E2E-Tests so angenehm wie möglich zu machen.
In den folgenden Abschnitten erfahren Sie, wie Sie mithilfe von Playwright einen E2E-Test für ein einfaches Login-Formular erzeugen lassen können. Das Formular weist ein Eingabefeld für den Usernamen und eins für das Passwort auf. Außerdem gibt es noch einen Button zum Senden des Formulars. Die Übermittlung des Formulars erfolgt über eine JavaScript-Funktion. Bei erfolgreicher Anmeldung werden die User auf den Pfad /list weitergeleitet. Der HTML-Code des Formulars sieht folgendermaßen aus:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>Login Form</title>
</head>
<body>
<div class="login-container">
<h2>Login</h2>
<form id="loginForm">
<input
type="text"
id="username"
name="username"
placeholder="Username"
required
/>
<input
type="password"
id="password"
name="password"
placeholder="Password"
required
/>
<button type="submit">Login</button>
</form>
</div>
</body>
</html>
Auf das Styling und das JavaScript verzichten wir hier bewusst, denn der E2E-Test ist ein klassischer Blackbox-Test, der die Funktionalität aus der Userperspektive überprüft.
Erzeugung eines E2E-Tests
Die Voraussetzung, dass Ihr E2E-Test funktionieren kann, ist eine Installation von Playwright, die Sie mit dem Kommando npx init playwright@latest erreichen. Die Playwright-Tests können Sie mit dem Kommando npx playwright test ausführen. Direkt nach der Installation sind jedoch lediglich Beispiel-Tests vorhanden. Das können Sie jedoch ändern, indem Sie ChatGPT bitten, einen Test für das Login-Formular für Sie zu erzeugen.
Damit der Test funktionieren kann, benötigt die KI einige Informationen von Ihnen. So müssen Sie die HTML-Struktur zur Verfügung stellen und festlegen, über welche Adresse das Formular erreichbar ist. Außerdem müssen Sie angeben, welcher Username und welches Passwort verwendet werden sollen und wohin nach dem erfolgreichen Login weitergeleitet wird. Der zugehörige Prompt könnte wie folgt aussehen:
Prompt: Create a Playwright Test for the following HTML Structure. Assume there is JavaScript that handles the form submission. The form can be found at http://localhost:3000/login. Use ‘admin’ as username and ‘test’ as password. After the successful login the user will be redirected to http://localhost:3000/list.
(Code des HTML-Formulars)
Here is a Playwright test for the provided HTML structure. This test script will fill in the username and password fields with “admin” and “test” respectively, submit the form, and check if the user is redirected to http://localhost:3000/list.
First, make sure you have Playwright installed. If not, you can install it using:
npm install @playwright/test
Next, create a test file (e.g., login.test.js) and add the following code:
// @playwright/test module
import { test, expect } from "@playwright/test";
test("login test", async ({ page }) => {
// Go to the login page
await page.goto("http://localhost:3000/login");
// Fill in the username
await page.fill("#username", "admin");
// Fill in the password
await page.fill("#password", "test");
// Click the login button
await page.click('button[type="submit"]');
// Check if the the redirected URL is the list page
await page.waitForURL("http://localhost:3000/list");
// Check that the new URL is the list page
expect(page.url()).toBe("http://localhost:3000/list");
});
Explanation of the code …
Legen Sie im test-Verzeichnis Ihrer Applikation eine neue Datei mit dem Namen login.test.js an, und führen Sie dann, wie in der Antwort auf den Prompt vorgeschlagen, das Test-Kommando aus. Läuft der Test erfolgreich durch, überprüft er damit Ihren Login-Prozess. ChatGPT hat hier auch die einzelnen Zeilen mit Kommentaren versehen, sodass Sie die Schritte gut nachvollziehen können. In der nachfolgenden Erklärung erfahren Sie sogar noch mehr darüber, was genau die einzelnen Kommandos bedeuten.
Eine Limitierung, mit der Sie zumindest bei LLMs wie ChatGPT leben müssen, ist, dass Sie keinen gesamten Workflow in einem Schritt mit einem E2E-Test abdecken können. Das Problem an dieser Stelle ist, dass die KI einen Workflow, der aus mehreren Ansichten besteht, nicht dynamisch durchlaufen kann. Deshalb müssen Sie hier Schritt für Schritt vorgehen und die einzelnen Teile dann zu einem Gesamtworkflow zusammensetzen.
Erzeugung eines Page-Objekts
Noch etwas übersichtlicher werden Ihre Tests, wenn Sie mit Page-Objekten arbeiten. Ein Page-Objekt stellt Ihnen sprechende Methoden zur Verfügung, mit denen Sie mit einer Seite interagieren können. Die Methoden können sowohl lesend als auch schreibend auf die Seite zugreifen und beispielsweise einen bestimmten Wert zur Überprüfung zurückgeben oder Werte in ein Formularfeld schreiben. Der Testcode wird auf diese Weise noch besser lesbar.
Um in Ihrem E2E-Test ein Page-Objekt zu verwenden, nutzen Sie die vorangegangene ChatGPT-Session und geben als nächsten Prompt Folgendes an:
Prompt: Could you include a Page Object in the test?
Certainly! Using the Page Object Model (POM) helps to organize and maintain your test code more efficiently. Below is an example that includes a Page Object for the login page and incorporates it into the test.
First, create a new file named LoginPage.js for the Page Object.
// LoginPage.js
export class LoginPage {
/**
* @param {import('@playwright/test').Page} page
*/
constructor(page) {
this.page = page;
this.usernameInput = '#username';
this.passwordInput = '#password';
this.submitButton = 'button[type="submit"]';
}
async goto() {
await this.page.goto('http://localhost:3000/login');
}
async login(username, password) {
await this.page.fill(this.usernameInput, username);
await this.page.fill(this.passwordInput, password);
await this.page.click(this.submitButton);
}
}
Next, update the test file to use this Page Object.
// login.test.js
import { test, expect } from '@playwright/test';
import { LoginPage } from './LoginPage';
test('login test', async ({ page }) => {
const loginPage = new LoginPage(page);
// Navigate to the login page
await loginPage.goto();
// Perform the login action
await loginPage.login('admin', 'test');
// Check if the the redirected URL is the list page
await page.waitForURL("http://localhost:3000/list");
// Check that the new URL is the list page
expect(page.url()).toBe('http://localhost:3000/list');
});
Explanation of the code …
Wenn es rein um die Anzahl der Zeilen geht, haben Sie sich durch den Einsatz des Page-Objekts nichts gespart. Die drei Zeilen, die durch das Ausfüllen des Formulars wegfallen, verlieren Sie durch den Import, die Instanziierung des Page-Objekts und den Aufruf der Methoden wieder. In einem größeren Test wird der Code jedoch meist deutlich kompakter und lesbarer. Außerdem können Sie die Page-Objekte zwischen verschiedenen E2E-Tests wiederverwenden und gewinnen dadurch. Lagern Sie beispielsweise den Login-Prozess in ein solches Page-Objekt aus, können Sie es in jedem E2E-Test verwenden, in dem Sie sich anmelden müssen.