Skip to content

Commit e702321

Browse files
committed
fix(phpunit): report empty discovery as an empty result
Discovery-only mode threw "PHPUnit discovery found no test files" and the discovery reader rejected files: [], so a component whose suite is entirely outside PHPUnit (standalone PHP smokes) could not get a discovery answer at all. Discovery now reports what exists; consumers decide whether zero PHPUnit files is acceptable. Execution mode still refuses to run nothing.
1 parent a17d664 commit e702321

3 files changed

Lines changed: 78 additions & 2 deletions

File tree

‎packages/runtime-playground/src/phpunit-command-handlers.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1384,9 +1384,12 @@ if ($discovery_only) {
13841384
}
13851385
list($directories, $suffixes, $prefixes, $excludes, $configured_files) = wp_codebox_phpunit_parse_config(${JSON.stringify(options.phpunitXml)}, $test_dir, $selected_testsuites);
13861386
$test_files = wp_codebox_phpunit_discover($directories, $suffixes, $prefixes, $excludes, $configured_files);
1387+
// Discovery reports what exists. An empty set is a valid answer for a
1388+
// component whose suite lives outside PHPUnit; the consumer decides
1389+
// whether zero PHPUnit files is acceptable. Execution still refuses to
1390+
// run nothing (see discover_tests below).
13871391
if (empty($test_files)) {
13881392
pg_log('NO_TEST_FILES');
1389-
throw new RuntimeException('PHPUnit discovery found no test files');
13901393
}
13911394
sort($test_files, SORT_STRING);
13921395
$discovery_result = array(

‎packages/runtime-playground/src/runtime-diagnostics.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ export async function readPluginPhpunitDiscoveryResult(server: PlaygroundCliServ
116116
|| typeof value.phpunit_xml !== "string"
117117
|| typeof value.test_root !== "string"
118118
|| !Array.isArray(value.selected_testsuites) || value.selected_testsuites.some((entry) => typeof entry !== "string")
119-
|| !Array.isArray(value.files) || value.files.length === 0 || value.files.some((entry) => typeof entry !== "string" || entry === "")) {
119+
|| !Array.isArray(value.files) || value.files.some((entry) => typeof entry !== "string" || entry === "")) {
120120
return undefined
121121
}
122122
return value as PhpunitDiscoveryResult

‎tests/phpunit-discovery-only.test.ts‎

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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, /STAGE_FAIL/)
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

Comments
 (0)