-
Notifications
You must be signed in to change notification settings - Fork 29.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
test_runner: add cwd option to run #54705
base: main
Are you sure you want to change the base?
Conversation
Review requested:
|
We need to turn the If we make the Same thing. The test object there will have a reference to the |
@cjihrig thanks for the support, I'm gonna take a look ASAP! |
4fa3784
to
3419393
Compare
src/node_options.cc
Outdated
@@ -671,6 +671,9 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { | |||
&EnvironmentOptions::test_coverage_lines, | |||
kAllowedInEnvvar); | |||
|
|||
AddOption("--experimental-test-cwd", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should add this. The cwd
option should be supported by the run()
API only IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, makes sense! I was thinking about a way to set the entire test runner's cwd
to allow this behavior to be configured via the CLI as well.
Btw, while working on this, I noticed an unexpected behavior related to isolation and watch mode.
I'm going to open a PR to ask for your feedback, @cjihrig
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the user wants to use the CLI, they could do something like cd path/to/tests && node --test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree
fc95c78
to
518bb16
Compare
lib/internal/test_runner/runner.js
Outdated
if (existsSync(cwd) === false) { | ||
throw new ERR_INVALID_ARG_VALUE('options.cwd', cwd, 'expects an existing directory'); | ||
} else if (!lstatSync(cwd).isDirectory()) { | ||
throw new ERR_INVALID_ARG_VALUE('options.cwd', cwd, 'expects a directory, a file was provided'); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather not do this. existsSync()
specifically is a race condition. Just assume that the cwd is a directory and handle any errors. For example, the child process APIs, which also take a cwd
option don't perform this type of validation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed the validation and added a couple of tests to check that run
handles an incorrect cwd without throwing errors
lib/internal/test_runner/coverage.js
Outdated
@@ -477,7 +477,7 @@ function sortCoverageFiles(a, b) { | |||
|
|||
function setupCoverage(options) { | |||
let originalCoverageDirectory = process.env.NODE_V8_COVERAGE; | |||
const cwd = process.cwd(); | |||
const cwd = options.cwd ?? process.cwd(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should ensure that options.cwd
always exists and remove the ?? process.cwd()
fallback.
lib/internal/test_runner/harness.js
Outdated
@@ -83,7 +83,7 @@ function createTestTree(rootTestOptions, globalOptions) { | |||
return globalRoot; | |||
} | |||
|
|||
function createProcessEventHandler(eventName, rootTest) { | |||
function createProcessEventHandler(eventName, rootTest, cwd) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to get the cwd
from the rootTest
here instead of adding another argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the meantime, I've seen that in harness.js
we have:
node/lib/internal/test_runner/harness.js
Lines 80 to 90 in c1afd2c
harness.resetCounters(); | |
globalRoot = new Test({ | |
__proto__: null, | |
...rootTestOptions, | |
harness, | |
name: '<root>', | |
}); | |
setupProcessState(globalRoot, globalOptions, harness); | |
globalRoot.startTime = hrtime(); | |
return globalRoot; | |
} |
While the method definition is:
node/lib/internal/test_runner/harness.js
Lines 182 to 184 in c1afd2c
function setupProcessState(root, globalOptions) { | |
const hook = createHook({ |
Can I remove harness
from the setupProcessState
method call, or should I do that in a separate PR?
Co-authored-by: Aviv Keller <[email protected]>
Co-authored-by: Aviv Keller <[email protected]>
Co-authored-by: Aviv Keller <[email protected]>
c0a6949
to
ec3ff3e
Compare
924c375
to
ac74667
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #54705 +/- ##
=======================================
Coverage 88.07% 88.08%
=======================================
Files 652 652
Lines 183542 183550 +8
Branches 35862 35863 +1
=======================================
+ Hits 161653 161672 +19
+ Misses 15144 15123 -21
- Partials 6745 6755 +10
|
const interval = setInterval(() => renameSync(fileToRenamePath, newFileNamePath), common.platformTimeout(1000)); | ||
const interval = setInterval(() => { | ||
renameSync(fileToRenamePath, newFileNamePath); | ||
clearInterval(interval); | ||
}, common.platformTimeout(1000)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @cjihrig, regarding these tests, I was working on a GitHub codespace yesterday, and I noticed that this test was flaky there.
The issue was with the interval: if the system is delayed for any reason beyond the timeout, a second run of "rename" (and similarly for "delete") is triggered, causing an error because the file has already been renamed and can no longer be found under its previous name.
I'll take a look at the other similar tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense. Timers in tests should be avoided like the plague if possible.
Do we need to use an interval for operations like that? For example, would it work to use a setTimeout()
and then reschedule the callback again once the timer fires?
I'm opening this PR as a draft to have a place where we can discuss this implementation.
Some background context:
During #54225, we discussed the possibility of adding a new option to
run
.This new option would be
cwd
.This change could impact many other parts of the code, such as:
#54225 (comment)
For this reason, we decided to work on this in a separate PR (#54225 (comment)).