/
globalSetup.ts
87 lines (80 loc) · 2.53 KB
/
globalSetup.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
import type { Plugin } from 'vite'
import { ViteNodeRunner } from 'vite-node/client'
import type { Vitest } from '../core'
import { toArray } from '../../utils'
interface GlobalSetupFile {
file: string
setup?: () => Promise<Function|void>|void
teardown?: Function
}
async function loadGlobalSetupFiles(ctx: Vitest): Promise<GlobalSetupFile[]> {
const node = ctx.vitenode
const server = ctx.server
const runner = new ViteNodeRunner({
root: server.config.root,
base: server.config.base,
fetchModule(id) {
return node.fetchModule(id)
},
resolveId(id, importer) {
return node.resolveId(id, importer)
},
})
const globalSetupFiles = toArray(server.config.test?.globalSetup)
return Promise.all(globalSetupFiles.map(file => loadGlobalSetupFile(file, runner)))
}
async function loadGlobalSetupFile(file: string, runner: ViteNodeRunner): Promise<GlobalSetupFile> {
const m = await runner.executeFile(file)
for (const exp of ['default', 'setup', 'teardown']) {
if (m[exp] != null && typeof m[exp] !== 'function')
throw new Error(`invalid export in globalSetup file ${file}: ${exp} must be a function`)
}
if (m.default) {
return {
file,
setup: m.default,
}
}
else if (m.setup || m.teardown) {
return {
file,
setup: m.setup,
teardown: m.teardown,
}
}
else {
throw new Error(`invalid globalSetup file ${file}. Must export setup, teardown or have a default export`)
}
}
export const GlobalSetupPlugin = (ctx: Vitest): Plugin => {
let globalSetupFiles: GlobalSetupFile[]
return {
name: 'vitest:global-setup-plugin',
enforce: 'pre',
async buildStart() {
if (!ctx.server.config.test?.globalSetup)
return
globalSetupFiles = await loadGlobalSetupFiles(ctx)
for (const globalSetupFile of globalSetupFiles) {
const teardown = await globalSetupFile.setup?.()
if (teardown == null || !!globalSetupFile.teardown)
continue
if (typeof teardown !== 'function')
throw new Error(`invalid return value in globalSetup file ${globalSetupFile.file}. Must return a function`)
globalSetupFile.teardown = teardown
}
},
async buildEnd() {
if (globalSetupFiles?.length) {
for (const globalSetupFile of globalSetupFiles.reverse()) {
try {
await globalSetupFile.teardown?.()
}
catch (error) {
console.error(`error during global teardown of ${globalSetupFile.file}`, error)
}
}
}
},
}
}