@@ -16,7 +16,7 @@ import type {
16
16
Test ,
17
17
TestContext ,
18
18
} from './types/tasks'
19
- import { getSafeTimers , shuffle } from '@vitest/utils'
19
+ import { shuffle } from '@vitest/utils'
20
20
import { processError } from '@vitest/utils/error'
21
21
import { collectTests } from './collect'
22
22
import { PendingError } from './errors'
@@ -174,37 +174,53 @@ export async function callSuiteHook<T extends keyof SuiteHooks>(
174
174
175
175
const packs = new Map < string , [ TaskResult | undefined , TaskMeta ] > ( )
176
176
const eventsPacks : [ string , TaskUpdateEvent ] [ ] = [ ]
177
- let updateTimer : any
178
- let previousUpdate : Promise < void > | undefined
179
-
180
- export function updateTask ( event : TaskUpdateEvent , task : Task , runner : VitestRunner ) : void {
181
- eventsPacks . push ( [ task . id , event ] )
182
- packs . set ( task . id , [ task . result , task . meta ] )
183
-
184
- const { clearTimeout, setTimeout } = getSafeTimers ( )
185
-
186
- clearTimeout ( updateTimer )
187
- updateTimer = setTimeout ( ( ) => {
188
- previousUpdate = sendTasksUpdate ( runner )
189
- } , 10 )
190
- }
191
-
192
- async function sendTasksUpdate ( runner : VitestRunner ) {
193
- const { clearTimeout } = getSafeTimers ( )
194
- clearTimeout ( updateTimer )
195
- await previousUpdate
177
+ const pendingTasksUpdates : Promise < void > [ ] = [ ]
196
178
179
+ function sendTasksUpdate ( runner : VitestRunner ) : void {
197
180
if ( packs . size ) {
198
181
const taskPacks = Array . from ( packs ) . map < TaskResultPack > ( ( [ id , task ] ) => {
199
182
return [ id , task [ 0 ] , task [ 1 ] ]
200
183
} )
201
184
const p = runner . onTaskUpdate ?.( taskPacks , eventsPacks )
185
+ if ( p ) {
186
+ pendingTasksUpdates . push ( p )
187
+ // remove successful promise to not grow array indefnitely,
188
+ // but keep rejections so finishSendTasksUpdate can handle them
189
+ p . then (
190
+ ( ) => pendingTasksUpdates . splice ( pendingTasksUpdates . indexOf ( p ) , 1 ) ,
191
+ ( ) => { } ,
192
+ )
193
+ }
202
194
eventsPacks . length = 0
203
195
packs . clear ( )
204
- return p
205
196
}
206
197
}
207
198
199
+ async function finishSendTasksUpdate ( runner : VitestRunner ) {
200
+ sendTasksUpdate ( runner )
201
+ await Promise . all ( pendingTasksUpdates )
202
+ }
203
+
204
+ function throttle < T extends ( ...args : any [ ] ) => void > ( fn : T , ms : number ) : T {
205
+ let last = 0
206
+ return function ( this : any , ...args : any [ ] ) {
207
+ const now = unixNow ( )
208
+ if ( now - last > ms ) {
209
+ last = now
210
+ return fn . apply ( this , args )
211
+ }
212
+ } as any
213
+ }
214
+
215
+ // throttle based on summary reporter's DURATION_UPDATE_INTERVAL_MS
216
+ const sendTasksUpdateThrottled = throttle ( sendTasksUpdate , 100 )
217
+
218
+ export function updateTask ( event : TaskUpdateEvent , task : Task , runner : VitestRunner ) : void {
219
+ eventsPacks . push ( [ task . id , event ] )
220
+ packs . set ( task . id , [ task . result , task . meta ] )
221
+ sendTasksUpdateThrottled ( runner )
222
+ }
223
+
208
224
async function callCleanupHooks ( cleanups : unknown [ ] ) {
209
225
await Promise . all (
210
226
cleanups . map ( async ( fn ) => {
@@ -561,7 +577,7 @@ export async function startTests(specs: string[] | FileSpecification[], runner:
561
577
562
578
await runner . onAfterRunFiles ?.( files )
563
579
564
- await sendTasksUpdate ( runner )
580
+ await finishSendTasksUpdate ( runner )
565
581
566
582
return files
567
583
}
0 commit comments