API mocking in Playwright is a powerful technique for testing web applications by intercepting and simulating API responses without relying on real backend services. This allows you to isolate front-end testing, simulate various scenarios, and improve test reliability and speed. Below is a comprehensive guide to API mocking in Playwright, including key methods, examples, and best practices.
Why Mock APIs in Playwright?
Mocking APIs offers several benefits:
- Isolation: Test front-end logic independently of backend availability or consistency.
- Efficiency: Avoid delays from real API calls, making tests faster.
- Control: Simulate edge cases, errors, or specific responses (e.g., server errors, empty data).
- Cost Reduction: Eliminate costs associated with hitting live APIs, especially third-party ones.
- Reproducibility: Ensure consistent test results by controlling API responses.
Mock API requests
The following code will intercept all the calls to */**/api/v1/fruits and will return a custom response instead. No requests to the API will be made. The test goes to the URL that uses the mocked route and asserts that mock data is present on the page.
Before mocking.

Example :
import { test, expect } from '@playwright/test'; test.describe('Mocking an API call', () => { test('mocks a fruit and does not call api', async ({ page }) => { // Mock the api call before navigating await page.route('*/**/api/v1/fruits', async (route) => { const json = [{ name: 'Strawberry', id: 21 }]; await route.fulfill({ json }); }); // Go to the page await page.goto('https://demo.playwright.dev/api-mocking'); // Assert that the Strawberry fruit is visible await expect(page.getByText('Strawberry')).toBeVisible(); }); });
After mocking.
Modify API responses
Sometimes, it is essential to make an API request, but the response needs to be patched to allow for reproducible testing. In that case, instead of mocking the request, one can perform the request and fulfill it with the modified response.
In the example below we intercept the call to the fruit API and add a new fruit called 'Loquat', to the data. We then go to the url and assert that this data is there:
Before mocking.

Example
test.describe('Intercepting the request and modifying it', () => { test('gets the json from api and adds a new fruit', 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: 'Playwright', id: 100 }); // Fulfill using the original response, while patching the response body // with the given JSON object. await route.fulfill({ response, json }); }); // Go to the page await page.goto('https://demo.playwright.dev/api-mocking'); // Assert that the new fruit is visible await expect(page.getByText('Playwright', { exact: true })).toBeVisible(); }); });
After mocking.
Mocking with HAR files
To record a HAR file we use page.routeFromHAR() or browserContext.routeFromHAR() method. This method takes in the path to the HAR file and an optional object of options. The options object can contain the URL so that only requests with the URL matching the specified glob pattern will be served from the HAR File. If not specified, all requests will be served from the HAR file.
Setting update option to true will create or update the HAR file with the actual network information instead of serving the requests from the HAR file. Use it when creating a test to populate the HAR with real data.
The update option updates the given HAR file with the actual network information instead of serving from the file. In order to record the HAR file, you need to set update to true.
await page.routeFromHAR('./hars/fruits.har', { url: '*/**/api/v1/fruits', update: true, });
Example
test.describe('Mocking with HAR files', () => { test('records or updates the HAR file', async ({ page }) => { // Get the response from the HAR file await page.routeFromHAR('./hars/fruits.har', { url: '*/**/api/v1/fruits', update: true, }); // Go to the page await page.goto('https://demo.playwright.dev/api-mocking'); // Assert that the Playwright fruit is visible await expect(page.getByText('Strawberry')).toBeVisible(); }); test('gets the json from HAR and checks the new fruit has been added', async ({ page }) => { // Replay API requests from HAR. // Either use a matching response from the HAR, // or abort the request if nothing matches. await page.routeFromHAR('./hars/fruits.har', { url: '*/**/api/v1/fruits', update: false, }); // Go to the page await page.goto('https://demo.playwright.dev/api-mocking'); // Assert that the Playwright fruit is visible await expect(page.getByText('Strawberry')).toBeVisible(); }); });
When you run the test you will see that the HAR file has been recorded in the hars folder. You can open the HAR file and see the request and response information. Under the content section of the fruits.har file you will see the name of a '.txt' file with a hashed name. This file contains the JSON response from your API call and is located inside the hars folder.
With Playwright you can intercept Browser HTTP requests and run your tests against the mock data with the route and fulfill methods. You can also intercept the API call and modify the response by passing in the response and your modified data to the route.fulfill method. You can use the routeFromHAR method to record the API call and response and then use the HAR file to run your tests against instead of hitting the API each time. You can also modify the HAR file and run your tests against the modified data.
No comments:
Post a Comment