@@ -250,3 +250,76 @@ echo "ok\\n";
250250 assert . equal ( execFileSync ( "php" , [ scriptPath ] , { encoding : "utf8" } ) , "ok\n" )
251251 } )
252252} )
253+
254+ // A component whose suite lives entirely outside PHPUnit (standalone PHP smokes)
255+ // has no PHPUnit files. Discovery must report that as an empty set; the consumer
256+ // decides whether zero PHPUnit files is acceptable.
257+ test ( "discovery-only reports an empty test root as an empty result" , async ( ) => {
258+ const code = phpunitRunCode ( {
259+ pluginSlug : "fixture" ,
260+ cwd : "/wordpress/wp-content/plugins/fixture" ,
261+ autoloadFile : "/wp-codebox-vendor/autoload.php" ,
262+ testsDir : "/wp-codebox-vendor/wp-phpunit/wp-phpunit" ,
263+ testRoot : "/wordpress/wp-content/plugins/fixture/tests" ,
264+ phpunitXml : "/wordpress/wp-content/plugins/fixture/phpunit.xml.dist" ,
265+ phpunitXmlIsDefault : true ,
266+ selectedTestFile : "" ,
267+ changedTestFiles : [ ] ,
268+ discoveryOnly : true ,
269+ phpunitArgs : [ ] ,
270+ env : { } ,
271+ wpConfigDefines : { } ,
272+ dependencyMounts : [ ] ,
273+ bootstrapFiles : [ ] ,
274+ bootstrapMode : "managed" ,
275+ projectBootstrap : "" ,
276+ multisite : false ,
277+ databaseType : "sqlite" ,
278+ } )
279+ const blockStart = code . indexOf ( "if ($discovery_only) {" )
280+ const blockEnd = code . indexOf ( "if (!is_array($wp_config_defines))" , blockStart )
281+ assert . ok ( blockStart >= 0 && blockEnd > blockStart , "expected the discovery-only block" )
282+ const discoveryBlock = code . slice ( blockStart , blockEnd )
283+
284+ const tempDir = mkdtempSync ( join ( tmpdir ( ) , "wp-codebox-phpunit-empty-discovery-" ) )
285+ const testsDir = join ( tempDir , "tests" )
286+ mkdirSync ( testsDir )
287+ writeFileSync ( join ( testsDir , "profile-smoke.php" ) , "<?php echo 'standalone smoke';\n" )
288+ const scriptPath = join ( tempDir , "discover.php" )
289+ writeFileSync (
290+ scriptPath ,
291+ `<?php
292+ function pg_log($message) { echo $message, "\\n"; }
293+ function pg_stage_begin($stage) {}
294+ function pg_stage_ok($stage) {}
295+ function pg_stage_fail($stage, Throwable $e) { echo 'STAGE_FAIL:', $e->getMessage(), "\\n"; }
296+ ${ extractPhpFunction ( code , "wp_codebox_phpunit_parse_config" ) }
297+ ${ extractPhpFunction ( code , "wp_codebox_phpunit_discover" ) }
298+ $discovery_only = true;
299+ $plugin_slug = 'fixture';
300+ $test_root = ${ phpString ( testsDir ) } ;
301+ $selected_testsuites = array();
302+ ${ discoveryBlock . replaceAll ( JSON . stringify ( "/wordpress/wp-content/plugins/fixture/phpunit.xml.dist" ) , phpString ( join ( tempDir , "phpunit.xml.dist" ) ) ) }
303+ ` ,
304+ )
305+ let output = ""
306+ try {
307+ output = execFileSync ( "php" , [ scriptPath ] , { encoding : "utf8" } )
308+ } catch ( error ) {
309+ assert . fail ( `empty discovery must exit 0: ${ ( error as { stdout ?: string } ) . stdout ?? error } ` )
310+ }
311+ assert . doesNotMatch ( output , / S T A G E _ F A I L / )
312+ const line = output . split ( "\n" ) . find ( ( entry ) => entry . startsWith ( "DISCOVERY_RESULT_JSON:" ) )
313+ assert . ok ( line , `expected a discovery result: ${ output } ` )
314+ assert . deepEqual ( JSON . parse ( line . slice ( "DISCOVERY_RESULT_JSON:" . length ) ) . files , [ ] )
315+
316+ const result = await runPhpunitCommand ( {
317+ artifactRoot : "/tmp/artifacts" ,
318+ mounts : [ ] ,
319+ runPlaygroundCommand : async ( ) => ( { exitCode : 0 , errors : "" , text : "" } ) ,
320+ runtimeSpec : wordpressRuntimeSpec ( { commands : [ "wordpress.phpunit" ] } ) ,
321+ server : { playground : { readFileAsText : async ( ) => `${ line } \n` } } as never ,
322+ spec : { command : "wordpress.phpunit" , args : [ "plugin-slug=fixture" , "discovery-only=1" ] } ,
323+ } )
324+ assert . deepEqual ( JSON . parse ( result ) . files , [ ] )
325+ } )
0 commit comments