Skip to content

Commit e26e066

Browse files
authoredNov 13, 2024··
feat(vitest): add onTestsRerun method to global setup context (#6803)
1 parent 9c8f7e3 commit e26e066

File tree

9 files changed

+104
-6
lines changed

9 files changed

+104
-6
lines changed
 

‎docs/config/index.md

+12
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,18 @@ inject('wsPort') === 3000
10891089
```
10901090
:::
10911091

1092+
Since Vitest 2.2.0, you can define a custom callback function to be called when Vitest reruns tests. If the function is asynchronous, the runner will wait for it to complete before executing the tests.
1093+
1094+
```ts
1095+
import type { GlobalSetupContext } from 'vitest/node'
1096+
1097+
export default function setup({ onTestsRerun }: GlobalSetupContext) {
1098+
onTestsRerun(async () => {
1099+
await restartDb()
1100+
})
1101+
}
1102+
```
1103+
10921104
### forceRerunTriggers<NonProjectOption />
10931105

10941106
- **Type**: `string[]`

‎packages/vitest/src/node/core.ts

+15-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { Writable } from 'node:stream'
33
import type { ViteDevServer } from 'vite'
44
import type { defineWorkspace } from 'vitest/config'
55
import type { SerializedCoverageConfig } from '../runtime/config'
6-
import type { ArgumentsType, OnServerRestartHandler, ProvidedContext, UserConsoleLog } from '../types/general'
6+
import type { ArgumentsType, OnServerRestartHandler, OnTestsRerunHandler, ProvidedContext, UserConsoleLog } from '../types/general'
77
import type { ProcessPool, WorkspaceSpec } from './pool'
88
import type { TestSpecification } from './spec'
99
import type { ResolvedConfig, UserConfig, VitestRunMode } from './types/config'
@@ -104,6 +104,7 @@ export class Vitest {
104104
private _onClose: (() => Awaited<unknown>)[] = []
105105
private _onSetServer: OnServerRestartHandler[] = []
106106
private _onCancelListeners: ((reason: CancelReason) => Promise<void> | void)[] = []
107+
private _onUserTestsRerun: OnTestsRerunHandler[] = []
107108

108109
async setServer(options: UserConfig, server: ViteDevServer, cliOptions: UserConfig) {
109110
this.unregisterWatcher?.()
@@ -119,6 +120,7 @@ export class Vitest {
119120
this.coverageProvider = undefined
120121
this.runningPromise = undefined
121122
this._cachedSpecs.clear()
123+
this._onUserTestsRerun = []
122124

123125
const resolved = resolveConfig(this.mode, options, server.config, this.logger)
124126

@@ -695,7 +697,10 @@ export class Vitest {
695697
files = files.filter(file => filteredFiles.some(f => f[1] === file))
696698
}
697699

698-
await this.report('onWatcherRerun', files, trigger)
700+
await Promise.all([
701+
this.report('onWatcherRerun', files, trigger),
702+
...this._onUserTestsRerun.map(fn => fn(files)),
703+
])
699704
await this.runFiles(files.flatMap(file => this.getProjectsByTestFile(file)), allTestsRun)
700705

701706
await this.report('onWatcherStart', this.state.getFiles(files))
@@ -817,7 +822,10 @@ export class Vitest {
817822

818823
const triggerIds = new Set(triggerId.map(id => relative(this.config.root, id)))
819824
const triggerLabel = Array.from(triggerIds).join(', ')
820-
await this.report('onWatcherRerun', files, triggerLabel)
825+
await Promise.all([
826+
this.report('onWatcherRerun', files, triggerLabel),
827+
...this._onUserTestsRerun.map(fn => fn(files)),
828+
])
821829

822830
await this.runFiles(files.flatMap(file => this.getProjectsByTestFile(file)), false)
823831

@@ -1154,4 +1162,8 @@ export class Vitest {
11541162
onClose(fn: () => void) {
11551163
this._onClose.push(fn)
11561164
}
1165+
1166+
onTestsRerun(fn: OnTestsRerunHandler): void {
1167+
this._onUserTestsRerun.push(fn)
1168+
}
11571169
}

‎packages/vitest/src/node/globalSetup.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ViteNodeRunner } from 'vite-node/client'
2-
import type { ProvidedContext } from '../types/general'
2+
import type { OnTestsRerunHandler, ProvidedContext } from '../types/general'
33
import type { ResolvedConfig } from './types/config'
44
import { toArray } from '@vitest/utils'
55

@@ -9,6 +9,7 @@ export interface GlobalSetupContext {
99
key: T,
1010
value: ProvidedContext[T]
1111
) => void
12+
onTestsRerun: (cb: OnTestsRerunHandler) => void
1213
}
1314

1415
export interface GlobalSetupFile {

‎packages/vitest/src/node/workspace.ts

+1
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ export class WorkspaceProject {
170170
const teardown = await globalSetupFile.setup?.({
171171
provide: (key, value) => this.provide(key, value),
172172
config: this.config,
173+
onTestsRerun: cb => this.ctx.onTestsRerun(cb),
173174
})
174175
if (teardown == null || !!globalSetupFile.teardown) {
175176
continue

‎packages/vitest/src/public/node.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,10 @@ export type {
126126
TscErrorInfo as TypeCheckErrorInfo,
127127
} from '../typecheck/types'
128128

129-
export type { OnServerRestartHandler } from '../types/general'
129+
export type {
130+
OnServerRestartHandler,
131+
OnTestsRerunHandler,
132+
} from '../types/general'
130133

131134
export { createDebugger } from '../utils/debugger'
132135

‎packages/vitest/src/types/general.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,5 @@ export interface ModuleGraphData {
4646
}
4747

4848
export type OnServerRestartHandler = (reason?: string) => Promise<void> | void
49-
49+
export type OnTestsRerunHandler = (testFiles: string[]) => Promise<void> | void
5050
export interface ProvidedContext {}

‎test/watch/fixtures/global-setup.ts

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { GlobalSetupContext } from 'vitest/node';
2+
3+
const calls: string[] = [];
4+
5+
(globalThis as any).__CALLS = calls
6+
7+
export default ({ onTestsRerun }: GlobalSetupContext) => {
8+
calls.push('start')
9+
onTestsRerun(() => {
10+
calls.push('rerun')
11+
})
12+
return () => {
13+
calls.push('end')
14+
}
15+
}

‎test/watch/fixtures/vitest.config.ts

+4
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,9 @@ export default defineConfig({
1818
forceRerunTriggers: [
1919
'**/force-watch/**',
2020
],
21+
22+
globalSetup: process.env.TEST_GLOBAL_SETUP
23+
? './global-setup.ts'
24+
: undefined,
2125
},
2226
})
+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { expect, test } from 'vitest'
2+
import { editFile, runVitest } from '../../test-utils'
3+
4+
const testFile = 'fixtures/math.test.ts'
5+
6+
test('global setup calls hooks correctly when file changes', async () => {
7+
process.env.TEST_GLOBAL_SETUP = 'true'
8+
const { vitest, ctx } = await runVitest({
9+
root: 'fixtures',
10+
watch: true,
11+
include: ['math.test.ts'],
12+
})
13+
14+
await vitest.waitForStdout('Waiting for file changes')
15+
16+
const calls = (globalThis as any).__CALLS as string[]
17+
expect(calls).toEqual(['start'])
18+
19+
editFile(testFile, testFileContent => `${testFileContent}\n\n`)
20+
21+
await vitest.waitForStdout('RERUN')
22+
expect(calls).toEqual(['start', 'rerun'])
23+
24+
await ctx?.close()
25+
26+
expect(calls).toEqual(['start', 'rerun', 'end'])
27+
})
28+
29+
test('global setup calls hooks correctly with a manual rerun', async () => {
30+
process.env.TEST_GLOBAL_SETUP = 'true'
31+
const { vitest, ctx } = await runVitest({
32+
root: 'fixtures',
33+
watch: true,
34+
include: ['math.test.ts'],
35+
})
36+
37+
await vitest.waitForStdout('Waiting for file changes')
38+
39+
const calls = (globalThis as any).__CALLS as string[]
40+
expect(calls).toEqual(['start'])
41+
42+
vitest.write('r')
43+
44+
await vitest.waitForStdout('RERUN')
45+
expect(calls).toEqual(['start', 'rerun'])
46+
47+
await ctx?.close()
48+
49+
expect(calls).toEqual(['start', 'rerun', 'end'])
50+
})

0 commit comments

Comments
 (0)
Please sign in to comment.