This guide shows how to run an OTP test for SMS-based MFA using Playwright.

For a broader checklist across email OTP, SMS OTP, magic links, TOTP, expiry, resends, and one-time-use checks, start with the [OTP testing and OTP checker workflow guide](/blog/otp-testing/).

## Quick answer: what is an OTP test?

An OTP test validates that one-time passcodes are sent, received, parsed, and accepted correctly during sign-up or login workflows.

For a complete release check, keep the browser journey primary, then verify the delivered SMS or email artifact: sender, body, code extraction, links, timing, and saved evidence.



{{LANDING_SHORTCODE:POST_CTA_BANNER:%7B%22title%22%3A%22Add%20message%20evidence%20after%20the%20OTP%20test%20passes%22%2C%22content%22%3A%22Use%20MailSlurp%20when%20Playwright%20auth%20tests%20need%20the%20OTP%20to%20arrive%2C%20the%20browser%20flow%20to%20complete%2C%20and%20the%20related%20email%20message%20to%20stay%20readable%20before%20release.%22%2C%22buttonHref%22%3A%22%2Fproduct%2Fdevice-previews%2F%22%2C%22buttonText%22%3A%22Explore%20device%20previews%22%2C%22buttonTheme%22%3A%22blue%22%2C%22image%22%3A%22%2Fassets%2Fhome%2Fdevice-render-devices.png%22%2C%22imageAlt%22%3A%22Email%20preview%20workflow%20across%20supported%20client%20and%20device%20contexts%22%2C%22imageWidth%22%3A%22800%22%2C%22imageHeight%22%3A%22415%22%2C%22imagePosition%22%3A%22%22%7D}}



## Why automate OTP tests?

- Authentication is a release-critical path
- Manual OTP testing is slow and inconsistent
- Real phone number flows expose production-like failure modes

## Test flow overview

1. Create a test phone number
2. Open application sign-up page with Playwright
3. Submit registration form
4. Wait for inbound SMS OTP code
5. Enter code and confirm successful login

In this guide we use a demo SMS auth app at [playground-sms.mailslurp.com](https://playground-sms.mailslurp.com).


[![MailSlurp video](https://img.youtube.com/vi/fsN_PXh9riM/hqdefault.jpg)](https://www.youtube.com/watch?v=fsN_PXh9riM)
[Open video on YouTube](https://www.youtube.com/watch?v=fsN_PXh9riM)


## Playwright setup

### Create project

```sh
mkdir test
cd test
npm init -y
```

### Install Playwright

```sh
npm init playwright@latest
```

## Implement OTP test with Playwright

### Load sign-up page



```typescript
// load playground app
await page.goto("https://playground-sms.mailslurp.com");
await page.click('[data-test="sign-in-create-account-link"]');
```



### Fetch a test phone number



```typescript
// fetch a phone number in US from our account
const mailslurp = new MailSlurp({ apiKey })
const { content }= await mailslurp.phoneController.getPhoneNumbers({
  phoneCountry: GetPhoneNumbersPhoneCountryEnum.US
})
const phone = content?.[0]!!
```



### Fill and submit registration form



```typescript
const password = "test-password-123"
// fill sign up form
await page.fill('input[name=phone_line_number]', phone.phoneNumber.replace("+1", ""));
await page.fill('input[name=password]', password);
```



### Wait for SMS and extract OTP



```typescript
// wait for the latest unread sms
const [sms] = await mailslurp.waitController.waitForSms({
  waitForSmsConditions: {
    count: 1,
    unreadOnly: true,
    phoneNumberId: phoneNumber.id,
    timeout: 30_000,
  },
});
// extract a code from body with regex
expect(sms.body).toContain("Your code: 123");
const [, code] = /.+:\s([0-9]{3})/.exec(sms.body)!!;
expect(code).toEqual("123");
```



### Submit OTP and verify account access



```typescript
// enter confirmation code
await page.fill('[data-test="confirm-sign-up-confirmation-code-input"]', code);
```





```typescript
await page.click('[data-test="confirm-sign-up-confirm-button"]');
```





```typescript
// fill out username (email) and password
await page.fill('[data-test="username-input"]', phone.phoneNumber);
await page.fill('[data-test="sign-in-password-input"]', password);
```





```typescript
// submit
await page.click('[data-test="sign-in-sign-in-button"]');
await page.waitForSelector("[data-test='greetings-nav']")
```



## Cross-framework note

The same OTP test pattern works in Cypress and Selenium:

- Create controlled number
- Trigger auth flow
- Wait for code
- Assert confirmation success

See [email and SMS testing guides](/guides/email-testing/) for related workflows.

## Related pages

- [OTP testing and OTP checker workflow guide](/blog/otp-testing/)
- [SMS API guide](/mobile/sms-api/)
- [Phone number SMS service](/product/phone-number-sms-service/)
- [Email for testing accounts](/guides/email-for-testing-test-email-accounts/)

## SMS OTP release checklist

Before shipping authentication changes, verify this sequence:

- Exercise auth sign-up and login paths in [Email Sandbox](/product/email-sandbox/).
- Run regression suites in CI with [Email Integration Testing](/product/email-integration-testing/).
- Capture OTP delivery and verification events through [Email Webhooks](/guides/email-webhooks/).
- Apply fraud-response and retry logic with [Email Automation Routing](/product/email-automation-routing/).
- Confirm delivery timing reliability with an [Email Deliverability Test](/testing/email-deliverability-test/).
- Preview related auth, invite, or reset emails with [Device previews](/product/device-previews/) when the flow sends an email alongside SMS.

## Final take

A reliable OTP test should run in CI for every release candidate. When auth flows break, users cannot onboard or sign in, so this is one of the highest ROI test suites to automate.
