Skip to content

doc(proposal): un/break --test#13

Open
JakobJingleheimer wants to merge 4 commits intomainfrom
proposals/unbreak-test-flag
Open

doc(proposal): un/break --test#13
JakobJingleheimer wants to merge 4 commits intomainfrom
proposals/unbreak-test-flag

Conversation

@JakobJingleheimer
Copy link
Member

A follow-up to the discussion in the 26 Jan 2026 team meeting

node
--test ./src/foo/*.test.js
--test ./src/bar/*.test.js
./src/not-pjson-main.js
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would the purpose of this be? The test runner runs for the two glob patterns and then does what with this entry point script? Executes it as a test too or just as a regular node script?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes, true. Let's say there is no such thing as an entry-point for test mode (I think that doesn't exist currently either). If there's any "entry-point" when --test is present, throw.

I think in order to run an arbitrary script, it should be done with --import (and friends); otherwise, you get into inception.

node
  --import ./test/env.setup.js
  --import ./test/fix-snapshot-naming.js
  --test ./src/foo/*.test.js
  --test ./src/bar/*.test.js

./src/not-pjson-main.js
```

An explicit entrypoint, like all node commands, must come last and must be a relative or absolute path (not a glob/pattern).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this tracks for test. Many users will only want to pass a single glob pattern; at least I know that I do! What would the explicit entry point do for a test script?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, okay, fair. So when watch mode is combined with test mode, shall we say that entry-point is not applicable—it's only applicable for watch mode separately?

@cjihrig
Copy link

cjihrig commented Feb 9, 2026

How will this work across versions? Please don't underestimate the pain that inconsistencies in the test runner CLI across versions cause for users (ie glob support). It takes years for these pain points to go away.

@JakobJingleheimer
Copy link
Member Author

@cjihrig we discussed in today's meeting. I'm about to update this with the 3rd option that was born from that. I'll ping you for review in a few minutes.

@cjihrig
Copy link

cjihrig commented Feb 9, 2026

Discussed with @JakobJingleheimer and apparently it will not break existing users, so 👍

@JakobJingleheimer
Copy link
Member Author

I think "option 3" will actually JustWork? --test is eager/hungry, so

node
  --test ./foo.test.js
  --test ./bar.test.js

currently results in:

[
  './foo.test.js',
  '--test',
  './bar.test.js',
]

--test is nonsense for a value, and it currently gets discarded (all flags after --test do).

We can backport support for --watch-path (that’s nonbreaking); it would just continue to not work in older versions if supplied after --test.

Copy link
Contributor

@Ethan-Arrowood Ethan-Arrowood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still seeing some parts of this talking about main entrypoints with the test runner which just doesn't make sense. I'd prefer we clean that up before merging this as that may only cause more confusion in further discussions.

Comment on lines +171 to +183
`test` would then work the same way:

```sh title='reads "main" etc from package.json'
node --test
```
```sh title='package.json "main" + an additional path'
node --test ./src/**/*.test.js
```
```sh title='explicit entrypoint + an additional path'
node
--test ./src/foo/*.test.js
--test ./src/bar/*.test.js
./src/not-pjson-main.js
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this section still needs to be updated, no? Test runs don't use main entrypoint or any entrypoint for that matter. It uses file patterns matching test files.

Comment on lines +198 to +199
--watch
./src/not-pjson-main.js
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe an newline character would change the CLI parsing here. This is the same as specifying a path for --watch. Or am I mistaken?

@JakobJingleheimer
Copy link
Member Author

I'm still seeing some parts of this talking about main entrypoints with the test runner which just doesn't make sense. I'd prefer we clean that up before merging this as that may only cause more confusion in further discussions.

Are you talking about the other options besides the one added yesterday? If so, my plan was to wait for people to weigh in; once one is selected, update the proposal to move the discard ones to a new "Rejected" section, and outdent the selected option.

If you're talking about the small bit mentioning --watch's value being discarded, doesn't that align with what you just said?

@Ethan-Arrowood
Copy link
Contributor

Maybe I'm not tracking; I am just confused by a script like:

node --watch ./src/not-pjson-main.js --test ./test/*.test.js

Like test mode should "overrule" the watch mode here. Unless the expectation is for that example to actually favor the watch entrypoint over test entries.

Take --watch out of the example for a moment. When you run node --test you don't invoke the package.json main script. Similarly, if you specified something like:

node main.js --test test.js

Only main.js is executed and the --test test.js is ignored.

So i want to be clear in our examples of what the behavior of combining --watch with --test is. IMO this is like a special case of "Test and Watch" that is distinct from just "Watch" or just "Test" modes.

I hope I'm making sense. Kinda difficult to explain I guess

@Ethan-Arrowood
Copy link
Contributor

Maybe my confusion / concern is that I'm conflating node --watch main.js to mean that not only is it watching main.js, but also executing it.

When you use --watch with --test, the paths specified are no longer being executed; instead it is just paths that need to be added to the watcher that would reinvoke the test process.

Thus we should be careful about language like "main entrypoint" because that implies its going to be executed (at least thats how I interpret it). I recognize that another interpretation is the main entrypoint is the default watch path.

Yeah this is a confusing one.

@ljharb
Copy link
Member

ljharb commented Feb 17, 2026

node --watch works. which implies that node --watch path/to/file is the same as node --path/to/file in watch mode.

In other words, node --watch ./src/not-pjson-main.js --test ./test/*.test.js should either be executing the file in watch mode, and then running the tests in watch mode - or, be an error - --watch should be treated as a boolean flag, not something that takes an argument.

@pmarchini
Copy link
Member

node --watch works. which implies that node --watch path/to/file is the same as node --path/to/file in watch mode.

In other words, node --watch ./src/not-pjson-main.js --test ./test/*.test.js should either be executing the file in watch mode, and then running the tests in watch mode - or, be an error - --watch should be treated as a boolean flag, not something that takes an argument.

Regarding node --watch nodejs/node#61740 (comment)

@cjihrig
Copy link

cjihrig commented Feb 18, 2026

Not sure if you all have seen these or not, but they seem relevant:

nodejs/node#61852
nodejs/node#61858

@pmarchini
Copy link
Member

Not sure if you all have seen these or not, but they seem relevant:

nodejs/node#61852 nodejs/node#61858

Regarding this, I took a look and tried running the repro against versions from 20 to the latest version. As far as I can see, we have never supported this specific behavior.

I'm also reviewing the proposed PR, but I have the impression that it's still a somewhat "hacky" solution.

I'm wondering if, following what we are proposing in this discussion and in line with other functionalities, we should support something like --test-argv.

Having such an option would automatically translate into config support as well.

@JakobJingleheimer
Copy link
Member Author

JakobJingleheimer commented Feb 23, 2026

@Ethan-Arrowood ohhhhhhhh! yes, now I get it:

node
  --watch ./bar.js
  --test ./foo.test.js

Does not do what I was / we were thinking: Here, it triggers watch mode with an entry-point of ./bar.js and --test ./foo.test.js is passed to ./bar.js (not node itself) as a custom argument.

What if a user lists --test before --watch though (same question for setting both in a config file):

node
  --test ./foo.test.js
  --watch ./bar.js

In that case, --test ./foo.test.js is a node argument, not a custom argument to pass to ./bar.js.

(I believe what we said in the meeting today is that this should throw; --watch with no value, and "watch": true/false in a config file are good.)

@vassudanagunta
Copy link

vassudanagunta commented Mar 5, 2026

If ‑‑test were a subcommand, not an option flag, things would get a lot simpler, cleaner and more intuitive.

None of the following would have any ambiguity:

node test
node test --watch
node test test/*.test.js
node test --watch test/*.test.js ‑‑reporter lcov
node test ‑‑reporter lcov test/*.test.js --watch
node test test/*.test.js other.test.js
node test test/*.test.js ‑‑reporter lcov other.test.js 
node test --only --concurrency=1 --update-snapshots
node test test/*.test.js -- "arg passed to test scripts"  

‑‑watch would remain an argument‑free switch. It would be a global option, not just for node test. It could be added to any of the above in any position except between ‑‑reporter and lcov, which should be obvious.

Test‑specific options such as ‑‑reporter would no longer need the redundant test- prefix, and can go in any position after the test subcommand.

The issues linked above by @cjihrig and @pmarchini, in addition to nodejs/node#51384 which @cjihrig identified as high impact (#21), would have clean resolution.

There is precedence for node subcommands: node inspect. In fact, the distinction between option and subcommand is exemplified by the comparing it with node ‑‑inspect:

node ‑‑inspect script.js  # "node script.js" with optional debugging listener enabled
node inspect script.js    # start interactive debugger against script.js

I would migrate at least ‑‑test and ‑‑run to subcommands, probably solving issues with the latter as well. The de facto mutual‑exclusivity/incompatibility of node inspect, --inspect, ‑‑test and ‑‑run would become syntactical:

task current proposed
execute script node [script] node [script]
test script(s) node ‑‑test [scripts...] node test [scripts...]
run named package.json shell script node ‑‑run [pkg‑script] node run [pkg‑script]
start interactive debugger
with node ‑‑inspect script in subprocess
node inspect [script] node inspect [script]

This isn't either‑or. One of the "un/break" proposals in this PR may make sense as a practical, near‑term fix to the current ‑‑test flag. But introducing a test subcommand may be the best long term solution. The current form could be maintained for compatibility, but deprecated with no promise of backports of new features added to the subcommands. User migration would almost always be a painless single line update.

Alternatively, a separate node-test executable could be introduced with all the same benefits and no backward compatibility concerns.

See also nodejs/node#53483 by @MoLow.

If there is appetite for this, I could write up a more in‑depth analysis, covering nuances such as how node <script that uses node:test> would fit.

@JakobJingleheimer
Copy link
Member Author

JakobJingleheimer commented Mar 8, 2026

If ‑‑test were a subcommand, not an option flag

That's an interesting idea; at first glance, it makes a lot of sense. @pmarchini what do you think? (If we do it, I think we should not tether that to --run, but that could maybe be done separately—not our purview here though).

IIR, there was some discussion within the PR introducing --run (nodejs/node#52190) about using a sub-command for it; I can't find that discussion now (it may well be buried in the hundreds of comments or some tangential issue, maybe nodejs/node#46534).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

8 participants