diff --git a/features/auth/auth_test.go b/features/auth/auth_test.go index 8171a48..39e698a 100644 --- a/features/auth/auth_test.go +++ b/features/auth/auth_test.go @@ -1,45 +1,14 @@ package auth import ( - "os" "testing" - "dance-lessons-coach/pkg/bdd" - - "github.com/cucumber/godog" + "dance-lessons-coach/pkg/bdd/testsetup" ) func TestAuthBDD(t *testing.T) { - // Set FEATURE environment variable for feature-specific configuration - os.Setenv("FEATURE", "auth") - - // 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 := true // Default for auth tests - if envStop := os.Getenv("GODOG_STOP_ON_FAILURE"); envStop != "" { - stopOnFailure = envStop == "true" || envStop == "1" - } - - suite := godog.TestSuite{ - Name: "dance-lessons-coach BDD Tests - Auth Feature", - TestSuiteInitializer: bdd.InitializeTestSuite, - ScenarioInitializer: bdd.InitializeScenario, - Options: &godog.Options{ - Format: "progress", - Paths: []string{"."}, - TestingT: t, - Strict: true, - Randomize: -1, - StopOnFailure: stopOnFailure, - Tags: tags, - }, - } + config := testsetup.NewFeatureConfig("auth", "progress", true) + suite := testsetup.CreateTestSuite(t, config, "dance-lessons-coach BDD Tests - Auth Feature") if suite.Run() != 0 { t.Fatal("non-zero status returned, failed to run auth BDD tests") diff --git a/features/bdd_test.go b/features/bdd_test.go index 6c74aa5..cd109f8 100644 --- a/features/bdd_test.go +++ b/features/bdd_test.go @@ -1,64 +1,30 @@ package features import ( - "os" "testing" - "dance-lessons-coach/pkg/bdd" - - "github.com/cucumber/godog" + "dance-lessons-coach/pkg/bdd/testsetup" ) func TestBDD(t *testing.T) { // Get feature name from environment variable or default to all features - feature := os.Getenv("FEATURE") + feature := testsetup.GetFeatureFromEnv() - var paths []string var suiteName string + var paths []string if feature == "" { // Run all features suiteName = "dance-lessons-coach BDD Tests - All Features" - paths = []string{ - "auth", - "config", - "greet", - "health", - "jwt", - } + paths = testsetup.GetAllFeaturePaths() } else { // Run specific feature suiteName = "dance-lessons-coach BDD Tests - " + feature + " Feature" paths = []string{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 := false // Default for all features test (don't stop on failure) - if envStop := os.Getenv("GODOG_STOP_ON_FAILURE"); envStop != "" { - stopOnFailure = envStop == "true" || envStop == "1" - } - - suite := godog.TestSuite{ - Name: suiteName, - TestSuiteInitializer: bdd.InitializeTestSuite, - ScenarioInitializer: bdd.InitializeScenario, - Options: &godog.Options{ - Format: "progress", - Paths: paths, - TestingT: t, - Strict: true, - Randomize: -1, - StopOnFailure: stopOnFailure, - Tags: tags, - }, - } + config := testsetup.NewMultiFeatureConfig(paths, "progress", false) + suite := testsetup.CreateMultiFeatureTestSuite(t, config, suiteName) if suite.Run() != 0 { t.Fatal("non-zero status returned, failed to run BDD tests") diff --git a/features/config/config_test.go b/features/config/config_test.go index ec6a7b1..79b5e0d 100644 --- a/features/config/config_test.go +++ b/features/config/config_test.go @@ -1,45 +1,14 @@ package config import ( - "os" "testing" - "dance-lessons-coach/pkg/bdd" - - "github.com/cucumber/godog" + "dance-lessons-coach/pkg/bdd/testsetup" ) func TestConfigBDD(t *testing.T) { - // Set FEATURE environment variable for feature-specific configuration - os.Setenv("FEATURE", "config") - - // 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 := false // Default for config tests (don't stop on failure) - if envStop := os.Getenv("GODOG_STOP_ON_FAILURE"); envStop != "" { - stopOnFailure = envStop == "true" || envStop == "1" - } - - suite := godog.TestSuite{ - Name: "dance-lessons-coach BDD Tests - Config Feature", - TestSuiteInitializer: bdd.InitializeTestSuite, - ScenarioInitializer: bdd.InitializeScenario, - Options: &godog.Options{ - Format: "progress", - Paths: []string{"."}, - TestingT: t, - Strict: true, - Randomize: -1, - StopOnFailure: stopOnFailure, - Tags: tags, - }, - } + config := testsetup.NewFeatureConfig("config", "progress", false) + suite := testsetup.CreateTestSuite(t, config, "dance-lessons-coach BDD Tests - Config Feature") if suite.Run() != 0 { t.Fatal("non-zero status returned, failed to run config BDD tests") diff --git a/features/greet/greet_test.go b/features/greet/greet_test.go index 0b1c1a3..2208fdc 100644 --- a/features/greet/greet_test.go +++ b/features/greet/greet_test.go @@ -1,45 +1,14 @@ package greet import ( - "os" "testing" - "dance-lessons-coach/pkg/bdd" - - "github.com/cucumber/godog" + "dance-lessons-coach/pkg/bdd/testsetup" ) func TestGreetBDD(t *testing.T) { - // Set FEATURE environment variable for feature-specific configuration - os.Setenv("FEATURE", "greet") - - // 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 := true // Default for greet tests - if envStop := os.Getenv("GODOG_STOP_ON_FAILURE"); envStop != "" { - stopOnFailure = envStop == "true" || envStop == "1" - } - - suite := godog.TestSuite{ - Name: "dance-lessons-coach BDD Tests - Greet Feature", - TestSuiteInitializer: bdd.InitializeTestSuite, - ScenarioInitializer: bdd.InitializeScenario, - Options: &godog.Options{ - Format: "progress", - Paths: []string{"."}, - TestingT: t, - Strict: true, - Randomize: -1, - StopOnFailure: stopOnFailure, - Tags: tags, - }, - } + config := testsetup.NewFeatureConfig("greet", "progress", true) + suite := testsetup.CreateTestSuite(t, config, "dance-lessons-coach BDD Tests - Greet Feature") if suite.Run() != 0 { t.Fatal("non-zero status returned, failed to run greet BDD tests") diff --git a/features/health/health_test.go b/features/health/health_test.go index b6fab8b..536630c 100644 --- a/features/health/health_test.go +++ b/features/health/health_test.go @@ -1,45 +1,14 @@ package health import ( - "os" "testing" - "dance-lessons-coach/pkg/bdd" - - "github.com/cucumber/godog" + "dance-lessons-coach/pkg/bdd/testsetup" ) func TestHealthBDD(t *testing.T) { - // Set FEATURE environment variable for feature-specific configuration - os.Setenv("FEATURE", "health") - - // 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 := true // Default for health tests - if envStop := os.Getenv("GODOG_STOP_ON_FAILURE"); envStop != "" { - stopOnFailure = envStop == "true" || envStop == "1" - } - - suite := godog.TestSuite{ - Name: "dance-lessons-coach BDD Tests - Health Feature", - TestSuiteInitializer: bdd.InitializeTestSuite, - ScenarioInitializer: bdd.InitializeScenario, - Options: &godog.Options{ - Format: "progress", - Paths: []string{"."}, - TestingT: t, - Strict: true, - Randomize: -1, - StopOnFailure: stopOnFailure, - Tags: tags, - }, - } + config := testsetup.NewFeatureConfig("health", "progress", true) + suite := testsetup.CreateTestSuite(t, config, "dance-lessons-coach BDD Tests - Health Feature") if suite.Run() != 0 { t.Fatal("non-zero status returned, failed to run health BDD tests") diff --git a/features/jwt/jwt_test.go b/features/jwt/jwt_test.go index c3e1247..e1fb5e2 100644 --- a/features/jwt/jwt_test.go +++ b/features/jwt/jwt_test.go @@ -1,45 +1,14 @@ package jwt import ( - "os" "testing" - "dance-lessons-coach/pkg/bdd" - - "github.com/cucumber/godog" + "dance-lessons-coach/pkg/bdd/testsetup" ) func TestJWTBDD(t *testing.T) { - // Set FEATURE environment variable for feature-specific configuration - os.Setenv("FEATURE", "jwt") - - // 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 := true // Default for JWT tests - if envStop := os.Getenv("GODOG_STOP_ON_FAILURE"); envStop != "" { - stopOnFailure = envStop == "true" || envStop == "1" - } - - suite := godog.TestSuite{ - Name: "dance-lessons-coach BDD Tests - JWT Feature", - TestSuiteInitializer: bdd.InitializeTestSuite, - ScenarioInitializer: bdd.InitializeScenario, - Options: &godog.Options{ - Format: "pretty", - Paths: []string{"."}, - TestingT: t, - Strict: true, - Randomize: -1, - StopOnFailure: stopOnFailure, - Tags: tags, - }, - } + config := testsetup.NewFeatureConfig("jwt", "pretty", true) + suite := testsetup.CreateTestSuite(t, config, "dance-lessons-coach BDD Tests - JWT Feature") if suite.Run() != 0 { t.Fatal("non-zero status returned, failed to run jwt BDD tests") diff --git a/pkg/bdd/testsetup/testsetup.go b/pkg/bdd/testsetup/testsetup.go new file mode 100644 index 0000000..611c52d --- /dev/null +++ b/pkg/bdd/testsetup/testsetup.go @@ -0,0 +1,194 @@ +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, + }, + } +}