Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 20 additions & 7 deletions docs/config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -1065,17 +1065,30 @@ Beware that the global setup is running in a different global scope, so your tes

:::code-group
```js [globalSetup.js]
export default function setup({ provide }) {
provide('wsPort', 3000)
export default function setup(project) {
project.provide('wsPort', 3000)
}
```
```ts [globalSetup.ts]
```ts [globalSetup.ts <Version>2.0.0</Version>]
import type { GlobalSetupContext } from 'vitest/node'

export default function setup({ provide }: GlobalSetupContext) {
provide('wsPort', 3000)
}

declare module 'vitest' {
export interface ProvidedContext {
wsPort: number
}
}
```
```ts [globalSetup.ts <Version>2.2.0</Version>]
import type { TestProject } from 'vitest/node'

export default function setup(project: TestProject) {
project.provide('wsPort', 3000)
}

declare module 'vitest' {
export interface ProvidedContext {
wsPort: number
Expand All @@ -1089,13 +1102,13 @@ inject('wsPort') === 3000
```
:::

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.
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 tests. Note that you cannot destruct the `project` like `{ onTestsRerun }` because it relies on the context.

```ts
import type { GlobalSetupContext } from 'vitest/node'
import type { TestProject } from 'vitest/node'

export default function setup({ onTestsRerun }: GlobalSetupContext) {
onTestsRerun(async () => {
export default function setup(project: TestProject) {
project.onTestsRerun(async () => {
await restartDb()
})
}
Expand Down
24 changes: 4 additions & 20 deletions packages/vitest/src/node/globalSetup.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,13 @@
import type { ViteNodeRunner } from 'vite-node/client'
import type { OnTestsRerunHandler, ProvidedContext } from '../types/general'
import type { ResolvedConfig } from './types/config'
import type { TestProject } from './project'
import { toArray } from '@vitest/utils'

export interface GlobalSetupContext {
/**
* Config of the current project.
*/
config: ResolvedConfig
/**
* Provide a value to the test context. This value will be available to all tests via `inject`.
*/
provide: <T extends keyof ProvidedContext & string>(
key: T,
value: ProvidedContext[T]
) => void
/**
* Register a function that will be called before tests run again in watch mode.
*/
onTestsRerun: (cb: OnTestsRerunHandler) => void
}
/** @deprecated use `TestProject` instead */
export type GlobalSetupContext = TestProject

export interface GlobalSetupFile {
file: string
setup?: (context: GlobalSetupContext) => Promise<Function | void> | void
setup?: (context: TestProject) => Promise<Function | void> | void
teardown?: Function
}

Expand Down
25 changes: 14 additions & 11 deletions packages/vitest/src/node/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import type {
InlineConfig as ViteInlineConfig,
} from 'vite'
import type { Typechecker } from '../typecheck/typechecker'
import type { ProvidedContext } from '../types/general'
import type { OnTestsRerunHandler, ProvidedContext } from '../types/general'
import type { Vitest } from './core'
import type { GlobalSetupFile } from './globalSetup'
import type { Logger } from './logger'
import type { BrowserServer } from './types/browser'
import type {
ResolvedConfig,
Expand Down Expand Up @@ -87,13 +88,15 @@ export class TestProject {
this.globalConfig = vitest.config
}

// "provide" is a property, not a method to keep the context when destructed in the global setup,
// making it a method would be a breaking change, and can be done in Vitest 3 at minimum
/**
* Provide a value to the test context. This value will be available to all tests with `inject`.
*/
provide<T extends keyof ProvidedContext & string>(
provide = <T extends keyof ProvidedContext & string>(
key: T,
value: ProvidedContext[T],
): void {
): void => {
try {
structuredClone(value)
}
Expand Down Expand Up @@ -217,11 +220,7 @@ export class TestProject {
)

for (const globalSetupFile of this._globalSetups) {
const teardown = await globalSetupFile.setup?.({
provide: (key, value) => this.provide(key, value),
config: this.config,
onTestsRerun: cb => this.vitest.onTestsRerun(cb),
})
const teardown = await globalSetupFile.setup?.(this)
if (teardown == null || !!globalSetupFile.teardown) {
continue
}
Expand All @@ -234,13 +233,17 @@ export class TestProject {
}
}

onTestsRerun(cb: OnTestsRerunHandler): void {
this.vitest.onTestsRerun(cb)
}

/** @deprecated */
teardownGlobalSetup() {
teardownGlobalSetup(): Promise<void> {
return this._teardownGlobalSetup()
}

/** @internal */
async _teardownGlobalSetup() {
async _teardownGlobalSetup(): Promise<void> {
if (!this._globalSetups) {
return
}
Expand All @@ -250,7 +253,7 @@ export class TestProject {
}

/** @deprecated use `vitest.logger` instead */
get logger() {
get logger(): Logger {
return this.vitest.logger
}

Expand Down
6 changes: 3 additions & 3 deletions test/watch/fixtures/global-setup.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { GlobalSetupContext } from 'vitest/node';
import { TestProject } from 'vitest/node';

const calls: string[] = [];

(globalThis as any).__CALLS = calls

export default ({ onTestsRerun }: GlobalSetupContext) => {
export default (project: TestProject) => {
calls.push('start')
onTestsRerun(() => {
project.onTestsRerun(() => {
calls.push('rerun')
})
return () => {
Expand Down