Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 38 additions & 22 deletions packages/runner/src/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type {
Test,
TestContext,
} from './types/tasks'
import { getSafeTimers, shuffle } from '@vitest/utils'
import { shuffle } from '@vitest/utils'
import { processError } from '@vitest/utils/error'
import { collectTests } from './collect'
import { PendingError } from './errors'
Expand Down Expand Up @@ -174,37 +174,53 @@ export async function callSuiteHook<T extends keyof SuiteHooks>(

const packs = new Map<string, [TaskResult | undefined, TaskMeta]>()
const eventsPacks: [string, TaskUpdateEvent][] = []
let updateTimer: any
let previousUpdate: Promise<void> | undefined

export function updateTask(event: TaskUpdateEvent, task: Task, runner: VitestRunner): void {
eventsPacks.push([task.id, event])
packs.set(task.id, [task.result, task.meta])

const { clearTimeout, setTimeout } = getSafeTimers()

clearTimeout(updateTimer)
updateTimer = setTimeout(() => {
previousUpdate = sendTasksUpdate(runner)
}, 10)
}

async function sendTasksUpdate(runner: VitestRunner) {
const { clearTimeout } = getSafeTimers()
clearTimeout(updateTimer)
await previousUpdate
const pendingTasksUpdates: Promise<void>[] = []

function sendTasksUpdate(runner: VitestRunner): void {
if (packs.size) {
const taskPacks = Array.from(packs).map<TaskResultPack>(([id, task]) => {
return [id, task[0], task[1]]
})
const p = runner.onTaskUpdate?.(taskPacks, eventsPacks)
if (p) {
pendingTasksUpdates.push(p)
// remove successful promise to not grow array indefnitely,
// but keep rejections so finishSendTasksUpdate can handle them
p.then(
() => pendingTasksUpdates.splice(pendingTasksUpdates.indexOf(p), 1),
() => {},
)
}
eventsPacks.length = 0
packs.clear()
return p
}
}

async function finishSendTasksUpdate(runner: VitestRunner) {
sendTasksUpdate(runner)
await Promise.all(pendingTasksUpdates)
}

function throttle<T extends (...args: any[]) => void>(fn: T, ms: number): T {
let last = 0
return function (this: any, ...args: any[]) {
const now = unixNow()
if (now - last > ms) {
last = now
return fn.apply(this, args)
}
} as any
}

// throttle based on summary reporter's DURATION_UPDATE_INTERVAL_MS
const sendTasksUpdateThrottled = throttle(sendTasksUpdate, 100)

export function updateTask(event: TaskUpdateEvent, task: Task, runner: VitestRunner): void {
eventsPacks.push([task.id, event])
packs.set(task.id, [task.result, task.meta])
sendTasksUpdateThrottled(runner)
}

async function callCleanupHooks(cleanups: unknown[]) {
await Promise.all(
cleanups.map(async (fn) => {
Expand Down Expand Up @@ -561,7 +577,7 @@ export async function startTests(specs: string[] | FileSpecification[], runner:

await runner.onAfterRunFiles?.(files)

await sendTasksUpdate(runner)
await finishSendTasksUpdate(runner)

return files
}
Expand Down