Beliebte Suchanfragen
|
//

Playwright Tests und API Mocking

10.5.2024 | 4 Minuten Lesezeit

Problemstellung

Ist man in einem Playwright- Test abhängig von externen Services wie APIs (die auch mal nicht erreichbar sein können), gibt es u. a. folgende Möglichkeiten, diese Tests adäquat auszuführen.

  • Die Anfrage tatsächlich aufrufen. Wie zum Beispiel eine Entwicklungsumgebung.
    • sollte das Backend nicht erreichbar sein, schlägt der Test fehl.
  • Einen eigenen Dienst wie Wiremock hochfahren und die Responses definieren.
  • Den entsprechenden HTTP Call simulieren.

Dieser Blogartikel geht näher auf den letzten Punkt ein.

Beispiel

Wenn man in seinem Test eine bestimmte Webseite aufruft, werden oft weitere implizite Anfragen durchgeführt. Das heißt, dass die zu testenden Websites während des Seitenaufbaus clientseitig weitere HTTP Calls auslösen. Im Folgenden wird anhand von Beispielen dieses Vorgehen Schritt für Schritt dargestellt.

Verwendet wird ein Dienst von jsonplaceholder.

Allgemeiner Test

Wir stellen uns bei dem unten implementierten Test vor, dass eine ganz bestimmte Anfrage implizit durchgeführt wird. Um dies zu verdeutlichen, leiten wir unseren Test direkt auf den Endpoint, um eine Basis für weitere Erweiterungen zu erarbeiten. In diesem Fall handelt es sich um /todos/1.

Dieses Pattern ist nicht praxisnah und dient nur der Einfachheit.

1import { test } from "@playwright/test";
2
3test.describe('Description', async () => {
4
5test('mytest', async ({ page }) => {
6
7  // given
8  // keine Voraussetzungen notwendig
9
10  // when
11  await page.goto('https://jsonplaceholder.typicode.com/todos/1')
12  
13  // then
14  // expectations...
15})
16
17}

Zum Zeitpunkt dieses Blogbeitrags hat GET /todos/1 folgende Response zurückgesendet.

1{
2  "userId": 1,
3  "id": 1,
4  "title": "delectus aut autem",
5  "completed": false
6}

Generische Erweiterung

Nun gilt es die Anfrage abzufangen und einen Callback auszuführen. Der Callback selber ist eine Funktion, die ausgeführt wird, sobald Playwright diese route erkennt. Der folgende, erweiterte Test von oben führt nach einem console.log den Request weiter und die Response bleibt die gleiche.

1import { Route, test } from "@playwright/test";
2
3test.describe('Description', async () => {
4  test('mytest', async ({ page }) => {
5
6    // given
7    // Führe für jede Anfrage auf diese URL ...
8    await page.route('https://jsonplaceholder.typicode.com/todos/1', async (route: Route) => {
9      // ... diesen callback aus
10      console.log('invoked HTTP call to given route')
11      await route.continue()
12    })
13
14    // when
15    await page.goto('https://jsonplaceholder.typicode.com/todos/1')
16    
17    // then
18    // expectations ...
19  })
20})

Wie oben schon erwähnt, ist diese Form des Herauspickens einer Anfrage auf einen Endpoint nicht gängig und wird zur Veranschaulichung verwendet. Dieser Test testet momentan keine Website, sondern nur eine Anfrage, bei der die Antwort auch noch gemockt wird.

Praxisbeispiel

Nun wird der Test umgewandelt. Wir greifen in unserem Test auf die Webseite zu. Dieser Aufruf löst weitere Anfragen aus. Hierzu gehört unter Anderem eine Anfrage, die an das Stylesheet style.css geht. Diese soll nun nicht wirklich durchgeführt werden. Die Response wird in diesem Beispiel als text/plain ersetzt und zurückgeliefert. Somit wird kein Styling auf der Seite geladen.

Hierfür bietet das Route Interface die Funktion fulfill() an, um diese Response zu definieren.

1import { Route, test } from "@playwright/test";
2
3test.describe('Description', async () => {
4  test('mytest', async ({ page }) => {
5
6    // given
7    // Führe für jede Anfrage auf diese URL ...
8    await page.route(
9      'https://jsonplaceholder.typicode.com/style.css',
10
11      // ... diesen callback aus
12      async (route: Route) => {
13        console.log('invoked HTTP call to given route')
14
15        // sende diese Response zurück
16        await route.fulfill({
17          status: 200,
18          contentType: 'text/plain',
19          body: 'No stylesheet for you',
20        })
21      },
22    )
23
24    // when
25    await page.goto('https://jsonplaceholder.typicode.com/')
26    
27    // then
28    // expectations ...
29  })
30})

Es empfiehlt sich, hier die Funktion so zu refactoren, um sie im

1test.beforeEach(() => {})

aufzurufen und somit vor jedem Test die routes responses zu definieren.

Einschub: Die route.request()-Funktion liefert den gesamten Request zurück und dadurch ist es möglich, bestimmte Requests zu filtern und entsprechend zu agieren. Um die Beispiele nicht zu verkomplizieren, wird auf die nicht näher eingegangen.

Playwright UI

Die Playwright UI, eigentlich ein Chromium Browser, bietet auch den allseits bekannten Network-Tab an. Hier kann man den gemockten Request sehen und auch den Body näher analysieren.

Reale AnfrageGemockte Anfrage
Styling ohne mockStyling mit mock

Limitationen

Es können nur Netzwerkanfragen gemockt werden, die auch aus dem Browser raus ausgelöst werden. Diese sind im Netzwerk-Tab aus den Developer Tools des Browsers zu finden. Der Grund hierfür ist, dass es sich bei Playwright um eine Library handelt, die den User und somit die Interaktion mit Browser simuliert.

Ist die zu testende Webanwendung mit einem Fullstack Framework wie NextJs oder Remix implementiert, ist es entsprechend möglich, dass HTTP Calls auch im Backend aufgerufen werden.

Auf diese hat der Browser keinen Zugriff und sie können nicht gemockt werden.

Fazit

Wie in diesem Blogbeitrag beschrieben, sind es nicht viele Schritte, um einen Request zu mocken. Gerade wenn man nicht Herr über das Backend ist, wird damit das Problem von konkret erwarteten Responses gelöst.

|

Beitrag teilen

//

Weitere Artikel in diesem Themenbereich

Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.

//

Gemeinsam bessere Projekte umsetzen.

Wir helfen deinem Unternehmen.

Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.

Hilf uns, noch besser zu werden.

Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.