Skip to content

Commit

Permalink
test_runner: add cwd option to run
Browse files Browse the repository at this point in the history
PR-URL: #54705
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
  • Loading branch information
pmarchini authored Oct 3, 2024
1 parent fe45be2 commit 1c7795e
Show file tree
Hide file tree
Showing 9 changed files with 283 additions and 50 deletions.
6 changes: 6 additions & 0 deletions doc/api/test.md
Original file line number Diff line number Diff line change
Expand Up @@ -1256,6 +1256,9 @@ added:
- v18.9.0
- v16.19.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/54705
description: Added the `cwd` option.
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/53937
description: Added coverage options.
Expand Down Expand Up @@ -1286,6 +1289,9 @@ changes:
parallel.
If `false`, it would only run one test file at a time.
**Default:** `false`.
* `cwd`: {string} Specifies the current working directory to be used by the test runner.
Serves as the base path for resolving files according to the [test runner execution model][].
**Default:** `process.cwd()`.
* `files`: {Array} An array containing the list of files to run.
**Default:** matching files from [test runner execution model][].
* `forceExit`: {boolean} Configures the test runner to exit the process once
Expand Down
5 changes: 2 additions & 3 deletions lib/internal/test_runner/coverage.js
Original file line number Diff line number Diff line change
Expand Up @@ -487,15 +487,14 @@ function sortCoverageFiles(a, b) {

function setupCoverage(options) {
let originalCoverageDirectory = process.env.NODE_V8_COVERAGE;
const cwd = process.cwd();

if (originalCoverageDirectory) {
// NODE_V8_COVERAGE was already specified. Convert it to an absolute path
// and store it for later. The test runner will use a temporary directory
// so that no preexisting coverage files interfere with the results of the
// coverage report. Then, once the coverage is computed, move the coverage
// files back to the original NODE_V8_COVERAGE directory.
originalCoverageDirectory = resolve(cwd, originalCoverageDirectory);
originalCoverageDirectory = resolve(options.cwd, originalCoverageDirectory);
}

const coverageDirectory = mkdtempSync(join(tmpdir(), 'node-coverage-'));
Expand All @@ -512,7 +511,7 @@ function setupCoverage(options) {
return new TestCoverage(
coverageDirectory,
originalCoverageDirectory,
cwd,
options.cwd,
options.coverageExcludeGlobs,
options.coverageIncludeGlobs,
{
Expand Down
3 changes: 2 additions & 1 deletion lib/internal/test_runner/harness.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ function createProcessEventHandler(eventName, rootTest) {
const name = test.hookType ? `Test hook "${test.hookType}"` : `Test "${test.name}"`;
let locInfo = '';
if (test.loc) {
const relPath = relative(process.cwd(), test.loc.file);
const relPath = relative(rootTest.config.cwd, test.loc.file);
locInfo = ` at ${relPath}:${test.loc.line}:${test.loc.column}`;
}

Expand Down Expand Up @@ -260,6 +260,7 @@ function lazyBootstrapRoot() {
loc: entryFile ? [1, 1, entryFile] : undefined,
};
const globalOptions = parseCommandLine();
globalOptions.cwd = process.cwd();
createTestTree(rootTestOptions, globalOptions);
globalRoot.reporter.on('test:summary', (data) => {
if (!data.success) {
Expand Down
25 changes: 14 additions & 11 deletions lib/internal/test_runner/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const {

const { spawn } = require('child_process');
const { finished } = require('internal/streams/end-of-stream');
const { resolve } = require('path');
const { resolve, sep, isAbsolute } = require('path');
const { DefaultDeserializer, DefaultSerializer } = require('v8');
const { getOptionValue } = require('internal/options');
const { Interface } = require('internal/readline/interface');
Expand All @@ -56,14 +56,14 @@ const {
validateObject,
validateOneOf,
validateInteger,
validateString,
validateStringArray,
} = require('internal/validators');
const { getInspectPort, isUsingInspector, isInspectorMessage } = require('internal/util/inspector');
const { isRegExp } = require('internal/util/types');
const { pathToFileURL } = require('internal/url');
const {
createDeferredPromise,
getCWDURL,
kEmptyObject,
} = require('internal/util');
const { kEmitMessage } = require('internal/test_runner/tests_stream');
Expand Down Expand Up @@ -137,7 +137,8 @@ function getRunArgs(path, { forceExit,
testSkipPatterns,
only,
argv: suppliedArgs,
execArgv }) {
execArgv,
cwd }) {
const argv = ArrayPrototypeFilter(process.execArgv, filterExecArgv);
if (forceExit === true) {
ArrayPrototypePush(argv, '--test-force-exit');
Expand Down Expand Up @@ -494,7 +495,8 @@ function watchFiles(testFiles, opts) {
// When file renamed (created / deleted) we need to update the watcher
if (newFileName) {
owners = new SafeSet().add(newFileName);
watcher.filterFile(resolve(newFileName), owners);
const resolveFileName = isAbsolute(newFileName) ? newFileName : resolve(opts.cwd, newFileName);
watcher.filterFile(resolveFileName, owners);
}

if (!newFileName && previousFileName) {
Expand Down Expand Up @@ -562,6 +564,7 @@ function run(options = kEmptyObject) {
functionCoverage = 0,
execArgv = [],
argv = [],
cwd = process.cwd(),
} = options;

if (files != null) {
Expand All @@ -586,6 +589,8 @@ function run(options = kEmptyObject) {
validateArray(globPatterns, 'options.globPatterns');
}

validateString(cwd, 'options.cwd');

if (globPatterns?.length > 0 && files?.length > 0) {
throw new ERR_INVALID_ARG_VALUE(
'options.globPatterns', globPatterns, 'is not supported when specifying \'options.files\'',
Expand Down Expand Up @@ -673,12 +678,9 @@ function run(options = kEmptyObject) {
lineCoverage: lineCoverage,
branchCoverage: branchCoverage,
functionCoverage: functionCoverage,
cwd,
};
const root = createTestTree(rootTestOptions, globalOptions);

// This const should be replaced by a run option in the future.
const cwd = process.cwd();

let testFiles = files ?? createTestFileList(globPatterns, cwd);

if (shard) {
Expand Down Expand Up @@ -731,7 +733,8 @@ function run(options = kEmptyObject) {
};
} else if (isolation === 'none') {
if (watch) {
filesWatcher = watchFiles(testFiles, opts);
const absoluteTestFiles = ArrayPrototypeMap(testFiles, (file) => (isAbsolute(file) ? file : resolve(cwd, file)));
filesWatcher = watchFiles(absoluteTestFiles, opts);
runFiles = async () => {
root.harness.bootstrapPromise = null;
root.harness.buildPromise = null;
Expand All @@ -744,7 +747,7 @@ function run(options = kEmptyObject) {
const { promise, resolve: finishBootstrap } = createDeferredPromise();

await root.runInAsyncScope(async () => {
const parentURL = getCWDURL().href;
const parentURL = pathToFileURL(cwd + sep).href;
const cascadedLoader = esmLoader.getOrInitializeCascadedLoader();
let topLevelTestCount = 0;

Expand All @@ -757,7 +760,7 @@ function run(options = kEmptyObject) {

for (let i = 0; i < testFiles.length; ++i) {
const testFile = testFiles[i];
const fileURL = pathToFileURL(testFile);
const fileURL = pathToFileURL(resolve(cwd, testFile));
const parent = i === 0 ? undefined : parentURL;
let threw = false;
let importError;
Expand Down
20 changes: 19 additions & 1 deletion test/fixtures/test-runner-watch.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,37 @@ const options = {
file: {
type: 'string',
},
cwd: {
type: 'string',
},
isolation: {
type: 'string',
},
};
const {
values,
positionals,
} = parseArgs({ args: process.argv.slice(2), options });

let files;
let cwd;
let isolation;

if (values.file) {
files = [values.file];
}

if (values.cwd) {
cwd = values.cwd;
}

if (values.isolation) {
isolation = values.isolation;
}

run({
files,
watch: true
watch: true,
cwd,
isolation,
}).compose(tap).pipe(process.stdout);
34 changes: 34 additions & 0 deletions test/parallel/test-runner-no-isolation-different-cwd.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { allowGlobals, mustCall } from '../common/index.mjs';
import * as fixtures from '../common/fixtures.mjs';
import { deepStrictEqual } from 'node:assert';
import { run } from 'node:test';

const stream = run({
cwd: fixtures.path('test-runner', 'no-isolation'),
isolation: 'none',
});


stream.on('test:pass', mustCall(4));
// eslint-disable-next-line no-unused-vars
for await (const _ of stream);
allowGlobals(globalThis.GLOBAL_ORDER);
deepStrictEqual(globalThis.GLOBAL_ORDER, [
'before one: <root>',
'suite one',
'before two: <root>',
'suite two',
'beforeEach one: suite one - test',
'beforeEach two: suite one - test',
'suite one - test',
'afterEach one: suite one - test',
'afterEach two: suite one - test',
'before suite two: suite two',
'beforeEach one: suite two - test',
'beforeEach two: suite two - test',
'suite two - test',
'afterEach one: suite two - test',
'afterEach two: suite two - test',
'after one: <root>',
'after two: <root>',
]);
Loading

0 comments on commit 1c7795e

Please sign in to comment.