implement-step-definitions
Implement step definitions for Gherkin scenarios, translating Given/When/Then into executable test code. Use after write-scenario when scenarios are defined but step definitions are missing.
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
implement-step-definitions
Skill Type: Actuator (BDD Workflow) Purpose: Translate Given/When/Then scenarios into executable test code Prerequisites:
- Feature file exists with Gherkin scenarios
- BDD framework available (Cucumber, Behave, etc.)
Agent Instructions
You are in the STEP DEFINITIONS phase of BDD (SCENARIO → STEP DEFINITIONS → IMPLEMENT → REFACTOR).
Your goal is to translate Given/When/Then steps into executable test code (step definitions).
Workflow
Step 1: Read Feature File
Parse the Gherkin scenarios:
- What Given/When/Then steps exist?
- Which steps are reusable across scenarios?
- What test fixtures are needed?
Example:
# features/authentication.feature
Scenario: Successful login
Given I am a registered user with email "user@example.com"
And my password is "SecurePassword123!"
When I enter email "user@example.com"
And I enter password "SecurePassword123!"
And I click the "Login" button
Then I should see "Welcome back"
# Unique steps needed:
# - Given I am a registered user with email {email}
# - And my password is {password}
# - When I enter email {email}
# - And I enter password {password}
# - And I click the {button} button
# - Then I should see {message}
Step 2: Determine Step Definition File Location
Follow BDD framework conventions:
Cucumber (JavaScript/TypeScript):
features/step_definitions/authentication_steps.js
features/step_definitions/authentication_steps.ts
Behave (Python):
features/steps/authentication_steps.py
Cucumber (Java):
src/test/java/steps/AuthenticationSteps.java
Step 3: Write Step Definitions
Template for Python (Behave):
# features/steps/authentication_steps.py
# Validates: <REQ-ID>
# Business Rules: BR-001, BR-002, BR-003
from behave import given, when, then
from src.auth.authentication import login
from test_helpers import create_test_user, get_ui_element
# Test fixtures
_test_users = {}
_login_result = None
_ui_state = {}
@given('I am a registered user with email "{email}"')
def step_impl(context, email):
"""Create a test user with specified email"""
# Validates: <REQ-ID>
user = create_test_user(email=email)
_test_users[email] = user
context.user = user
@given('my password is "{password}"')
def step_impl(context, password):
"""Set user's password"""
context.user.set_password(password)
@when('I enter email "{email}"')
def step_impl(context, email):
"""User enters email in login form"""
_ui_state['email_input'] = email
@when('I enter password "{password}"')
def step_impl(context, password):
"""User enters password in login form"""
_ui_state['password_input'] = password
@when('I click the "{button}" button')
def step_impl(context, button):
"""User clicks a button"""
if button == "Login":
# Perform login action
global _login_result
email = _ui_state.get('email_input')
password = _ui_state.get('password_input')
_login_result = login(email, password)
@then('I should see "{message}"')
def step_impl(context, message):
"""Verify user sees expected message"""
# This would check UI in real implementation
# For now, check login result
if message == "Welcome back":
assert _login_result.success == True
else:
assert _login_result.error == message
@then('I should be redirected to the dashboard')
def step_impl(context):
"""Verify user is redirected"""
assert _login_result.success == True
# In real implementation, check URL or page content
Key elements:
- ✅ Tag with REQ-* key in comments
- ✅ One step definition per unique step
- ✅ Parameterized step definitions (use
{parameter}) - ✅ Reusable across scenarios
- ✅ Clear docstrings explaining step purpose
Template for JavaScript (Cucumber):
// features/step_definitions/authentication_steps.js
// Validates: <REQ-ID>
// Business Rules: BR-001, BR-002, BR-003
const { Given, When, Then } = require('@cucumber/cucumber');
const { login } = require('../../src/auth/authentication');
const assert = require('assert');
let testUser;
let loginResult;
let uiState = {};
Given('I am a registered user with email {string}', function(email) {
// Validates: <REQ-ID>
testUser = createTestUser(email);
});
Given('my password is {string}', function(password) {
testUser.setPassword(password);
});
When('I enter email {string}', function(email) {
uiState.email = email;
});
When('I enter password {string}', function(password) {
uiState.password = password;
});
When('I click the {string} button', function(button) {
if (button === 'Login') {
loginResult = login(uiState.email, uiState.password);
}
});
Then('I should see {string}', function(message) {
if (message === 'Welcome back') {
assert.strictEqual(loginResult.success, true);
} else {
assert.strictEqual(loginResult.error, message);
}
});
Step 4: Run Scenarios (Expect FAILURE)
Run BDD framework:
# Behave (Python)
behave features/authentication.feature
# Cucumber (JavaScript)
npm run cucumber
# Cucumber (Java)
mvn test -Dcucumber.options="features/authentication.feature"
Expected output:
Feature: User Login
Background:
Given the application is running PASSED
And I am on the login page PASSED
Scenario: Successful login
Given I am a registered user PASSED
And my password is "SecurePassword123!" PASSED
When I enter email "user@example.com" PASSED
And I enter password "SecurePassword123!" PASSED
And I click the "Login" button FAILED
AttributeError: 'NoneType' object has no attribute 'success'
(login function doesn't exist yet)
✅ This is GOOD! Steps execute but implementation doesn't exist yet.
Step 5: Commit Step Definitions
Create commit:
git add features/steps/authentication_steps.py
git commit -m "STEP DEF: Add step definitions for <REQ-ID>
Implement step definitions for user login scenarios.
Step definitions:
- Given steps: Set up test users and state
- When steps: Simulate user actions
- Then steps: Verify expected outcomes
Steps: 12 step definitions (scenarios fail - no implementation yet)
Validates: <REQ-ID>
"
Output Format
When you complete the STEP DEFINITIONS phase, show:
[STEP DEFINITIONS Phase - <REQ-ID>]
Feature File: features/authentication.feature
Step Definitions Created:
Given steps (4):
✓ I am a registered user with email {email}
✓ my password is {password}
✓ the application is running
✓ I am on the login page
When steps (5):
✓ I enter email {email}
✓ I enter password {password}
✓ I click the {button} button
✓ I attempt to login with email {email} and password {password}
Then steps (3):
✓ I should see {message}
✓ I should be redirected to the dashboard
✓ my account should be locked
Step Definition File: features/steps/authentication_steps.py (12 steps, 142 lines)
Running scenarios...
Scenario: Successful login FAILED (no implementation)
Scenario: Login fails invalid email FAILED (no implementation)
Scenario: Login fails short password FAILED (no implementation)
Scenario: Account locks after 3 fails FAILED (no implementation)
Result: 5 scenarios FAILED ✓ (expected - implementation missing)
Commit: STEP DEF: Add step definitions for <REQ-ID>
✅ STEP DEFINITIONS Phase Complete!
Next: Invoke implement-feature skill to implement functionality
Prerequisites Check
Before invoking this skill, ensure:
- Feature file exists (from write-scenario)
- BDD framework available
- Step definitions directory exists
If prerequisites not met:
- No feature file → Invoke
write-scenarioskill first - No BDD framework → Ask user which to install
Next Steps
After STEP DEFINITIONS phase completes:
- Do NOT implement feature yet (that's next phase)
- Invoke
implement-featureskill to implement functionality - Scenarios should PASS after implementation
Step Definition Patterns
Parameterized Steps
✅ Good (reusable):
@given('I am a user with email "{email}"')
def step_impl(context, email):
context.user = create_user(email)
❌ Bad (hard-coded):
@given('I am a user with email user@example.com')
def step_impl(context):
context.user = create_user('user@example.com')
Shared Context
Use context object to share state between steps:
@given('I am logged in')
def step_impl(context):
context.user = login()
@when('I view my profile')
def step_impl(context):
context.profile = get_profile(context.user) # Uses user from Given
@then('I should see my email')
def step_impl(context):
assert context.profile.email == context.user.email
Test Helpers
Extract common logic to helpers:
# test_helpers.py
def create_test_user(email, password="DefaultPass123!"):
"""Create a user for testing"""
user = User(email=email)
user.set_password(password)
user.save()
return user
def cleanup_test_users():
"""Delete all test users"""
User.delete_where(email__startswith="test_")
Notes
Why step definitions separate from implementation?
- Step definitions = test automation code
- Implementation = production code
- Separation of concerns (test vs production)
- Step definitions can test multiple implementations
Step definition reusability:
- Same step definitions can test multiple features
- Parameterized steps increase reusability
- Keep step definitions simple and focused
Homeostasis Goal:
desired_state:
all_steps_defined: true
steps_reusable: true
scenarios_executable: true
"Excellence or nothing" 🔥
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-01-20
- Index updated
- 2026-01-26
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!