How to Mock and Stub API Calls in Playwright E2E Tests with Python
This code demonstrates how to mock and stub API responses in Playwright end-to-end tests using Python's unittest.mock patch and Playwright's APIRequestContext.
pip install playwright
Python code
27 linesimport re
from unittest.mock import patch
from playwright.sync_api import sync_playwright
def verify_api_mock(page, mock_url, mock_response):
with patch("playwright.sync_api.APIRequestContext.get") as mock_get:
mock_get.return_value.json.return_value = mock_response
mock_get.return_value.status_code = 200
page.goto("https://example.com")
result = page.evaluate(f"""() => fetch('{mock_url}').then(r => r.json())""")
return result
if __name__ == "__main__":
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
mock_data = {"user": "testuser", "id": 123}
result = verify_api_mock(page, "https://api.example.com/user", mock_data)
assert result == mock_data
print("Mock API test passed:", result)
print("Response keys:", sorted(result.keys()))
print("User:", result["user"])
browser.close()
Output
Mock API test passed: {'user': 'testuser', 'id': 123}
Response keys: ['id', 'user']
User: testuser
How it works
The test uses unittest.mock.patch to replace APIRequestContext.get with a mock that returns a controlled response. When the page code calls fetch() to a mocked URL, the patched method intercepts the request and returns the pre-defined JSON. This isolates the frontend from real backend dependencies, making tests fast and deterministic. The mock_get.return_value.json.return_value chain sets the mocked JSON payload, while status_code simulates a successful HTTP response. This pattern is perfect for E2E tests where you want to test UI behavior without relying on live APIs.
Common mistakes
- Patching the wrong target: use `playwright.sync_api.APIRequestContext.get`, not the page's fetch.
- Forgetting to set `status_code` on the mock, causing failures in code that checks HTTP status.
- Mocking `fetch` directly in the browser instead of patching the Python-side API client, which can lead to inconsistencies.
- Not restoring the patch after the test, potentially leaking mocks into other tests.
Variations
- Use `page.route` to intercept network requests and return mock responses instead of patching Python methods.
- Create a reusable pytest fixture that initializes the browser and mocks API responses.
Real-world use cases
- Testing UI flows in CI pipelines without depending on flaky external APIs.
- Simulating different API responses (success, error, empty) to verify frontend error handling.
- Stubbing backend endpoints when they are not yet implemented, enabling frontend development to proceed independently.
Sponsored
More from Testing & modern typing
- Capture stdout and stderr with pytest capsys easy
- Characterization Test for Legacy Python Code medium
- Dataclass with Type Hints Fields in Python easy
- Dependency Injection in Python for Testability easy
- Design Data Helpers with Python TypedDict and Literal easy
- Fix and Test a Regression Bug in Python with Unit Tests easy
Keep learning
Related tutorials and quizzes for this topic.