@@ -88,11 +88,12 @@ export abstract class BaseReporter implements Reporter {
8888 return
8989 }
9090
91- const tests = getTests ( task )
92- const failed = tests . filter ( t => t . result ?. state === 'fail' )
93- const skipped = tests . filter ( t => t . mode === 'skip' || t . mode === 'todo' )
91+ const suites = getSuites ( task )
92+ const allTests = getTests ( task )
93+ const failed = allTests . filter ( t => t . result ?. state === 'fail' )
94+ const skipped = allTests . filter ( t => t . mode === 'skip' || t . mode === 'todo' )
9495
95- let state = c . dim ( `${ tests . length } test${ tests . length > 1 ? 's' : '' } ` )
96+ let state = c . dim ( `${ allTests . length } test${ allTests . length > 1 ? 's' : '' } ` )
9697
9798 if ( failed . length ) {
9899 state += c . dim ( ' | ' ) + c . red ( `${ failed . length } failed` )
@@ -120,52 +121,79 @@ export abstract class BaseReporter implements Reporter {
120121
121122 this . log ( ` ${ title } ${ task . name } ${ suffix } ` )
122123
123- const anyFailed = tests . some ( test => test . result ?. state === 'fail' )
124+ for ( const suite of suites ) {
125+ const tests = suite . tasks . filter ( task => task . type === 'test' )
124126
125- for ( const test of tests ) {
126- const { duration, retryCount, repeatCount } = test . result || { }
127- let suffix = ''
128-
129- if ( retryCount != null && retryCount > 0 ) {
130- suffix += c . yellow ( ` (retry x${ retryCount } )` )
127+ if ( ! ( 'filepath' in suite ) ) {
128+ this . printSuite ( suite )
131129 }
132130
133- if ( repeatCount != null && repeatCount > 0 ) {
134- suffix += c . yellow ( ` (repeat x${ repeatCount } )` )
135- }
131+ for ( const test of tests ) {
132+ const { duration, retryCount, repeatCount } = test . result || { }
133+ const padding = this . getTestIndentation ( test )
134+ let suffix = ''
136135
137- if ( test . result ?. state === 'fail' ) {
138- this . log ( c . red ( ` ${ taskFail } ${ getTestName ( test , c . dim ( ' > ' ) ) } ${ this . getDurationPrefix ( test ) } ` ) + suffix )
136+ if ( retryCount != null && retryCount > 0 ) {
137+ suffix += c . yellow ( ` (retry x${ retryCount } )` )
138+ }
139+
140+ if ( repeatCount != null && repeatCount > 0 ) {
141+ suffix += c . yellow ( ` (repeat x${ repeatCount } )` )
142+ }
143+
144+ if ( test . result ?. state === 'fail' ) {
145+ this . log ( c . red ( ` ${ padding } ${ taskFail } ${ this . getTestName ( test , c . dim ( ' > ' ) ) } ${ this . getDurationPrefix ( test ) } ` ) + suffix )
139146
140- test . result ?. errors ?. forEach ( ( e ) => {
141147 // print short errors, full errors will be at the end in summary
142- this . log ( c . red ( ` ${ F_RIGHT } ${ e ?. message } ` ) )
143- } )
144- }
148+ test . result ?. errors ?. forEach ( ( error ) => {
149+ const message = this . formatShortError ( error )
145150
146- // also print slow tests
147- else if ( duration && duration > this . ctx . config . slowTestThreshold ) {
148- this . log (
149- ` ${ c . yellow ( c . dim ( F_CHECK ) ) } ${ getTestName ( test , c . dim ( ' > ' ) ) } `
150- + ` ${ c . yellow ( Math . round ( duration ) + c . dim ( 'ms' ) ) } ${ suffix } ` ,
151- )
152- }
151+ if ( message ) {
152+ this . log ( c . red ( ` ${ padding } ${ message } ` ) )
153+ }
154+ } )
155+ }
153156
154- else if ( this . ctx . config . hideSkippedTests && ( test . mode === 'skip' || test . result ?. state === 'skip' ) ) {
155- // Skipped tests are hidden when --hideSkippedTests
156- }
157+ // also print slow tests
158+ else if ( duration && duration > this . ctx . config . slowTestThreshold ) {
159+ this . log (
160+ ` ${ padding } ${ c . yellow ( c . dim ( F_CHECK ) ) } ${ this . getTestName ( test , c . dim ( ' > ' ) ) } `
161+ + ` ${ c . yellow ( Math . round ( duration ) + c . dim ( 'ms' ) ) } ${ suffix } ` ,
162+ )
163+ }
157164
158- // also print skipped tests that have notes
159- else if ( test . result ?. state === 'skip' && test . result . note ) {
160- this . log ( ` ${ getStateSymbol ( test ) } ${ getTestName ( test ) } ${ c . dim ( c . gray ( ` [${ test . result . note } ]` ) ) } ` )
161- }
165+ else if ( this . ctx . config . hideSkippedTests && ( test . mode === 'skip' || test . result ?. state === 'skip' ) ) {
166+ // Skipped tests are hidden when --hideSkippedTests
167+ }
168+
169+ // also print skipped tests that have notes
170+ else if ( test . result ?. state === 'skip' && test . result . note ) {
171+ this . log ( ` ${ padding } ${ getStateSymbol ( test ) } ${ this . getTestName ( test ) } ${ c . dim ( c . gray ( ` [${ test . result . note } ]` ) ) } ` )
172+ }
162173
163- else if ( this . renderSucceed || anyFailed ) {
164- this . log ( ` ${ getStateSymbol ( test ) } ${ getTestName ( test , c . dim ( ' > ' ) ) } ${ suffix } ` )
174+ else if ( this . renderSucceed || failed . length > 0 ) {
175+ this . log ( ` ${ padding } ${ getStateSymbol ( test ) } ${ this . getTestName ( test , c . dim ( ' > ' ) ) } ${ suffix } ` )
176+ }
165177 }
166178 }
167179 }
168180
181+ protected printSuite ( _task : Task ) : void {
182+ // Suite name is included in getTestName by default
183+ }
184+
185+ protected getTestName ( test : Task , separator ?: string ) : string {
186+ return getTestName ( test , separator )
187+ }
188+
189+ protected formatShortError ( error : ErrorWithDiff ) : string {
190+ return `${ F_RIGHT } ${ error . message } `
191+ }
192+
193+ protected getTestIndentation ( _test : Task ) {
194+ return ' '
195+ }
196+
169197 private getDurationPrefix ( task : Task ) {
170198 if ( ! task . result ?. duration ) {
171199 return ''
0 commit comments