From 4409d779dbabb811b72670da66da4fdb77200e96 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Fri, 9 Aug 2024 15:15:00 +0200 Subject: [PATCH] feat(vitest): add "provide" option (#6253) --- docs/config/index.md | 52 +++++++++++++++++-- packages/vitest/src/node/cli/cli-config.ts | 1 + .../vitest/src/node/config/resolveConfig.ts | 2 + packages/vitest/src/node/types/config.ts | 23 +++++++- packages/vitest/src/node/workspace.ts | 17 ++++++ test/workspaces/globalTest.ts | 2 + .../space_3/global-provide.space-3-test.ts | 2 + test/workspaces/space_3/vitest.config.ts | 3 ++ test/workspaces/vitest.config.ts | 3 ++ 9 files changed, 101 insertions(+), 4 deletions(-) diff --git a/docs/config/index.md b/docs/config/index.md index 5d7bf73595be..6e9971a54627 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -1003,6 +1003,54 @@ afterEach(() => { globalThis.resetBeforeEachTest = true ``` +### provide 2.1.0 {#provide} + +- **Type:** `Partial` + +Define values that can be accessed inside your tests using `inject` method. + +:::code-group +```ts [vitest.config.js] +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + provide: { + API_KEY: '123', + }, + }, +}) +``` +```ts [my.test.js] +import { expect, inject, test } from 'vitest' + +test('api key is defined', () => { + expect(inject('API_KEY')).toBe('123') +}) +``` +::: + +::: warning +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. +::: + +::: tip +If you are using TypeScript, you will need to augment `ProvidedContext` type for type safe access: + +```ts +// vitest.shims.d.ts + +declare module 'vitest' { + export interface ProvidedContext { + API_KEY: string + } +} + +// mark this file as a module so augmentation works correctly +export {} +``` +::: + ### globalSetup - **Type:** `string | string[]` @@ -1018,7 +1066,7 @@ Multiple globalSetup files are possible. setup and teardown are executed sequent ::: warning 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). -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: +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: :::code-group ```js [globalSetup.js] @@ -1033,8 +1081,6 @@ export default function setup({ provide }: GlobalSetupContext) { provide('wsPort', 3000) } -// You can also extend `ProvidedContext` type -// to have type safe access to `provide/inject` methods: declare module 'vitest' { export interface ProvidedContext { wsPort: number diff --git a/packages/vitest/src/node/cli/cli-config.ts b/packages/vitest/src/node/cli/cli-config.ts index 960a3dcb3829..b9bf3295262e 100644 --- a/packages/vitest/src/node/cli/cli-config.ts +++ b/packages/vitest/src/node/cli/cli-config.ts @@ -794,6 +794,7 @@ export const cliOptionsConfig: VitestCLIOptions = { compare: null, outputJson: null, json: null, + provide: null, } export const benchCliOptionsConfig: Pick< diff --git a/packages/vitest/src/node/config/resolveConfig.ts b/packages/vitest/src/node/config/resolveConfig.ts index 939ab65ba7fd..e75e9d617ba0 100644 --- a/packages/vitest/src/node/config/resolveConfig.ts +++ b/packages/vitest/src/node/config/resolveConfig.ts @@ -140,6 +140,8 @@ export function resolveConfig( mode, } as any as ResolvedConfig + resolved.provide ??= {} + const inspector = resolved.inspect || resolved.inspectBrk resolved.inspector = { diff --git a/packages/vitest/src/node/types/config.ts b/packages/vitest/src/node/types/config.ts index bf866ec4fa8a..019b0f6714f4 100644 --- a/packages/vitest/src/node/types/config.ts +++ b/packages/vitest/src/node/types/config.ts @@ -10,7 +10,7 @@ import type { } from '../reporters' import type { TestSequencerConstructor } from '../sequencers/types' import type { ChaiConfig } from '../../integrations/chai/config' -import type { Arrayable, ErrorWithDiff, ParsedStack } from '../../types/general' +import type { Arrayable, ErrorWithDiff, ParsedStack, ProvidedContext } from '../../types/general' import type { JSDOMOptions } from '../../types/jsdom-options' import type { HappyDOMOptions } from '../../types/happy-dom-options' import type { EnvironmentOptions } from '../../types/environment' @@ -731,6 +731,27 @@ export interface InlineConfig { waitForDebugger?: boolean } + /** + * Define variables that will be returned from `inject` in the test environment. + * @example + * ```ts + * // vitest.config.ts + * export default defineConfig({ + * test: { + * provide: { + * someKey: 'someValue' + * } + * } + * }) + * ``` + * ```ts + * // test file + * import { inject } from 'vitest' + * const value = inject('someKey') // 'someValue' + * ``` + */ + provide?: Partial + /** * Configuration options for expect() matches. */ diff --git a/packages/vitest/src/node/workspace.ts b/packages/vitest/src/node/workspace.ts index 40a6a21b5ed8..e85b5d1275e2 100644 --- a/packages/vitest/src/node/workspace.ts +++ b/packages/vitest/src/node/workspace.ts @@ -364,6 +364,14 @@ export class WorkspaceProject { project.server = ctx.server project.runner = ctx.runner project.config = ctx.config + for (const _providedKey in ctx.config.provide) { + const providedKey = _providedKey as keyof ProvidedContext + // type is very strict here, so we cast it to any + (project.provide as (key: string, value: unknown) => void)( + providedKey, + ctx.config.provide[providedKey], + ) + } project.testProject = new TestProject(project) return project } @@ -384,6 +392,15 @@ export class WorkspaceProject { server.config, this.ctx.logger, ) + for (const _providedKey in this.config.provide) { + const providedKey = _providedKey as keyof ProvidedContext + // type is very strict here, so we cast it to any + (this.provide as (key: string, value: unknown) => void)( + providedKey, + this.config.provide[providedKey], + ) + } + this.testProject = new TestProject(this) this.server = server diff --git a/test/workspaces/globalTest.ts b/test/workspaces/globalTest.ts index 771dca6aed17..439a06a3dec5 100644 --- a/test/workspaces/globalTest.ts +++ b/test/workspaces/globalTest.ts @@ -7,6 +7,8 @@ declare module 'vitest' { globalSetup: boolean globalSetupOverriden: boolean invalidValue: unknown + projectConfigValue: boolean + globalConfigValue: boolean } } diff --git a/test/workspaces/space_3/global-provide.space-3-test.ts b/test/workspaces/space_3/global-provide.space-3-test.ts index 4cf6b70dd48c..2c893c09a99d 100644 --- a/test/workspaces/space_3/global-provide.space-3-test.ts +++ b/test/workspaces/space_3/global-provide.space-3-test.ts @@ -3,5 +3,7 @@ import { expect, inject, test } from 'vitest' test('global setup provides data correctly', () => { expect(inject('globalSetup')).toBe(true) expect(inject('globalSetupOverriden')).toBe(true) + expect(inject('projectConfigValue')).toBe(true) + expect(inject('globalConfigValue')).toBe(true) expect(inject('invalidValue')).toBe(undefined) }) diff --git a/test/workspaces/space_3/vitest.config.ts b/test/workspaces/space_3/vitest.config.ts index 956f9e5c8c84..0d32cd5002de 100644 --- a/test/workspaces/space_3/vitest.config.ts +++ b/test/workspaces/space_3/vitest.config.ts @@ -5,5 +5,8 @@ export default defineProject({ include: ['**/*.space-3-test.ts'], environment: 'node', globalSetup: './localSetup.ts', + provide: { + projectConfigValue: true, + }, }, }) diff --git a/test/workspaces/vitest.config.ts b/test/workspaces/vitest.config.ts index ae8998934730..d6bbb3a1a486 100644 --- a/test/workspaces/vitest.config.ts +++ b/test/workspaces/vitest.config.ts @@ -16,5 +16,8 @@ export default defineConfig({ CONFIG_VAR: 'root', CONFIG_OVERRIDE: 'root', }, + provide: { + globalConfigValue: true, + }, }, })