Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/api/test.md
Original file line number Diff line number Diff line change
Expand Up @@ -1384,6 +1384,9 @@ added:
- v18.9.0
- v16.19.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/61367
description: Add the `env` option.
- version: v24.7.0
pr-url: https://github.com/nodejs/node/pull/59443
description: Added a rerunFailuresFilePath option.
Expand Down Expand Up @@ -1504,6 +1507,7 @@ changes:
* `functionCoverage` {number} Require a minimum percent of covered functions. If code
coverage does not reach the threshold specified, the process will exit with code `1`.
**Default:** `0`.
* `env` {Object} Specify environment variables to be passed along to the test process. This options is not compatible with `isolation='none'`.
Copy link
Member

Choose a reason for hiding this comment

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

I think it might be worth specifying here that these variables will override those from the main process

* Returns: {TestsStream}

**Note:** `shard` is used to horizontally parallelize test running across
Expand Down
12 changes: 11 additions & 1 deletion lib/internal/test_runner/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ function runTestFile(path, filesWatcher, opts) {
const subtest = opts.root.createSubtest(FileTest, testPath, testOpts, async (t) => {
const args = getRunArgs(path, opts);
const stdio = ['pipe', 'pipe', 'pipe'];
const env = { __proto__: null, ...process.env, NODE_TEST_CONTEXT: 'child-v8' };
const env = opts.env || { __proto__: null, ...process.env, NODE_TEST_CONTEXT: 'child-v8' };
Copy link
Member

Choose a reason for hiding this comment

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

NODE_TEST_CONTEXT is used by the test runner to identify the runner subprocesses, and removing it may cause issues with the reporters.

It must be preserved even if the user passes opts.env.

I would suggest, in any case, adding a snapshot test when using this option to cover the E2E once the option has been provided!

if (watchMode) {
stdio.push('ipc');
env.WATCH_REPORT_DEPENDENCIES = '1';
Expand Down Expand Up @@ -610,6 +610,7 @@ function run(options = kEmptyObject) {
argv = [],
cwd = process.cwd(),
rerunFailuresFilePath,
env,
} = options;

if (files != null) {
Expand Down Expand Up @@ -718,6 +719,14 @@ function run(options = kEmptyObject) {
validatePath(globalSetupPath, 'options.globalSetupPath');
}

if (env != null) {
validateObject(env);

if (isolation === 'none') {
throw new ERR_INVALID_ARG_VALUE('options.env', env, 'is not supported with isolation=\'none\'');
}
}

const rootTestOptions = { __proto__: null, concurrency, timeout, signal };
const globalOptions = {
__proto__: null,
Expand Down Expand Up @@ -763,6 +772,7 @@ function run(options = kEmptyObject) {
argv,
execArgv,
rerunFailuresFilePath,
env,
};

if (isolation === 'process') {
Expand Down
5 changes: 5 additions & 0 deletions test/fixtures/test-runner/process-env.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const { test } = require('node:test');

test('process.env is correct', (t) => {
t.assert.strictEqual(process.env.FOOBAR, 'FUZZBUZZ');
});
17 changes: 17 additions & 0 deletions test/parallel/test-runner-run.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,23 @@ describe('require(\'node:test\').run', { concurrency: true }, () => {
});
});

describe('env', () => {
it('should allow env variables to be configured', async () => {
const stream = run({ files: [join(testFixtures, 'process-env.js')], env: { FOOBAR: 'FUZZBUZZ' } });
stream.on('test:fail', common.mustNotCall());
stream.on('test:pass', common.mustCall(1));
// eslint-disable-next-line no-unused-vars
for await (const _ of stream);
});

it('should throw error when env is specified with isolation=none', async () => {
assert.throws(() => run({ env: { foo: 'bar' }, isolation: 'none' }), {
code: 'ERR_INVALID_ARG_VALUE',
message: /The property 'options\.env' is not supported with isolation='none'\. Received { foo: 'bar' }/
});
});
});

describe('forceExit', () => {
it('throws for non-boolean values', () => {
[Symbol(), {}, 0, 1, '1', Promise.resolve([])].forEach((forceExit) => {
Expand Down
Loading