Mocking OTP Send and Verify APIs in Playwright

Here’s a blog post draft for mocking OTP scenarios using Playwright:
Mocking APIs during end-to-end (E2E) testing ensures faster and more reliable tests by eliminating dependencies on external services. In this blog, we’ll explore how to mock OTP send and OTP verify APIs using Playwright.
By the end of this tutorial, you’ll learn to:
Mock OTP send success and failure.
Mock OTP verify success and failure.
Let’s get started!
Why Mock API Calls in E2E Tests?
Reliability: Avoid flaky tests caused by slow or unreliable API responses.
Flexibility: Test edge cases like API failures easily.
Speed: Run tests faster by skipping real API calls.
Playwright simplifies API mocking with its powerful route
method, allowing you to intercept and mock requests during test execution.
Step 1: Setup Playwright
First, ensure Playwright is installed in your project. If not, install it using:
npm install @playwright/test
Update your test file or configuration to use the Playwright Test Runner.
Step 2: Mock OTP Send
Let’s start by mocking the OTP send API.
Scenario 1: OTP Send Success
Here’s how to simulate a successful OTP send response:
import { test, expect } from '@playwright/test';
test('should mock OTP send success', async ({ page }) => {
// Intercept the OTP send request
await page.route('**/api/send-otp', async (route) => {
// Respond with a success message
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
success: true,
message: 'OTP sent successfully',
}),
});
});
// Navigate to the login page
await page.goto('https://example.com/login');
// Simulate user input and OTP send
await page.fill('#phone-input', '9876543210');
await page.click('#send-otp-button');
// Validate success message
const otpSendMessage = await page.textContent('#otp-send-message');
expect(otpSendMessage).toBe('OTP sent successfully');
});
Scenario 2: OTP Send Failure
For failure scenarios, return an error response like this:
test('should mock OTP send failure', async ({ page }) => {
// Intercept the OTP send request
await page.route('**/api/send-otp', async (route) => {
// Respond with an error message
await route.fulfill({
status: 400,
contentType: 'application/json',
body: JSON.stringify({
success: false,
message: 'Failed to send OTP. Please try again.',
}),
});
});
// Simulate user input and OTP send
await page.fill('#phone-input', '1234567890');
await page.click('#send-otp-button');
// Validate error message
const otpSendError = await page.textContent('#otp-send-error');
expect(otpSendError).toBe('Failed to send OTP. Please try again.');
});
Step 3: Mock OTP Verify
Next, let’s mock the OTP verification API.
Scenario 1: OTP Verify Success
Simulate a successful OTP verification like this:
test('should mock OTP verify success', async ({ page }) => {
// Intercept the OTP verify request
await page.route('**/api/verify-otp', async (route) => {
// Respond with a success message
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
success: true,
message: 'OTP verified successfully',
}),
});
});
// Simulate user input and OTP verification
await page.fill('#otp-input', '123456');
await page.click('#verify-otp-button');
// Validate success message
const successMessage = await page.textContent('#login-success-message');
expect(successMessage).toBe('Login successful!');
});
Scenario 2: OTP Verify Failure
For failure scenarios, mock an invalid OTP response:
test('should mock OTP verify failure', async ({ page }) => {
// Intercept the OTP verify request
await page.route('**/api/verify-otp', async (route) => {
// Respond with an error message
await route.fulfill({
status: 401,
contentType: 'application/json',
body: JSON.stringify({
success: false,
message: 'Invalid OTP. Please try again.',
}),
});
});
// Simulate user input and OTP verification
await page.fill('#otp-input', '000000');
await page.click('#verify-otp-button');
// Validate error message
const errorMessage = await page.textContent('#otp-verify-error');
expect(errorMessage).toBe('Invalid OTP. Please try again.');
});
Bonus: Dynamic OTP Verification
To simulate dynamic responses based on the OTP value:
await page.route('**/api/verify-otp', async (route, request) => {
const requestBody = JSON.parse(request.postData());
const response = requestBody.otp === '123456'
? { success: true, message: 'OTP verified successfully' }
: { success: false, message: 'Invalid OTP' };
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(response),
});
});
This enables you to mock different responses based on the OTP entered by the user.
Conclusion
By using Playwright’s route
method, you can easily mock OTP send and verify APIs to test both success and failure scenarios. This approach ensures your tests are:
Independent of backend APIs.
Reliable, even when external services are unavailable.
Capable of testing edge cases effectively.
Key Takeaways
Use
page.route
to intercept and mock network requests.Use
route.fulfill
to provide custom responses.Simulate user interactions and validate results with assertions.
Mocking API calls allows you to focus on testing your app’s frontend behavior without worrying about backend dependencies. Try these examples in your Playwright tests and share your feedback!
Happy Testing!
Subscribe to my newsletter
Read articles from Pawan Gangwani directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Pawan Gangwani
Pawan Gangwani
I’m Pawan Gangwani, a passionate Full Stack Developer with over 12 years of experience in web development. Currently serving as a Lead Software Engineer at Lowes India, I specialize in modern web applications, particularly in React and performance optimization. I’m dedicated to best practices in coding, testing, and Agile methodologies. Outside of work, I enjoy table tennis, exploring new cuisines, and spending quality time with my family.