The shop has 47 checks and all of them are green. And then a customer writes to support: placed an order with a promo code, cancelled it — and got back 340 less than they paid. Every check is honest: the refund was checked without a promo code (paid 3400, got 3400 back), the discount in the cart (3400 became 3060). The bug lives between them: the discounted amount travels from the cart into the payment and from there into the refund, and on that last leg the discount is subtracted a second time.
A chain of actions a person walks end to end to reach a single goal is called a user scenario. It differs from a set of isolated checks in one way: the world is not reset between steps — the data travels onward, the state changes, and every next step works with whatever the previous one left behind.
An isolated check looks into a single column: clicked — saw the result. A scenario carries all four rows of state through the whole chain, and at the last joint something becomes visible that is visible nowhere else: the cancellation gave back the money and the points, but never returned the item to stock.
A chain is not the sum of separate checks
An individual case starts from a clean sheet: the order is created with a database query, the "paid" status is set by hand. That keeps the case independent of its neighbours — but nobody walks the transitions between steps: the order in the refund check never arrived from the payment, it appeared already correct.
A scenario walks the transitions itself and sees two classes of things. The data travels the whole path and changes: the amount 3060 appears in the cart, goes off to the gateway, comes back into the account page, gets printed in the email and takes part in the refund — five places, and one of them recalculating it once more is enough. The state changes and does not roll back: after the payment the stock is lower, the points are granted, the promo code is used — and "the cancellation returned the money but not the item to stock" is only visible on an order that really went through the payment.
Where the steps come from: a real buyer's path, not a map of screens
The first scenario a beginner writes usually follows the menu top to bottom: home page, catalogue, cart, checkout, account. The result is a tour of the interface with no goal in it — and it will find exactly a screen that failed to load, because a person walking the menu never buys anything.
The steps come from what people actually do: from support tickets, where a dozen messages a month collapse into three or four repeating paths; from behaviour counters, which show the path nine buyers out of ten take and the step where they drop out; from the analyst's story, which delivers a normal purchase as a ready-made chain in fifteen minutes. And if it is unclear what should happen at a step, that is a hole in the requirements.
Finished steps are checked against one rule: a step is named in the words of the goal, not the words of the interface. "Choose delivery for the day after tomorrow" survives a redesign, "click the third tab" goes stale the first time the buttons move; labels and data live inside the test case. And a scenario ends at the person's goal — the item received and the email with its number.
One end-to-end scenario: from guest to refund
The expected result is written after every step: "everything broke at the end" is worthless when you don't know where it diverged.
Preconditions: "Coffee grinder" at 3400, 7 items in stock; promo code SPRING10 gives 10% and does not apply to delivery; delivery 300; the mailbox anna@example.com is readable; test card 4111 1111 1111 1111.
- A guest puts the grinder into the cart — one line for 3400, still 7 items in stock (the cart reserves nothing), no sign-in needed.
- Clicks "Check out" and registers — the cart is not empty: the first real joint, the guest's cart moves over to the new account; a registration email arrives, "My orders" is still empty.
- Enters
SPRING10— "Discount 340", total 3060; the discount comes off the product, not off the total with delivery; the code is not marked as used yet. - Picks delivery and goes to the payment page — delivery 300 on its own line, total 3360, the discount not recalculated; the payment page shows the same number as the cart.
- Pays by card — the "Order paid" page with a number; the gateway charged exactly 3360; in "My orders" the status is "Paid" and the amount 3360; the stock drops to 6; 306 points are credited (10% of the product amount);
SPRING10is marked as used. - The order email — arrives at
anna@example.com, the address that was entered rather than a default from the settings; the same number, the same 3360 and 340; the link opens the order for this buyer. - Cancels the order and waits for the refund — status "Cancelled"; the card is credited with 3360, not 3020 with the discount taken off twice and not 3060 without delivery; the points are taken back, balance 0; the stock is 7 again; a cancellation email arrives.
The bug from the beginning of the article is caught by step 7: the product credits 3020, because the discount is taken off once more from an already discounted amount. The second bug, the one drawn above, shows up in the same step: the stock never came back to seven.
Joints: what to check where more than one system is involved
Most steps do not end on the screen: the email goes out through a mail service, the money through a gateway, the stock lives in a warehouse system. And the screen says "Order paid" both when all is well and when the email never left. Hence the rule: a joint has two ends, and you look at both.
The email — did it arrive at the address the buyer entered, do the numbers inside match, does the link open for the right user; the common mistake is ticking "the email arrived" without opening it, while the template carries the price without the discount. The stock — down by exactly one after the payment, back after the cancellation, and not down twice after a second click on "Confirm" (a database query or the admin panel). The account — the order is visible to its own buyer and not to anybody else. The money — exactly the amount charged comes back: "Refunded" is the account talking about itself, the fact lives in the gateway, and what actually went out is visible in the Network tab.
Joints do not fire instantly: the email takes seconds, the stock is recalculated by a background job, a bank refund takes days — so the scenario states how long to wait and by which sign to decide that you have waited enough.
Interruptions and personas: a live person does not walk a straight line
They go back, open a second tab, get distracted for an hour, press "Pay" a second time because the first time nothing seemed to happen. A scenario written as a straight line checks none of that, and support untangles exactly those stories: that is where money goes missing. Interruptions are written as branches off the main path. Back from the payment page — is the discount still alive, was a second order created, was the item reserved twice. A repeated payment — expect one charge and one order, and look in the gateway: the screen often shows one order while there are two charges. Two tabs — in one the cart was assembled ten minutes ago, in the other the last item has just been bought. A pause — an hour later the reservation, the session and the promo code have expired and the price has changed: expect a message and a preserved cart. Interruptions are checked around the points of no return — the steps after which the money is charged, the email is sent, the order has gone to the courier.
Those branches are suggested by personas — generalized images of users along two axes, skill level and appetite for experimentation:
| Low skill | High skill | |
|---|---|---|
| Not inclined to experiment | "Cautious" | "Conservative" |
| Inclined to experiment | "Reckless" | "Sophisticated" |
Our scenario walked by "Reckless" comes with two tabs and a double click on "Pay", walked by "Sophisticated" — with hotkeys and workarounds: different walks of one path give different findings in five minutes instead of an hour of aimless clicking (the same trick feeds an exploratory session). If "Reckless" breaks the payment with a double click twice in a row, that is already a permanent case in the suite.
How many scenarios to keep, in which suites, and what stays for the smoke check
The temptation to describe more paths produces forty scenarios at twenty minutes of walking each within a week, and nobody runs them. Keep as many as the team actually walks before a release — usually five to seven — and pick them by the cost of a mistake: money, frequency (the most walked path breaks for everyone at once), irreversibility (a sent email cannot be recalled, an order with the courier cannot be stopped). And a scenario does not enumerate variants: "let's also check an expired card and a declined authorization" turns the path into a tree that can be neither walked nor repaired — enumerating values lives in point cases (test design techniques, decision tables).
Cases are stored in suites — test suites. In a free suite the cases are independent and run in any order; one fails, the rest still go, and regression rests on that. In a sequential one the order matters and the result of one case becomes the starting state of the next: "register" → "assemble the cart" → "pay" → "cancel and get the refund". Fewer steps and the transitions are walked; the price is fragility — the second case fails and the report gets five "blocked" entries instead of five honest results. So agree where the run can be restarted from: usually a step with prepared data such as "start from paying order number such-and-such".
A full walk of our scenario is twenty to forty minutes, so nobody runs it before every build. A short smoke version of three or four minutes is carved out of it, and what gets cut is the detail, not the steps: out go the email contents, the database comparisons, the promo code and the cancellation, leaving the skeleton — into the cart, pay with the test card, see the order in the account. The step where money changes hands and the step after which the path branches have to stay: drop the payment, and the short check starts going green on a product where nothing can be bought, and people trust it. That version is also the first to move into automation.
In short
- A scenario is a chain of actions toward one goal with no reset between steps: the data travels onward, the state stays changed, and only a scenario sees the bugs at the joints.
- The steps come from a real person's path, not from a map of screens, and are named in the words of the goal; the expected result is written after every step. A joint has two ends: the screen says "sent" — the mail service, the gateway, the warehouse or the account has to say "received", and it does not happen instantly.
- Keep five to seven scenarios: by money, by how often the path is walked, by how irreversible a mistake is; enumerating variants inside a step does not belong in a scenario.
- Interruptions — Back, a repeated click, two tabs, a pause — are written as branches and checked around the points of no return; personas suggest them.
- Scenarios live in sequential suites: fewer steps, but a failed case blocks the tail; for the daily check a short version is carved out of the scenario.
What to read next
- How to write a test case: steps and expected result — what every scenario step is made of and where the expected result comes from.
- Black Box, White Box, and Grey Box; Smoke, Regression, and Sanity — where the short version of a scenario lands.
- Test plan and test suites: how to organize your checks — where scenario suites are kept and how a run is planned.
- SQL for Testers — how to look at the other end of a joint: stock, order status, points spent.