Sponsored Link
Looking for a unified way to  viewmonitor, and  debug Playwright Test Automation runs?
Try the Playwright Dashboard by today. Use the coupon code PWSOL10 for a 12 month 10% discount.

How do I mock HTTP network traffic for a specific response via in Playwright?

I recently had a scenario where I wanted to make a check on a UI element but the data within the UI element was a count that other tests in my suite would affect. There were really 2 approaches I saw forward. One was intercept the network traffic and scrape the value, and make the assertion on that value, or the Second option was to intercept and mock the response to a value I pass in.

In this article I'll walk through a simple scenario of intercepting and mocking a network request.

The first thing we do is create a variable called count which we set to 100. This can be any amount, as it's what we will pass into the test name, the mockMessageCount function and use in the assertion.

In this test I have a lot of actions in the beforeEach method, Ideally I would abstract a lot of that away to a page object so the test is a bit more dry. this test assumes that you will be logged in when the test section starts. In the beforeEach I also call the method away mockMessageCount(page, count). This code is making a call to the async function listed at the bottom of the test spec. This could easily exist in a different file, by exporting the function from it's own file, and importing into the test. The code below uses the route class, for any urls that end with "/message/count". we then fulfill the message with a status and response body. I knew what shape to build the response with from making the request from https://automationintesting.online/message/count. This is unauthenticated so you can click and see the current count.

export async function mockMessageCount(page, messageCount) {
  await page.route("**/message/count", (route) =>
    route.fulfill({
      status: 200,
      body: JSON.stringify({ count: messageCount }),
    })
  );
}

Since we pass in 100 as the count into the mockMessageCount, the 100 value is mocked in the Playwright test. The full test can be found below.

import { test, expect, selectors } from "@playwright/test";

test.describe("/admin Checks", async () => {
  let count = "100";

  test.beforeEach(async ({ page }) => {
    selectors.setTestIdAttribute("data-testid");

    // This calls an async function that exists at the bottom of this page, it takes the page instance and a number
    await mockMessageCount(page, count);
    await page.goto("https://automationintesting.online/");
    await page.getByRole("button", { name: "Let me hack!" }).click();
    await page.getByRole("link", { name: "Admin panel" }).click();
    await page.getByTestId("username").click();
    await page.getByTestId("username").fill("admin");
    await page.getByTestId("password").click();
    await page.getByTestId("password").fill("password");
    await page.getByTestId("submit").click();
  });

  test(`Validate Message Count is ${count}`, async ({ page }) => {
    await expect(page.getByRole("link", { name: "Logout" })).toHaveText(
      "Logout"
    );

    const messageCountSpan = page
      .locator('[href*="#/admin/messages"]')
      .locator("span");

    await expect(messageCountSpan).toHaveText(`${count}`);
  });
});

// This function uses the route class and fulfill intercepting what was sent form the server and fulfill it with our provided response (mocking!)
export async function mockMessageCount(page, messageCount) {
  await page.route("**/message/count", (route) =>
    route.fulfill({
      status: 200,
      body: JSON.stringify({ count: messageCount }),
    })
  );
}

Reviewing the docs will help give you more insight into what all is possible with the page.route class. Below is a brief summary of what is possible.

abort() Aborts the route's request.

continue() Continues route's request with optional overrides.

fallback()When several routes match the given pattern, they run in the order opposite to their registration. That way the last registered route can always override all the previous ones. In the example below, request will be handled by the bottom-most handler first, then it'll fall back to the previous one and in the end will be aborted by the first registered route.

fetch() Performs the request and fetches result without fulfilling it, so that the response could be modified and then fulfilled.

fulfill() Fulfills route's request with given response.


The code from the example can be found here at this repo.

playwright-demo/messageCount.spec.ts at master · BMayhew/playwright-demo
A Repo to show off some playwright scripts. Contribute to BMayhew/playwright-demo development by creating an account on GitHub.

Thanks for reading! If you found this helpful, reach out and let me know on LinkedIn or consider buying me a cup of coffee. If you want more content delivered to you in your inbox subscribe below.