Skip to content

Commit bbb71b2

Browse files
bartlomiejuclaude
andcommitted
chore(x): require filter arg for test commands and add --list support
Test commands (test-unit, test-node, test-compat, test-spec) now require a filter argument to select which tests to run, and support --list to print all available tests. This makes the commands more explicit and discoverable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 38810a5 commit bbb71b2

File tree

1 file changed

+159
-58
lines changed

1 file changed

+159
-58
lines changed

tools/x/main.ts

Lines changed: 159 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,42 @@ interface Command {
1919
* the hood.
2020
*/
2121
help: string;
22-
fn: () => Promise<void>;
22+
fn: (args: string[]) => Promise<void>;
2323
}
2424

25-
function buildCommands(root: ReturnType<typeof $.path>): Record<string, Command> {
25+
function cargoTestCommand(
26+
root: ReturnType<typeof $.path>,
27+
baseArgs: string[],
28+
opts: { description: string; help: string; stepName: string },
29+
): Command {
30+
return {
31+
description: opts.description,
32+
help: opts.help,
33+
async fn(args: string[]) {
34+
if (args.includes("--list")) {
35+
await $`cargo test ${baseArgs} -- --list`.cwd(root);
36+
return;
37+
}
38+
if (args.length === 0) {
39+
$.logError(
40+
"A filter argument is required. Use --list to see available tests.",
41+
);
42+
Deno.exit(1);
43+
}
44+
$.logStep(`Running ${opts.stepName}...`);
45+
await $`cargo test ${baseArgs} -- ${args.join(" ")}`.cwd(root);
46+
$.logStep(`${opts.stepName} complete.`);
47+
},
48+
};
49+
}
50+
51+
function buildCommands(
52+
root: ReturnType<typeof $.path>,
53+
): Record<string, Command> {
2654
const fmtCmd: Command = {
2755
description: "Format all code (JS/TS/Rust/etc. via dprint)",
28-
help: `Formats the entire codebase using the project's formatting tool chain.
56+
help:
57+
`Formats the entire codebase using the project's formatting tool chain.
2958
This runs dprint (configured in dprint.json) which handles JavaScript,
3059
TypeScript, JSON, JSONC, Markdown, TOML, and Rust formatting.
3160
@@ -34,7 +63,7 @@ in the './x verify' pre-commit workflow.
3463
3564
Under the hood:
3665
deno run -A tools/format.js`,
37-
async fn() {
66+
async fn(_args: string[]) {
3867
$.logStep("Formatting code...");
3968
await $`deno run -A tools/format.js`.cwd(root);
4069
$.logStep("Formatting complete.");
@@ -49,7 +78,7 @@ not modified any Rust code.
4978
5079
Under the hood:
5180
deno run -A tools/lint.js --js`,
52-
async fn() {
81+
async fn(_args: string[]) {
5382
$.logStep("Linting JavaScript/TypeScript...");
5483
await $`deno run -A tools/lint.js --js`.cwd(root);
5584
$.logStep("JS lint complete.");
@@ -59,7 +88,8 @@ Under the hood:
5988
return {
6089
"setup": {
6190
description: "Initial setup: build deno and test_server",
62-
help: `Sets up the development environment by compiling both the main 'deno'
91+
help:
92+
`Sets up the development environment by compiling both the main 'deno'
6393
binary and the 'test_server' binary used by the test suite.
6494
6595
Run this once after cloning the repository, or after pulling changes that
@@ -68,7 +98,7 @@ testing.
6898
6999
Under the hood:
70100
cargo build --bin deno --bin test_server`,
71-
async fn() {
101+
async fn(_args: string[]) {
72102
$.logStep("Setting up development environment...");
73103
$.logStep("Building deno and test_server...");
74104
await $`cargo build --bin deno --bin test_server`.cwd(root);
@@ -89,7 +119,7 @@ it skips the linking step.
89119
90120
Under the hood:
91121
cargo build --bin deno`,
92-
async fn() {
122+
async fn(_args: string[]) {
93123
$.logStep("Building Deno...");
94124
await $`cargo build --bin deno`.cwd(root);
95125
$.logStep("Build complete.");
@@ -107,83 +137,124 @@ of a full build.
107137
108138
Under the hood:
109139
cargo check`,
110-
async fn() {
140+
async fn(_args: string[]) {
111141
$.logStep("Checking (no linking)...");
112142
await $`cargo check`.cwd(root);
113143
$.logStep("Check complete.");
114144
},
115145
},
116-
"test-unit": {
117-
description: "Run Deno runtime unit tests",
118-
help: `Runs the Deno runtime unit tests. These are JavaScript/TypeScript tests
146+
"test-unit": cargoTestCommand(
147+
root,
148+
["-p", "unit_tests", "--test", "unit"],
149+
{
150+
description: "Run Deno runtime unit tests",
151+
stepName: "unit tests",
152+
help:
153+
`Runs the Deno runtime unit tests. These are JavaScript/TypeScript tests
119154
that exercise Deno's built-in APIs (e.g. Deno.readFile, Deno.serve,
120155
Web API implementations) by running them inside the Deno runtime itself.
121156
122157
The test files live under tests/unit/ and are compiled into the
123158
'unit_tests' crate.
124159
160+
Requires a filter argument to select which tests to run. The filter is
161+
a substring match against test names.
162+
163+
Usage:
164+
./x test-unit <filter> Run tests matching the filter
165+
./x test-unit --list List all available tests
166+
167+
Examples:
168+
./x test-unit streams Run tests with "streams" in their name
169+
./x test-unit fetch Run tests with "fetch" in their name
170+
125171
Under the hood:
126-
cargo test -p unit_tests --test unit`,
127-
async fn() {
128-
$.logStep("Running unit tests...");
129-
await $`cargo test -p unit_tests --test unit`.cwd(root);
130-
$.logStep("Unit tests complete.");
172+
cargo test -p unit_tests --test unit -- <filter>`,
131173
},
132-
},
133-
"test-node": {
174+
),
175+
"test-node": cargoTestCommand(root, [
176+
"-p",
177+
"unit_node_tests",
178+
"--test",
179+
"unit_node",
180+
], {
134181
description: "Run Node.js API unit tests",
182+
stepName: "Node.js unit tests",
135183
help: `Runs unit tests for Deno's Node.js compatibility layer. These tests
136184
verify that Deno's implementations of Node.js built-in modules (fs,
137185
path, http, crypto, etc.) behave correctly.
138186
139187
The test files live under tests/unit_node/ and are compiled into the
140188
'unit_node_tests' crate.
141189
190+
Requires a filter argument to select which tests to run. The filter is
191+
a substring match against test names.
192+
193+
Usage:
194+
./x test-node <filter> Run tests matching the filter
195+
./x test-node --list List all available tests
196+
197+
Examples:
198+
./x test-node crypto Run tests with "crypto" in their name
199+
./x test-node http Run tests with "http" in their name
200+
142201
Under the hood:
143-
cargo test -p unit_node_tests --test unit_node`,
144-
async fn() {
145-
$.logStep("Running Node.js unit tests...");
146-
await $`cargo test -p unit_node_tests --test unit_node`.cwd(root);
147-
$.logStep("Node.js unit tests complete.");
148-
},
149-
},
150-
"test-compat": {
202+
cargo test -p unit_node_tests --test unit_node -- <filter>`,
203+
}),
204+
"test-compat": cargoTestCommand(root, ["--test", "node_compat"], {
151205
description: "Run Node.js compatibility tests",
206+
stepName: "Node.js compatibility tests",
152207
help: `Runs the Node.js compatibility test suite. These tests use actual
153208
Node.js test cases (ported or adapted) to verify that Deno's node:*
154209
module implementations match Node.js behavior.
155210
156211
The test runner lives in tests/node_compat/runner/.
157212
213+
Requires a filter argument to select which tests to run. The filter is
214+
a substring match against test names.
215+
216+
Usage:
217+
./x test-compat <filter> Run tests matching the filter
218+
./x test-compat --list List all available tests
219+
220+
Examples:
221+
./x test-compat fs Run tests with "fs" in their name
222+
./x test-compat path Run tests with "path" in their name
223+
158224
Under the hood:
159-
deno task --cwd tests/node_compat/runner test`,
160-
async fn() {
161-
$.logStep("Running Node.js compatibility tests...");
162-
await $`deno task --cwd tests/node_compat/runner test`.cwd(root);
163-
$.logStep("Node.js compatibility tests complete.");
164-
},
165-
},
166-
"test-spec": {
225+
cargo test --test node_compat -- <filter>`,
226+
}),
227+
"test-spec": cargoTestCommand(root, [
228+
"-p",
229+
"specs_tests",
230+
"--test",
231+
"specs",
232+
], {
167233
description: "Run spec (integration) tests",
168-
help: `Runs the spec integration tests. These are the primary integration tests
234+
stepName: "spec tests",
235+
help:
236+
`Runs the spec integration tests. These are the primary integration tests
169237
for Deno's CLI — each test defines CLI commands to execute and asserts
170238
on their stdout/stderr output.
171239
172240
Spec tests live under tests/specs/. Each test directory contains a
173241
'__test__.jsonc' file describing the commands to run and expected output
174242
(using wildcards like [WILDCARD], [WILDLINE], etc.).
175243
176-
Use this to verify end-to-end CLI behavior after making changes to
177-
subcommands, flag parsing, error messages, or module resolution.
244+
Requires a filter argument to select which tests to run. The filter is
245+
a substring match against test names.
246+
247+
Usage:
248+
./x test-spec <filter> Run tests matching the filter
249+
./x test-spec --list List all available tests
250+
251+
Examples:
252+
./x test-spec fmt Run spec tests with "fmt" in their name
253+
./x test-spec run Run spec tests with "run" in their name
178254
179255
Under the hood:
180-
cargo test -p specs_tests --test specs`,
181-
async fn() {
182-
$.logStep("Running spec tests...");
183-
await $`cargo test -p specs_tests --test specs`.cwd(root);
184-
$.logStep("Spec tests complete.");
185-
},
186-
},
256+
cargo test -p specs_tests --test specs -- <filter>`,
257+
}),
187258
"fmt": fmtCmd,
188259
"lint": {
189260
description: "Lint all code (JS/TS + Rust)",
@@ -196,7 +267,7 @@ changed JS/TS files, './x lint-js' is faster.
196267
197268
Under the hood:
198269
deno run -A tools/lint.js`,
199-
async fn() {
270+
async fn(_args: string[]) {
200271
$.logStep("Linting code...");
201272
await $`deno run -A tools/lint.js`.cwd(root);
202273
$.logStep("Linting complete.");
@@ -205,7 +276,8 @@ Under the hood:
205276
"lint-js": lintJsCmd,
206277
"verify": {
207278
description: "Pre-commit verification (fmt + lint-js)",
208-
help: `Runs the recommended pre-commit checks: formats all code, then lints
279+
help:
280+
`Runs the recommended pre-commit checks: formats all code, then lints
209281
JavaScript/TypeScript. This is the minimum verification you should do
210282
before committing changes that only touch JS/TS files.
211283
@@ -216,10 +288,10 @@ compilation errors.
216288
Equivalent to running:
217289
./x fmt
218290
./x lint-js`,
219-
async fn() {
291+
async fn(_args: string[]) {
220292
$.logStep("Running pre-commit verification...");
221-
await fmtCmd.fn();
222-
await lintJsCmd.fn();
293+
await fmtCmd.fn([]);
294+
await lintJsCmd.fn([]);
223295
$.logStep("Verification complete.");
224296
},
225297
},
@@ -232,16 +304,39 @@ Equivalent to running:
232304

233305
function printHelp(COMMANDS: Record<string, Command>) {
234306
console.log();
235-
console.log(` ${bold(cyan("x"))} ${dim("-")} Developer CLI for contributing to Deno`);
307+
console.log(
308+
` ${bold(cyan("x"))} ${dim("-")} Developer CLI for contributing to Deno`,
309+
);
236310
console.log();
237311
console.log(` ${bold("USAGE")}`);
238312
console.log(` ${dim("$")} ./x ${green("<command>")} [options]`);
239313
console.log();
240314
console.log(` ${bold("EXAMPLES")}`);
241-
console.log(` ${dim("$")} ./x ${green("build")} ${dim("# build the deno binary")}`);
242-
console.log(` ${dim("$")} ./x ${green("test-spec")} ${dim("# run spec integration tests")}`);
243-
console.log(` ${dim("$")} ./x ${green("fmt")} ${dim("# format the codebase")}`);
244-
console.log(` ${dim("$")} ./x ${green("build --help")} ${dim("# show detailed help for a command")}`);
315+
console.log(
316+
` ${dim("$")} ./x ${green("build")} ${
317+
dim("# build the deno binary")
318+
}`,
319+
);
320+
console.log(
321+
` ${dim("$")} ./x ${green("test-unit streams")} ${
322+
dim('# run unit tests matching "streams"')
323+
}`,
324+
);
325+
console.log(
326+
` ${dim("$")} ./x ${green("test-spec --list")} ${
327+
dim("# list all available spec tests")
328+
}`,
329+
);
330+
console.log(
331+
` ${dim("$")} ./x ${green("fmt")} ${
332+
dim("# format the codebase")
333+
}`,
334+
);
335+
console.log(
336+
` ${dim("$")} ./x ${green("build --help")} ${
337+
dim("# show detailed help for a command")
338+
}`,
339+
);
245340
console.log();
246341
console.log(` ${bold("COMMANDS")}`);
247342
for (const [name, cmd] of Object.entries(COMMANDS)) {
@@ -251,13 +346,19 @@ function printHelp(COMMANDS: Record<string, Command>) {
251346
console.log(` ${bold("OPTIONS")}`);
252347
console.log(` ${yellow("--help, -h")} Show this help message`);
253348
console.log();
254-
console.log(` Run ${cyan("./x <command> --help")} for detailed information about a specific command.`);
349+
console.log(
350+
` Run ${
351+
cyan("./x <command> --help")
352+
} for detailed information about a specific command.`,
353+
);
255354
console.log();
256355
}
257356

258357
function printCommandHelp(name: string, cmd: Command) {
259358
console.log();
260-
console.log(` ${bold(cyan("x"))} ${bold(green(name))} ${dim("-")} ${cmd.description}`);
359+
console.log(
360+
` ${bold(cyan("x"))} ${bold(green(name))} ${dim("-")} ${cmd.description}`,
361+
);
261362
console.log();
262363
for (const line of cmd.help.split("\n")) {
263364
console.log(` ${line}`);
@@ -297,5 +398,5 @@ export async function main(dirname: string) {
297398
Deno.exit(0);
298399
}
299400

300-
await cmd.fn();
401+
await cmd.fn(args.slice(1));
301402
}

0 commit comments

Comments
 (0)