@@ -88,11 +88,12 @@ export abstract class BaseReporter implements Reporter {
88
88
return
89
89
}
90
90
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' )
94
95
95
- let state = c . dim ( `${ tests . length } test${ tests . length > 1 ? 's' : '' } ` )
96
+ let state = c . dim ( `${ allTests . length } test${ allTests . length > 1 ? 's' : '' } ` )
96
97
97
98
if ( failed . length ) {
98
99
state += c . dim ( ' | ' ) + c . red ( `${ failed . length } failed` )
@@ -120,52 +121,79 @@ export abstract class BaseReporter implements Reporter {
120
121
121
122
this . log ( ` ${ title } ${ task . name } ${ suffix } ` )
122
123
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' )
124
126
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 )
131
129
}
132
130
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 = ''
136
135
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 )
139
146
140
- test . result ?. errors ?. forEach ( ( e ) => {
141
147
// 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 )
145
150
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
+ }
153
156
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
+ }
157
164
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
+ }
162
173
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
+ }
165
177
}
166
178
}
167
179
}
168
180
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
+
169
197
private getDurationPrefix ( task : Task ) {
170
198
if ( ! task . result ?. duration ) {
171
199
return ''
0 commit comments