Gherkin gets a bad reputation from teams who adopted it, wrote scenarios nobody could read, and concluded the format was the problem. It usually isn't. Here are the four failure modes and what to do instead.
Failure 1: Gherkin as a UI script
# Bad
When I click the button with id "submit-btn"
And I wait 2 seconds
And I click the third row in the table
This breaks when the button gets renamed, and it describes mechanics rather than behaviour. Six months later nobody can tell what it was protecting.
# Better
When the customer submits the order
Then the order appears in their history with status "pending"
The rule: Gherkin describes what the user achieves, the step definitions describe how. If your feature file mentions a CSS selector, the abstraction has leaked.
Failure 2: Given as a setup dumping ground
# Bad
Given a user exists
And the user has an email
And the user is verified
And the user has a subscription
And the subscription is active
And the subscription has 5 seats
And 3 seats are used
Nobody reads this. Collapse it into one meaningful state:
# Better
Given an active subscription with 3 of 5 seats used
The detail lives in the step definition, where it belongs. A Given should name a situation, not enumerate a database.
Failure 3: Multiple Whens
# Bad
When the user adds an item
And the user applies a discount code
And the user checks out
Then the total is correct
Three triggers means three behaviours means the failure tells you nothing about which one broke. And 'the total is correct' is not an assertion — correct according to what?
One When per scenario. If you genuinely need a sequence, the earlier steps are Givens — they are setup, not the thing under test.
Failure 4: Then with no observable
# Bad
Then the system processes the payment
Then the data is saved correctly
Neither is observable. 'Processes' and 'correctly' cannot fail in any specific way, so the step definition ends up asserting something arbitrary, and the scenario passes forever regardless of behaviour.
# Better
Then the order status is "paid"
And a receipt is sent to the customer's email address
The shape that works
Scenario: discount code cannot be applied twice
Given an order with the code SAVE10 already applied
When the customer applies SAVE10 again
Then the order total is unchanged
And the customer is told the code is already applied
One situation. One trigger. Two observable outcomes. Readable by someone who has never seen the codebase — which is the actual test of whether your Gherkin is any good.
Where generation helps, and where it doesn't
Once criteria are in this shape, enumerating the surrounding cases is mechanical: the expired code, the invalid code, the code that applies to no items in the basket, the code used by a different customer. That is what a generator is genuinely good at — GoQA produces these from criteria and exports them to Gherkin, Playwright, or Cypress.
What it will not do is decide that 'used by a different customer' is the one carrying real risk. That is still your call, and it is the more important half.
Top comments (0)