A Deep Dive into Requests Interception Using Playwright’s page.*: Key Differences and Best Practices for Test Automation

Sergii Domnenko
4 min readJan 20, 2025

Intercepting network requests is an essential feature in modern test automation, enabling testers to mock responses, validate outgoing requests, and simulate various network scenarios. Playwright, a powerful browser automation tool, offers a suite of features for request interception through its page.* APIs. This article will explore all available options for request interception in Playwright, provide practical examples, and conclude with a comparison table summarizing their differences and best practices.

Why Intercept Network Requests?

Intercepting network requests during automated testing can help you:

  • Mock API responses to isolate tests from backend changes or downtime.
  • Test how the application handles slow or failed network calls.
  • Validate outgoing requests and ensure adherence to API contracts.
  • Control test data dynamically without modifying server behaviour.

Playwright provides several methods for achieving these goals. Let’s explore each.

1. page.route

The page.route method allows you to define a handler for specific network requests. This handler can modify, fulfill, or abort requests based on custom logic.

Example Usage:

  await page.route('**/api/data', route => {
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ message: 'Mocked data' })
});
});

Features:

  • Granular control: Match requests using glob patterns or regular expressions.
  • Handlers: Use handlers to mock responses, abort requests, or pass through original requests.

Best Use Cases:

  • Mocking API calls for frontend tests.
  • Simulating edge cases, such as server errors or delays.

2. page.on('request') and page.on('response')

Playwright’s event listeners provide insights into network activity by exposing request and response events. These methods are useful for validating request parameters and response content.

Example Usage:

  page.on('request', request => {
console.log(`Request made: ${request.url()} - ${request.method()}`);
});
page.on('response', response => {
console.log(`Response received: ${response.url()} - ${response.status()}`);
});

Features:

  • Real-time monitoring: Logs network activity during test execution.
  • Validation: Verify outgoing requests and incoming responses.

Best Use Cases:

  • Debugging network issues.
  • Verifying API integration behaviour.

3. page.on('requestfailed')

The page.on('requestfailed') event is triggered when a network request fails. This can be useful for debugging failed requests or testing how the application handles such scenarios.

Example Usage:

page.on('requestfailed', request => {
console.log(`Request failed: ${request.url()} - ${request.failure()?.errorText}`);
});

Features:

  • Error tracking: Captures failure reasons such as DNS errors or connection timeouts.
  • Debugging: Provides insights into why specific requests failed.

Best Use Cases:

  • Testing how the application handles network failures.
  • Debugging connectivity issues.

4. page.on('requestfinished')

The page.on('requestfinished') event is triggered when a network request is completed. This can be used to validate the sequence and completion of network activity.

Example Usage:

page.on('requestfinished', request => {
console.log(`Request finished: ${request.url()} - ${request.method()}`);
});

Features:

  • Completion tracking: Monitors when network requests have been completed.
  • Validation: Ensures all expected requests are successfully processed.

Best Use Cases:

  • Verifying that all expected network requests are completed.
  • Tracking resource loading during page interactions.

5. page.waitForRequest()

The page.waitForRequest method allows you to wait for a specific request to be made. This is particularly useful in scenarios where actions on the page trigger network requests.

Example Usage:

await page.click('button#submit');
const request = await page.waitForRequest('**/api/submit');
console.log(`Request made to: ${request.url()}`);

Features:

  • Targeted waiting: Ensures specific requests are made before proceeding.
  • Synchronization: Avoids flaky tests by waiting for network activity.

Best Use Cases:

  • Synchronizing tests with network calls triggered by user interactions.
  • Debugging dynamic behavior that depends on API requests.

6. page.route with Conditional Handling

Using page.route, you can implement conditional logic to handle different requests in unique ways. This is especially useful for applications with dynamic API behavior.

Example Usage:

await page.route('**/api/*', route => {
if (route.request().url().includes('/users')) {
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ users: [] })
});
} else {
route.continue();
}
});

Features:

  • Dynamic handling: Customize behavior for specific endpoints.
  • Fallback options: Use route.continue() to pass unhandled requests through.

Best Use Cases:

  • Mocking complex APIs with multiple endpoints.
  • Combining mock responses with live requests.

7. context.route

While page.route works at the page level, context.route applies request interception rules to all pages within a browser context.

Example Usage:

await context.route('**/api/global', route => {
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ globalData: true })
});
});

Features:

  • Global scope: Automatically applies to all pages in the context.
  • Convenience: Simplifies test setup for multi-page workflows.

Best Use Cases:

  • Testing applications with multi-tab or multi-page functionality.
  • Mocking shared API responses across multiple pages.

Comparison Table

Best Practices for Request Interception

  1. Use Glob Patterns Wisely: Avoid overly generic patterns like **/*, which may unintentionally match unintended requests.
  2. Leverage context.route for Multi-Page Scenarios: Simplify setups by intercepting requests at the context level for workflows involving multiple tabs.
  3. Combine Interception and Monitoring: Use page.route to mock or modify requests, and page.on('response') to validate the application’s behavior.
  4. Synchronize with page.waitForRequest: Ensure actions triggering network requests are fully processed before proceeding.
  5. Clean Up After Tests: Ensure all routes and event listeners are removed to avoid memory leaks and unpredictable behaviour in subsequent tests.

Conclusion

Playwright provides a comprehensive toolkit for intercepting and handling network requests. Whether you need to mock API responses, validate network activity, or simulate edge cases, its page.* and context.* APIs have you covered. By understanding their features, limitations, and best use cases, you can enhance your test automation framework and create robust, reliable tests.

Happy testing!

--

--

Sergii Domnenko
Sergii Domnenko

Written by Sergii Domnenko

QA Lead with various experience in testing. Sharing aggregated practical knowledge with wide audience. Test Automation, Improvements, Review, Coaching.

No responses yet