Accessing meta from Vitest state after tests finish
After tests finish running, meta information can be accessed from Vitest state by creating a Vitest instance and calling start(). The returned testModules array contains TestModule objects with meta properties accessible via `testModule.meta()` and child meta via `testModule.children.at(0).meta()`.
VitestPluginContext properties
VitestPluginContext provides three main properties: (1) project - the current test project the plugin belongs to; (2) vitest - the global Vitest instance with a config property that can be mutated directly; (3) injectTestProjects - a method to inject test projects.
defineCacheKeyGenerator method signature
The defineCacheKeyGenerator method has the signature: function defineCacheKeyGenerator(callback: (context: CacheKeyIdGeneratorContext) => string | undefined | null | false): void. The callback receives a CacheKeyIdGeneratorContext with environment, id, and sourceCode properties, and should return a string for cache key generation, or undefined, null, or false if the module should not be cached.
injectTestProjects method signature
The injectTestProjects method has the signature: function injectTestProjects(config: TestProjectConfiguration | TestProjectConfiguration[]): Promise<TestProject[]>. It accepts a config glob pattern, filepath, or inline configuration, and returns a promise resolving to an array of resolved test projects.
defineCacheKeyGenerator usage conditions
defineCacheKeyGenerator is called only if fsModuleCache is enabled. It should be used when a plugin can be registered with different options that affect the transform result, ensuring Vitest generates the correct hash.
Plugin typing for both Vite and Vitest
When writing a plugin for both Vite and Vitest, use the Plugin type from the vite entrypoint and add a reference to vitest/config (/// <reference types="vitest/config" />) to ensure configureVitest is augmented correctly.
configureVitest plugin hook
Vitest supports a configureVitest plugin hook since version 3.1.0. This is a Vite plugin hook that accepts a VitestPluginContext parameter. It runs early in the Vitest lifecycle, allowing changes to configuration like coverage and reporters, and can manipulate the global config from a test project.
defineCacheKeyGenerator example
Example: If a plugin uses options like replacePropertyKey and replacePropertyValue in its transform method, the defineCacheKeyGenerator callback should return these options concatenated as a unique string to ensure correct cache hashing. If false is returned, the module will not be cached on the file system.
Config mutation restrictions in configureVitest
In configureVitest, you can mutate vitest.config directly for properties like coverage.enabled and reporters. However, modifying vitest.reporters will have no effect because reporters are not created yet and this will be overwritten. Modify the config instead if you need to inject your own reporter.
CacheKeyIdGeneratorContext interface
CacheKeyIdGeneratorContext contains three properties: environment (DevEnvironment), id (string), and sourceCode (string). This context is passed to the defineCacheKeyGenerator callback.
injectTestProjects filtering behavior
Vitest filters projects during config resolution, so if the user defined a filter, an injected project might not be resolved unless it matches the filter. The filter can be updated via vitest.config.project option to include the test project, affecting only projects injected with injectTestProjects.
project.browser field timing in configureVitest
If relying on a browser feature within configureVitest, the project.browser field is not set yet. Use reporter.onBrowserInit event instead for browser-specific logic.
injectTestProjects inheritance and naming
When using injectTestProjects, you can inherit the current project config by setting the extends property to reference the config file via project.vite.config.configFile. The name property is never inherited because Vitest does not allow multiple projects with the same name; each project must have a unique name. All used names are available in the vitest.projects array.
Vite type exports from vitest/node
Vitest re-exports all Vite type-only imports via a Vite namespace from vitest/node, allowing plugin developers to keep versions in sync. This can be imported as: import type { Vite, VitestPluginContext } from 'vitest/node'.
Config resolution state in configureVitest
Vitest has already resolved the config when configureVitest runs, so some types might differ from user configuration. Properties like setupFile are not resolved again, so if adding new files, make sure to resolve them first.
ModuleRunner injection for file importing
Vitest injects an instance of ModuleRunner from 'vite/module-runner' as the moduleRunner property on the runner class. The ModuleRunner exposes an import(filepath: string) method used to import test files in a Vite-friendly environment by resolving imports and transforming file content at runtime so Node can understand it.
VitestRunner interface - file lifecycle and context
VitestRunner provides onBeforeRunFiles(files: File[]) called before running all tests in collected paths; onAfterRunFiles(files: File[]) called right after; extendTaskContext(context: TestContext): TestContext called when new context for a test is defined to add custom properties.
Task suite property traversal
Every task has a suite property that references the suite it is located in. Top-level test or describe are not equal to file. File never has a suite property. The suite property is useful to traverse tasks from the bottom up.
TaskResult interface - retries and repeats
TaskResult has retryCount?: number the amount of times the task was retried (only if failed and retry option set); repeatCount?: number the amount of times the task was repeated (only if repeats option set, includes retryCount).
TaskResult interface - memory and hooks
TaskResult has heap?: number heap size in bytes after task finished (only if logHeapUsage option set and process.memoryUsage defined); hooks?: Partial<Record<'afterAll' | 'beforeAll' | 'beforeEach' | 'afterEach', TaskState>> state of hooks related to this task useful during reporting.
Task function handler requirement
If you don't have a custom runner or didn't define runTask method, Vitest will try to retrieve a task automatically. If you didn't add a function with setFn, it will fail.
Test task interface
Test<ExtraContext = object> extends TaskBase with properties: type: 'test'; context: TestContext & ExtraContext test context passed to the test function; file: File the root task of the file; pending?: boolean whether the task was skipped by calling context.skip(); fails?: boolean whether the task should succeed if it fails; promises?: Promise<any>[] to store promises from async expects to wait for before finishing the test.
Suite task interface
Suite extends TaskBase with properties: type: 'suite'; file: File the root task of the file; tasks: Task[] an array of tasks that are part of the suite.
createTaskCollector for custom test methods
Vitest exposes createTaskCollector utility to create custom test methods. It behaves the same as a test but calls a custom method during collection phase. The function receives name: string, fn: function, and timeout parameters. Use getCurrentSuite().task() to add the task to the current suite with meta properties and handler.
Task result availability in suites and tests
Suites can only have a result field if an error thrown within a suite callback or beforeAll/afterAll callbacks prevents them from collecting tests. Tests always have a result field after their callbacks are called. If an error was thrown in beforeEach or afterEach callbacks, the error will be present in task.result.errors.
Extending runner from TestRunner for features
If you want to use snapshot support and other features, extend your custom runner from TestRunner imported from 'vitest'. TestRunner also exposes NodeBenchmarkRunner if you want to extend benchmark functionality.
File task interface
File extends Suite with properties: pool?: string (default 'forks') indicating the name of the pool the file belongs to; filepath: string the path to the file in UNIX format; projectName: string | undefined the name of the test project the file belongs to; collectDuration?: number the time in milliseconds to collect all tests in the file including importing dependencies; setupDuration?: number the time in milliseconds to import the setup file.
Custom runner class constructor
When initiating a VitestRunner class, Vitest passes down SerializedConfig which the runner should expose as a config property in the constructor. The runner class is instantiated by passing config: SerializedConfig as the constructor argument.
VitestRunner interface - properties
VitestRunner must expose config: SerializedConfig as a publicly available configuration property. It optionally defines pool?: string indicating the name of the current pool, which can affect how stack trace is inferred on the server side.
VitestRunner interface - task updates and imports
VitestRunner defines onTaskUpdate(task: [string, TaskResult | undefined, TaskMeta | undefined][]): Promise<void> called when a task is updated in the same thread as tests; importFile(filepath: string, source: VitestRunnerImportSource) called when certain files are imported during collection or setup; injectValue(key: string) called when runner attempts to get value when test.extend is used with { injected: true }.
VitestRunner interface - custom test and suite handling
VitestRunner optionally defines runSuite(suite: Suite): Promise<void> to handle suite execution instead of usual Vitest suite partition, and runTask(test: TaskPopulated): Promise<void> to handle test execution with custom test functions. Both preserve before and after hooks.
VitestRunner interface - task execution hooks
VitestRunner provides task execution hooks: onBeforeRunTask(test: Test) called before running a single test without result; onBeforeTryTask(test: Test, options: { retry: number; repeats: number }) called before running the test function with result and state; onAfterRunTask(test: Test) called after result and state are set; onAfterTryTask(test: Test, options: { retry: number; repeats: number }) called right after running test function without new state; onAfterRetryTask(test: Test, options: { retry: number; repeats: number }) called after retry resolution with new state.
TaskResult interface - state and errors
TaskResult has state: TaskState indicating task outcome (pass or fail, inheriting task.mode during collection); errors?: TestError[] errors that occurred during execution (multiple possible with expect.soft()); duration?: number milliseconds the task took to run; startTime?: number milliseconds when task started.
VitestRunner interface - lifecycle hooks
VitestRunner is a class interface for custom test runners. The runner receives test collection and execution lifecycle callbacks: onBeforeCollect(paths: string[]) called before collecting tests; onCollected(files: File[]) called after collection; onCancel(reason: CancelReason) called when runner should cancel next test runs.
Custom test method with createTaskCollector example
Example custom task created with createTaskCollector:
export const myCustomTask = TestRunner.createTaskCollector(
function (name, fn, timeout) {
TestRunner.getCurrentSuite().task(name, {
...this, // preserves 'todo'/'skip'/...
meta: {
customPropertyToDifferentiateTask: true
},
handler: fn,
timeout,
})
}
)
This creates a task method that can be used like myCustomTask('name', () => {}) and supports modifiers like myCustomTask.todo().
VitestRunner interface - suite hooks
VitestRunner provides suite hooks: onBeforeRunSuite(suite: Suite) called before running a single suite without result; onAfterRunSuite(suite: Suite) called after running a single suite with state and result.
TestSpecification moduleId property format
The moduleId property contains the ID of the module in Vite's module graph, usually an absolute file path using posix separator. Correct formats: 'C:/Users/Documents/project/example.test.ts' or '/Users/mac/project/example.test.ts'. Incorrect format: 'C:\\Users\\Documents\\project\\example.test.ts' with backslashes.
createSpecification expects resolved module identifier
The createSpecification method expects a resolved module identifier. It does not auto-resolve the file or check that it exists on the file system.
TestSpecification taskId property
The taskId property contains the test module's identifier.
createSpecification method basic example
Example of creating a TestSpecification: const specification = project.createSpecification(resolve('./example.test.ts'), {testLines: [20, 40], testNamePattern: /hello world/, testIds: ['1223128da3_0_0_0', '1223128da3_0_0'], testTagsFilter: ['frontend and backend']});
TestSpecification pool property
The pool property contains the pool configuration in which the test module will run. It is possible to have multiple pools in a single test project when typecheck.enabled is set. This means it is possible to have several specifications with the same moduleId but different pool values.
TestSpecification testNamePattern property
The testNamePattern property is a regexp that matches the name of the test in the module. This value will override the global testNamePattern option if it is set. Available since version 4.1.0.
TestSpecification testModule property
The testModule property is an instance of TestModule associated with the specification. If the test was not queued yet, this property will be undefined.
TestSpecification toJSON method
The toJSON method is a function with signature: function toJSON(): SerializedTestSpecification. It generates a JSON-friendly object that can be consumed by the Browser Mode or Vitest UI.
TestSpecification testTagsFilter property
The testTagsFilter property contains the tags filter that a test must pass in order to be included in the run. Multiple filters are treated as AND. Available since version 4.1.0.
TestSpecification project property
The project property references the TestProject that the test module belongs to.
TestSpecification testLines property
The testLines property is an array of line numbers in the source code where test files are defined. This field is only defined if the createSpecification method received an array. If there is no test on at least one of the lines specified, the whole suite will fail.
TestSpecification class purpose
The TestSpecification class describes what module to run as a test and its parameters. It is created by calling the createSpecification method on a test project.
TestSpecification testIds property
The testIds property contains the ids of tasks inside of this specification to run. Available since version 4.1.0.
assertType requires --typecheck flag
To enable typechecking with assertType, the --typecheck flag must be passed when running tests. Without this flag, type assertions will not be checked.
assertType example with function overloads
Example showing assertType with function overloads:
import { assertType } from 'vitest'
function concat(a: string, b: string): string
function concat(a: number, b: number): number
function concat(a: string | number, b: string | number): string | number
assertType<string>(concat('a', 'b'))
assertType<number>(concat(1, 2))
// @ts-expect-error wrong types
assertType(concat('a', 2))
This example demonstrates asserting the return types of overloaded functions. The third assertion is marked with @ts-expect-error to indicate that mixing string and number arguments should produce a type error.
assertType signature and purpose
assertType is a function with type signature <T>(value: T): void. It asserts that an argument's type is equal to the generic type parameter provided. The function does nothing at runtime and requires the --typecheck flag to be passed to enable typechecking during test execution.
assertType as alternative to expectTypeOf
assertType can be used as an alternative to expectTypeOf for type assertions. Both serve the purpose of checking that a value matches an expected type at compile time.
vitest.state is experimental and stores test information
The state property is experimental (except vitest.state.getReportedEntity). Public state may have breaking changes that don't follow SemVer, so pin Vitest's version when using it. Global state stores information about current tests using internal serializable Task API by default. The Reported Tasks API is recommended by calling state.getReportedEntity() instead of accessing state.idMap directly.
vitest.snapshot is the global snapshot manager
The snapshot property is the global snapshot manager. Vitest keeps track of all snapshots using the snapshot.add method. You can get the latest summary of snapshots via the vitest.snapshot.summary property.
vitest.vite is a global ViteDevServer instance
The vite property is a global ViteDevServer instance.
vitest.cache stores test results and file stats
The cache property is a cache manager that stores information about latest test results and test file stats. In Vitest itself this is only used by the default sequencer to sort tests.
vitest.mode is always 'test' since Vitest 5
The mode property is deprecated. Since Vitest 5, this property is always 'test'.
vitest.config returns root config
The config property returns the root (or global) config. If projects are defined, they will reference this as globalConfig. This is Vitest config and does not extend Vite config; it only has resolved values from the test property.
vitest.watcher tracks file changes and reruns tests
The watcher property (available since Vitest 4.0.0) is an instance of a Vitest watcher with useful methods to track file changes and rerun tests. You can use onFileChange, onFileDelete or onFileCreate with your own watcher if the built-in watcher is disabled.