Files
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

13 KiB

name, description, license, metadata
name description license metadata
bdd-testing 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. MIT
author version based-on
dance-lessons-coach Team 1.0.0 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

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

./scripts/run-bdd-tests.sh

Validates BDD tests and fails if any undefined, pending, or skipped steps are found.

Arguments:

  • None

Create New Feature

# 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

# 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

# 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

// 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

// 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

// ✅ 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

// ✅ 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

// ✅ 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

// ✅ 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

# 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

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