BugMojoBugMojoBugMojo
FeaturesPricingBlogHelpAbout
Add to ChromeLog inGet started
BugMojoBugMojo

Bug reports that actually help fix bugs — capture, replay, share.

A product of Softech Infra.

Product

  • Features
  • Pricing
  • Browser extension
  • Get started
  • Log in

Resources

  • Help & guides
  • Blog
  • Compare
  • Glossary

Company

  • About
  • Contact
  • Security
  • Privacy
  • Terms
  • Sitemap
© 2026 BugMojo. All rights reserved.
AllGuidesEngineeringPlaybooksCompareGlossaryAlternativesBy roleBug tracking by framework
  1. Home
  2. Blog
  3. Guides
  4. Writing Acceptance Criteria That Prevent Bugs Before They Ship
Guides

Writing Acceptance Criteria That Prevent Bugs Before They Ship

Vague acceptance criteria are future bugs in disguise. Here is how to write Given/When/Then scenarios, cover the negative and edge cases everyone skips, and turn every criterion into a pass/fail QA test before any code is written.

ManviManvi·Jun 26, 2026·8 min read
Guides
Isometric line-art Given/When/Then criteria rows feeding a bug-capture card read by an AI agent over MCP
TL;DR

Acceptance criteria are the contract for done. Write them as Given / When / Then scenarios, one action per scenario, with an observable outcome you can assert. For every happy-path scenario, write at least one negative scenario for the empty, invalid, boundary, permission, and failure cases. Each scenario then becomes one row in a pass/fail QA checklist before code exists. Vague criteria are not cheap shortcuts: defects from poor requirements can consume up to 85% of project rework costs.

Most bugs do not start in code. They start in a sentence like "the form should handle errors gracefully." That line passes review, ships into a sprint, and three weeks later a customer pastes a 4,000-character note into a field nobody bounded, the request times out, and their draft vanishes. Nobody wrote that bug. They wrote an ambiguous acceptance criterion and let the runtime fill in the blanks.

Acceptance criteria (AC) are the conditions a feature must satisfy to be accepted as complete. Done well, they are the cheapest defect prevention you have, because they catch the ambiguity while it still costs a comment instead of a rollback. This guide covers the Given/When/Then pattern, the negative and edge cases teams skip most, how a fuzzy adjective becomes a production defect, and how to turn finished criteria into a QA checklist that exists before the feature is built.

What makes acceptance criteria actually prevent bugs?

Acceptance criteria prevent bugs when each one is specific, testable, and written before code. The Given/When/Then format forces a known starting state, a single action, and one observable outcome that maps directly to a pass/fail test. Pairing every positive scenario with a negative scenario closes the gaps where defects hide. Ambiguity, not complexity, is the top cause of requirement-driven failure.

The mechanism is boring and reliable: a testable criterion has exactly one answer to the question "did this pass?". The official Gherkin reference defines the three clauses precisely. Given steps put the system in a known state before interaction. When steps describe a single event or action. Then steps describe an expected outcome that you verify by asserting the actual observable result against the expected one (Cucumber Gherkin reference). That structure is not ceremony. It is what makes a criterion checkable by a human or a machine without debate.

The stakes are not theoretical. CISQ estimates the cost of poor software quality in the US at a minimum of $2.41 trillion, with accumulated technical debt accounting for roughly $1.52 trillion of it (CISQ, 2022). A 2025 comparative study in the Ain Shams Engineering Journal, reviewing 57 papers plus an industrial survey, found ambiguous requirements to be the top cause of prolonged analysis and project failure (ScienceDirect, 2025). Ambiguity is the disease; testable criteria are the cure.

The Given/When/Then pattern, with copy-paste examples

Use one action per scenario. If you find yourself writing a second When, you have two scenarios. Keep the Then to observable output, not internal state you cannot see from the outside. Here is a positive scenario plus the negative scenarios that the happy-path version usually leaves out.

login.featuregherkin
Feature: Account login

  # Positive / happy path
  Scenario: Member signs in with valid credentials
    Given a verified member account exists for "ana@acme.com"
    And the member is on the sign-in page
    When she submits the email and the correct password
    Then she lands on the dashboard within 2 seconds
    And a session cookie is set with a 24-hour expiry

  # Negative: wrong password (the message must NOT leak which field is wrong)
  Scenario: Sign-in fails with an incorrect password
    Given a verified member account exists for "ana@acme.com"
    When she submits the email with the wrong password
    Then she stays on the sign-in page
    And sees "Email or password is incorrect"
    And the entered email remains pre-filled

  # Edge: rate limit after repeated failures
  Scenario: Sign-in is throttled after 5 failed attempts
    Given 5 failed sign-in attempts in the last 10 minutes for "ana@acme.com"
    When she submits any credentials
    Then she sees "Too many attempts. Try again in 15 minutes."
    And no authentication request is sent to the backend
checkout.featuregherkin
Feature: Apply discount code at checkout

  Scenario: Valid code reduces the order total
    Given a cart with a subtotal of $100.00
    And an active code "SAVE20" for 20% off
    When the shopper applies "SAVE20"
    Then the displayed total becomes $80.00
    And the code appears as a removable line item

  Scenario: Expired code is rejected without changing the total
    Given a cart with a subtotal of $100.00
    And a code "SPRING" that expired yesterday
    When the shopper applies "SPRING"
    Then the total stays $100.00
    And an inline error reads "This code has expired"

  Scenario: A second code cannot stack on an applied code
    Given "SAVE20" is already applied to the cart
    When the shopper applies "SAVE10"
    Then the total still reflects only "SAVE20"
    And a message reads "Only one code can be used per order"

Not every criterion needs a scenario. Atlassian and AltexSoft both document two standard formats: scenario-oriented (the Gherkin blocks above, for behavior with user interaction) and rule-oriented (a bulleted list of constraints) for simple or technical requirements (Atlassian; AltexSoft). A password policy is fine as a rule list:

  • Password must be at least 12 characters.
  • Must contain one number and one symbol.
  • The last 5 passwords cannot be reused.
  • Submitting an invalid password shows the specific failed rule, not a generic error.

Mix them freely. Rules capture the constraints; scenarios capture the behaviors that need step-by-step verification.

The negative and edge cases everyone skips

Happy-path criteria are easy to write and easy to pass, which is exactly why they hide bugs. The defects live in the cases nobody bothered to specify. Treat the list below as a checklist: for each positive scenario, ask which of these applies and write the matching negative scenario with its expected error state.

  • Empty / missing input — required field left blank, null payload, no file selected.
  • Boundary values — 0, 1, the maximum, and max + 1. Off-by-one lives here.
  • Invalid format — malformed email, negative quantity, wrong file type.
  • Duplicate / double-click — same form submitted twice, idempotency of payments.
  • Permissions changed mid-action — session expired, role revoked between page load and submit.
  • Network failure / timeout — request never returns; what happens to the user's entered data?
  • Concurrency — two users editing the same record; last-write-wins or a conflict prompt?
Why vague requirements are expensive
US cost of poor software quality ($T)
2.41
Of which: technical debt ($T)
1.52
Rework cost from poor requirements (% , Jama)
85
Source: CISQ 2022; Jama Software 2024
The fuzzy-adjective test

If a criterion contains fast, user-friendly, properly, gracefully, intuitive, or etc., it is not testable and it is a future bug. Replace each with a number or a concrete observable outcome. "Loads fast" becomes "renders the first row within 2 seconds on a throttled 3G profile." "Handles errors" becomes three named scenarios with exact messages.

Turning acceptance criteria into a QA test checklist

This is the payoff. Because each scenario is already structured as setup / action / assertion, it converts to a test case with zero translation: the Given is your setup, the When is the step, the Then is the assertion. Build a checklist where every row is one scenario with an explicit expected result and a pass/fail box. Crucially, the checklist exists before the feature is built, so QA and developers agree on done up front instead of arguing about it at review.

  • One row per Given/When/Then scenario, positive and negative alike.
  • Each row states the exact expected result (the Then), not a vague "works."
  • Cross-check rows against boundary, permission, and failure conditions before marking the story ready.
  • Link each failing row to evidence: a reproduction, the console error, and the network call at the moment the assertion broke.

For the full pre-ship pass, hand this checklist to your manual QA testing checklist, and when a row fails, capture it using the steps-to-reproduce guide so the expected-vs-actual gap is unambiguous.

FeatureBugMojoCucumber / BDD runnerJira + Jama / TestRail
Stores Given/When/Then scenariosAs attached AC on a bugYes, native .feature filesYes, native fields
Executes scenarios as automated testsNo — not a test runnerYes, core capabilityVia TestRail integrations
Captures rrweb replay + console + network on a failed ThenYes, one-clickNoNo
Exposes AC-linked failure evidence to an AI agent over MCPYes — uniqueNoNo
Formal requirements / test-management administrationMinimalN/AYes — their core
Where AC-linked failure evidence lives: BugMojo vs. dedicated tooling. BugMojo is honestly weaker on native test execution and formal requirements administration.

Here is the part no BDD tool, error monitor, or tracker does. When a Then clause fails during a QA pass, the failure is usually just a sentence in a ticket and a screenshot. BugMojo's browser extension captures the rrweb session replay, console logs, and network requests at the moment the assertion broke, and its MCP server exposes that bundle to an AI coding agent such as Claude Code or Cursor. The agent reads the failure with full context, maps the broken assertion back to the exact Given/When/Then scenario, and proposes a fix, instead of a human re-typing the criterion into a ticket.

Be clear about the trade: BugMojo is not a test runner and not a requirements-management suite. Cucumber executes scenarios; Jama and TestRail own formal requirements and test administration. BugMojo's wedge is the loop from failed criterion to AI-readable evidence, and that loop is the one no competitor offers.

Key takeaways
  • Write criteria as Given/When/Then: known state, one action, one observable outcome.
  • For every positive scenario, write at least one negative scenario with its expected error state.
  • Ban fuzzy adjectives — replace each with a number or a concrete result.
  • Each scenario becomes one pass/fail QA row that exists before code is written.
  • When a Then fails, attach replay + console + network so the gap is provable and AI-readable.
⁓ ⁓ ⁓
Turn failed acceptance criteria into one-click, AI-readable evidence

BugMojo captures the rrweb replay, console logs, and network requests the moment a Then clause breaks, then hands the bundle to your AI agent over MCP. Map the failure back to the exact scenario and ship the fix.

Try BugMojo free

Frequently asked questions

Frequently asked questions

Sources

  1. Gherkin Reference — Given/When/Then keywords and scenario structure — Cucumber (SmartBear) (2024)
  2. The Cost of Poor Software Quality in the US: A 2022 Report — Consortium for Information & Software Quality (CISQ) (2022-11)
  3. A Guide to Poor Requirements: Causes, Repercussions, and How to Fix Them — Jama Software (2024)
  4. Acceptance Criteria for User Stories in Agile: Purposes, Formats, Examples, and Best Practices — AltexSoft (2024)
  5. What is Acceptance Criteria? Definition, Examples, & Tips — Atlassian (2024)
  6. Ensuring quality in software requirement engineering process: A comparative study — Ain Shams Engineering Journal (ScienceDirect) (2025-08)
Share:
Manvi
Manvi· QA Tester

Manvi is a Quality Assurance Tester with three years of experience. For her, quality is not just about finding bugs — it is about ensuring the best possible experience for every user.

On this page

  • What makes acceptance criteria actually prevent bugs?
  • The Given/When/Then pattern, with copy-paste examples
  • The negative and edge cases everyone skips
  • Turning acceptance criteria into a QA test checklist

Get bug-tracking insights, weekly.

Engineering deep-dives, QA playbooks, and honest tool comparisons. No spam — unsubscribe in one click.