Skip to content

Commit fa18b17

Browse files
atlowChemiMoLow
authored andcommitted
test_runner: add testNamePatterns to run api
Accept a `testNamePatterns` value in the `run` fn, and drill those patterns to the spawned processes. PR-URL: #47648 Reviewed-By: Moshe Atlow <moshe@atlow.co.il> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
1 parent 27a696f commit fa18b17

4 files changed

Lines changed: 63 additions & 7 deletions

File tree

‎doc/api/test.md‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,10 @@ unless a destination is explicitly provided.
709709

710710
<!-- YAML
711711
added: v18.9.0
712+
changes:
713+
- version: REPLACEME
714+
pr-url: https://github.com/nodejs/node/pull/47628
715+
description: Add a testNamePatterns option.
712716
-->
713717

714718
*`options` {Object} Configuration options for running tests. The following
@@ -734,6 +738,12 @@ added: v18.9.0
734738
number. If a nullish value is provided, each process gets its own port,
735739
incremented from the primary's `process.debugPort`.
736740
**Default:**`undefined`.
741+
*`testNamePatterns` {string|RegExp|Array} A String, RegExp or a RegExp Array,
742+
that can be used to only run tests whose name matches the provided pattern.
743+
Test name patterns are interpreted as JavaScript regular expressions.
744+
For each test that is executed, any corresponding test hooks, such as
745+
`beforeEach()`, are also run.
746+
**Default:**`undefined`.
737747
* Returns: {TestsStream}
738748

739749
```mjs

‎lib/internal/test_runner/runner.js‎

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
'use strict';
22
const{
33
ArrayFrom,
4+
ArrayIsArray,
45
ArrayPrototypeFilter,
56
ArrayPrototypeForEach,
67
ArrayPrototypeIncludes,
78
ArrayPrototypeIndexOf,
9+
ArrayPrototypeMap,
810
ArrayPrototypePush,
911
ArrayPrototypeSlice,
1012
ArrayPrototypeSome,
@@ -33,11 +35,13 @@ const { FilesWatcher } = require('internal/watch_mode/files_watcher');
3335
constconsole=require('internal/console/global');
3436
const{
3537
codes: {
38+
ERR_INVALID_ARG_TYPE,
3639
ERR_TEST_FAILURE,
3740
},
3841
}=require('internal/errors');
3942
const{ validateArray, validateBoolean, validateFunction }=require('internal/validators');
4043
const{ getInspectPort, isUsingInspector, isInspectorMessage }=require('internal/util/inspector');
44+
const{ isRegExp }=require('internal/util/types');
4145
const{ kEmptyObject }=require('internal/util');
4246
const{ createTestTree }=require('internal/test_runner/harness');
4347
const{
@@ -53,6 +57,7 @@ const { YAMLToJs } = require('internal/test_runner/yaml_to_js');
5357
const{ TokenKind }=require('internal/test_runner/tap_lexer');
5458

5559
const{
60+
convertStringToRegExp,
5661
countCompletedTest,
5762
doesPathMatchFilter,
5863
isSupportedFileType,
@@ -137,11 +142,14 @@ function filterExecArgv(arg, i, arr) {
137142
!ArrayPrototypeSome(kFilterArgValues,(p)=>arg===p||(i>0&&arr[i-1]===p)||StringPrototypeStartsWith(arg,`${p}=`));
138143
}
139144

140-
functiongetRunArgs({ path, inspectPort }){
145+
functiongetRunArgs({ path, inspectPort, testNamePatterns}){
141146
constargv=ArrayPrototypeFilter(process.execArgv,filterExecArgv);
142147
if(isUsingInspector()){
143148
ArrayPrototypePush(argv,`--inspect-port=${getInspectPort(inspectPort)}`);
144149
}
150+
if(testNamePatterns){
151+
ArrayPrototypeForEach(testNamePatterns,(pattern)=>ArrayPrototypePush(argv,`--test-name-pattern=${pattern}`));
152+
}
145153
ArrayPrototypePush(argv,path);
146154

147155
returnargv;
@@ -255,9 +263,9 @@ class FileTest extends Test {
255263
construnningProcesses=newSafeMap();
256264
construnningSubtests=newSafeMap();
257265

258-
functionrunTestFile(path,root,inspectPort,filesWatcher){
266+
functionrunTestFile(path,root,inspectPort,filesWatcher,testNamePatterns){
259267
constsubtest=root.createSubtest(FileTest,path,async(t)=>{
260-
constargs=getRunArgs({ path, inspectPort });
268+
constargs=getRunArgs({ path, inspectPort, testNamePatterns});
261269
conststdio=['pipe','pipe','pipe'];
262270
constenv={ ...process.env,NODE_TEST_CONTEXT: 'child'};
263271
if(filesWatcher){
@@ -339,7 +347,7 @@ function runTestFile(path, root, inspectPort, filesWatcher) {
339347
returnpromise;
340348
}
341349

342-
functionwatchFiles(testFiles,root,inspectPort){
350+
functionwatchFiles(testFiles,root,inspectPort,testNamePatterns){
343351
constfilesWatcher=newFilesWatcher({throttle: 500,mode: 'filter'});
344352
filesWatcher.on('changed',({ owners })=>{
345353
filesWatcher.unfilterFilesOwnedBy(owners);
@@ -353,7 +361,7 @@ function watchFiles(testFiles, root, inspectPort) {
353361
awaitonce(runningProcess,'exit');
354362
}
355363
awaitrunningSubtests.get(file);
356-
runningSubtests.set(file,runTestFile(file,root,inspectPort,filesWatcher));
364+
runningSubtests.set(file,runTestFile(file,root,inspectPort,filesWatcher,testNamePatterns));
357365
},undefined,(error)=>{
358366
triggerUncaughtException(error,true/* fromPromise */);
359367
}));
@@ -365,6 +373,7 @@ function run(options) {
365373
if(options===null||typeofoptions!=='object'){
366374
options=kEmptyObject;
367375
}
376+
let{ testNamePatterns }=options;
368377
const{ concurrency, timeout, signal, files, inspectPort, watch, setup }=options;
369378

370379
if(files!=null){
@@ -376,20 +385,36 @@ function run(options) {
376385
if(setup!=null){
377386
validateFunction(setup,'options.setup');
378387
}
388+
if(testNamePatterns!=null){
389+
if(!ArrayIsArray(testNamePatterns)){
390+
testNamePatterns=[testNamePatterns];
391+
}
392+
validateArray(testNamePatterns,'options.testNamePatterns');
393+
testNamePatterns=ArrayPrototypeMap(testNamePatterns,(value,i)=>{
394+
if(isRegExp(value)){
395+
returnvalue;
396+
}
397+
constname=`options.testNamePatterns[${i}]`;
398+
if(typeofvalue==='string'){
399+
returnconvertStringToRegExp(value,name);
400+
}
401+
thrownewERR_INVALID_ARG_TYPE(name,['string','RegExp'],value);
402+
});
403+
}
379404

380405
constroot=createTestTree({ concurrency, timeout, signal });
381406
consttestFiles=files??createTestFileList();
382407

383408
letpostRun=()=>root.postRun();
384409
letfilesWatcher;
385410
if(watch){
386-
filesWatcher=watchFiles(testFiles,root,inspectPort);
411+
filesWatcher=watchFiles(testFiles,root,inspectPort,testNamePatterns);
387412
postRun=undefined;
388413
}
389414
construnFiles=()=>{
390415
root.harness.bootstrapComplete=true;
391416
returnSafePromiseAllSettledReturnVoid(testFiles,(path)=>{
392-
constsubtest=runTestFile(path,root,inspectPort,filesWatcher);
417+
constsubtest=runTestFile(path,root,inspectPort,filesWatcher,testNamePatterns);
393418
runningSubtests.set(path,subtest);
394419
returnsubtest;
395420
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
'use strict';
2+
consttest=require('node:test');
3+
4+
test('this should be skipped');
5+
test('this should be executed');

‎test/parallel/test-runner-run.mjs‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,20 @@ describe('require(\'node:test\').run', { concurrency: true }, () => {
101101
assert.strictEqual(result[11],'# todo 0\n');
102102
assert.match(result[12],/#duration_ms\d+\.?\d*/);
103103
});
104+
105+
it('should skip tests not matching testNamePatterns - RegExp',async()=>{
106+
constresult=awaitrun({files: [join(testFixtures,'test/skip_by_name.cjs')],testNamePatterns: [/executed/]})
107+
.compose(tap)
108+
.toArray();
109+
assert.strictEqual(result[2],'ok 1 - this should be skipped # SKIP test name does not match pattern\n');
110+
assert.strictEqual(result[5],'ok 2 - this should be executed\n');
111+
});
112+
113+
it('should skip tests not matching testNamePatterns - string',async()=>{
114+
constresult=awaitrun({files: [join(testFixtures,'test/skip_by_name.cjs')],testNamePatterns: ['executed']})
115+
.compose(tap)
116+
.toArray();
117+
assert.strictEqual(result[2],'ok 1 - this should be skipped # SKIP test name does not match pattern\n');
118+
assert.strictEqual(result[5],'ok 2 - this should be executed\n');
119+
});
104120
});

0 commit comments

Comments
 (0)