@@ -125,55 +125,63 @@ export async function runTest(test: Test, runner: VitestRunner) {
125
125
126
126
setCurrentTest ( test )
127
127
128
- const retry = test . retry || 1
129
- for ( let retryCount = 0 ; retryCount < retry ; retryCount ++ ) {
130
- let beforeEachCleanups : HookCleanupCallback [ ] = [ ]
131
- try {
132
- await runner . onBeforeTryTest ?.( test , retryCount )
128
+ const repeats = typeof test . repeats === 'number' ? test . repeats : 1
133
129
134
- beforeEachCleanups = await callSuiteHook ( test . suite , test , 'beforeEach' , runner , [ test . context , test . suite ] )
130
+ for ( let repeatCount = 0 ; repeatCount < repeats ; repeatCount ++ ) {
131
+ const retry = test . retry || 1
135
132
136
- test . result . retryCount = retryCount
133
+ for ( let retryCount = 0 ; retryCount < retry ; retryCount ++ ) {
134
+ let beforeEachCleanups : HookCleanupCallback [ ] = [ ]
135
+ try {
136
+ await runner . onBeforeTryTest ?.( test , { retry : retryCount , repeats : repeatCount } )
137
137
138
- if ( runner . runTest ) {
139
- await runner . runTest ( test )
140
- }
141
- else {
142
- const fn = getFn ( test )
143
- if ( ! fn )
144
- throw new Error ( 'Test function is not found. Did you add it using `setFn`?' )
145
- await fn ( )
146
- }
138
+ test . result . retryCount = retryCount
139
+ test . result . repeatCount = repeatCount
147
140
148
- // some async expect will be added to this array, in case user forget to await theme
149
- if ( test . promises ) {
150
- const result = await Promise . allSettled ( test . promises )
151
- const errors = result . map ( r => r . status === 'rejected' ? r . reason : undefined ) . filter ( Boolean )
152
- if ( errors . length )
153
- throw errors
154
- }
141
+ beforeEachCleanups = await callSuiteHook ( test . suite , test , 'beforeEach' , runner , [ test . context , test . suite ] )
155
142
156
- await runner . onAfterTryTest ?.( test , retryCount )
143
+ if ( runner . runTest ) {
144
+ await runner . runTest ( test )
145
+ }
146
+ else {
147
+ const fn = getFn ( test )
148
+ if ( ! fn )
149
+ throw new Error ( 'Test function is not found. Did you add it using `setFn`?' )
150
+ await fn ( )
151
+ }
157
152
158
- test . result . state = 'pass'
159
- }
160
- catch ( e ) {
161
- failTask ( test . result , e )
162
- }
153
+ // some async expect will be added to this array, in case user forget to await theme
154
+ if ( test . promises ) {
155
+ const result = await Promise . allSettled ( test . promises )
156
+ const errors = result . map ( r => r . status === 'rejected' ? r . reason : undefined ) . filter ( Boolean )
157
+ if ( errors . length )
158
+ throw errors
159
+ }
163
160
164
- try {
165
- await callSuiteHook ( test . suite , test , 'afterEach' , runner , [ test . context , test . suite ] )
166
- await callCleanupHooks ( beforeEachCleanups )
167
- }
168
- catch ( e ) {
169
- failTask ( test . result , e )
170
- }
161
+ await runner . onAfterTryTest ?.( test , { retry : retryCount , repeats : repeatCount } )
171
162
172
- if ( test . result . state === 'pass' )
173
- break
163
+ if ( ! test . repeats )
164
+ test . result . state = 'pass'
165
+ else if ( test . repeats && retry === retryCount )
166
+ test . result . state = 'pass'
167
+ }
168
+ catch ( e ) {
169
+ failTask ( test . result , e )
170
+ }
174
171
175
- // update retry info
176
- updateTask ( test , runner )
172
+ try {
173
+ await callSuiteHook ( test . suite , test , 'afterEach' , runner , [ test . context , test . suite ] )
174
+ await callCleanupHooks ( beforeEachCleanups )
175
+ }
176
+ catch ( e ) {
177
+ failTask ( test . result , e )
178
+ }
179
+
180
+ if ( test . result . state === 'pass' )
181
+ break
182
+ // update retry info
183
+ updateTask ( test , runner )
184
+ }
177
185
}
178
186
179
187
if ( test . result . state === 'fail' )
@@ -291,30 +299,30 @@ export async function runSuite(suite: Suite, runner: VitestRunner) {
291
299
catch ( e ) {
292
300
failTask ( suite . result , e )
293
301
}
294
- }
295
302
296
- suite . result . duration = now ( ) - start
297
-
298
- if ( suite . mode === 'run' ) {
299
- if ( ! hasTests ( suite ) ) {
300
- suite . result . state = 'fail'
301
- if ( ! suite . result . error ) {
302
- const error = processError ( new Error ( `No test found in suite ${ suite . name } ` ) )
303
- suite . result . error = error
304
- suite . result . errors = [ error ]
303
+ if ( suite . mode === 'run' ) {
304
+ if ( ! hasTests ( suite ) ) {
305
+ suite . result . state = 'fail'
306
+ if ( ! suite . result . error ) {
307
+ const error = processError ( new Error ( `No test found in suite ${ suite . name } ` ) )
308
+ suite . result . error = error
309
+ suite . result . errors = [ error ]
310
+ }
311
+ }
312
+ else if ( hasFailed ( suite ) ) {
313
+ suite . result . state = 'fail'
314
+ }
315
+ else {
316
+ suite . result . state = 'pass'
305
317
}
306
318
}
307
- else if ( hasFailed ( suite ) ) {
308
- suite . result . state = 'fail'
309
- }
310
- else {
311
- suite . result . state = 'pass'
312
- }
313
- }
314
319
315
- await runner . onAfterRunSuite ?. ( suite )
320
+ updateTask ( suite , runner )
316
321
317
- updateTask ( suite , runner )
322
+ suite . result . duration = now ( ) - start
323
+
324
+ await runner . onAfterRunSuite ?.( suite )
325
+ }
318
326
}
319
327
320
328
async function runSuiteChild ( c : Task , runner : VitestRunner ) {
0 commit comments