How to test a signup flow
Test signup validation, duplicate emails, account enumeration, verification emails, and post-signup state with plain-English scenarios.
Signup is the worst flow to break, for one specific reason: the people who hit the bug are, by definition, not your users yet. They don't file a ticket. They don't email support. They close the tab, and your only evidence is a dip in a conversion chart someone checks on Thursdays.
It's also one of the most bug-dense flows in a typical web app, because it touches everything at once — client validation, server validation, the database's uniqueness constraints, an email service, a session layer, and a redirect. Six systems, one form.
This is the playbook for testing all of it without writing a line of test code: what "testing signup" actually has to cover, and the plain-English prompts to cover it. The same structure we used for magic-link auth, applied to the flow that feeds it.
What "testing the signup flow" actually means
The happy path — valid email, valid password, lands on dashboard — is maybe a fifth of the surface. A real check covers:
- Input validation, both sides. Empty fields, malformed emails, weak passwords — rejected with errors a human can act on. And critically: the client and the server must agree on the rules.
- Password policy sanity. NIST SP 800-63B says passwords must be at least 8 characters and that verifiers should permit at least 64, so passphrases work. The classic shipped bug is a mismatch: client allows 200 characters, server (or its bcrypt call, which truncates input at 72 bytes) effectively doesn't. The user signs up successfully and can never log in again.
- Duplicate accounts. Signing up twice with the same email fails cleanly the second time — including with case variations (
Bob@example.comvsbob@example.com) and Gmail-style plus-aliases if you treat those as equivalent. - Account enumeration. The duplicate-email error shouldn't be a user-existence oracle. OWASP's Authentication Cheat Sheet covers this under response discrepancy: wording and timing shouldn't reveal whether an address is registered. (There's a real tension here with usability — many products deliberately accept the leak on signup and mitigate with rate limiting. The point is to decide, not to ship the leak by accident.)
- The verification email. It arrives, the link works, the link works only once, and an unverified account is in the state you intended — blocked, limited, or grace-period — not some accidental fourth state.
- Post-signup state. The session is live, the dashboard renders for a brand-new user (empty states!), and the welcome email doesn't fire twice.
- The double-submit. Two fast clicks on "Create account" make one account, not two — and not one account plus one unhandled 500.
Most teams test items 1 and 6 manually, ship, and discover items 2, 4, and 7 from production weirdness over the following year. The prompts below are ordered to catch the expensive ones first.
Prompt 1: validation, both sides of the wire
Test signup validation on https://staging.yourapp.com/signup.
Try each of these and confirm the form rejects it with a clear,
specific error message:
1. Empty email, empty password
2. "not-an-email" as the email
3. A valid email with a 4-character password
4. A valid email with a password of only spaces
Then try a password of exactly 100 characters with a valid email.
If signup succeeds, IMMEDIATELY try logging in with that same
email and password on /login. If login fails after a successful
signup, flag it as a critical bug.
Watch the network tab throughout: flag any request that returns
4xx/5xx without a corresponding visible error in the UI.That second paragraph is the client/server mismatch test — the silent account-killer from item 2. The agent signs up and then verifies the credential round-trips. A scripted suite almost never checks this because the signup test and the login test are different files with different fixtures.
Prompt 2: duplicates and what the error reveals
On https://staging.yourapp.com/signup:
1. Sign up with "dup-test@yourapp.test" and a valid password.
Confirm it succeeds.
2. Open a fresh incognito window and sign up again with the exact
same email. Confirm it fails with a sensible error.
3. Try once more with "DUP-TEST@yourapp.test" (different casing).
Report whether this creates a second account or is treated as
a duplicate.
4. Record the exact wording of the duplicate-email error. Note
whether it confirms the account exists, and how long the
response took compared to a successful signup.Step 3 finds the case-sensitivity bug that creates two accounts for one human, which surfaces months later as "I logged in and all my data is gone." Step 4 gives you the evidence to make the enumeration call from item 4 deliberately — wording and timing, recorded, per OWASP's guidance.
Prompt 3: the verification email
Same setup requirement as the magic-link playbook: a test inbox the agent can read — a catch-all domain or a hosted inbox service — passed in via your scenario config rather than hardcoded.
Sign up on https://staging.yourapp.com/signup with
"verify-test@yourapp.test" and a valid password.
1. Note what the app says happens next (e.g. "check your email").
2. Before verifying: try to use the app. Report exactly what an
unverified account can and cannot do.
3. Open the test inbox at {{INBOX_URL}}, find the verification
email, and click the link. Confirm the account becomes verified
and the UI reflects it.
4. Click the same verification link a second time. Report what
happens — it should fail gracefully or no-op, not error.
5. Sign up with another address, request a resend of the
verification email if the UI offers it, and confirm the resend
arrives and works.Step 2 is the one that finds real product bugs: the unverified user who can somehow reach billing, or the opposite — the unverified user stuck on a dead-end page with no resend button at all.
Prompt 4: post-signup state and the double-submit
On https://staging.yourapp.com/signup, sign up with a fresh email
and watch closely:
1. On the form, click "Create account" twice in rapid succession.
Report whether the UI disables the button, and check the network
log for duplicate POST requests. If two requests fired, report
whether both returned success.
2. After landing in the app, inspect the first-run experience:
does the dashboard render correctly for a user with no data?
Any empty-state screens that are broken, blank, or show
placeholder text like "undefined"?
3. Reload the page. Confirm the session persists.
4. Log out and log back in with the same credentials. Confirm it
works and lands somewhere sensible.
Report all console errors seen at any point, even ones that didn't
visibly break anything.New-user empty states are the most under-tested screens in SaaS, because everyone on the team has an old account full of data. A scenario that signs up a new user sees that empty account. A scenario that uses a saved login sees whatever that login has. (Why a script misses this.)
Reading the results
The run ends Passed, Failed, or Error. Error means the check could not verify the scenario. It is not a pass. Evidence is screenshots, console output, and network requests recorded as method, URL, and status — including the signup POST and its status. Response bodies are not part of that log. Read the network list even when the run passed: a 500 from a side call can leave the UI looking fine. The session command is the event list.
Make it a habit, not an audit
The leverage is running them on deploys that touch auth, accounts, email, or the dashboard shell. Save each prompt as a test scenario and wire it into CI. A standard run costs 1 credit. The price list is /pricing.
A renamed button does not, by itself, require a new sentence. A new step, or a new rule, does. You update the sentence. Monito does not rewrite it to stay green.
The one to run right now
If you only run a single check today, run the credential round-trip — it's the cheapest test with the worst failure mode:
On https://staging.yourapp.com/signup, create an account with a
fresh email and a 100-character password. If signup succeeds, log
out and log back in with the same credentials on /login. If login
rejects the password that signup accepted, flag it as a critical
bug with screenshots of both attempts. Also report any console
errors or failed network requests along the way.Sign up, point a check at staging, and paste the prompt. The onboarding wizard does not charge its first run. The report is the evidence. The command is monito check.
Related posts
- What self-healing tests actually heal
- Testing magic link auth: expiry and reuse
- How to test SSO login: access control and bypasses