forked from vitest-dev/vitest
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cli.ts
152 lines (126 loc) · 4.03 KB
/
cli.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import readline from 'readline'
import cac from 'cac'
import { execa } from 'execa'
import type { UserConfig } from '../types'
import { version } from '../../package.json'
import { ensurePackageInstalled } from '../utils'
import type { Vitest } from './index'
import { createVitest } from './index'
const CLOSE_TIMEOUT = 1_000
const cli = cac('vitest')
cli
.version(version)
.option('-r, --root <path>', 'root path')
.option('-c, --config <path>', 'path to config file')
.option('-u, --update', 'update snapshot')
.option('-w, --watch', 'watch mode')
.option('-o, --open', 'open UI', { default: false })
.option('-t, --testNamePattern <pattern>', 'run test names with the specified pattern')
.option('--api', 'listen to port and serve API')
.option('--threads', 'enabled threads', { default: true })
.option('--silent', 'silent console output from tests')
.option('--reporter <name>', 'reporter')
.option('--coverage', 'use c8 for coverage')
.option('--run', 'do not watch')
.option('--global', 'inject apis globally')
.option('--dom', 'mock browser api with happy-dom')
.option('--environment <env>', 'runner environment', { default: 'node' })
.option('--passWithNoTests', 'pass when no tests found')
.help()
cli
.command('run [...filters]')
.action(run)
cli
.command('watch [...filters]')
.action(dev)
cli
.command('dev [...filters]')
.action(dev)
cli
.command('[...filters]')
.action(dev)
cli.parse()
async function dev(cliFilters: string[], argv: UserConfig) {
if (argv.watch == null)
argv.watch = !process.env.CI && !argv.run
await run(cliFilters, argv)
}
async function run(cliFilters: string[], options: UserConfig) {
process.env.VITEST = 'true'
process.env.NODE_ENV = 'test'
if (!await ensurePackageInstalled('vite'))
process.exit(1)
if (typeof options.coverage === 'boolean')
options.coverage = { enabled: options.coverage }
const ctx = await createVitest(options)
if (ctx.config.coverage.enabled) {
if (!await ensurePackageInstalled('c8'))
process.exit(1)
if (!process.env.NODE_V8_COVERAGE) {
process.env.NODE_V8_COVERAGE = ctx.config.coverage.tempDirectory
const { exitCode } = await execa(process.argv0, process.argv.slice(1), { stdio: 'inherit' })
process.exit(exitCode)
}
}
if (ctx.config.environment && ctx.config.environment !== 'node') {
if (!await ensurePackageInstalled(ctx.config.environment))
process.exit(1)
}
if (process.stdin.isTTY && ctx.config.watch)
registerConsoleShortcuts(ctx)
process.chdir(ctx.config.root)
ctx.onServerRestarted(() => {
// TODO: re-consider how to re-run the tests the server smartly
ctx.start(cliFilters)
})
try {
await ctx.start(cliFilters)
}
catch (e) {
process.exitCode = 1
throw e
}
finally {
if (!ctx.config.watch)
await ctx.close()
}
if (!ctx.config.watch) {
// force process exit if it hangs
setTimeout(() => process.exit(), CLOSE_TIMEOUT).unref()
}
}
function closeServerAndExitProcess(ctx: Vitest) {
const closePromise = ctx.close()
let timeout: NodeJS.Timeout
const timeoutPromise = new Promise((resolve, reject) => {
timeout = setTimeout(() => reject(new Error(`close timed out after ${CLOSE_TIMEOUT}ms`)), CLOSE_TIMEOUT)
})
Promise.race([closePromise, timeoutPromise]).then(
() => {
clearTimeout(timeout)
process.exit(0)
},
(err) => {
clearTimeout(timeout)
console.error('error during close', err)
process.exit(1)
},
)
}
function registerConsoleShortcuts(ctx: Vitest) {
readline.emitKeypressEvents(process.stdin)
process.stdin.setRawMode(true)
process.stdin.on('keypress', (str: string, key: any) => {
if (str === '\x03' || str === '\x1B' || (key && key.ctrl && key.name === 'c')) { // ctrl-c or esc
closeServerAndExitProcess(ctx)
return
}
// is running, ignore keypress
if (ctx.runningPromise)
return
// press any key to exit on first run
if (ctx.isFirstRun)
closeServerAndExitProcess(ctx)
// TODO: add more commands
})
}