11'use strict' ;
22const {
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');
3335const console = require ( 'internal/console/global' ) ;
3436const {
3537 codes : {
38+ ERR_INVALID_ARG_TYPE ,
3639 ERR_TEST_FAILURE ,
3740 } ,
3841} = require ( 'internal/errors' ) ;
3942const { validateArray, validateBoolean, validateFunction } = require ( 'internal/validators' ) ;
4043const { getInspectPort, isUsingInspector, isInspectorMessage } = require ( 'internal/util/inspector' ) ;
44+ const { isRegExp } = require ( 'internal/util/types' ) ;
4145const { kEmptyObject } = require ( 'internal/util' ) ;
4246const { createTestTree } = require ( 'internal/test_runner/harness' ) ;
4347const {
@@ -53,6 +57,7 @@ const { YAMLToJs } = require('internal/test_runner/yaml_to_js');
5357const { TokenKind } = require ( 'internal/test_runner/tap_lexer' ) ;
5458
5559const {
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- function getRunArgs ( { path, inspectPort } ) {
145+ function getRunArgs ( { path, inspectPort, testNamePatterns } ) {
141146 const argv = 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 return argv ;
@@ -255,9 +263,9 @@ class FileTest extends Test {
255263const runningProcesses = new SafeMap ( ) ;
256264const runningSubtests = new SafeMap ( ) ;
257265
258- function runTestFile ( path , root , inspectPort , filesWatcher ) {
266+ function runTestFile ( path , root , inspectPort , filesWatcher , testNamePatterns ) {
259267 const subtest = root . createSubtest ( FileTest , path , async ( t ) => {
260- const args = getRunArgs ( { path, inspectPort } ) ;
268+ const args = getRunArgs ( { path, inspectPort, testNamePatterns } ) ;
261269 const stdio = [ 'pipe' , 'pipe' , 'pipe' ] ;
262270 const env = { ...process . env , NODE_TEST_CONTEXT : 'child' } ;
263271 if ( filesWatcher ) {
@@ -339,7 +347,7 @@ function runTestFile(path, root, inspectPort, filesWatcher) {
339347 return promise ;
340348}
341349
342- function watchFiles ( testFiles , root , inspectPort ) {
350+ function watchFiles ( testFiles , root , inspectPort , testNamePatterns ) {
343351 const filesWatcher = new FilesWatcher ( { throttle : 500 , mode : 'filter' } ) ;
344352 filesWatcher . on ( 'changed' , ( { owners } ) => {
345353 filesWatcher . unfilterFilesOwnedBy ( owners ) ;
@@ -353,7 +361,7 @@ function watchFiles(testFiles, root, inspectPort) {
353361 await once ( runningProcess , 'exit' ) ;
354362 }
355363 await runningSubtests . 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 || typeof options !== '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+ return value ;
396+ }
397+ const name = `options.testNamePatterns[${ i } ]` ;
398+ if ( typeof value === 'string' ) {
399+ return convertStringToRegExp ( value , name ) ;
400+ }
401+ throw new ERR_INVALID_ARG_TYPE ( name , [ 'string' , 'RegExp' ] , value ) ;
402+ } ) ;
403+ }
379404
380405 const root = createTestTree ( { concurrency, timeout, signal } ) ;
381406 const testFiles = files ?? createTestFileList ( ) ;
382407
383408 let postRun = ( ) => root . postRun ( ) ;
384409 let filesWatcher ;
385410 if ( watch ) {
386- filesWatcher = watchFiles ( testFiles , root , inspectPort ) ;
411+ filesWatcher = watchFiles ( testFiles , root , inspectPort , testNamePatterns ) ;
387412 postRun = undefined ;
388413 }
389414 const runFiles = ( ) => {
390415 root . harness . bootstrapComplete = true ;
391416 return SafePromiseAllSettledReturnVoid ( testFiles , ( path ) => {
392- const subtest = runTestFile ( path , root , inspectPort , filesWatcher ) ;
417+ const subtest = runTestFile ( path , root , inspectPort , filesWatcher , testNamePatterns ) ;
393418 runningSubtests . set ( path , subtest ) ;
394419 return subtest ;
395420 } ) ;
0 commit comments