88 ArrayPrototypeSlice,
99 ArrayPrototypeSome,
1010 ArrayPrototypeSort,
11+ Number,
1112 ObjectAssign,
13+ ObjectKeys,
1214 PromisePrototypeThen,
13- SafePromiseAll,
1415 SafePromiseAllReturnVoid,
1516 SafePromiseAllSettledReturnVoid,
1617 SafeMap,
@@ -35,7 +36,14 @@ const { validateArray, validateBoolean } = require('internal/validators');
3536const { getInspectPort, isUsingInspector, isInspectorMessage } = require ( 'internal/util/inspector' ) ;
3637const { kEmptyObject } = require ( 'internal/util' ) ;
3738const { createTestTree } = require ( 'internal/test_runner/harness' ) ;
38- const { kSubtestsFailed, Test } = require ( 'internal/test_runner/test' ) ;
39+ const {
40+ kAborted,
41+ kCancelledByParent,
42+ kSubtestsFailed,
43+ kTestCodeFailure,
44+ kTestTimeoutFailure,
45+ Test,
46+ } = require ( 'internal/test_runner/test' ) ;
3947const { TapParser } = require ( 'internal/test_runner/tap_parser' ) ;
4048const { YAMLToJs } = require ( 'internal/test_runner/yaml_to_js' ) ;
4149const { TokenKind } = require ( 'internal/test_runner/tap_lexer' ) ;
@@ -55,6 +63,9 @@ const kFilterArgs = ['--test', '--experimental-test-coverage', '--watch'];
5563const kFilterArgValues = [ '--test-reporter' , '--test-reporter-destination' ] ;
5664const kDiagnosticsFilterArgs = [ 'tests' , 'pass' , 'fail' , 'cancelled' , 'skipped' , 'todo' , 'duration_ms' ] ;
5765
66+ const kCanceledTests = new SafeSet ( )
67+ . add ( kCancelledByParent ) . add ( kAborted ) . add ( kTestTimeoutFailure ) ;
68+
5869// TODO(cjihrig): Replace this with recursive readdir once it lands.
5970function processPath ( path , testFiles , options ) {
6071 const stats = statSync ( path ) ;
@@ -133,6 +144,11 @@ function getRunArgs({ path, inspectPort }) {
133144
134145class FileTest extends Test {
135146 #buffer = [ ] ;
147+ #counters = { __proto__ : null , all : 0 , failed : 0 , passed : 0 , cancelled : 0 , skipped : 0 , todo : 0 , totalFailed : 0 } ;
148+ failedSubtests = false ;
149+ #skipReporting( ) {
150+ return this . #counters. all > 0 && ( ! this . error || this . error . failureType === kSubtestsFailed ) ;
151+ }
136152 #checkNestedComment( { comment } ) {
137153 const firstSpaceIndex = StringPrototypeIndexOf ( comment , ' ' ) ;
138154 if ( firstSpaceIndex === - 1 ) return false ;
@@ -141,8 +157,6 @@ class FileTest extends Test {
141157 ArrayPrototypeIncludes ( kDiagnosticsFilterArgs , StringPrototypeSlice ( comment , 0 , firstSpaceIndex ) ) ;
142158 }
143159 #handleReportItem( { kind, node, comments, nesting = 0 } ) {
144- nesting += 1 ;
145-
146160 if ( comments ) {
147161 ArrayPrototypeForEach ( comments , ( comment ) => this . reporter . diagnostic ( nesting , this . name , comment ) ) ;
148162 }
@@ -153,17 +167,20 @@ class FileTest extends Test {
153167 break ;
154168
155169 case TokenKind . TAP_PLAN :
170+ if ( nesting === 0 && this . #skipReporting( ) ) {
171+ break ;
172+ }
156173 this . reporter . plan ( nesting , this . name , node . end - node . start + 1 ) ;
157174 break ;
158175
159176 case TokenKind . TAP_SUBTEST_POINT :
160177 this . reporter . start ( nesting , this . name , node . name ) ;
161178 break ;
162179
163- case TokenKind . TAP_TEST_POINT :
164- // eslint-disable-next-line no-case-declarations
180+ case TokenKind . TAP_TEST_POINT : {
181+
165182 const { todo, skip, pass } = node . status ;
166- // eslint-disable-next-line no-case-declarations
183+
167184 let directive ;
168185
169186 if ( skip ) {
@@ -174,29 +191,21 @@ class FileTest extends Test {
174191 directive = kEmptyObject ;
175192 }
176193
177- if ( pass ) {
178- this . reporter . ok (
179- nesting ,
180- this . name ,
181- node . id ,
182- node . description ,
183- YAMLToJs ( node . diagnostics ) ,
184- directive ,
185- ) ;
186- } else {
187- this . reporter . fail (
188- nesting ,
189- this . name ,
190- node . id ,
191- node . description ,
192- YAMLToJs ( node . diagnostics ) ,
193- directive ,
194- ) ;
194+ const diagnostics = YAMLToJs ( node . diagnostics ) ;
195+ const cancelled = kCanceledTests . has ( diagnostics . error ?. failureType ) ;
196+ const testNumber = nesting === 0 ? ( Number ( node . id ) + this . testNumber - 1 ) : node . id ;
197+ const method = pass ? 'ok' : 'fail' ;
198+ this . reporter [ method ] ( nesting , this . name , testNumber , node . description , diagnostics , directive ) ;
199+ if ( nesting === 0 ) {
200+ super . countSubtest
201+ . call ( { finished : true , skipped : skip , isTodo : todo , passed : pass , cancelled } , this . #counters) ;
202+ this . failedSubtests ||= ! pass ;
195203 }
196204 break ;
197205
206+ }
198207 case TokenKind . COMMENT :
199- if ( nesting === 1 && this . #checkNestedComment( node ) ) {
208+ if ( nesting === 0 && this . #checkNestedComment( node ) ) {
200209 // Ignore file top level diagnostics
201210 break ;
202211 }
@@ -216,10 +225,24 @@ class FileTest extends Test {
216225 this . reportStarted ( ) ;
217226 this . #handleReportItem( ast ) ;
218227 }
228+ countSubtest ( counters ) {
229+ if ( this . #counters. all === 0 ) {
230+ return super . countSubtest ( counters ) ;
231+ }
232+ ArrayPrototypeForEach ( ObjectKeys ( counters ) , ( key ) => {
233+ counters [ key ] += this . #counters[ key ] ;
234+ } ) ;
235+ }
236+ reportStarted ( ) { }
219237 report ( ) {
220- this . reportStarted ( ) ;
238+ const skipReporting = this . #skipReporting( ) ;
239+ if ( ! skipReporting ) {
240+ super . reportStarted ( ) ;
241+ }
221242 ArrayPrototypeForEach ( this . #buffer, ( ast ) => this . #handleReportItem( ast ) ) ;
222- super . report ( ) ;
243+ if ( ! skipReporting ) {
244+ super . report ( ) ;
245+ }
223246 }
224247}
225248
@@ -274,16 +297,14 @@ function runTestFile(path, root, inspectPort, filesWatcher) {
274297 subtest . addToReport ( ast ) ;
275298 } ) ;
276299
277- const { 0 : { 0 : code , 1 : signal } } = await SafePromiseAll ( [
278- once ( child , 'exit' , { signal : t . signal } ) ,
279- child . stdout . toArray ( { signal : t . signal } ) ,
280- ] ) ;
300+ const { 0 : code , 1 : signal } = await once ( child , 'exit' , { signal : t . signal } ) ;
281301
282302 runningProcesses . delete ( path ) ;
283303 runningSubtests . delete ( path ) ;
284304 if ( code !== 0 || signal !== null ) {
285305 if ( ! err ) {
286- err = ObjectAssign ( new ERR_TEST_FAILURE ( 'test failed' , kSubtestsFailed ) , {
306+ const failureType = subtest . failedSubtests ? kSubtestsFailed : kTestCodeFailure ;
307+ err = ObjectAssign ( new ERR_TEST_FAILURE ( 'test failed' , failureType ) , {
287308 __proto__ : null ,
288309 exitCode : code ,
289310 signal : signal ,
0 commit comments