Template
Test plan template
A copyable test plan template covering scope, approach, entry and exit criteria, environments, roles and risks. The short version teams actually keep updated.
A usable bug report needs seven things: a title naming what broke and where, the environment it happened in, numbered steps to reproduce it, the expected result, the actual result, the severity, and evidence. The pair of expected and actual is what makes it a bug report rather than a complaint, and the environment is what makes it reproducible by somebody else.
Most bug reports fail for the same reason: they describe the reporter's frustration rather than the conditions that produce the fault. A report that says checkout is broken cannot be triaged, because nobody can tell whether it failed for everyone or for one person on an old browser with an expired session.
In the template
Copy it as it is. There is no email step, and nothing on this page is behind one.
## Title One sentence: what broke, and where. ## Environment Browser and version: Operating system: Screen size: URL: Application version or build: Logged in as (role, never a password): ## Steps to reproduce 1. 2. 3. Reproduces: every time / [n] of [m] attempts ## Expected result ## Actual result ## Severity Blocker / Major / Minor / Trivial Who it affects: everyone / one account / one browser / unknown ## Evidence Screenshot or recording: Console errors: Failed network requests: ## Notes Anything you tried that changed the outcome.
## Title Checkout: Place order stays disabled after a valid promo code is applied ## Environment Browser and version: Safari 17.4 Operating system: macOS 14.4 Screen size: 1440x900 URL: /checkout/payment Application version or build: 2.14.0 Logged in as (role, never a password): standard customer, no previous orders ## Steps to reproduce 1. Add SKU-9931 to the basket at 40.00. 2. Go to checkout and continue to the payment step. 3. Enter the promo code SPRING20. 4. Press Apply. Reproduces: 4 of 5 attempts. The attempt that worked had the code pasted rather than typed. ## Expected result The discount is applied and Place order becomes enabled. ## Actual result A discount line appears reading 8.00 and the total reads 32.00, but Place order stays disabled. ## Severity Major. The order cannot be completed with a promo code, and there is no workaround inside checkout. Who it affects: one browser. Reproduced on Safari 17.4, not reproducible on Chrome 141. ## Evidence Screenshot or recording: attached, taken the moment after Apply. Console errors: TypeError: Cannot read properties of undefined (reading 'total') at cart-summary.js Failed network requests: POST /api/cart/promo returned 500 ## Notes Started after the release on the 24th. The previous build applies the same code and enables the button.
The template below is the field set that makes a report actionable. Each field exists because leaving it out produces a specific, predictable follow-up question, and every follow-up costs a triage cycle.
Scroll the table sideways for the examples.
| Field | Why it earns its place | Example |
|---|---|---|
| Title | What broke and where, in one sentence. This is what appears in the queue, and it is what somebody scans to spot a duplicate. | Checkout: Place order button stays disabled after applying a valid promo code |
| Environment | Browser and version, operating system, screen size, and the url. Most bugs that cannot be reproduced are environment-specific, and this is the field that turns cannot reproduce into reproduced on Safari 17. | Safari 17.4, macOS 14.4, 1440x900, /checkout/payment |
| Steps to reproduce | Numbered, starting from a state anybody can reach. The test is whether a person who has never seen the bug can follow them without guessing. | 1. Add any item to the basket. 2. Go to checkout. 3. Enter promo code SPRING20. 4. Click Apply. |
| Expected result | What should have happened. Without it, a triager has to infer the intended behaviour, and they will sometimes infer wrong. | The discount is applied and Place order becomes enabled. |
| Actual result | What happened instead, described rather than interpreted. Say the button stayed disabled, not that the promo system is broken. | The discount line appears, but Place order stays disabled. |
| Severity | How much damage the bug does, not how soon you want it fixed. Those are separate judgements and separate fields. | Major: the order cannot be completed with a promo code. |
| Evidence | A screenshot or recording, plus console errors and failed network requests if you can get them. The console line is frequently the whole diagnosis. | Screenshot attached. Console: TypeError reading 'total' of undefined. POST /api/cart/promo returned 500. |
| Notes optional | Anything that changed the outcome: a retry that worked, a second browser that did not fail, a time it started happening. | Does not happen in Chrome. Started after the release on the 24th. |
Not this
Checkout is broken, please fix asap. The promo code thing isn't working and customers are complaining.
This instead
Checkout: Place order stays disabled after a valid promo code is applied Safari 17.4 on macOS 14.4, build 2.14.0, at /checkout/payment 1. Add SKU-9931 to the basket. 2. Go to checkout. 3. Enter SPRING20. 4. Press Apply. Expected: the discount applies and Place order becomes enabled. Actual: a discount line reads 8.00, the total reads 32.00, Place order stays disabled. Console: TypeError reading 'total' of undefined. POST /api/cart/promo returned 500.
Both describe the same fault. The first cannot be acted on, because every sentence in it is a question somebody now has to ask: which browser, which code, what should have happened, is it everyone or is it you. Each of those questions costs a triage cycle, and there are four of them. The second costs the reporter about ninety seconds, and the console line at the end of it is frequently the whole diagnosis.
A report with only the actual result describes a symptom. A report with both describes a gap, and the gap is the bug. The two fields also catch a whole class of non-bugs: writing them out side by side is often the moment a reporter notices that the software did what it was supposed to do and the expectation was wrong. That report never reaches triage, which is the cheapest possible outcome.
The person who found the bug knows how much damage it does, because they watched it happen. They do not know what else is in the release, so they cannot rank it against the roadmap. Asking a reporter for severity is reasonable; asking for priority produces a number that whoever owns the schedule will overwrite anyway. Keep the fields separate and only ask for the one the reporter can answer.
Environment, console errors and failed requests are the fields reporters skip, and they are also the three a person cannot reasonably be expected to collect: nobody opens developer tools before complaining. That is the argument for capturing them automatically rather than asking. Every follow-up question a report avoids is a triage cycle it does not cost.
The template above is a sequence, and the sequence follows the order the report gets read rather than the order it gets written. The title comes first because it is the only part visible in a queue. The environment comes before the steps because it decides whether the steps below can be followed at all: a reproduction attempt made on the wrong browser fails for a reason that has nothing to do with the bug. Steps, expected result and actual result sit together because they are read together, in one pass, by whoever tries to reproduce it. Evidence follows them rather than leading, so it can be skimmed when the reproduction worked and read closely when it did not. Notes go last because it is the one field with no fixed shape, and an open field placed higher up tends to absorb the whole report. Keeping one heading per field is also what lets the same format work as a form with one input per heading, and as a single ticket description pasted into an issue tracker that offers nothing but one text box.
A title naming what broke and where, the environment it happened in, numbered steps to reproduce it, the expected result, the actual result, severity, and evidence such as a screenshot, console errors or failed network requests. Steps, expected and actual are the three that make it actionable.
Name the area, then the specific failure: "Checkout: Place order stays disabled after a valid promo code" rather than "checkout broken". The title is what somebody scans to spot a duplicate, so it has to be distinguishable from every other checkout bug at a glance.
No. Severity, yes, since they watched the damage happen. Priority is a comparison against everything else in the release, which the reporter has no view of, so it belongs to whoever owns the schedule.
Say so explicitly and record everything about the times it did happen: how many attempts out of how many, what was different, the exact time. An intermittent bug reported as intermittent is triageable; the same bug reported as if it were deterministic wastes a cycle when nobody can reproduce it.
Title, environment, steps to reproduce, expected result, actual result, severity, evidence, notes. There is no formal standard behind that order, but it is the one nearly every tracker's default template converges on, because it matches the order the report is read: identify, then reproduce, then diagnose. A format that puts evidence or free-text notes near the top gets read out of order or not at all.
Template
A copyable test plan template covering scope, approach, entry and exit criteria, environments, roles and risks. The short version teams actually keep updated.
Template
A copyable test case template with the fields that make a run repeatable: preconditions, exact test data, per-step expected results, and a recorded outcome.
Template
A copyable UAT test plan template: scope, who signs off, the business scenarios to run, entry and exit criteria, and how a failure gets recorded.
Environment, console and network attach themselves, on the free plan.