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, }, } }