/
entry.ts
127 lines (101 loc) · 4.62 KB
/
entry.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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import type { VitestRunner, VitestRunnerConstructor } from '@vitest/runner'
import { startTests } from '@vitest/runner'
import { resolve } from 'pathe'
import type { ContextTestEnvironment, ResolvedConfig } from '../types'
import { getWorkerState, resetModules } from '../utils'
import { vi } from '../integrations/vi'
import { distDir } from '../paths'
import { startCoverageInsideWorker, stopCoverageInsideWorker, takeCoverageInsideWorker } from '../integrations/coverage'
import { setupChaiConfig } from '../integrations/chai'
import { setupGlobalEnv, withEnv } from './setup.node'
import { rpc } from './rpc'
import type { VitestExecutor } from './execute'
const runnersFile = resolve(distDir, 'runners.js')
async function getTestRunnerConstructor(config: ResolvedConfig, executor: VitestExecutor): Promise<VitestRunnerConstructor> {
if (!config.runner) {
const { VitestTestRunner, NodeBenchmarkRunner } = await executor.executeFile(runnersFile)
return (config.mode === 'test' ? VitestTestRunner : NodeBenchmarkRunner) as VitestRunnerConstructor
}
const mod = await executor.executeId(config.runner)
if (!mod.default && typeof mod.default !== 'function')
throw new Error(`Runner must export a default function, but got ${typeof mod.default} imported from ${config.runner}`)
return mod.default as VitestRunnerConstructor
}
async function getTestRunner(config: ResolvedConfig, executor: VitestExecutor): Promise<VitestRunner> {
const TestRunner = await getTestRunnerConstructor(config, executor)
const testRunner = new TestRunner(config)
// inject private executor to every runner
Object.defineProperty(testRunner, '__vitest_executor', {
value: executor,
enumerable: false,
configurable: false,
})
if (!testRunner.config)
testRunner.config = config
if (!testRunner.importFile)
throw new Error('Runner must implement "importFile" method.')
// patch some methods, so custom runners don't need to call RPC
const originalOnTaskUpdate = testRunner.onTaskUpdate
testRunner.onTaskUpdate = async (task) => {
const p = rpc().onTaskUpdate(task)
await originalOnTaskUpdate?.call(testRunner, task)
return p
}
const originalOnCollected = testRunner.onCollected
testRunner.onCollected = async (files) => {
const state = getWorkerState()
files.forEach((file) => {
file.prepareDuration = state.durations.prepare
file.environmentLoad = state.durations.environment
// should be collected only for a single test file in a batch
state.durations.prepare = 0
state.durations.environment = 0
})
rpc().onCollected(files)
await originalOnCollected?.call(testRunner, files)
}
const originalOnAfterRun = testRunner.onAfterRun
testRunner.onAfterRun = async (files) => {
const coverage = await takeCoverageInsideWorker(config.coverage, executor)
rpc().onAfterSuiteRun({ coverage })
await originalOnAfterRun?.call(testRunner, files)
}
return testRunner
}
// browser shouldn't call this!
export async function run(files: string[], config: ResolvedConfig, environment: ContextTestEnvironment, executor: VitestExecutor): Promise<void> {
const workerState = getWorkerState()
await setupGlobalEnv(config)
await startCoverageInsideWorker(config.coverage, executor)
if (config.chaiConfig)
setupChaiConfig(config.chaiConfig)
const runner = await getTestRunner(config, executor)
workerState.durations.prepare = performance.now() - workerState.durations.prepare
// @ts-expect-error untyped global
globalThis.__vitest_environment__ = environment
workerState.durations.environment = performance.now()
await withEnv(environment.name, environment.options || config.environmentOptions || {}, executor, async () => {
workerState.durations.environment = performance.now() - workerState.durations.environment
for (const file of files) {
if (workerState.isCancelling) {
// TODO: Mark as skipped and break
}
// it doesn't matter if running with --threads
// if running with --no-threads, we usually want to reset everything before running a test
// but we have --isolate option to disable this
if (config.isolate) {
workerState.mockMap.clear()
resetModules(workerState.moduleCache, true)
}
workerState.filepath = file
await startTests([file], runner)
workerState.filepath = undefined
// reset after tests, because user might call `vi.setConfig` in setupFile
vi.resetConfig()
// mocks should not affect different files
vi.restoreAllMocks()
}
await stopCoverageInsideWorker(config.coverage, executor)
})
workerState.environmentTeardownRun = true
}