github.com/saucelabs/saucectl@v0.175.1/internal/cmd/run/cucumber.go (about) 1 package run 2 3 import ( 4 "os" 5 6 "github.com/rs/zerolog/log" 7 "github.com/saucelabs/saucectl/internal/ci" 8 cmds "github.com/saucelabs/saucectl/internal/cmd" 9 "github.com/saucelabs/saucectl/internal/config" 10 "github.com/saucelabs/saucectl/internal/cucumber" 11 "github.com/saucelabs/saucectl/internal/flags" 12 "github.com/saucelabs/saucectl/internal/framework" 13 "github.com/saucelabs/saucectl/internal/http" 14 "github.com/saucelabs/saucectl/internal/region" 15 "github.com/saucelabs/saucectl/internal/report/captor" 16 "github.com/saucelabs/saucectl/internal/saucecloud" 17 "github.com/saucelabs/saucectl/internal/saucecloud/retry" 18 "github.com/saucelabs/saucectl/internal/segment" 19 "github.com/saucelabs/saucectl/internal/usage" 20 "github.com/saucelabs/saucectl/internal/viper" 21 "github.com/spf13/cobra" 22 "github.com/spf13/pflag" 23 "golang.org/x/text/cases" 24 "golang.org/x/text/language" 25 ) 26 27 // NewCucumberCmd creates the 'run' command for cucumber. 28 func NewCucumberCmd() *cobra.Command { 29 sc := flags.SnakeCharmer{Fmap: map[string]*pflag.Flag{}} 30 31 cmd := &cobra.Command{ 32 Use: "cucumberjs", 33 Short: "Run Cucumber test", 34 SilenceUsage: true, 35 Hidden: true, 36 TraverseChildren: true, 37 PreRunE: func(cmd *cobra.Command, args []string) error { 38 sc.BindAll() 39 return preRun() 40 }, 41 Run: func(cmd *cobra.Command, args []string) { 42 // Test patterns are passed in via positional args. 43 viper.Set("suite::options::paths", args) 44 45 exitCode, err := runCucumber(cmd, true) 46 if err != nil { 47 log.Err(err).Msg("failed to execute run command") 48 } 49 os.Exit(exitCode) 50 }, 51 } 52 53 sc.Fset = cmd.Flags() 54 55 sc.String("name", "suite::name", "", "Set the name of the job as it will appear on Sauce Labs.") 56 sc.String("platformName", "suite::platformName", "", "Run against this platform.") 57 58 // Cucumber 59 sc.String("scenario-name", "suite::options::name", "", "Regular expressions of which scenario names should match one of to be run") 60 sc.StringSlice("paths", "suite::options::paths", []string{}, "Paths to where the feature files are, using glob pattern") 61 sc.StringSlice("excludedTestFiles", "suite::options::excludedTestFiles", []string{}, "Exclude test files to skip the tests, using glob pattern") 62 sc.Bool("backtrace", "suite::options::backtrace", false, "Show the full backtrace for errors") 63 sc.StringSlice("require", "suite::options::require", []string{}, "Paths to where your support code is, for CommonJS.") 64 sc.StringSlice("import", "suite::options::import", []string{}, "Paths to where your support code is, for ESM") 65 sc.StringSlice("scenario-tags", "suite::options::tags", []string{}, "Tag expression to filter which scenarios should be run") 66 sc.StringSlice("format", "suite::options::format", []string{}, "Name/path and (optionally) output file path of each formatter to use") 67 sc.Int("parallel", "suite::options::parallel", 0, "Run tests in parallel with the given number of worker processes, default: 0") 68 sc.Int("passThreshold", "suite::passThreshold", 1, "The minimum number of successful attempts for a suite to be considered as 'passed'.") 69 70 return cmd 71 } 72 73 func runCucumber(cmd *cobra.Command, isCLIDriven bool) (int, error) { 74 if !isCLIDriven { 75 config.ValidateSchema(gFlags.cfgFilePath) 76 } 77 78 p, err := cucumber.FromFile(gFlags.cfgFilePath) 79 if err != nil { 80 return 1, err 81 } 82 83 p.CLIFlags = flags.CaptureCommandLineFlags(cmd.Flags()) 84 85 if err := applyCucumberFlags(&p); err != nil { 86 return 1, err 87 } 88 89 cucumber.SetDefaults(&p) 90 91 if err := cucumber.Validate(&p); err != nil { 92 return 1, err 93 } 94 95 regio := region.FromString(p.Sauce.Region) 96 if !gFlags.noAutoTagging { 97 p.Sauce.Metadata.Tags = append(p.Sauce.Metadata.Tags, ci.GetTags()...) 98 } 99 100 tracker := segment.DefaultTracker 101 if regio == region.Staging { 102 tracker.Enabled = false 103 } 104 105 go func() { 106 props := usage.Properties{} 107 props.SetFramework("playwright-cucumberjs").SetFVersion(p.Playwright.Version).SetFlags(cmd.Flags()).SetSauceConfig(p.Sauce). 108 SetArtifacts(p.Artifacts).SetNPM(p.Npm).SetNumSuites(len(p.Suites)).SetJobs(captor.Default.TestResults). 109 SetSlack(p.Notifications.Slack).SetSharding(cucumber.IsSharded(p.Suites)).SetLaunchOrder(p.Sauce.LaunchOrder). 110 SetSmartRetry(p.IsSmartRetried()).SetReporters(p.Reporters) 111 tracker.Collect(cases.Title(language.English).String(cmds.FullName(cmd)), props) 112 _ = tracker.Close() 113 }() 114 115 cleanupArtifacts(p.Artifacts) 116 117 creds := regio.Credentials() 118 119 restoClient := http.NewResto(regio.APIBaseURL(), creds.Username, creds.AccessKey, 0) 120 restoClient.ArtifactConfig = p.Artifacts.Download 121 testcompClient := http.NewTestComposer(regio.APIBaseURL(), creds, testComposerTimeout) 122 webdriverClient := http.NewWebdriver(regio.WebDriverBaseURL(), creds, webdriverTimeout) 123 appsClient := *http.NewAppStore(regio.APIBaseURL(), creds.Username, creds.AccessKey, gFlags.appStoreTimeout) 124 rdcClient := http.NewRDCService(regio.APIBaseURL(), creds.Username, creds.AccessKey, rdcTimeout, config.ArtifactDownload{}) 125 insightsClient := http.NewInsightsService(regio.APIBaseURL(), creds, insightsTimeout) 126 iamClient := http.NewUserService(regio.APIBaseURL(), creds, iamTimeout) 127 128 log.Info().Msg("Running Playwright-Cucumberjs in Sauce Labs") 129 r := saucecloud.CucumberRunner{ 130 Project: p, 131 CloudRunner: saucecloud.CloudRunner{ 132 ProjectUploader: &appsClient, 133 JobService: saucecloud.JobService{ 134 VDCStarter: &webdriverClient, 135 RDCStarter: &rdcClient, 136 VDCReader: &restoClient, 137 RDCReader: &rdcClient, 138 VDCWriter: &testcompClient, 139 VDCStopper: &restoClient, 140 RDCStopper: &rdcClient, 141 VDCDownloader: &restoClient, 142 }, 143 TunnelService: &restoClient, 144 MetadataService: &testcompClient, 145 InsightsService: &insightsClient, 146 UserService: &iamClient, 147 BuildService: &restoClient, 148 Region: regio, 149 ShowConsoleLog: p.ShowConsoleLog, 150 Reporters: createReporters(p.Reporters, p.Notifications, p.Sauce.Metadata, &testcompClient, &restoClient, 151 "cucumber", "sauce", gFlags.async), 152 Async: gFlags.async, 153 FailFast: gFlags.failFast, 154 MetadataSearchStrategy: framework.NewSearchStrategy(p.Playwright.Version, p.RootDir), 155 NPMDependencies: p.Npm.Dependencies, 156 Retrier: &retry.SauceReportRetrier{ 157 VDCReader: &restoClient, 158 ProjectUploader: &appsClient, 159 Project: &p, 160 }, 161 }, 162 } 163 164 p.Npm.Packages = cleanPlaywrightPackages(p.Npm, p.Playwright.Version) 165 return r.RunProject() 166 } 167 168 func applyCucumberFlags(p *cucumber.Project) error { 169 if gFlags.selectedSuite != "" { 170 if err := cucumber.FilterSuites(p, gFlags.selectedSuite); err != nil { 171 return err 172 } 173 } 174 175 // Use the adhoc suite instead, if one is provided 176 if p.Suite.Name != "" { 177 p.Suites = []cucumber.Suite{p.Suite} 178 } 179 180 return nil 181 }