Files
dance-lessons-coach/.vibe/skills/bdd-testing/SKILL.md
Gabriel Radureau 30af706590 🤖 feat: enhance agent skills for BDD testing and CI/CD management
Skill Improvements:
- BDD Testing Skill: Enhanced step templates, debugging guides, and patterns
- Gitea Client Skill: Added wiki management, issue tracking, and workflow monitoring
- Product Owner Assistant: Improved user story workflow and documentation
- Commit Message Skill: Better gitmoji integration and issue referencing
- Changelog Manager: Enhanced change tracking and documentation
- Skill Creator: Improved skill generation templates and validation
- Swagger Documentation: Updated OpenAPI integration guides

Key Features:
- BDD best practices documentation
- Gitea API client with wiki support
- User story implementation workflow
- Git commit message standardization
- Skill development patterns
- OpenAPI/Swagger documentation generation

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-04-09 00:26:08 +02:00

398 lines
13 KiB
Markdown

---
name: bdd-testing
description: Behavior-Driven Development testing for dance-lessons-coach using Godog. Use when creating or running BDD tests, implementing new features with BDD, or validating API endpoints through Gherkin scenarios.
license: MIT
metadata:
author: dance-lessons-coach Team
version: "1.0.0"
based-on: pkg/bdd implementation
---
# BDD Testing for dance-lessons-coach
Behavior-Driven Development testing framework using Godog for the dance-lessons-coach project. This skill provides comprehensive guidance for creating, running, and maintaining BDD tests that validate API endpoints and system behavior.
## Key Concepts
### Black Box Testing Principles
- **External API Only**: Tests interact only through public HTTP endpoints
- **No Internal Access**: No direct access to database, services, or internal components
- **Real HTTP Requests**: Actual network calls to verify system behavior
- **Isolation**: Each scenario runs with fresh client instances
### Hybrid In-Process Testing
- **Real Server Code**: Uses actual server implementation running in-test process
- **Fixed Port**: Test server runs on port 9191
- **No External Processes**: Avoids complex process management
- **Graceful Shutdown**: Proper server lifecycle management
## Commands
### Run BDD Tests
```bash
go test ./features/...
```
Runs all BDD tests in the features directory using Godog test runner.
**Arguments:**
- None (uses standard Go test infrastructure)
### Validate BDD Tests
```bash
./scripts/run-bdd-tests.sh
```
Validates BDD tests and fails if any undefined, pending, or skipped steps are found.
**Arguments:**
- None
### Create New Feature
```bash
# Create new feature file
touch features/<feature_name>.feature
# Add Gherkin scenarios
# Implement step definitions in pkg/bdd/steps/
```
**Arguments:**
- `feature_name` - Name of the feature (e.g., "greet", "health")
## Workflows
### Implementing a New BDD Feature
1. **Create Feature File**: Define scenarios in Gherkin syntax
2. **Implement Steps**: Add step definitions following Godog's exact patterns
3. **Run Tests**: Execute and debug scenarios
4. **Validate**: Ensure no undefined/pending steps
5. **Document**: Add feature documentation
### Debugging BDD Tests
1. **Check Step Patterns**: Ensure steps match Godog's exact regex patterns
2. **Verify Server**: Confirm test server is running on port 9191
3. **Inspect Responses**: Check actual vs expected API responses
4. **Review Logs**: Examine test output for undefined steps
5. **Validate JSON**: Ensure proper JSON escaping in feature files
## Usage Examples
### Creating a Greet Feature
```gherkin
# features/greet.feature
Feature: Greet Service
The greet service should return appropriate greetings
Scenario: Default greeting
Given the server is running
When I request the default greeting
Then the response should be "{\"message\":\"Hello world!\"}"
Scenario: Personalized greeting
Given the server is running
When I request a greeting for "John"
Then the response should be "{\"message\":\"Hello John!\"}"
```
### Creating a Health Feature
```gherkin
# features/health.feature
Feature: Health Endpoint
The health endpoint should indicate server status
Scenario: Health check returns healthy status
Given the server is running
When I request the health endpoint
Then the response should be "{\"status\":\"healthy\"}"
```
### Implementing Step Definitions
```go
// pkg/bdd/steps/steps.go
func (sc *StepContext) theServerIsRunning() error {
// Actually verify the server is running by checking the readiness endpoint
return sc.client.Request("GET", "/api/ready", nil)
}
func (sc *StepContext) iRequestAGreetingFor(name string) error {
return sc.client.Request("GET", fmt.Sprintf("/api/v1/greet/%s", name), nil)
}
func (sc *StepContext) iRequestTheDefaultGreeting() error {
return sc.client.Request("GET", "/api/v1/greet/", nil)
}
func (sc *StepContext) iRequestTheHealthEndpoint() error {
return sc.client.Request("GET", "/api/health", nil)
}
func (sc *StepContext) theResponseShouldBe(arg1, arg2 string) error {
// The regex captures the full JSON from the feature file, including quotes
// We need to extract just the key and value without the surrounding quotes and backslashes
// Remove the surrounding quotes and backslashes
cleanArg1 := strings.Trim(arg1, `"\`)
cleanArg2 := strings.Trim(arg2, `"\`)
// Build the expected JSON string
expected := fmt.Sprintf(`{"%s":"%s"}`, cleanArg1, cleanArg2)
return sc.client.ExpectResponseBody(expected)
}
```
### Registering Steps
```go
// pkg/bdd/steps/steps.go
func InitializeAllSteps(ctx *godog.ScenarioContext, client *testserver.Client) {
sc := NewStepContext(client)
// Use Godog's EXACT regex patterns and parameter names
ctx.Step(`^I request a greeting for "([^"]*)"$`, sc.iRequestAGreetingFor)
ctx.Step(`^I request the default greeting$`, sc.iRequestTheDefaultGreeting)
ctx.Step(`^I request the health endpoint$`, sc.iRequestTheHealthEndpoint)
ctx.Step(`^the response should be "{\"([^"]*)\":\"([^"]*)"}"$`, sc.theResponseShouldBe)
ctx.Step(`^the server is running$`, sc.theServerIsRunning)
}
```
## Gotchas
### Step Pattern Matching
- **Use Godog's Exact Patterns**: Step regex must match Godog's suggestions precisely
- **Use Exact Parameter Names**: Godog expects `arg1, arg2`, not descriptive names
- **Avoid Undefined Warnings**: Even small deviations cause "undefined step" warnings
- **Test Patterns First**: Use `godog.ErrPending` to verify patterns work before implementing logic
- **Don't Over-Optimize Regex**: Use the patterns Godog provides, even if they seem verbose
### Critical Requirements from Validated Implementation
1. **Godog has very specific requirements** for step pattern matching:
- Use the **exact regex pattern** that Godog suggests in error messages
- Use the **exact parameter names** that Godog suggests (`arg1, arg2`, etc.)
- Match the feature file syntax **exactly** including quotes and JSON formatting
2. **The "undefined" warnings are not a Godog bug** - they occur when step definitions don't match Godog's expected patterns exactly:
- Using different regex patterns than what Godog suggests
- Using descriptive parameter names instead of `arg1, arg2`
- Not escaping quotes properly in JSON patterns
- Trying to be "clever" with regex optimization
3. **Solution**: Always use the exact pattern and parameter names that Godog suggests in its error messages.
### JSON Escaping
- **Feature Files**: Use double backslashes for quotes: `"{\\"message\\":\\"Hello\\"}"`
- **Step Implementation**: Trim surrounding quotes and backslashes from captured groups
- **Response Validation**: Trim trailing newlines from JSON responses
### Server Verification
- **Actual HTTP Requests**: `theServerIsRunning` must make real HTTP call to `/api/ready`
- **No Mocking**: Black box testing requires real server verification
- **Port Conflicts**: Test server runs on fixed port 9191
### Context Handling
- **ScenarioContext vs Context**: Steps receive `*godog.ScenarioContext`, not `context.Context`
- **Client Access**: Store client in StepContext struct for step access
- **Fresh Instances**: Each scenario gets new client instance
## Best Practices
### Step Definition Patterns
```go
// ✅ DO: Use Godog's exact regex patterns and parameter names
ctx.Step(`^I request a greeting for "([^"]*)"$`, sc.iRequestAGreetingFor)
ctx.Step(`^the response should be "{\"([^"]*)\":\"([^"]*)"}"$`, sc.theResponseShouldBe)
// ❌ DON'T: Use different parameter names or patterns
ctx.Step(`^I request greeting "(.*)"$`, sc.iRequestAGreetingFor) // Wrong pattern
ctx.Step(`^the response should be "{\"message\":\"([^"]*)"}"$`, sc.theResponseShouldBe) // Wrong pattern
```
### Validated Step Definition Strategy
1. **First eliminate "undefined" warnings** by using Godog's exact suggested patterns
2. **Return `godog.ErrPending`** initially to confirm pattern matching works
3. **Then implement actual validation** logic
4. **One pattern per step type** - Use generic patterns to cover similar steps
### Response Validation
```go
// ✅ DO: Trim newlines and properly unescape JSON
func (c *Client) ExpectResponseBody(expected string) error {
actual := strings.TrimSuffix(string(c.lastBody), "\n")
if actual != expected {
return fmt.Errorf("expected %q, got %q", expected, actual)
}
return nil
}
// ❌ DON'T: Assume exact string matching without cleanup
func (c *Client) ExpectResponseBody(expected string) error {
if string(c.lastBody) != expected { // May fail due to newlines
return fmt.Errorf("mismatch")
}
}
```
### Test Server Management
```go
// ✅ DO: Use hybrid in-process testing
func (s *Server) Start() error {
// Start real server in same process
go func() {
if err := s.httpServer.ListenAndServe(); err != nil {
log.Error().Err(err).Msg("Test server failed")
}
}()
return s.waitForServerReady()
}
// ❌ DON'T: Use external process management
func startServer() {
// Avoid: cmd := exec.Command("go", "run", "./cmd/server")
}
```
### Response Validation
```go
// ✅ DO: Trim newlines and properly unescape JSON
func (c *Client) ExpectResponseBody(expected string) error {
actual := strings.TrimSuffix(string(c.lastBody), "\n")
if actual != expected {
return fmt.Errorf("expected %q, got %q", expected, actual)
}
return nil
}
// ❌ DON'T: Assume exact string matching without cleanup
func (c *Client) ExpectResponseBody(expected string) error {
if string(c.lastBody) != expected { // May fail due to newlines
return fmt.Errorf("mismatch")
}
}
```
## Progressive Disclosure
### Core Instructions (SKILL.md)
- BDD testing fundamentals
- Common workflows and patterns
- Gotchas and best practices
- Basic troubleshooting
### Detailed Reference (references/)
- **GODOG_PATTERNS.md**: Advanced step pattern examples
- **TEST_SERVER.md**: Test server implementation details
- **DEBUGGING.md**: Advanced debugging techniques
- **EXAMPLES.md**: Complete feature examples
### Scripts (scripts/)
- **run-bdd-tests.sh**: Test validation and execution
- **debug-steps.sh**: Step pattern debugging
- **generate-stubs.sh**: Step definition stub generation
## Validation
### Test Validation Script
```bash
# scripts/run-bdd-tests.sh
#!/bin/bash
set -e
echo "Running BDD tests..."
go test ./features/... -v
# Fail if any undefined/pending/skipped steps
echo "Validating test results..."
if go test ./features/... 2>&1 | grep -q "undefined\|pending\|skipped"; then
echo "ERROR: Found undefined, pending, or skipped steps"
exit 1
fi
echo "✓ All BDD tests passed with no undefined steps"
```
### Common Validation Issues
| Issue | Cause | Solution |
|-------|-------|----------|
| Undefined steps | Step pattern doesn't match Godog's exact regex | Use Godog's suggested pattern |
| JSON mismatch | Trailing newlines or improper escaping | Trim newlines, properly unescape JSON |
| Server not running | Test server failed to start | Check port 9191, verify server logs |
| Context errors | Wrong context type passed to steps | Use `*godog.ScenarioContext`, not `context.Context` |
## References
- [Godog Documentation](https://github.com/cucumber/godog)
- [Gherkin Reference](https://cucumber.io/docs/gherkin/)
- [BDD Best Practices](references/BDD_BEST_PRACTICES.md)
- [Test Server Implementation](references/TEST_SERVER.md)
- [Debugging Guide](references/DEBUGGING.md)
## Troubleshooting
### "Undefined Step" Warnings
**Symptoms:** Tests pass but show "undefined step" warnings
**Cause:** Step regex doesn't match Godog's exact pattern suggestions
**Solution:**
1. Run `godog --format=progress` to see suggested patterns
2. Update step registration to use exact patterns
3. Ensure function names match step descriptions
### JSON Comparison Failures
**Symptoms:** Response validation fails despite correct JSON
**Cause:** Trailing newlines or improper escaping in feature files
**Solution:**
1. Trim newlines: `strings.TrimSuffix(response, "\n")`
2. Properly escape JSON in feature files: `"{\\"key\\":\\"value\\"}"`
3. Trim quotes in step implementation: `strings.Trim(arg, `"\`)`
### Server Connection Errors
**Symptoms:** "connection refused" or server not responding
**Cause:** Test server not running or port conflict
**Solution:**
1. Verify server on port 9191: `curl http://localhost:9191/api/ready`
2. Check server logs for startup errors
3. Ensure no other process using port 9191
### Context Type Mismatches
**Symptoms:** Compilation errors about context types
**Cause:** Passing wrong context type to step functions
**Solution:**
1. Store `*godog.ScenarioContext` in StepContext
2. Use stored context for step registration
3. Access client through StepContext struct
## Assets
- **feature-template.feature**: Gherkin feature file template
- **step-template.go**: Go step definition template
- **test-server-template.go**: Test server implementation template
- **validation-script.sh**: Test validation script template