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,
@@ -138,11 +143,14 @@ function filterExecArgv(arg, i, arr) {
138143 ! ArrayPrototypeSome ( kFilterArgValues , ( p ) => arg === p || ( i > 0 && arr [ i - 1 ] === p ) || StringPrototypeStartsWith ( arg , `${ p } =` ) ) ;
139144}
140145
141- function getRunArgs ( { path, inspectPort } ) {
146+ function getRunArgs ( { path, inspectPort, testNamePatterns } ) {
142147 const argv = ArrayPrototypeFilter ( process . execArgv , filterExecArgv ) ;
143148 if ( isUsingInspector ( ) ) {
144149 ArrayPrototypePush ( argv , `--inspect-port=${ getInspectPort ( inspectPort ) } ` ) ;
145150 }
151+ if ( testNamePatterns ) {
152+ ArrayPrototypeForEach ( testNamePatterns , ( pattern ) => ArrayPrototypePush ( argv , `--test-name-pattern=${ pattern } ` ) ) ;
153+ }
146154 ArrayPrototypePush ( argv , path ) ;
147155
148156 return argv ;
@@ -256,9 +264,9 @@ class FileTest extends Test {
256264const runningProcesses = new SafeMap ( ) ;
257265const runningSubtests = new SafeMap ( ) ;
258266
259- function runTestFile ( path , root , inspectPort , filesWatcher ) {
267+ function runTestFile ( path , root , inspectPort , filesWatcher , testNamePatterns ) {
260268 const subtest = root . createSubtest ( FileTest , path , async ( t ) => {
261- const args = getRunArgs ( { path, inspectPort } ) ;
269+ const args = getRunArgs ( { path, inspectPort, testNamePatterns } ) ;
262270 const stdio = [ 'pipe' , 'pipe' , 'pipe' ] ;
263271 const env = { ...process . env , NODE_TEST_CONTEXT : 'child' } ;
264272 if ( filesWatcher ) {
@@ -340,7 +348,7 @@ function runTestFile(path, root, inspectPort, filesWatcher) {
340348 return promise ;
341349}
342350
343- function watchFiles ( testFiles , root , inspectPort ) {
351+ function watchFiles ( testFiles , root , inspectPort , testNamePatterns ) {
344352 const filesWatcher = new FilesWatcher ( { throttle : 500 , mode : 'filter' } ) ;
345353 filesWatcher . on ( 'changed' , ( { owners } ) => {
346354 filesWatcher . unfilterFilesOwnedBy ( owners ) ;
@@ -354,7 +362,7 @@ function watchFiles(testFiles, root, inspectPort) {
354362 await once ( runningProcess , 'exit' ) ;
355363 }
356364 await runningSubtests . get ( file ) ;
357- runningSubtests . set ( file , runTestFile ( file , root , inspectPort , filesWatcher ) ) ;
365+ runningSubtests . set ( file , runTestFile ( file , root , inspectPort , filesWatcher , testNamePatterns ) ) ;
358366 } , undefined , ( error ) => {
359367 triggerUncaughtException ( error , true /* fromPromise */ ) ;
360368 } ) ) ;
@@ -366,6 +374,7 @@ function run(options) {
366374 if ( options === null || typeof options !== 'object' ) {
367375 options = kEmptyObject ;
368376 }
377+ let { testNamePatterns } = options ;
369378 const { concurrency, timeout, signal, files, inspectPort, watch, setup } = options ;
370379
371380 if ( files != null ) {
@@ -377,20 +386,36 @@ function run(options) {
377386 if ( setup != null ) {
378387 validateFunction ( setup , 'options.setup' ) ;
379388 }
389+ if ( testNamePatterns != null ) {
390+ if ( ! ArrayIsArray ( testNamePatterns ) ) {
391+ testNamePatterns = [ testNamePatterns ] ;
392+ }
393+ validateArray ( testNamePatterns , 'options.testNamePatterns' ) ;
394+ testNamePatterns = ArrayPrototypeMap ( testNamePatterns , ( value , i ) => {
395+ if ( isRegExp ( value ) ) {
396+ return value ;
397+ }
398+ const name = `options.testNamePatterns[${ i } ]` ;
399+ if ( typeof value === 'string' ) {
400+ return convertStringToRegExp ( value , name ) ;
401+ }
402+ throw new ERR_INVALID_ARG_TYPE ( name , [ 'string' , 'RegExp' ] , value ) ;
403+ } ) ;
404+ }
380405
381406 const root = createTestTree ( { concurrency, timeout, signal } ) ;
382407 const testFiles = files ?? createTestFileList ( ) ;
383408
384409 let postRun = ( ) => root . postRun ( ) ;
385410 let filesWatcher ;
386411 if ( watch ) {
387- filesWatcher = watchFiles ( testFiles , root , inspectPort ) ;
412+ filesWatcher = watchFiles ( testFiles , root , inspectPort , testNamePatterns ) ;
388413 postRun = undefined ;
389414 }
390415 const runFiles = ( ) => {
391416 root . harness . bootstrapComplete = true ;
392417 return SafePromiseAllSettledReturnVoid ( testFiles , ( path ) => {
393- const subtest = runTestFile ( path , root , inspectPort , filesWatcher ) ;
418+ const subtest = runTestFile ( path , root , inspectPort , filesWatcher , testNamePatterns ) ;
394419 runningSubtests . set ( path , subtest ) ;
395420 return subtest ;
396421 } ) ;
0 commit comments