Tutorial · 5 min read

Playwright SMS verification: automate OTP in E2E tests

Provision a number, drive the signup with Playwright, and read the OTP from the Eveses API inside your test — full TypeScript example.

Phone verification is the wall most end-to-end suites hit. With a programmatic number you can test the real signup, code and all.

The pattern

  1. Buy a number before the test.
  2. Type it into the signup form.
  3. Poll the API for the code, type it in.
  4. Finish the order in teardown.
import { test, expect } from '@playwright/test';
import { Eveses } from '@eveses/sdk';

const eveses = new Eveses({ key: process.env.EVESES_KEY! });

test('phone signup', async ({ page }) => {
  const order = await eveses.orders.create({
    country: 'ua', mode: 'activation', service: 'yourapp',
  });

  await page.goto('/signup');
  await page.getByLabel('Phone').fill(order.phone);
  await page.getByRole('button', { name: 'Send code' }).click();

  // wait for the OTP via the API, not the UI
  const code = await poll(() => eveses.orders.sms(order.order_id)
    .then(o => o.sms?.[0]?.otp));

  await page.getByLabel('Code').fill(code);
  await expect(page.getByText('Welcome')).toBeVisible();

  await eveses.orders.finish(order.order_id);
});

async function poll<T>(fn: () => Promise<T | undefined>, ms = 1500): Promise<T> {
  for (;;) { const v = await fn(); if (v) return v; await new Promise(r => setTimeout(r, ms)); }
}

Because you only pay for delivered codes (with refunds for misses), a flaky run doesn't cost you. Run it in CI on every PR — buy the number in a beforeAll, finish it in afterAll.


Ready to build? Create a free Eveses account, top up a wallet, and grab your API key — no KYC. See the API docs or live pricing.

FAQ

▸Can Playwright tests receive a real SMS code?
Yes — provision a number from the API, then read the OTP via GET /orders/{id}/sms while Playwright drives the UI.
▸Is this safe to run in CI?
Yes. Store the API key as a CI secret, buy a number per run, and finish it in teardown so you only pay for delivered codes.
Related guides