Skip to content

Commit abb5133

Browse files
committed
test_runner: accept testOnly in run
PR-URL: nodejs/node#49753 Fixes: nodejs/node#49733 Reviewed-By: Chemi Atlow <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Raz Luvaton <[email protected]>
1 parent 5f38e70 commit abb5133

File tree

4 files changed

+43
-17
lines changed

4 files changed

+43
-17
lines changed

graal-nodejs/doc/api/test.md

+2
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,8 @@ changes:
889889
number. If a nullish value is provided, each process gets its own port,
890890
incremented from the primary's `process.debugPort`.
891891
**Default:** `undefined`.
892+
* `only`: {boolean} If truthy, the test context will only run tests that
893+
have the `only` option set
892894
* `setup` {Function} A function that accepts the `TestsStream` instance
893895
and can be used to setup listeners before any tests are run.
894896
**Default:** `undefined`.

graal-nodejs/lib/internal/test_runner/runner.js

+24-17
Original file line numberDiff line numberDiff line change
@@ -156,14 +156,17 @@ function filterExecArgv(arg, i, arr) {
156156
!ArrayPrototypeSome(kFilterArgValues, (p) => arg === p || (i > 0 && arr[i - 1] === p) || StringPrototypeStartsWith(arg, `${p}=`));
157157
}
158158

159-
function getRunArgs({ path, inspectPort, testNamePatterns }) {
159+
function getRunArgs(path, { inspectPort, testNamePatterns, only }) {
160160
const argv = ArrayPrototypeFilter(process.execArgv, filterExecArgv);
161161
if (isUsingInspector()) {
162162
ArrayPrototypePush(argv, `--inspect-port=${getInspectPort(inspectPort)}`);
163163
}
164-
if (testNamePatterns) {
164+
if (testNamePatterns != null) {
165165
ArrayPrototypeForEach(testNamePatterns, (pattern) => ArrayPrototypePush(argv, `--test-name-pattern=${pattern}`));
166166
}
167+
if (only === true) {
168+
ArrayPrototypePush(argv, '--test-only');
169+
}
167170
ArrayPrototypePush(argv, path);
168171

169172
return argv;
@@ -347,17 +350,17 @@ class FileTest extends Test {
347350
}
348351
}
349352

350-
function runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns) {
353+
function runTestFile(path, filesWatcher, opts) {
351354
const watchMode = filesWatcher != null;
352-
const subtest = root.createSubtest(FileTest, path, async (t) => {
353-
const args = getRunArgs({ __proto__: null, path, inspectPort, testNamePatterns });
355+
const subtest = opts.root.createSubtest(FileTest, path, async (t) => {
356+
const args = getRunArgs(path, opts);
354357
const stdio = ['pipe', 'pipe', 'pipe'];
355358
const env = { __proto__: null, ...process.env, NODE_TEST_CONTEXT: 'child-v8' };
356359
if (watchMode) {
357360
stdio.push('ipc');
358361
env.WATCH_REPORT_DEPENDENCIES = '1';
359362
}
360-
if (root.harness.shouldColorizeTestFiles) {
363+
if (opts.root.harness.shouldColorizeTestFiles) {
361364
env.FORCE_COLOR = '1';
362365
}
363366

@@ -404,7 +407,7 @@ function runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns) {
404407
filesWatcher.runningProcesses.delete(path);
405408
filesWatcher.runningSubtests.delete(path);
406409
if (filesWatcher.runningSubtests.size === 0) {
407-
root.reporter[kEmitMessage]('test:watch:drained');
410+
opts.root.reporter[kEmitMessage]('test:watch:drained');
408411
}
409412
}
410413

@@ -427,10 +430,10 @@ function runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns) {
427430
return subtest.start();
428431
}
429432

430-
function watchFiles(testFiles, root, inspectPort, signal, testNamePatterns) {
433+
function watchFiles(testFiles, opts) {
431434
const runningProcesses = new SafeMap();
432435
const runningSubtests = new SafeMap();
433-
const watcher = new FilesWatcher({ __proto__: null, debounce: 200, mode: 'filter', signal });
436+
const watcher = new FilesWatcher({ __proto__: null, debounce: 200, mode: 'filter', signal: opts.signal });
434437
const filesWatcher = { __proto__: null, watcher, runningProcesses, runningSubtests };
435438

436439
watcher.on('changed', ({ owners }) => {
@@ -446,19 +449,19 @@ function watchFiles(testFiles, root, inspectPort, signal, testNamePatterns) {
446449
}
447450
if (!runningSubtests.size) {
448451
// Reset the topLevel counter
449-
root.harness.counters.topLevel = 0;
452+
opts.root.harness.counters.topLevel = 0;
450453
}
451454
await runningSubtests.get(file);
452-
runningSubtests.set(file, runTestFile(file, root, inspectPort, filesWatcher, testNamePatterns));
455+
runningSubtests.set(file, runTestFile(file, filesWatcher, opts));
453456
}, undefined, (error) => {
454457
triggerUncaughtException(error, true /* fromPromise */);
455458
}));
456459
});
457-
if (signal) {
460+
if (opts.signal) {
458461
kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation;
459-
signal.addEventListener(
462+
opts.signal.addEventListener(
460463
'abort',
461-
() => root.postRun(),
464+
() => opts.root.postRun(),
462465
{ __proto__: null, once: true, [kResistStopPropagation]: true },
463466
);
464467
}
@@ -471,14 +474,17 @@ function run(options) {
471474
options = kEmptyObject;
472475
}
473476
let { testNamePatterns, shard } = options;
474-
const { concurrency, timeout, signal, files, inspectPort, watch, setup } = options;
477+
const { concurrency, timeout, signal, files, inspectPort, watch, setup, only } = options;
475478

476479
if (files != null) {
477480
validateArray(files, 'options.files');
478481
}
479482
if (watch != null) {
480483
validateBoolean(watch, 'options.watch');
481484
}
485+
if (only != null) {
486+
validateBoolean(only, 'options.only');
487+
}
482488
if (shard != null) {
483489
validateObject(shard, 'options.shard');
484490
// Avoid re-evaluating the shard object in case it's a getter
@@ -524,14 +530,15 @@ function run(options) {
524530

525531
let postRun = () => root.postRun();
526532
let filesWatcher;
533+
const opts = { __proto__: null, root, signal, inspectPort, testNamePatterns, only };
527534
if (watch) {
528-
filesWatcher = watchFiles(testFiles, root, inspectPort, signal, testNamePatterns);
535+
filesWatcher = watchFiles(testFiles, opts);
529536
postRun = undefined;
530537
}
531538
const runFiles = () => {
532539
root.harness.bootstrapComplete = true;
533540
return SafePromiseAllSettledReturnVoid(testFiles, (path) => {
534-
const subtest = runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns);
541+
const subtest = runTestFile(path, filesWatcher, opts);
535542
filesWatcher?.runningSubtests.set(path, subtest);
536543
return subtest;
537544
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
'use strict';
2+
const test = require('node:test');
3+
4+
test('this should be skipped');
5+
test.only('this should be executed');

graal-nodejs/test/parallel/test-runner-run.mjs

+12
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,18 @@ describe('require(\'node:test\').run', { concurrency: true }, () => {
148148
assert.strictEqual(result[5], 'ok 2 - this should be executed\n');
149149
});
150150

151+
it('should pass only to children', async () => {
152+
const result = await run({
153+
files: [join(testFixtures, 'test_only.js')],
154+
only: true
155+
})
156+
.compose(tap)
157+
.toArray();
158+
159+
assert.strictEqual(result[2], 'ok 1 - this should be skipped # SKIP \'only\' option not set\n');
160+
assert.strictEqual(result[5], 'ok 2 - this should be executed\n');
161+
});
162+
151163
it('should emit "test:watch:drained" event on watch mode', async () => {
152164
const controller = new AbortController();
153165
await run({

0 commit comments

Comments
 (0)