33const {
44 ArrayPrototypeJoin,
55 ArrayPrototypePop,
6+ ArrayPrototypePush,
67 ArrayPrototypeShift,
78 ArrayPrototypeUnshift,
89 hardenRegExp,
@@ -36,6 +37,7 @@ class SpecReporter extends Transform {
3637 #stack = [ ] ;
3738 #reported = [ ] ;
3839 #indentMemo = new SafeMap ( ) ;
40+ #failedTests = [ ] ;
3941
4042 constructor ( ) {
4143 super ( { writableObjectMode : true } ) ;
@@ -60,54 +62,74 @@ class SpecReporter extends Transform {
6062 ) , `\n${ indent } ` ) ;
6163 return `\n${ indent } ${ message } \n` ;
6264 }
63- #handleEvent ( { type, data } ) {
65+ #formatTestReport ( type , data , prefix = '' , indent = '' , hasChildren = false , skippedSubtest = false ) {
6466 let color = colors [ type ] ?? white ;
6567 let symbol = symbols [ type ] ?? ' ' ;
66-
68+ const duration_ms = data . details ?. duration_ms ? ` ${ gray } (${ data . details . duration_ms } ms)${ white } ` : '' ;
69+ const title = `${ data . name } ${ duration_ms } ${ skippedSubtest ? ' # SKIP' : '' } ` ;
70+ if ( hasChildren ) {
71+ // If this test has had children - it was already reported, so slightly modify the output
72+ return `${ prefix } ${ indent } ${ color } ${ symbols [ 'arrow:right' ] } ${ white } ${ title } \n` ;
73+ }
74+ const error = this . #formatError( data . details ?. error , indent ) ;
75+ if ( skippedSubtest ) {
76+ color = gray ;
77+ symbol = symbols [ 'hyphen:minus' ] ;
78+ }
79+ return `${ prefix } ${ indent } ${ color } ${ symbol } ${ title } ${ white } ${ error } ` ;
80+ }
81+ #handleTestReportEvent( type , data ) {
82+ const subtest = ArrayPrototypeShift ( this . #stack) ; // This is the matching `test:start` event
83+ if ( subtest ) {
84+ assert ( subtest . type === 'test:start' ) ;
85+ assert ( subtest . data . nesting === data . nesting ) ;
86+ assert ( subtest . data . name === data . name ) ;
87+ }
88+ let prefix = '' ;
89+ while ( this . #stack. length ) {
90+ // Report all the parent `test:start` events
91+ const parent = ArrayPrototypePop ( this . #stack) ;
92+ assert ( parent . type === 'test:start' ) ;
93+ const msg = parent . data ;
94+ ArrayPrototypeUnshift ( this . #reported, msg ) ;
95+ prefix += `${ this . #indent( msg . nesting ) } ${ symbols [ 'arrow:right' ] } ${ msg . name } \n` ;
96+ }
97+ let hasChildren = false ;
98+ if ( this . #reported[ 0 ] && this . #reported[ 0 ] . nesting === data . nesting && this . #reported[ 0 ] . name === data . name ) {
99+ ArrayPrototypeShift ( this . #reported) ;
100+ hasChildren = true ;
101+ }
102+ const skippedSubtest = subtest && data . skip && data . skip !== undefined ;
103+ const indent = this . #indent( data . nesting ) ;
104+ return `${ this . #formatTestReport( type , data , prefix , indent , hasChildren , skippedSubtest ) } \n` ;
105+ }
106+ #handleEvent( { type, data } ) {
67107 switch ( type ) {
68108 case 'test:fail' :
69- case 'test:pass' : {
70- const subtest = ArrayPrototypeShift ( this . #stack) ; // This is the matching `test:start` event
71- if ( subtest ) {
72- assert ( subtest . type === 'test:start' ) ;
73- assert ( subtest . data . nesting === data . nesting ) ;
74- assert ( subtest . data . name === data . name ) ;
75- }
76- let prefix = '' ;
77- while ( this . #stack. length ) {
78- // Report all the parent `test:start` events
79- const parent = ArrayPrototypePop ( this . #stack) ;
80- assert ( parent . type === 'test:start' ) ;
81- const msg = parent . data ;
82- ArrayPrototypeUnshift ( this . #reported, msg ) ;
83- prefix += `${ this . #indent( msg . nesting ) } ${ symbols [ 'arrow:right' ] } ${ msg . name } \n` ;
84- }
85- const skippedSubtest = subtest && data . skip && data . skip !== undefined ;
86- const indent = this . #indent( data . nesting ) ;
87- const duration_ms = data . details ?. duration_ms ? ` ${ gray } (${ data . details . duration_ms } ms)${ white } ` : '' ;
88- const title = `${ data . name } ${ duration_ms } ${ skippedSubtest ? ' # SKIP' : '' } ` ;
89- if ( this . #reported[ 0 ] && this . #reported[ 0 ] . nesting === data . nesting && this . #reported[ 0 ] . name === data . name ) {
90- // If this test has had children - it was already reported, so slightly modify the output
91- ArrayPrototypeShift ( this . #reported) ;
92- return `${ prefix } ${ indent } ${ color } ${ symbols [ 'arrow:right' ] } ${ white } ${ title } \n\n` ;
93- }
94- const error = this . #formatError( data . details ?. error , indent ) ;
95- if ( skippedSubtest ) {
96- color = gray ;
97- symbol = symbols [ 'hyphen:minus' ] ;
98- }
99- return `${ prefix } ${ indent } ${ color } ${ symbol } ${ title } ${ error } ${ white } \n` ;
100- }
109+ ArrayPrototypePush ( this . #failedTests, data ) ;
110+ return this . #handleTestReportEvent( type , data ) ;
111+ case 'test:pass' :
112+ return this . #handleTestReportEvent( type , data ) ;
101113 case 'test:start' :
102114 ArrayPrototypeUnshift ( this . #stack, { __proto__ : null , data, type } ) ;
103115 break ;
104116 case 'test:diagnostic' :
105- return `${ color } ${ this . #indent( data . nesting ) } ${ symbol } ${ data . message } ${ white } \n` ;
117+ return `${ colors [ type ] } ${ this . #indent( data . nesting ) } ${ symbols [ type ] } ${ data . message } ${ white } \n` ;
106118 }
107119 }
108120 _transform ( { type, data } , encoding , callback ) {
109121 callback ( null , this . #handleEvent( { type, data } ) ) ;
110122 }
123+ _flush ( callback ) {
124+ const results = [ `\n${ colors [ 'test:fail' ] } ${ symbols [ 'test:fail' ] } failing tests:${ white } \n` ] ;
125+ for ( let i = 0 ; i < this . #failedTests. length ; i ++ ) {
126+ ArrayPrototypePush ( results , this . #formatTestReport(
127+ 'test:fail' ,
128+ this . #failedTests[ i ] ,
129+ ) ) ;
130+ }
131+ callback ( null , ArrayPrototypeJoin ( results , '\n' ) ) ;
132+ }
111133}
112134
113135module . exports = SpecReporter ;
0 commit comments