GIVEN-WHEN-THEN Scenarios Guide
Master the art of writing clear, testable scenarios using GIVEN-WHEN-THEN format.
What are GIVEN-WHEN-THEN Scenarios?
GIVEN-WHEN-THEN is a format for writing test scenarios that express requirements as examples. Also known as Gherkin or BDD (Behavior-Driven Development) style.
Format:
GIVEN [initial context]
WHEN [action/event]
THEN [expected outcome]Why it works:
- Easy to understand for all stakeholders
- Bridge between business and technical teams
- Directly translatable to automated tests
- Clear acceptance criteria
Anatomy of a Scenario
GIVEN: Setup and Context
What it means: The initial state and preconditions
Describes:
- What data exists
- What configuration is in place
- What user state or role applies
- Prerequisites for the action
Examples:
- **GIVEN** a user "alice@example.com" is registered in the system
- **GIVEN** alice is logged in to the application
- **GIVEN** alice has an active subscription
- **GIVEN** the database contains 100 product records
- **GIVEN** the current time is 3:00 PM on a FridayBest practices:
- Be specific with concrete values
- Use names and identifiers, not abstractions
- Include necessary setup state
- Keep it concise but complete
WHEN: Action or Trigger
What it means: What happens to trigger the scenario
Describes:
- What the user does
- What action is triggered
- What event occurs
- What external stimulus applies
Examples:
- **WHEN** alice clicks the "Login" button
- **WHEN** alice submits the form with valid credentials
- **WHEN** the system processes a new order
- **WHEN** a scheduled task runs at midnight
- **WHEN** the API receives a GET requestBest practices:
- One primary action per scenario
- Describe the action clearly
- Use user-centric language
- Avoid implementation details
THEN: Expected Outcome
What it means: What should happen as a result
Describes:
- What state changes
- What output is produced
- What the user sees
- What data is modified
Examples:
- **THEN** alice is logged into the system
- **THEN** alice sees the dashboard page
- **THEN** an order confirmation email is sent
- **THEN** the order status changes to "Processing"
- **THEN** the API returns HTTP 200 with order detailsBest practices:
- Describe observable outcomes
- One main outcome per THEN (use AND for related outcomes)
- Be specific about state changes
- Make it testable
AND/OR: Additional Details
Purpose: Chain multiple related conditions or outcomes
Examples:
### Scenario: Multi-step Login
- **GIVEN** a registered user exists
- **AND** the user's account is active
- **WHEN** the user enters valid email and password
- **THEN** the user receives a JWT token
- **AND** the user is redirected to the dashboard
- **AND** a login event is loggedBest practices:
- Use AND for additional related items
- Use OR for alternative conditions
- Keep the main GIVEN-WHEN-THEN clear
- Don't overuse AND (limit to 2-3 per section)
Writing Effective Scenarios
Principle 1: One Scenario, One Outcome Path
Each scenario should test one primary outcome (happy path or one type of failure).
Good:
### Scenario 1: Successful Login
- **GIVEN** user with correct password exists
- **WHEN** user enters correct credentials
- **THEN** user is logged in
### Scenario 2: Wrong Password
- **GIVEN** user exists in system
- **WHEN** user enters wrong password
- **THEN** login fails with error messageBad (mixes multiple outcomes):
### Scenario: Login
- **GIVEN** a user
- **WHEN** they log in
- **THEN** they might succeed or fail depending on password
- **AND** they see the dashboard or error messagePrinciple 2: Use Concrete, Specific Values
Vague:
- **GIVEN** a user
- **WHEN** they enter an email
- **THEN** something happensSpecific:
- **GIVEN** a user account with email "alice@example.com"
- **WHEN** they enter email "alice@example.com" and correct password
- **THEN** they receive a JWT token valid for 24 hoursPrinciple 3: Focus on What, Not How
Specify behavior, not implementation.
Implementation-focused (avoid):
- **GIVEN** the database has a user record
- **WHEN** the authentication function hashes the password
- **THEN** the bcrypt result matches the stored hashBehavior-focused (better):
- **GIVEN** alice is registered with password "SecurePass123"
- **WHEN** alice logs in with correct password
- **THEN** authentication succeedsPrinciple 4: Make Scenarios Independent
Each scenario should work standalone.
Dependent (bad):
### Scenario 1: User registers
- [Registration steps]
- **THEN** user is created
### Scenario 2: User logs in
- **GIVEN** the user from Scenario 1
- [Login steps]Independent (good):
### Scenario 1: User registration
- **GIVEN** [setup for registration]
- **WHEN** [registration action]
- **THEN** [registration succeeds]
### Scenario 2: User login
- **GIVEN** registered user "alice@example.com" exists
- **WHEN** [login action]
- **THEN** [login succeeds]Scenario Templates
Template 1: Happy Path (Success)
### Scenario: [Feature - Success Case]
- **GIVEN** [valid preconditions]
- **AND** [additional context]
- **WHEN** [user performs action]
- **THEN** [successful outcome]
- **AND** [related successful outcome]Example:
### Scenario: User creates account successfully
- **GIVEN** user "bob@example.com" is not yet registered
- **AND** the registration page is open
- **WHEN** bob enters email, password, and confirms
- **THEN** account is created successfully
- **AND** bob receives confirmation email
- **AND** bob is redirected to login pageTemplate 2: Error/Failure Case
### Scenario: [Feature - Failure Case]
- **GIVEN** [preconditions that lead to failure]
- **WHEN** [user performs action]
- **THEN** [specific error occurs]
- **AND** [system state is preserved]Example:
### Scenario: Login fails with wrong password
- **GIVEN** user "charlie@example.com" is registered
- **WHEN** charlie enters correct email but wrong password
- **THEN** login fails with error "Invalid credentials"
- **AND** charlie's account remains unlocked
- **AND** login attempt is logged for securityTemplate 3: Edge Case / Boundary
### Scenario: [Feature - Edge Case]
- **GIVEN** [boundary condition setup]
- **WHEN** [action at boundary]
- **THEN** [boundary handled correctly]Example:
### Scenario: Maximum password length
- **GIVEN** the maximum password length is 128 characters
- **WHEN** user sets password to exactly 128 characters
- **THEN** password is accepted
- **AND** all characters are stored correctlyTemplate 4: Security/Permission
### Scenario: [Feature - Permission/Security]
- **GIVEN** user with [role/permission] is trying action
- **WHEN** [action that requires permission]
- **THEN** [access granted/denied appropriately]Example:
### Scenario: Unauthorized access prevented
- **GIVEN** david is not logged in
- **WHEN** david tries to access the dashboard directly
- **THEN** david is redirected to login page
- **AND** no data is exposedComplete Scenario Example
Here's a feature with multiple well-written scenarios:
# User Authentication Feature
## Scenarios
### Scenario 1: Successful Email/Password Login
- **GIVEN** user "alice@example.com" registered with password "Secure123!"
- **AND** alice is not currently logged in
- **WHEN** alice navigates to login page
- **AND** alice enters email "alice@example.com"
- **AND** alice enters password "Secure123!"
- **AND** alice clicks "Sign In" button
- **THEN** login succeeds
- **AND** alice receives JWT token with 24-hour expiration
- **AND** alice is redirected to dashboard
- **AND** alice sees "Welcome, Alice" personalization
### Scenario 2: Login Fails with Incorrect Password
- **GIVEN** user "bob@example.com" is registered
- **AND** bob is not logged in
- **WHEN** bob enters correct email "bob@example.com"
- **AND** bob enters incorrect password "WrongPass456"
- **AND** bob clicks "Sign In"
- **THEN** login fails
- **AND** bob sees error message "Email or password is incorrect"
- **AND** bob remains on login page
- **AND** bob is not logged in
### Scenario 3: Login Fails with Non-existent Email
- **GIVEN** no user account exists for "unknown@example.com"
- **WHEN** someone enters "unknown@example.com" in login
- **AND** they enter any password
- **AND** they click "Sign In"
- **THEN** login fails
- **AND** the error message shows "Email or password is incorrect"
- **AND** the system does NOT reveal whether email exists
- **AND** login attempt is logged for security
### Scenario 4: Account Lockout After Multiple Failures
- **GIVEN** user "charlie@example.com" exists
- **AND** charlie has failed login 5 times in the last 15 minutes
- **WHEN** charlie attempts to log in again
- **THEN** login is rejected
- **AND** charlie sees message "Account locked. Try again in 15 minutes."
- **AND** charlie receives security alert email
- **AND** support team is notified
### Scenario 5: Password Reset Token Works
- **GIVEN** "diana@example.com" has forgotten her password
- **AND** diana is at password reset page
- **WHEN** diana enters "diana@example.com"
- **AND** diana clicks "Send Reset Email"
- **THEN** password reset email is sent within 1 minute
- **AND** email contains unique reset link
- **WHEN** diana clicks the reset link in the email
- **AND** link is within 1-hour validity window
- **THEN** reset page loads with password entry field
- **WHEN** diana enters new password "NewPass789"
- **AND** confirms new password
- **AND** clicks "Update Password"
- **THEN** password is updated
- **AND** diana can log in with new password
- **AND** old password no longer works
### Scenario 6: Expired Reset Token is Rejected
- **GIVEN** diana received password reset link 2 hours ago
- **AND** reset link has 1-hour expiration
- **WHEN** diana clicks the expired reset link
- **THEN** page shows "Link has expired"
- **AND** diana must request a new reset email
- **AND** no password change occursCommon Mistakes in Scenarios
Mistake 1: Too Much Implementation Detail
Bad (too technical):
- **WHEN** the POST /api/auth/login endpoint receives a JSON payload
- **AND** bcrypt validates the hash against stored value
- **THEN** the JWT is signed with RS256 algorithmGood (behavior-focused):
- **WHEN** alice submits login form with credentials
- **THEN** alice receives authentication tokenMistake 2: Missing Preconditions
Bad (unclear setup):
- **GIVEN** a user
- **WHEN** they log in
- **THEN** they see the dashboardGood (clear setup):
- **GIVEN** user "alice@example.com" is registered
- **AND** alice is not currently logged in
- **WHEN** alice submits login credentials
- **THEN** alice sees the dashboardMistake 3: Multiple Paths in One Scenario
Bad (too many outcomes):
- **GIVEN** a user with valid or invalid credentials
- **WHEN** they click login
- **THEN** they succeed or see an errorGood (one outcome per scenario):
### Scenario: Valid credentials
- **GIVEN** user with valid credentials
- **WHEN** they click login
- **THEN** they succeed
### Scenario: Invalid credentials
- **GIVEN** user with invalid password
- **WHEN** they click login
- **THEN** they see errorMistake 4: Vague Assertions
Bad (untestable):
- **THEN** the system behaves correctly
- **AND** the response is good
- **AND** everything works fineGood (testable):
- **THEN** HTTP status 200 is returned
- **AND** response includes user ID and name
- **AND** authentication token is valid for 24 hoursScenario Coverage Checklist
For complete specifications, cover:
- [ ] Happy path: Normal successful flow
- [ ] Validation failures: Invalid input
- [ ] Error conditions: Expected failures
- [ ] Edge cases: Boundary values
- [ ] Security: Permission/authorization
- [ ] Integration: Multiple system interactions
- [ ] Concurrency: Race conditions (if applicable)
- [ ] Performance: Load or timeout scenarios
- [ ] Recovery: Error recovery steps
Translating to Tests
Well-written GIVEN-WHEN-THEN scenarios translate easily to automated tests:
Scenario:
### Scenario: User login succeeds
- **GIVEN** user "test@example.com" with password "Secret123"
- **WHEN** user submits login form
- **THEN** user receives JWT tokenTest Code:
test('User login succeeds', () => {
// GIVEN
const user = createUser('test@example.com', 'Secret123');
// WHEN
const response = submitLoginForm('test@example.com', 'Secret123');
// THEN
expect(response.token).toBeDefined();
expect(isValidJWT(response.token)).toBe(true);
});Quick Checklist for Scenarios
Before finalizing scenarios:
- [ ] Scenario has clear GIVEN-WHEN-THEN structure
- [ ] GIVEN describes complete, specific preconditions
- [ ] WHEN describes single primary action
- [ ] THEN describes observable, testable outcome
- [ ] Scenario works independently
- [ ] Scenario uses concrete values, not abstractions
- [ ] Scenario focuses on behavior, not implementation
- [ ] Related outcomes use AND, alternative use OR
- [ ] Happy path and error cases both covered
- [ ] Edge cases are considered