@@ -395,8 +395,10 @@ class Test extends AsyncResource {
395395    this . parent  =  parent ; 
396396    this . testNumber  =  0 ; 
397397    this . outputSubtestCount  =  0 ; 
398-     this . filteredSubtestCount  =  0 ; 
398+     this . diagnostics  =  [ ] ; 
399399    this . filtered  =  false ; 
400+     this . filteredByName  =  false ; 
401+     this . hasOnlyTests  =  false ; 
400402
401403    if  ( parent  ===  null )  { 
402404      this . root  =  this ; 
@@ -413,26 +415,48 @@ class Test extends AsyncResource {
413415    }  else  { 
414416      const  nesting  =  parent . parent  ===  null  ? parent . nesting  :
415417        parent . nesting  +  1 ; 
418+       const  {  config,  isFilteringByName,  isFilteringByOnly }  =  parent . root . harness ; 
416419
417420      this . root  =  parent . root ; 
418421      this . harness  =  null ; 
419-       this . config  =  this . root . harness . config ; 
422+       this . config  =  config ; 
420423      this . concurrency  =  parent . concurrency ; 
421424      this . nesting  =  nesting ; 
422-       this . only  =  only   ??   ( parent . only   &&   ! parent . runOnlySubtests ) ; 
425+       this . only  =  only ; 
423426      this . reporter  =  parent . reporter ; 
424427      this . runOnlySubtests  =  false ; 
425428      this . childNumber  =  parent . subtests . length  +  1 ; 
426429      this . timeout  =  parent . timeout ; 
427430      this . entryFile  =  parent . entryFile ; 
428431
429-       if  ( this . willBeFiltered ( ) )  { 
430-         this . filtered  =  true ; 
431-         this . parent . filteredSubtestCount ++ ; 
432+       if  ( isFilteringByName )  { 
433+         this . filteredByName  =  this . willBeFilteredByName ( ) ; 
434+         if  ( ! this . filteredByName )  { 
435+           for  ( let  t  =  this . parent ;  t  !==  null  &&  t . filteredByName ;  t  =  t . parent )  { 
436+             t . filteredByName  =  false ; 
437+           } 
438+         } 
432439      } 
433440
434-       if  ( this . config . only  &&  only  ===  false )  { 
435-         fn  =  noop ; 
441+       if  ( isFilteringByOnly )  { 
442+         if  ( this . only )  { 
443+           // If filtering impacts the tests within a suite, then the suite only 
444+           // runs those tests. If filtering does not impact the tests within a 
445+           // suite, then all tests are run. 
446+           this . parent . runOnlySubtests  =  true ; 
447+ 
448+           if  ( this . parent  ===  this . root  ||  this . parent . startTime  ===  null )  { 
449+             for  ( let  t  =  this . parent ;  t  !==  null  &&  ! t . hasOnlyTests ;  t  =  t . parent )  { 
450+               t . hasOnlyTests  =  true ; 
451+             } 
452+           } 
453+         }  else  if  ( this . only  ===  false )  { 
454+           fn  =  noop ; 
455+         } 
456+       }  else  if  ( only  ||  this . parent . runOnlySubtests )  { 
457+         const  warning  = 
458+           "'only' and 'runOnly' require the --test-only command-line option." ; 
459+         this . diagnostic ( warning ) ; 
436460      } 
437461    } 
438462
@@ -491,7 +515,6 @@ class Test extends AsyncResource {
491515    this . endTime  =  null ; 
492516    this . passed  =  false ; 
493517    this . error  =  null ; 
494-     this . diagnostics  =  [ ] ; 
495518    this . message  =  typeof  skip  ===  'string'  ? skip  :
496519      typeof  todo  ===  'string'  ? todo  : null ; 
497520    this . activeSubtests  =  0 ; 
@@ -509,12 +532,6 @@ class Test extends AsyncResource {
509532      ownAfterEachCount : 0 , 
510533    } ; 
511534
512-     if  ( ! this . config . only  &&  ( only  ||  this . parent ?. runOnlySubtests ) )  { 
513-       const  warning  = 
514-         "'only' and 'runOnly' require the --test-only command-line option." ; 
515-       this . diagnostic ( warning ) ; 
516-     } 
517- 
518535    if  ( loc  ===  undefined )  { 
519536      this . loc  =  undefined ; 
520537    }  else  { 
@@ -542,9 +559,27 @@ class Test extends AsyncResource {
542559    } 
543560  } 
544561
545-   willBeFiltered ( )  { 
546-     if  ( this . config . only  &&  ! this . only )  return  true ; 
562+   applyFilters ( )  { 
563+     if  ( this . error )  { 
564+       // Never filter out errors. 
565+       return ; 
566+     } 
547567
568+     if  ( this . filteredByName )  { 
569+       this . filtered  =  true ; 
570+       return ; 
571+     } 
572+ 
573+     if  ( this . root . harness . isFilteringByOnly  &&  ! this . only  &&  ! this . hasOnlyTests )  { 
574+       if  ( this . parent . runOnlySubtests  || 
575+           this . parent . hasOnlyTests  || 
576+           this . only  ===  false )  { 
577+         this . filtered  =  true ; 
578+       } 
579+     } 
580+   } 
581+ 
582+   willBeFilteredByName ( )  { 
548583    const  {  testNamePatterns,  testSkipPatterns }  =  this . config ; 
549584
550585    if  ( testNamePatterns  &&  ! testMatchesPattern ( this ,  testNamePatterns ) )  { 
@@ -757,12 +792,10 @@ class Test extends AsyncResource {
757792    ArrayPrototypePush ( this . diagnostics ,  message ) ; 
758793  } 
759794
760-   get  shouldFilter ( )  { 
761-     return  this . filtered  &&  this . parent ?. filteredSubtestCount  >  0 ; 
762-   } 
763- 
764795  start ( )  { 
765-     if  ( this . shouldFilter )  { 
796+     this . applyFilters ( ) ; 
797+ 
798+     if  ( this . filtered )  { 
766799      noopTestStream  ??=  new  TestsStream ( ) ; 
767800      this . reporter  =  noopTestStream ; 
768801      this . run  =  this . filteredRun ; 
@@ -970,7 +1003,7 @@ class Test extends AsyncResource {
9701003    this . mock ?. reset ( ) ; 
9711004
9721005    if  ( this . parent  !==  null )  { 
973-       if  ( ! this . shouldFilter )  { 
1006+       if  ( ! this . filtered )  { 
9741007        const  report  =  this . getReportDetails ( ) ; 
9751008        report . details . passed  =  this . passed ; 
9761009        this . testNumber  ||=  ++ this . parent . outputSubtestCount ; 
@@ -1159,7 +1192,7 @@ class TestHook extends Test {
11591192  getRunArgs ( )  { 
11601193    return  this . #args; 
11611194  } 
1162-   willBeFiltered ( )  { 
1195+   willBeFilteredByName ( )  { 
11631196    return  false ; 
11641197  } 
11651198  postRun ( )  { 
@@ -1192,7 +1225,6 @@ class Suite extends Test {
11921225      this . fn  =  options . fn  ||  this . fn ; 
11931226      this . skipped  =  false ; 
11941227    } 
1195-     this . runOnlySubtests  =  this . config . only ; 
11961228
11971229    try  { 
11981230      const  {  ctx,  args }  =  this . getRunArgs ( ) ; 
@@ -1216,21 +1248,6 @@ class Suite extends Test {
12161248
12171249  postBuild ( )  { 
12181250    this . buildPhaseFinished  =  true ; 
1219-     if  ( this . filtered  && 
1220-         ( this . filteredSubtestCount  !==  this . subtests . length  ||  this . error ) )  { 
1221-       // A suite can transition from filtered to unfiltered based on the 
1222-       // tests that it contains - in case of children matching patterns. 
1223-       this . filtered  =  false ; 
1224-       this . parent . filteredSubtestCount -- ; 
1225-     }  else  if  ( 
1226-       this . config . only  && 
1227-       this . config . testNamePatterns  ==  null  && 
1228-       this . config . testSkipPatterns  ==  null  && 
1229-       this . filteredSubtestCount  ===  this . subtests . length 
1230-     )  { 
1231-       // If no subtests are marked as "only", run them all 
1232-       this . filteredSubtestCount  =  0 ; 
1233-     } 
12341251  } 
12351252
12361253  getRunArgs ( )  { 
0 commit comments