1616use QIT_CLI \Environment \Environments \E2E \E2EEnvironment ;
1717use QIT_CLI \Environment \Environments \EnvInfo ;
1818use QIT_CLI \Environment \Environments \Environment ;
19- use QIT_CLI \Environment \Extension ;
2019use QIT_CLI \LocalTests \E2E \E2ETestManager ;
20+ use QIT_CLI \LocalTests \LocalTestRunNotifier ;
2121use QIT_CLI \WooExtensionsList ;
2222use Symfony \Component \Console \Command \Command ;
2323use Symfony \Component \Console \Input \ArrayInput ;
2727use Symfony \Component \Console \Output \NullOutput ;
2828use Symfony \Component \Console \Output \OutputInterface ;
2929use Symfony \Component \Console \Output \StreamOutput ;
30+ use Symfony \Component \Console \Style \SymfonyStyle ;
3031use function QIT_CLI \is_windows ;
3132
3233class RunE2ECommand extends DynamicCommand {
@@ -45,20 +46,25 @@ class RunE2ECommand extends DynamicCommand {
4546 /** @var WooExtensionsList */
4647 protected $ woo_extensions_list ;
4748
49+ /** @var LocalTestRunNotifier */
50+ protected $ test_run_notifier ;
51+
4852 protected static $ defaultName = 'run:e2e ' ; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.PropertyNotSnakeCase
4953
5054 public function __construct (
5155 E2EEnvironment $ e2e_environment ,
5256 Cache $ cache ,
5357 OutputInterface $ output ,
5458 E2ETestManager $ e2e_test_manager ,
55- WooExtensionsList $ woo_extensions_list
59+ WooExtensionsList $ woo_extensions_list ,
60+ LocalTestRunNotifier $ test_run_notifier
5661 ) {
5762 $ this ->e2e_environment = $ e2e_environment ;
5863 $ this ->cache = $ cache ;
5964 $ this ->output = $ output ;
6065 $ this ->e2e_test_manager = $ e2e_test_manager ;
6166 $ this ->woo_extensions_list = $ woo_extensions_list ;
67+ $ this ->test_run_notifier = $ test_run_notifier ;
6268 parent ::__construct ( static ::$ defaultName ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
6369 }
6470
@@ -74,8 +80,9 @@ protected function configure() {
7480 ] );
7581
7682 $ this
77- ->addArgument ( 'woo_extension ' , InputArgument::OPTIONAL , 'A QIT plugin-syntax as defined in the documentation: source:action:test-tags: slug. Only "source" is required, and it can be a slug, a file, a URL. Action can be "activate", "bootstrap", and "test", and test-tags are a comme-separated list of tests. Slug is usually not required. Read the docs . ' )
83+ ->addArgument ( 'woo_extension ' , InputArgument::OPTIONAL , 'The slug or WooCommerce ID of the main extension under test . ' )
7884 ->addArgument ( 'test ' , InputArgument::OPTIONAL , '(Optional) The tests for the main extension under test. Accepts test tags, or a test directory. If not set, will use the "default" test tag of this extension. ' )
85+ ->addOption ( 'source ' , null , InputOption::VALUE_OPTIONAL , 'The source of the main extension under test. Accepts a slug, a file, a URL. If not provided, the source will be the slug. ' )
7986 ->addOption ( 'wp ' , null , InputOption::VALUE_OPTIONAL , 'The WordPress version. Accepts "stable", "nightly", or a version number. ' , 'stable ' )
8087 ->addOption ( 'woo ' , null , InputOption::VALUE_OPTIONAL , 'The WooCommerce Version. Accepts "stable", "nightly", or a GitHub Tag (eg: 8.6.1). ' )
8188 ->addOption ( 'plugin ' , 'p ' , InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY , 'Plugin to activate in the environment. Accepts paths, Woo.com slugs/product IDs, WordPress.org slugs or GitHub URLs. ' , [] )
@@ -85,8 +92,10 @@ protected function configure() {
8592 ->addOption ( 'require ' , 'r ' , InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY , 'Load PHP file before running the command (may be used more than once). ' )
8693 ->addOption ( 'config ' , null , InputOption::VALUE_OPTIONAL , '(Optional) QIT config file to use. ' )
8794 ->addOption ( 'object_cache ' , 'o ' , InputOption::VALUE_NONE , 'Whether to enable Object Cache (Redis) in the environment. ' )
95+ ->addOption ( 'sut_action ' , null , InputOption::VALUE_OPTIONAL , 'What action to use for the main extension under test. Accepts "activate", "install" and "test". Default to "test" ' , 'test ' )
8896 ->addOption ( 'no_activate ' , 's ' , InputOption::VALUE_NONE , 'Skip activating plugins in the environment. ' )
8997 ->addOption ( 'shard ' , null , InputOption::VALUE_OPTIONAL , 'Playwright Sharding argument. ' )
98+ ->addOption ( 'no_upload_report ' , null , InputOption::VALUE_NONE , 'Do not upload the report to QIT Manager. ' )
9099 ->addOption ( 'update_snapshots ' , null , InputOption::VALUE_NONE , 'Update snapshots where applicable (eg: Playwright Snapshots). ' )
91100 ->addOption ( 'pw_options ' , null , InputOption::VALUE_OPTIONAL , 'Additional options and parameters to pass to Playwright. ' )
92101 ->addOption ( 'ui ' , null , InputOption::VALUE_NONE , 'Runs tests in UI mode. In this mode, you can start and view the tests running. ' )
@@ -127,12 +136,15 @@ protected function execute( InputInterface $input, OutputInterface $output ): in
127136 $ test_mode = E2ETestManager::$ test_modes ['headless ' ];
128137 }
129138
130- $ wait = $ input ->getOption ( 'up_only ' ) || $ test_mode === E2ETestManager::$ test_modes ['codegen ' ];
131- $ woo_extension = $ input ->getArgument ( 'woo_extension ' );
132- $ test = $ input ->getArgument ( 'test ' );
133- $ shard = $ input ->getOption ( 'shard ' );
134- $ update_snapshots = $ input ->getOption ( 'update_snapshots ' );
135- $ pw_options = $ input ->getOption ( 'pw_options ' ) ?? '' ;
139+ $ wait = $ input ->getOption ( 'up_only ' ) || $ test_mode === E2ETestManager::$ test_modes ['codegen ' ];
140+ $ woo_extension = $ input ->getArgument ( 'woo_extension ' );
141+ $ test = $ input ->getArgument ( 'test ' );
142+ $ woocommerce_version = $ input ->getOption ( 'woo ' );
143+ $ shard = $ input ->getOption ( 'shard ' );
144+ $ update_snapshots = $ input ->getOption ( 'update_snapshots ' );
145+ $ pw_options = $ input ->getOption ( 'pw_options ' ) ?? '' ;
146+ $ source = $ input ->getOption ( 'source ' ) ?? $ woo_extension ;
147+ $ sut_action = $ input ->getOption ( 'sut_action ' );
136148
137149 if ( ! empty ( $ pw_options ) ) {
138150 // Remove wrapping double quotes if they exist.
@@ -148,39 +160,49 @@ protected function execute( InputInterface $input, OutputInterface $output ): in
148160 App::setVar ( 'pw_options ' , $ pw_options );
149161
150162 // Validate the extension is set if needed.
151- if ( empty ( $ woo_extension ) && ! $ wait ) {
152- $ output ->writeln ( '<error>The extension parameter is only optional in --up_only or --codegen modes.</error> ' );
163+ if ( empty ( $ woo_extension ) ) {
164+ if ( ! empty ( $ source ) ) {
165+ $ output ->writeln ( '<error>The extension parameter is required when the source parameter is set.</error> ' );
153166
154- return Command::INVALID ;
167+ return Command::INVALID ;
168+ }
169+ if ( ! empty ( $ sut_action ) ) {
170+ $ output ->writeln ( '<error>The extension parameter is required when the sut_action parameter is set.</error> ' );
171+
172+ return Command::INVALID ;
173+ }
174+ if ( ! $ wait ) {
175+ $ output ->writeln ( '<error>The extension parameter is only optional in --up_only or --codegen modes.</error> ' );
176+
177+ return Command::INVALID ;
178+ }
155179 }
156180
157181 if ( ! empty ( $ woo_extension ) ) {
158- if ( ! empty ( $ test ) ) {
159- if ( ! file_exists ( $ test ) ) {
160- $ output ->writeln ( "<error>Test file ' $ test' does not exist.</error> " );
161-
162- return Command::INVALID ;
182+ // Validate WooExtension.
183+ try {
184+ if ( is_numeric ( $ woo_extension ) ) {
185+ $ woo_extension = $ this ->woo_extensions_list ->get_woo_extension_slug_by_id ( $ woo_extension );
186+ $ woo_extension_id = $ woo_extension ;
187+ } else {
188+ $ woo_extension_id = $ this ->woo_extensions_list ->get_woo_extension_id_by_slug ( $ woo_extension );
163189 }
164- $ woo_extension = sprintf ( '%s:test:%s ' , $ woo_extension , realpath ( $ test ) );
165- } else {
166- $ has_action = false ;
190+ } catch ( \Exception $ e ) {
191+ $ output ->writeln ( sprintf ( '<error>%s</error> ' , $ e ->getMessage () ) );
167192
168- foreach ( Extension::ACTIONS as $ action ) {
169- if ( strpos ( $ woo_extension , ": $ action " ) !== false ) {
170- $ has_action = true ;
171- break ;
172- }
173- }
193+ return Command::INVALID ;
194+ }
174195
175- if ( ! $ has_action ) {
176- $ woo_extension = "$ woo_extension:test " ;
177- }
196+ if ( ! empty ( $ test ) ) {
197+ $ woo_extension_extension_syntax = sprintf ( '%s:%s:base64%s ' , $ woo_extension , $ sut_action , base64_encode ( $ test ) );
198+ } else {
199+ $ woo_extension_extension_syntax = sprintf ( '%s:%s ' , $ woo_extension , $ sut_action );
178200 }
179201
180202 if ( $ input ->getOption ( 'testing_theme ' ) ) {
181- $ env_up_options ['--theme ' ][] = $ woo_extension ;
203+ $ env_up_options ['--theme ' ][] = $ woo_extension_extension_syntax ;
182204 } else {
183- $ env_up_options ['--plugin ' ][] = $ woo_extension ;
205+ $ env_up_options ['--plugin ' ][] = $ woo_extension_extension_syntax ;
184206 }
185207 }
186208
@@ -240,6 +262,11 @@ protected function execute( InputInterface $input, OutputInterface $output ): in
240262
241263 putenv ( 'QIT_UP_AND_TEST=1 ' ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_putenv
242264 putenv ( sprintf ( 'QIT_SUT=%s ' , $ woo_extension ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_putenv
265+ if ( ! empty ( $ woo_extension_id ) ) {
266+ App::setVar ( 'QIT_SUT ' , (int ) $ woo_extension_id );
267+ }
268+
269+ App::setVar ( 'should_upload_report ' , ! $ input ->getOption ( 'no_upload_report ' ) );
243270
244271 $ up_exit_status_code = $ env_up_command ->run (
245272 new ArrayInput ( $ env_up_options ),
@@ -259,6 +286,14 @@ protected function execute( InputInterface $input, OutputInterface $output ): in
259286 /** @var E2EEnvInfo $env_info */
260287 $ env_info = E2EEnvInfo::from_array ( $ env_json );
261288
289+ App::singleton ( E2EEnvInfo::class, $ env_info );
290+
291+ if ( ! empty ( $ woo_extension_id ) ) {
292+ $ env_info ->sut_slug = $ woo_extension ;
293+ $ env_info ->sut_id = $ woo_extension_id ;
294+ $ this ->test_run_notifier ->notify_test_started ( $ woo_extension_id , $ woocommerce_version ?? 'none ' , $ env_info );
295+ }
296+
262297 // Store in $GLOBALS so that's available in the shutdown function.
263298 $ GLOBALS ['env_to_shutdown ' ] = $ env_info ;
264299
@@ -271,11 +306,15 @@ protected function execute( InputInterface $input, OutputInterface $output ): in
271306
272307 $ exit_status_code = $ this ->e2e_test_manager ->run_tests ( $ env_info , $ test_mode , $ wait , $ shard );
273308
309+ $ io = new SymfonyStyle ( $ input , $ output );
310+
274311 if ( $ exit_status_code === Command::SUCCESS ) {
312+ $ io ->success ( "Tests passed. Run 'qit e2e-report' to view the report. " );
313+
275314 return Command::SUCCESS ;
276315 } else {
277316 if ( $ test_mode === E2ETestManager::$ test_modes ['headless ' ] ) {
278- $ this -> output -> writeln ( sprintf ( ' <error> Tests failed. Exit status code: %s</error> ' , $ exit_status_code ) );
317+ $ io -> error ( " Tests failed. Run 'qit e2e-report' to view the report. " );
279318 }
280319
281320 return Command::FAILURE ;
0 commit comments