Files
dance-lessons-coach/pkg/bdd/testsetup/testsetup.go
Gabriel Radureau aa4823eb11 ♻️ refactor: make BDD test setup DRY with shared testsetup package
- Create pkg/bdd/testsetup package with shared test configuration functions
- Refactor all feature test files to use shared setup (70+ lines reduced)
- Implement dynamic feature path detection by scanning filesystem for directories
- Add getProjectRoot() function to find project root via go.mod
- Maintain all existing functionality (tags, stop on failure, etc.)
- Add fallback to hardcoded paths if filesystem access fails
- Sort feature paths for consistent test execution order

Before: ~35 lines per test file with duplicated setup code
After: ~5 lines per test file using shared functions

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistralai.com>
2026-04-10 10:24:25 +02:00

195 lines
5.0 KiB
Go

package testsetup
import (
"fmt"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"testing"
"dance-lessons-coach/pkg/bdd"
"github.com/cucumber/godog"
)
// FeatureConfig holds configuration for a feature test
type FeatureConfig struct {
FeatureName string
Format string
StopOnFailure bool
}
// MultiFeatureConfig holds configuration for multi-feature tests
type MultiFeatureConfig struct {
Paths []string
Format string
StopOnFailure bool
}
// NewFeatureConfig creates a new feature configuration
func NewFeatureConfig(featureName, format string, stopOnFailure bool) *FeatureConfig {
return &FeatureConfig{
FeatureName: featureName,
Format: format,
StopOnFailure: stopOnFailure,
}
}
// NewMultiFeatureConfig creates a new multi-feature configuration
func NewMultiFeatureConfig(paths []string, format string, stopOnFailure bool) *MultiFeatureConfig {
return &MultiFeatureConfig{
Paths: paths,
Format: format,
StopOnFailure: stopOnFailure,
}
}
// GetFeatureFromEnv gets the feature name from environment variable
func GetFeatureFromEnv() string {
return os.Getenv("FEATURE")
}
// GetAllFeaturePaths returns paths for all features by scanning the filesystem
func GetAllFeaturePaths() []string {
// Get the project root directory
projectRoot, err := getProjectRoot()
if err != nil {
// Fallback to hardcoded list if we can't determine project root
return []string{
"auth",
"config",
"greet",
"health",
"jwt",
}
}
// Read the features directory from project root
featuresPath := filepath.Join(projectRoot, "features")
entries, err := os.ReadDir(featuresPath)
if err != nil {
// Fallback to hardcoded list if filesystem access fails
return []string{
"auth",
"config",
"greet",
"health",
"jwt",
}
}
var paths []string
for _, entry := range entries {
// Only include directories (features) that are not hidden and not test files
if entry.IsDir() && !strings.HasPrefix(entry.Name(), ".") {
paths = append(paths, entry.Name())
}
}
// Sort paths for consistent ordering
sort.Strings(paths)
return paths
}
// getProjectRoot finds the project root directory by looking for go.mod
func getProjectRoot() (string, error) {
// Start from current directory and walk up the tree
dir, err := os.Getwd()
if err != nil {
return "", err
}
// Walk up the directory tree until we find go.mod or reach root
for {
// Check if go.mod exists in current directory
if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
return dir, nil
}
// Move up one directory
parent := filepath.Dir(dir)
if parent == dir {
// Reached root directory
break
}
dir = parent
}
// If we get here, we didn't find go.mod - return original working directory
return "", fmt.Errorf("could not find project root (go.mod not found)")
}
// CreateTestSuite creates a configured godog test suite
func CreateTestSuite(t *testing.T, config *FeatureConfig, suiteName string) godog.TestSuite {
// Set FEATURE environment variable for feature-specific configuration
os.Setenv("FEATURE", config.FeatureName)
// Allow tag override via environment variable
tags := os.Getenv("GODOG_TAGS")
if tags == "" {
// Default tags if not overridden
tags = "~@flaky && ~@todo && ~@skip"
}
// Allow stop on failure override via environment variable
stopOnFailure := config.StopOnFailure
if envStop := os.Getenv("GODOG_STOP_ON_FAILURE"); envStop != "" {
// Support various boolean formats
stopOnFailure, _ = strconv.ParseBool(envStop)
}
return godog.TestSuite{
Name: suiteName,
TestSuiteInitializer: bdd.InitializeTestSuite,
ScenarioInitializer: bdd.InitializeScenario,
Options: &godog.Options{
Format: config.Format,
Paths: []string{"."},
TestingT: t,
Strict: true,
Randomize: -1,
StopOnFailure: stopOnFailure,
Tags: tags,
},
}
}
// CreateMultiFeatureTestSuite creates a configured godog test suite for multiple features
func CreateMultiFeatureTestSuite(t *testing.T, config *MultiFeatureConfig, suiteName string) godog.TestSuite {
// Set FEATURE environment variable for feature-specific configuration
// For multi-feature tests, we don't set a specific feature
os.Setenv("FEATURE", "")
// Allow tag override via environment variable
tags := os.Getenv("GODOG_TAGS")
if tags == "" {
// Default tags if not overridden
tags = "~@flaky && ~@todo && ~@skip"
}
// Allow stop on failure override via environment variable
stopOnFailure := config.StopOnFailure
if envStop := os.Getenv("GODOG_STOP_ON_FAILURE"); envStop != "" {
// Support various boolean formats
stopOnFailure, _ = strconv.ParseBool(envStop)
}
return godog.TestSuite{
Name: suiteName,
TestSuiteInitializer: bdd.InitializeTestSuite,
ScenarioInitializer: bdd.InitializeScenario,
Options: &godog.Options{
Format: config.Format,
Paths: config.Paths,
TestingT: t,
Strict: true,
Randomize: -1,
StopOnFailure: stopOnFailure,
Tags: tags,
},
}
}