How to test a multi-step form: state, branches, and the back button
A multi-step form is a state machine wearing a progress bar. Here's how to test one end to end — per-step validation, conditional branches, back-button state, and the final payload — in plain English, no scripts.
How to test a multi-step form: state, branches, and the back button
A single form is easy to test: fill the fields, submit, check what happened. A multi-step form looks like the same thing spread over three screens, and that framing is exactly why it ships broken. It isn't one form in three parts. It's a small state machine with a progress bar bolted on top — a pile of accumulated answers that has to survive forward navigation, backward navigation, conditional branches that hide and show whole steps, a browser refresh, and a final submit that has to gather every field the user touched, including the ones that scrolled off screen two steps ago.
The happy path — fill step one, next, fill step two, next, fill step three, submit — is the part that works, because it's the part everyone clicks by hand before shipping. The bugs live in the transitions: the value that resets when you go back to fix a typo, the step that should have been skipped but wasn't, the validation you can walk straight past, and the submit payload that's missing the field from step one because that step unmounted and took its state with it. This is the playbook for testing the whole state machine without writing a line of Playwright.
What "testing a multi-step form" actually has to cover
The fields are trivial. The machine around them is where the surface is:
- Per-step validation that actually gates. Each step should refuse to advance while it's invalid — and crucially, the "Next" button is not the same guarantee as the final "Submit." A wizard that validates on submit but lets you skip through empty steps is a wizard that collects garbage and 500s at the end.
- State that survives navigation. Go forward, go back, go forward again. Every answer you already gave should still be there. The classic bug is a step that re-mounts on "Back" and clears itself, so returning to fix one typo silently wipes the other four fields.
- Conditional branches. "Are you a business or an individual?" on step one changes which steps exist after it. Pick business, you get a tax-ID step; pick individual, you skip it. Both paths need coverage, and so does the nasty case: choose business, fill the tax-ID step, go back, switch to individual — does the now-irrelevant tax ID get cleared, or does it ride along in the final payload?
- The progress indicator's honesty. "Step 2 of 4" should match reality, including when a branch makes it 3 steps instead of 4. A progress bar that lies about how many steps remain is a small bug that reliably increases abandonment.
- Refresh and resume. Reload mid-wizard. Does the user land back where they were with answers intact, or on step one with an empty form and a bad mood? Whichever you intend, test that it's what actually happens.
- The final payload. This is the one that matters. When the user hits submit on the last step, does the request contain every field from every step — including hidden branch fields and step-one values the UI stopped showing long ago? Multi-step forms love to submit a subset of themselves.
- The double-submit. One click on the final button makes one record. Two fast clicks make one record, not two, and not one record plus one unhandled error.
Most teams test items 1 and the happy path, ship, and meet items 2, 3, and 6 as production support tickets over the following months — usually reported as "it lost my information," which is the hardest bug to reproduce because it depends on the exact order the user clicked. The prompts below drive that order deliberately.
Nothing below references a field ID, a step selector, or a DOM path. A multi-step form gets redesigned constantly — steps get split, merged, reordered — and a test pinned to today's step indices rots on the first redesign. Describing intent instead of steps is why this approach scales where scripted form tests don't.
Prompt 1: the happy path, then break the navigation
Step 2 is the test almost no scripted suite runs, because the scripted suite fills the form once, front to back, and submits — it never navigates backward, so it never sees the re-mount bug. The agent reads the actual rendered values on each step, so "the field is still there" and "the field looks there but reverted to the default" come back as different outcomes instead of one green tick.
Prompt 2: per-step validation that can't be skipped
Step 4 is the one that finds the expensive bug: a wizard where the "Next" button validates but a clickable step-number breadcrumb doesn't, so a user (or an impatient one) jumps to the end and submits a half-empty form. The server then either rejects it with a confusing error or, worse, accepts it and creates a broken record. An agent that tries the breadcrumb and the button finds the gap between them; a script that only clicks "Next" never does.
Prompt 3: the conditional branch, both directions
Step 3 is the single highest-value check in this whole post. Conditional branches are usually tested in the forward direction only — pick A, see A's steps; pick B, see B's steps — and that passes. The bug hides in the switch: fields from the abandoned branch that never get cleared and ride along in the final submission, so a user who briefly considered the business plan ships a tax ID they don't have to your backend. Testing it by hand requires remembering to do exactly this dance every time; an agent does it the same way on every run, which is the reason agents catch bugs your scripts miss.
Prompt 4: refresh, resume, and the final payload
Step 3 is the payoff. The most common serious multi-step-form bug is a submission missing early-step data, because those steps unmounted and their state wasn't lifted anywhere durable. It passes every visual check — the UI looked complete — and only shows up in the request body or in a database row that's missing a column the user definitely filled in. The agent reading the actual network request is the only witness to that gap; a screenshot shows a happy confirmation screen sitting on top of an incomplete record.
Reading the results
Each run comes back as a Monito Session, not a pass/fail bit: a screenshot timeline of every step and transition, the network log with the real final submit request and its exact payload, console output, and the agent's reasoning wherever it made a judgment call. For multi-step forms the two documents to read are the screenshot timeline — because state bugs are transitions, and you want to see the field the moment before and after it reset — and the final submit request, which is the only place the "looked complete, submitted incomplete" bug is visible.
The prompts survive your redesigns because none of them names a step index, a field, or a selector — only what the wizard is for. Split a step in two, reorder them, add a branch: the intent didn't change, so the prompt didn't either. That's the same property that makes an agent-driven signup test outlast the form it tests, and it's why a prompt is a better long-term artifact than a spec for anything with a UI that moves.
The one to run right now
If you run a single check today, run the branch-switch-and-payload test — it's the cheapest way to catch the two nastiest multi-step bugs at once (leftover branch data and an incomplete final submit):
Save it as a Test Scenario, pin it to your staging Project, and wire it into CI against every preview deploy that touches onboarding, checkout, or any other wizard. A full run is typically 8–13 credits — roughly $0.08–$0.13 — and your first run is free. Point it at staging, paste the prompt, and read the payload. If every field the user typed is in the request and nothing from the abandoned branch is, you've earned the one flow you can't afford to lose users in.