Automating OTP Login Flows With Service Virtualization
OTP-based authentication is one of the most challenging scenario to automate in end-to-end testing. Unlike passwords, OTPs are delivered through external systems such as SMS gateways, email providers, or messaging platforms. Once an application sends the OTP request, the test loses visibility into what happens next.
As a result, many teams either maintain special "test users" that bypass OTP validation or exclude OTP scenarios from automated test suites altogether. Both approaches reduce confidence in production-like testing.
A better alternative is to use service virtualization to observe, capture, and control OTP traffic while keeping the application behavior unchanged.
The above video is a complete tutorial on how to achieve this.
The application sends OTP requests through Beeceptor, which acts as a proxy between the application and the SMS provider (Twilio). Beeceptor records the request, forwards it to Twilio, and stores the complete payload in request history. The OTP still reaches the user's phone, but the test automation now has a reliable source from which it can retrieve the generated code.
When the application triggers an OTP, Beeceptor captures the outbound request and makes it available through its Request History API.
Playwright Test Script
The Playwright test remains straightforward and simple. It performs the normal user actions like fills the phone no, triggers OTP generation, retrieves the OTP from Beeceptor, and validates the successful login.
test('Send OTP, read it from Beeceptor, and auto-fill login form', async ({ page }) => {
await page.goto(APP_URL);
await page.click('#sendBtn');
await page.locator('#otpStep').waitFor({ state: 'visible' });
await sleep(5s); // Wait for the OTP trigger
const otp = await getLatestOtpFromBeeceptor(); // Query Beeceptor for latest OTP
await page.fill('#otp', otp);
await page.click('#verifyBtn');
await expect(page.locator('.header'))
.toHaveText(/Login successful/i);
});
Fetching the OTP
The interesting part happens behind the scenes. Instead of waiting for an SMS to arrive on a physical device, the automation queries Beeceptor's Request History API. The helper function polls the endpoint, retrieves recent requests, and searches multiple payload locations for an OTP value.
async function getLatestOtpFromBeeceptor() {
const response = await fetch(
`https://api.beeceptor.com/api/v2/endpoints/${BEECEPTOR_ENDPOINT_NAME}/requests?mode=verbose`,
{
headers: {
Authorization: BEECEPTOR_API_KEY,
Accept: 'application/json'
}
}
);
const requests = await response.json();
for (const req of requests.data) {
// Find first 4-8 digit OTP in the request payload that Beeceptor captured.
const match = req?.request?.body.match(/\b\d{4,8}\b/);
if (match) {
return match[0];
}
}
throw new Error('OTP not found');
}
The code handles different response formats and inspects request bodies and a simple regular expression extracts the OTP digits from the request's payload. This approach makes the automation resilient even when OTP formats vary slightly between environments.
Build Virtual API With AI
Modern AI-assisted tooling makes this process even easier. In the demo video, an MCP-enabled AI agent, Codex, analyzes Beeceptor's request history, identifies OTP traffic, and automatically creates a mock rule from the captured request-response pair.
The generated mock rule intercepts future OTP requests and returns a simulated response immediately. The Playwright test continues to retrieve the OTP from Beeceptor, but the request never reaches Twilio. The entire authentication workflow remains testable while eliminating SMS charges and reducing external dependencies.
Because the OTP is retrieved directly from the intercepted traffic from Beeceptor, the test no longer depends on SMS delivery delays, carrier latency, device availability, or third-party inbox integrations. Execution becomes faster and significantly more reliable, and saves cost of SMS delivery.
Summary
This pattern extends beyond OTP testing. Any workflow that relies on external communication can be validated in a similar way. You use service virtualization to automate email verification flows, password reset journeys, payment authorization callbacks, webhook processing, shipping notifications, fraud checks, and multi-factor authentication systems. Instead of interacting with external systems directly, tests observe the traffic flowing through the virtualized layer.
The benefits become even more significant at scale. Large regression suites often execute thousands of OTP scenarios daily. Each execution may generate billable SMS messages. Over time, SMS costs become substantial, especially when running parallel test environments across multiple branches and CI pipelines.
This is where service virtualization provides another advantage. Once traffic patterns are understood, the external dependency can be replaced entirely with a mock response. The application still behaves exactly as if the SMS provider were present, but no message is sent and no third-party infrastructure is involved.