Mock The API Data (Request & Responses) With Playwright

KailashPathak
8 min readMay 28, 2024

--

What covered in this Blog

How mocking is beneficial?
Mocking Data at the time of request
Mocking Data at the time of getting the response
How to mock data In Playwright with example in detail?

Mocking API responses” refers to the practice of creating simulated responses from an API without actually interacting with the real API. This technique is commonly used in software development, especially during testing phases, to mimic the behavior of real API endpoints. By using mock responses, developers can isolate specific parts of their code for testing purposes without relying on external services, thus enabling more efficient and controlled testing environments.

There are various tools and libraries available for mocking API responses in different programming languages and frameworks.Mocking API responses with Playwright is a useful technique for testing your web applications without relying on real API servers. It allows you to simulate different scenarios and responses from your APIs, making your tests more robust and independent of external services.

How mocking is beneficial

Mocking API responses using tools like Playwright can offer several benefits. Some of the benefit explained below

Isolation for Testing: By mocking API responses, you can isolate the testing of front-end and back-end components. This means that you can thoroughly test the behavior of your front-end application without being dependent on the availability or consistency of the back-end services.

Efficiency in Testing: Mocking responses allows testers to simulate various scenarios and edge cases without relying on the actual back-end infrastructure. This can speed up the testing process significantly, as you can quickly simulate different responses without waiting for the actual APIs to respond.

Controlled Testing Environment: With mocked responses, you have full control over the data and scenarios your tests encounter. This allows you to create specific test cases to cover various scenarios, such as successful responses, error responses, or edge cases.

Cost Reduction: Using mocked responses reduces the need for making actual API calls during testing, which can save on API usage costs, especially when dealing with third-party services that may have usage-based pricing models.

Testing Edge Cases: With mocked API responses, you can simulate various scenarios, including error conditions, edge cases, and situations that might be difficult or impossible to reproduce with the actual API. This enables more comprehensive testing of your application’s error handling and resilience.

Mocking data using Playwright

In Playwright, the page.route() method is used to intercept and modify network requests made by a web page. This method allows you to intercept specific requests and respond to them programmatically.

Here’s how the page.route() method works:

Route Setup: You call the page.route() method and provide a URL pattern or a predicate function that matches the requests you want to handle. The method returns a Route object.

const route = await page.route('**/api/data', route => {…});

Request Interception: When the page makes a request that matches the specified URL pattern or predicate function, Playwright intercepts the request and pauses it before sending it out.

Request Handling: The page.route() method takes a callback function that receives the intercepted Route object. Within this callback, you can perform various actions on the intercepted request:

  • Continue the request: Call route.continue() to allow the request to be sent as-is.
  • Fulfill the request: Call route.fulfill() to provide a custom response for the request without sending it to the server.
  • Abort the request: Call route.abort() to cancel the request and return an error.

Response Handling: If you continue the request, Playwright will receive the response from the server and complete the request lifecycle. If you fulfilled the request, the provided custom response will be used instead.

Mocking API Data In Playwright

In Playwright, using the page.route() method, you can indeed mock data at both the time of request interception and response interception.

Mocking Data at the Time of Request:

When a request is intercepted, you have the opportunity to modify it before it is sent. This means you can manipulate the request headers, body, URL, method, etc. to match your testing scenario or to simulate different conditions. For example, you can change the request parameters, add custom headers, or even redirect the request to a different endpoint.

Mocking Data at the Time of Response:

Once the request is sent, and a response is received (or intercepted), you can also modify the response data before it reaches the browser. This allows you to simulate various server responses without actually making requests to the server. You can provide custom response bodies, set specific HTTP status codes, modify response headers, or even simulate error conditions.

Example Mocking API Data In Playwright

Here’s a simple example demonstrating the usage of page.route() in Playwright:

Let’s say you have a web page that makes a request to an API endpoint https://demo.playwright.dev/api-mocking/ . You want to intercept this request and provide a mock response for testing purposes.

Example :

Mocking Data at the time of requesting the data:

Let’s consider the example of the “api-mocking” demo from the Playwright website (https://demo.playwright.dev/api-mocking). Here’s how we can use Playwright to mock the API response at the time of the request:

const { test, expect } = require("@playwright/test");
test("mocks a fruit and doesn't call api", async ({ page }) => {
// Mock the api call before navigating
await page.route("*/**/api/v1/fruits", async (route) => {
const json = [
{ name: "Lucuma", id: 11 },
{ name: "Guava", id: 12 },
{ name: "Kiwi", id: 13 },
{ name: "Peach", id: 14 },
{ name: "Fig", id: 15 },
];
await route.fulfill({ json });
});
// Go to the page
await page.goto("https://demo.playwright.dev/api-mocking");
// Assert that the Raspberries fruit is visible
await expect(page.getByText("Guava")).toBeVisible();
});

Code Walkthrough:

const { test, expect } = require(“@playwright/test”);

This line imports the test and expect functions from the Playwright testing library.

test("mocks a fruit and doesn't call api", async ({ page }) => {
// …
});

This is a Playwright test case. The test function takes a description string and an asynchronous callback function. The callback function receives an object with the page property, which represents the browser page instance.

await page.route("\\*\\/\*\\/api/v1/fruits", async (route) => {
const json = [
{ name: "Lucuma", id: 11 },
{ name: "Guava", id: 12 },
{ name: "Kiwi", id: 13 },
{ name: "Peach", id: 14 },
{ name: "Fig", id: 15 },
];
await route.fulfill({ json });
});

This part of the code sets up a mock for the /api/v1/fruits API route. Whenever the browser navigates to a URL that matches this route pattern, the provided callback function will be executed. Inside the callback, an array of fruit objects is created, and the route.fulfill method is called with this array as the response data. This means that instead of making an actual API call, the test will receive the mocked data.

await page.goto("https://demo.playwright.dev/api-mocking");

This line navigates the browser page to the specified URL.

await expect(page.getByText("Guava")).toBeVisible();

After navigating to the page, this line asserts that the text “Guava” (which is one of the mocked fruit names) is visible on the page. The getByText method is used to retrieve the element containing the given text, and the toBeVisible assertion checks if that element is visible.

Execute the test case

Let’s execute the test case using below command

npx playwright test tests/mockRequest.spec.js - ui

In the screenshot below you can see five fruits that we added or / mock displaying in below screen.

Example :

Mocking Data at the time of getting the Response:

Let’s look at an example of mocking data at the time of the response using the https://demo.playwright.dev/api-mocking

const { test, expect } = require("@playwright/test");
test("Modify API responses ", async ({ page }) => {
// Get the response and add to it
await page.route("*/**/api/v1/fruits", async (route) => {
const response = await route.fetch();
const json = await response.json();
json.push(
{ name: "Dragon fruit", id: 11 },
{ name: "Gooseberries", id: 12 },
{ name: "Coconut", id: 13 }
);
// Fulfill using the original response, to modify the response with given JSON object.
await route.fulfill({ response, json });
});
// Go to the page
await page.goto("https://demo.playwright.dev/api-mocking");
// Assert to verify that the new fruit is visible
await expect(page.getByText("Dragon fruit", { exact: true })).toBeVisible();
});

Code Walkthrough:

const { test, expect } = require("@playwright/test");

This line imports the test and expect functions from the @playwright/test module. The test function is used to define a test case, and the expect function is used for making assertions in the test case.

test("Modify API responses ", async ({ page }) => {

Inside the test function, an asynchronous function is defined using the async keyword. This function takes a page object as a parameter, which represents the browser page that Playwright will interact with.

await page.route("\\*/\\*\\*/api/v1/fruits", async (route) => {

This line sets up a route interception for any URLs that match the pattern */*/api/v1/fruits. The async function passed as the second argument to page.route will be called whenever a request matches this pattern.

const response = await route.fetch();
const json = await response.json();

Inside the async function, route.fetch() is used to fetch the original response for the intercepted request. Then, response.json() is used to parse the response body as JSON.

json.push(
{ name: "Dragon fruit", id: 11 },
{ name: "Apple", id: 12 },
{ name: "Mango", id: 13 }
);

This line modifies the parsed JSON data by adding three new objects representing fruits. js

await route.fulfill({ response, json });

The route.fulfill method is used to fulfill the intercepted request with a modified response. The response option is set to the original response object, and the json option is set to the modified JSON data.

await page.goto("https://demo.playwright.dev/api-mocking");

This line navigates the browser page to the URL https://demo.playwright.dev/api-mocking

await expect(page.getByText(“Dragon fruit”, { exact: true })).toBeVisible();

Finally, this line asserts that the text “Dragon fruit” is visible on the page. The page.getByText method is used to select an element containing the specified text, and the expect(…).toBeVisible() assertion checks if the selected element is visible on the page.

Modern software development requires API testing, and Playwright offers a strong, adaptable framework for building thorough API test suites. You can create tests that cover every step of the application flow with Playwright, from interacting with UI elements to submitting API queries and validating the responses. As a result, Playwright turns into an extraordinarily comprehensive tool that enables you to test the UI’s connection with the API and provides you with a comprehensive understanding of your application’s capabilities.

Execute the test case

Let’s execute the test case using below command

npx playwright test tests/mockResponce.spec.js - ui

In the below screenshot you can see three new fruits (Dragon fruit,Apple,Mango) are added and displaying in below screenshot

Story originally publish at https://talent500.co/blog/mock-the-api-data-with-playwright/

Wrapping up

In conclusion, mocking API responses with Playwright is a powerful technique for testing web applications that rely on external APIs. By intercepting and modifying API responses, developers can simulate various scenarios and edge cases that would be difficult to reproduce.Overall, Playwright’s API mocking capabilities provide developers with a powerful tool for building robust and reliable web applications, enabling them to write more comprehensive tests and catch potential issues earlier in the development cycle.

--

--

KailashPathak

|| Cypress.io Ambassador || https://qaautomationlabs.com/blog || PMI-ACP® |ITIL® || PRINCE2® || Cypress|| Selenium| WebdriverIO |API Automation QATube®