Skip to content
Testing

Test sign-in and texting with real SMS.

A mocked code proves your form works. A real number proves the text arrives. Give each test its own line, read the code in one call, and run it on every push.

Three lines in your test.

Mark the number, trigger the text, then wait for the code. Only a text that arrives after the mark counts, so a stale code never passes a test and parallel runs never read each other's codes.

Why each test gets its own number

e2e/sign-in.spec.ts
const number = phonekit.number("sign-in-tests")
const after = await number.mark()

await page
  .getByRole("button", { name: "Send code" })
  .click()
const code = await number.waitForOtp({ after })

await page
  .getByLabel("Verification code")
  .fill(code)

✓ sign-in with SMS code (4.2 s)

Test anything your app texts.

Codes are where most teams start. Every wait returns the whole message, so the same test checks whatever your product sends.

  • Sign-in codes

    Sign-up, sign-in, phone change and two-step checks, with the code pulled out for you.

  • Invites and magic links

    Wait for the link, check where it goes, and open it in the browser your test controls.

  • Confirmations and alerts

    Bookings, orders, reminders and alerts. Assert on the text your product actually sent.

  • Conversations

    Text your product from your own numbers and check each reply, turn by turn.

Products that text, tested end to end.

If your product lives in the text channel, a code isn't enough. Give a test agent its own number, text your product and check the reply. Your numbers can text each other, so you can test a whole conversation.

Proven on every push.

Give CI a read-only key for its own numbers and one number per worker. A broken text path fails the build, not your users.

Run it in GitHub Actions

The details.

Numbers
US numbers. Standard is local VoIP; Mobile is a real SIM line, for flows that only text mobiles. VoIP or real SIM
Messages
The whole text of every message, with codes and links pulled out. Wait by sender, content or link. SDK
Freshness
Mark the number before the text is sent. Only a later text counts. One number per test
Waiting
The SDK checks every second until the deadline you set, up to an hour. SDK
Languages
JS/TS SDK for Node test runners, an HTTP API for any language, and a CLI for any shell. API
CI
A read-only key limited to its own numbers, with one number per worker. CI guide
Sending
Tests text inside a closed loop, with per-number limits. Limits
Price
From $29 a month for four numbers. Extra Standard numbers are $5 a month. Pricing

Questions

Can it read any text, not just codes?

Yes. Every wait returns the whole message: sender, body and time. Codes and links are pulled out for convenience, and you can wait for a message from a given sender, containing given text or linking to a given site.

Do I still need real SMS if I mock the code?

Keep the mocks for speed. Add one real journey for each way users sign in, so a broken text path fails a test instead of reaching users.

Which test frameworks and languages work?

The JS/TS SDK fits Playwright, Cypress and other Node test runners. The HTTP API works from any language, and the CLI works from any shell or CI step.

How long does a code take to arrive?

As long as the service that sends it takes. Phonekit hands the code over as soon as the text lands, and your test fails clearly at the deadline you set if nothing arrives.

Can tests run in parallel?

Yes. Give each worker its own number. Each test marks its number before the text is sent, so it never reads another run's code.

Does Phonekit replace my SMS provider?

No. Your app keeps sending through its own provider. Phonekit is the number that receives the text, and can text back within its limits.

Can I test a product that texts its users?

Yes. Give a test its own number, text your product and assert on the reply. Your numbers can text each other to test a whole conversation.

Get a number.

Tell us what you're testing. We'll set up your workspace.

Get a number