Skip to content

Commit 4409d77

Browse files
authored
feat(vitest): add "provide" option (#6253)
1 parent 00dfc1a commit 4409d77

File tree

9 files changed

+101
-4
lines changed

9 files changed

+101
-4
lines changed

docs/config/index.md

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,54 @@ afterEach(() => {
10031003
globalThis.resetBeforeEachTest = true
10041004
```
10051005

1006+
### provide <Version>2.1.0</Version> {#provide}
1007+
1008+
- **Type:** `Partial<ProvidedContext>`
1009+
1010+
Define values that can be accessed inside your tests using `inject` method.
1011+
1012+
:::code-group
1013+
```ts [vitest.config.js]
1014+
import { defineConfig } from 'vitest/config'
1015+
1016+
export default defineConfig({
1017+
test: {
1018+
provide: {
1019+
API_KEY: '123',
1020+
},
1021+
},
1022+
})
1023+
```
1024+
```ts [my.test.js]
1025+
import { expect, inject, test } from 'vitest'
1026+
1027+
test('api key is defined', () => {
1028+
expect(inject('API_KEY')).toBe('123')
1029+
})
1030+
```
1031+
:::
1032+
1033+
::: warning
1034+
Properties have to be strings and values need to be [serializable](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#supported_types) because this object will be transferred between different processes.
1035+
:::
1036+
1037+
::: tip
1038+
If you are using TypeScript, you will need to augment `ProvidedContext` type for type safe access:
1039+
1040+
```ts
1041+
// vitest.shims.d.ts
1042+
1043+
declare module 'vitest' {
1044+
export interface ProvidedContext {
1045+
API_KEY: string
1046+
}
1047+
}
1048+
1049+
// mark this file as a module so augmentation works correctly
1050+
export {}
1051+
```
1052+
:::
1053+
10061054
### globalSetup
10071055

10081056
- **Type:** `string | string[]`
@@ -1018,7 +1066,7 @@ Multiple globalSetup files are possible. setup and teardown are executed sequent
10181066
::: warning
10191067
Global setup runs only if there is at least one running test. This means that global setup might start running during watch mode after test file is changed (the test file will wait for global setup to finish before running).
10201068

1021-
Beware that the global setup is running in a different global scope, so your tests don't have access to variables defined here. However, you can pass down serializable data to tests via `provide` method:
1069+
Beware that the global setup is running in a different global scope, so your tests don't have access to variables defined here. However, you can pass down serializable data to tests via [`provide`](#provide) method:
10221070

10231071
:::code-group
10241072
```js [globalSetup.js]
@@ -1033,8 +1081,6 @@ export default function setup({ provide }: GlobalSetupContext) {
10331081
provide('wsPort', 3000)
10341082
}
10351083

1036-
// You can also extend `ProvidedContext` type
1037-
// to have type safe access to `provide/inject` methods:
10381084
declare module 'vitest' {
10391085
export interface ProvidedContext {
10401086
wsPort: number

packages/vitest/src/node/cli/cli-config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,7 @@ export const cliOptionsConfig: VitestCLIOptions = {
794794
compare: null,
795795
outputJson: null,
796796
json: null,
797+
provide: null,
797798
}
798799

799800
export const benchCliOptionsConfig: Pick<

packages/vitest/src/node/config/resolveConfig.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ export function resolveConfig(
140140
mode,
141141
} as any as ResolvedConfig
142142

143+
resolved.provide ??= {}
144+
143145
const inspector = resolved.inspect || resolved.inspectBrk
144146

145147
resolved.inspector = {

packages/vitest/src/node/types/config.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import type {
1010
} from '../reporters'
1111
import type { TestSequencerConstructor } from '../sequencers/types'
1212
import type { ChaiConfig } from '../../integrations/chai/config'
13-
import type { Arrayable, ErrorWithDiff, ParsedStack } from '../../types/general'
13+
import type { Arrayable, ErrorWithDiff, ParsedStack, ProvidedContext } from '../../types/general'
1414
import type { JSDOMOptions } from '../../types/jsdom-options'
1515
import type { HappyDOMOptions } from '../../types/happy-dom-options'
1616
import type { EnvironmentOptions } from '../../types/environment'
@@ -731,6 +731,27 @@ export interface InlineConfig {
731731
waitForDebugger?: boolean
732732
}
733733

734+
/**
735+
* Define variables that will be returned from `inject` in the test environment.
736+
* @example
737+
* ```ts
738+
* // vitest.config.ts
739+
* export default defineConfig({
740+
* test: {
741+
* provide: {
742+
* someKey: 'someValue'
743+
* }
744+
* }
745+
* })
746+
* ```
747+
* ```ts
748+
* // test file
749+
* import { inject } from 'vitest'
750+
* const value = inject('someKey') // 'someValue'
751+
* ```
752+
*/
753+
provide?: Partial<ProvidedContext>
754+
734755
/**
735756
* Configuration options for expect() matches.
736757
*/

packages/vitest/src/node/workspace.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,14 @@ export class WorkspaceProject {
364364
project.server = ctx.server
365365
project.runner = ctx.runner
366366
project.config = ctx.config
367+
for (const _providedKey in ctx.config.provide) {
368+
const providedKey = _providedKey as keyof ProvidedContext
369+
// type is very strict here, so we cast it to any
370+
(project.provide as (key: string, value: unknown) => void)(
371+
providedKey,
372+
ctx.config.provide[providedKey],
373+
)
374+
}
367375
project.testProject = new TestProject(project)
368376
return project
369377
}
@@ -384,6 +392,15 @@ export class WorkspaceProject {
384392
server.config,
385393
this.ctx.logger,
386394
)
395+
for (const _providedKey in this.config.provide) {
396+
const providedKey = _providedKey as keyof ProvidedContext
397+
// type is very strict here, so we cast it to any
398+
(this.provide as (key: string, value: unknown) => void)(
399+
providedKey,
400+
this.config.provide[providedKey],
401+
)
402+
}
403+
387404
this.testProject = new TestProject(this)
388405

389406
this.server = server

test/workspaces/globalTest.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ declare module 'vitest' {
77
globalSetup: boolean
88
globalSetupOverriden: boolean
99
invalidValue: unknown
10+
projectConfigValue: boolean
11+
globalConfigValue: boolean
1012
}
1113
}
1214

test/workspaces/space_3/global-provide.space-3-test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@ import { expect, inject, test } from 'vitest'
33
test('global setup provides data correctly', () => {
44
expect(inject('globalSetup')).toBe(true)
55
expect(inject('globalSetupOverriden')).toBe(true)
6+
expect(inject('projectConfigValue')).toBe(true)
7+
expect(inject('globalConfigValue')).toBe(true)
68
expect(inject('invalidValue')).toBe(undefined)
79
})

test/workspaces/space_3/vitest.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@ export default defineProject({
55
include: ['**/*.space-3-test.ts'],
66
environment: 'node',
77
globalSetup: './localSetup.ts',
8+
provide: {
9+
projectConfigValue: true,
10+
},
811
},
912
})

test/workspaces/vitest.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,8 @@ export default defineConfig({
1616
CONFIG_VAR: 'root',
1717
CONFIG_OVERRIDE: 'root',
1818
},
19+
provide: {
20+
globalConfigValue: true,
21+
},
1922
},
2023
})

0 commit comments

Comments
 (0)