Skip to content

Commit cd4d84e

Browse files
test_runner: add env option to run function
Support an `env` option that is passed to the underlying child_process. Fixes: #60709
1 parent e1fc3dc commit cd4d84e

File tree

4 files changed

+37
-1
lines changed

4 files changed

+37
-1
lines changed

doc/api/test.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,6 +1384,9 @@ added:
13841384
- v18.9.0
13851385
- v16.19.0
13861386
changes:
1387+
- version: REPLACEME
1388+
pr-url: https://github.com/nodejs/node/pull/61367
1389+
description: Add the `env` option.
13871390
- version: v24.7.0
13881391
pr-url: https://github.com/nodejs/node/pull/59443
13891392
description: Added a rerunFailuresFilePath option.
@@ -1504,6 +1507,7 @@ changes:
15041507
* `functionCoverage` {number} Require a minimum percent of covered functions. If code
15051508
coverage does not reach the threshold specified, the process will exit with code `1`.
15061509
**Default:** `0`.
1510+
* `env` {Object} Specify environment variables to be passed along to the test process. This options is not compatible with `isolation='none'`.
15071511
* Returns: {TestsStream}
15081512

15091513
**Note:** `shard` is used to horizontally parallelize test running across

lib/internal/test_runner/runner.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ function runTestFile(path, filesWatcher, opts) {
403403
const subtest = opts.root.createSubtest(FileTest, testPath, testOpts, async (t) => {
404404
const args = getRunArgs(path, opts);
405405
const stdio = ['pipe', 'pipe', 'pipe'];
406-
const env = { __proto__: null, ...process.env, NODE_TEST_CONTEXT: 'child-v8' };
406+
const env = opts.env || { __proto__: null, ...process.env, NODE_TEST_CONTEXT: 'child-v8' };
407407
if (watchMode) {
408408
stdio.push('ipc');
409409
env.WATCH_REPORT_DEPENDENCIES = '1';
@@ -610,6 +610,7 @@ function run(options = kEmptyObject) {
610610
argv = [],
611611
cwd = process.cwd(),
612612
rerunFailuresFilePath,
613+
env,
613614
} = options;
614615

615616
if (files != null) {
@@ -718,6 +719,14 @@ function run(options = kEmptyObject) {
718719
validatePath(globalSetupPath, 'options.globalSetupPath');
719720
}
720721

722+
if (env != null) {
723+
validateObject(env);
724+
725+
if (isolation === 'none') {
726+
throw new ERR_INVALID_ARG_VALUE('options.env', env, 'is not supported with isolation=\'none\'');
727+
}
728+
}
729+
721730
const rootTestOptions = { __proto__: null, concurrency, timeout, signal };
722731
const globalOptions = {
723732
__proto__: null,
@@ -763,6 +772,7 @@ function run(options = kEmptyObject) {
763772
argv,
764773
execArgv,
765774
rerunFailuresFilePath,
775+
env,
766776
};
767777

768778
if (isolation === 'process') {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const { test } = require('node:test');
2+
3+
test('process.env is correct', (t) => {
4+
t.assert.strictEqual(process.env.FOOBAR, 'FUZZBUZZ');
5+
});

test/parallel/test-runner-run.mjs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,23 @@ describe('require(\'node:test\').run', { concurrency: true }, () => {
650650
});
651651
});
652652

653+
describe('env', () => {
654+
it('should allow env variables to be configured', async () => {
655+
const stream = run({ files: [join(testFixtures, 'process-env.js')], env: { FOOBAR: 'FUZZBUZZ' } });
656+
stream.on('test:fail', common.mustNotCall());
657+
stream.on('test:pass', common.mustCall(1));
658+
// eslint-disable-next-line no-unused-vars
659+
for await (const _ of stream);
660+
});
661+
662+
it('should throw error when env is specified with isolation=none', async () => {
663+
assert.throws(() => run({ env: { foo: 'bar' }, isolation: 'none' }), {
664+
code: 'ERR_INVALID_ARG_VALUE',
665+
message: /The property 'options\.env' is not supported with isolation='none'\. Received { foo: 'bar' }/
666+
});
667+
});
668+
});
669+
653670
describe('forceExit', () => {
654671
it('throws for non-boolean values', () => {
655672
[Symbol(), {}, 0, 1, '1', Promise.resolve([])].forEach((forceExit) => {

0 commit comments

Comments
 (0)