Developers
How to test an SMS OTP flow: a checklist beyond “the code arrived”
·SMS.Red·Markdown
A good SMS OTP test checks the whole authentication journey: destination entry, code request, waiting, resend, code validation, expiry and recovery. Successful delivery is one observation, not proof that the flow handles duplicate messages, leading zeros, late arrivals or repeated submission safely.
Use synthetic messages and isolated sender stubs for most automated tests. Reserve real receiving orders for a small, explicitly budgeted acceptance check against the system you are authorized to test. This separates repeatable application behavior from carrier delivery and avoids buying numbers to run every unit case.
Define the states before writing tests
List the states your user can encounter: no number entered, invalid destination, request in progress, waiting for a code, resend unavailable, code submitted, rejected code, expired attempt and successful verification. Also define the result of a lost response: an uncertain request is not the same as a confirmed failure.
Write expected transitions between these states. The interface should not invite a second request merely because the first is slow. It should also distinguish an app policy rejection from a delivery delay, since those require different recovery instructions.
The minimum input-and-code matrix
- Paste an international number into both single-field and country-selector forms; confirm the resulting destination.
- Enter a code with leading zeros and verify that it remains a string.
- Paste a code with surrounding whitespace and check the documented normalization behavior.
- Deliver two messages out of order and ensure the active challenge is not matched solely by “last item received.”
- Submit a code twice and verify the second submission cannot create another authenticated result.
- Deliver a message after challenge expiry and ensure the UI explains why delivery did not make it valid.
OWASP's OTP guidance recommends short validity, single use and strict attempt limits. Test your implementation's chosen policy explicitly rather than assuming your SMS provider enforces the entire account flow.
Test resend and latency independently
Use a stub that delays delivery, returns no message, or delivers the earlier request after a later one. Verify that the resend control follows your server's policy and that a browser refresh does not reset a server-side attempt limit.
Twilio's retry guidance explains why retry buffers reduce repeated messages and unnecessary spend. Its example timing is provider-specific; choose and test your own policy for the authentication system you operate. For a third-party app, follow that app's displayed timer instead.
Test the receiving integration as its own boundary
With SMS.Red, discover the service from the account/store catalog, request an exact duration quote, and keep the assigned order ID. Read the actual expiresAt value rather than constructing an expiry from your requested duration. Test message pagination and preserve the full text even when an extracted code is present.
Simulate an uncertain purchase response before performing any live test. Persist the idempotency key and approved price ceiling, then reconcile through the purchase-attempt endpoint. The purchase-safety guide explains why a new key is a new intended purchase, not a harmless retry.
Keep evidence useful without exposing codes
Record request and receipt times, order identifiers, transitions and redacted error details. Avoid logging real OTPs or full SMS bodies. Make screenshots and test reports use synthetic values; a passing test should not publish a still-valid credential.
For a real acceptance check, define success in advance: one intended order, known maximum spend, correct destination, received message associated with that order and no duplicate purchase. A missing carrier message should be recorded as a delivery observation, not silently replaced with a fabricated successful code.
FAQ
Do all automated tests need a paid SMS number?
No. Most state, parsing and retry cases should use isolated fixtures. A real test checks the delivery boundary and needs its own budget and authorization.
Should I extract only the first six digits from any SMS?
No. Message formats vary, and unrelated numeric content can appear. Keep full text, use the known sender/application context and test extraction deliberately.
What is the most important timeout test?
Verify that a lost purchase response cannot cause a second order through a newly generated idempotency key.
Get a number on SMS.Red
The same products as these guides: a 20-minute OTP or a rental.
Open the dashboard