/
with-async-leaks-detecter.ts
49 lines (40 loc) · 1.26 KB
/
with-async-leaks-detecter.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import asyncHooks from 'node:async_hooks'
import { relative } from 'pathe'
import { rpc } from '../rpc'
import { VitestTestRunner } from './test'
export interface HangingOps {
type: string
stack: string
taskId?: string
}
export class VitestTestRunnerWithAsyncLeaksDetecter extends VitestTestRunner {
private hangingOps: Map<number, HangingOps> = new Map()
private asyncHook: asyncHooks.AsyncHook = asyncHooks.createHook({
init: (id, type) => {
const task = this.workerState.current
const filepath = task?.file?.filepath || this.workerState.filepath
let stack = new Error('STACK_TRACE_ERROR').stack
if (filepath && stack?.includes(filepath)) {
stack = stack.split(/\n\s+/).findLast(s => s.includes(filepath))
if (stack) {
const hangingOp = {
type,
stack,
taskId: task?.id || relative(this.config.root, filepath),
}
this.hangingOps.set(id, hangingOp)
}
}
},
destroy: id => this.hangingOps.delete(id),
})
onBeforeRunFiles() {
super.onBeforeRunFiles()
this.asyncHook.enable()
}
onAfterRunFiles() {
rpc().detectAsyncLeaks(Array.from(this.hangingOps.values()))
this.asyncHook.disable()
super.onAfterRunFiles()
}
}