# Vitest > This guide lists advanced APIs to run tests via a Node.js script. If you just want to [run tests](/guide/), you probably don't need this. It is primarily used by library authors. --- # Source: https://vitest.dev/guide/advanced.md --- url: /guide/advanced.md --- # Getting Started advanced {#getting-started} ::: warning This guide lists advanced APIs to run tests via a Node.js script. If you just want to [run tests](/guide/), you probably don't need this. It is primarily used by library authors. ::: You can import any method from the `vitest/node` entry-point. ## startVitest ```ts function startVitest( mode: VitestRunMode, cliFilters: string[] = [], options: CliOptions = {}, viteOverrides?: ViteUserConfig, vitestOptions?: VitestOptions, ): Promise ``` You can start running Vitest tests using its Node API: ```js import { startVitest } from 'vitest/node' const vitest = await startVitest('test') await vitest.close() ``` `startVitest` function returns [`Vitest`](/api/advanced/vitest) instance if tests can be started. If watch mode is not enabled, Vitest will call `close` method automatically. If watch mode is enabled and the terminal supports TTY, Vitest will register console shortcuts. You can pass down a list of filters as a second argument. Vitest will run only tests that contain at least one of the passed-down strings in their file path. Additionally, you can use the third argument to pass in CLI arguments, which will override any test config options. Alternatively, you can pass in the complete Vite config as the fourth argument, which will take precedence over any other user-defined options. After running the tests, you can get the results from the [`state.getTestModules`](/api/advanced/test-module) API: ```ts import type { TestModule } from 'vitest/node' const vitest = await startVitest('test') console.log(vitest.state.getTestModules()) // [TestModule] ``` ::: tip The ["Running Tests"](/guide/advanced/tests#startvitest) guide has a usage example. ::: ## createVitest ```ts function createVitest( mode: VitestRunMode, options: CliOptions, viteOverrides: ViteUserConfig = {}, vitestOptions: VitestOptions = {}, ): Promise ``` You can create Vitest instance by using `createVitest` function. It returns the same [`Vitest`](/api/advanced/vitest) instance as `startVitest`, but it doesn't start tests and doesn't validate installed packages. ```js import { createVitest } from 'vitest/node' const vitest = await createVitest('test', { watch: false, }) ``` ::: tip The ["Running Tests"](/guide/advanced/tests#createvitest) guide has a usage example. ::: ## resolveConfig ```ts function resolveConfig( options: UserConfig = {}, viteOverrides: ViteUserConfig = {}, ): Promise<{ vitestConfig: ResolvedConfig viteConfig: ResolvedViteConfig }> ``` This method resolves the config with custom parameters. If no parameters are given, the `root` will be `process.cwd()`. ```ts import { resolveConfig } from 'vitest/node' // vitestConfig only has resolved "test" properties const { vitestConfig, viteConfig } = await resolveConfig({ mode: 'custom', configFile: false, resolve: { conditions: ['custom'] }, test: { setupFiles: ['/my-setup-file.js'], pool: 'threads', }, }) ``` ::: info Due to how Vite's `createServer` works, Vitest has to resolve the config during the plugin's `configResolve` hook. Therefore, this method is not actually used internally and is exposed exclusively as a public API. If you pass down the config to the `startVitest` or `createVitest` APIs, Vitest will still resolve the config again. ::: ::: warning The `resolveConfig` doesn't resolve `projects`. To resolve projects configs, Vitest needs an established Vite server. Also note that `viteConfig.test` will not be fully resolved. If you need Vitest config, use `vitestConfig` instead. ::: ## parseCLI ```ts function parseCLI(argv: string | string[], config: CliParseOptions = {}): { filter: string[] options: CliOptions } ``` You can use this method to parse CLI arguments. It accepts a string (where arguments are split by a single space) or a strings array of CLI arguments in the same format that Vitest CLI uses. It returns a filter and `options` that you can later pass down to `createVitest` or `startVitest` methods. ```ts import { parseCLI } from 'vitest/node' const result = parseCLI('vitest ./files.ts --coverage --browser=chrome') result.options // { // coverage: { enabled: true }, // browser: { name: 'chrome', enabled: true } // } result.filter // ['./files.ts'] ``` --- # Source: https://vitest.dev/config/alias.md --- url: /config/alias.md --- # alias * **Type:** `Record | Array<{ find: string | RegExp, replacement: string, customResolver?: ResolverFunction | ResolverObject }>` Define custom aliases when running inside tests. They will be merged with aliases from `resolve.alias`. ::: warning Vitest uses Vite SSR primitives to run tests which has [certain pitfalls](https://vitejs.dev/guide/ssr.html#ssr-externals). 1. Aliases affect only modules imported directly with an `import` keyword by an [inlined](#server-deps-inline) module (all source code is inlined by default). 2. Vitest does not support aliasing `require` calls. 3. If you are aliasing an external dependency (e.g., `react` -> `preact`), you may want to alias the actual `node_modules` packages instead to make it work for externalized dependencies. Both [Yarn](https://classic.yarnpkg.com/en/docs/cli/add/#toc-yarn-add-alias) and [pnpm](https://pnpm.io/aliases/) support aliasing via the `npm:` prefix. ::: --- # Source: https://vitest.dev/config/allowonly.md --- url: /config/allowonly.md --- # allowOnly * **Type**: `boolean` * **Default**: `!process.env.CI` * **CLI:** `--allowOnly`, `--allowOnly=false` By default, Vitest does not permit tests marked with the [`only`](/api/#test-only) flag in Continuous Integration (CI) environments. Conversely, in local development environments, Vitest allows these tests to run. ::: info Vitest uses [`std-env`](https://www.npmjs.com/package/std-env) package to detect the environment. ::: You can customize this behavior by explicitly setting the `allowOnly` option to either `true` or `false`. ::: code-group ```js [vitest.config.js] import { defineConfig } from 'vitest/config' export default defineConfig({ test: { allowOnly: true, }, }) ``` ```bash [CLI] vitest --allowOnly ``` ::: When enabled, Vitest will not fail the test suite if tests marked with [`only`](/api/#test-only) are detected, including in CI environments. When disabled, Vitest will fail the test suite if tests marked with [`only`](/api/#test-only) are detected, including in local development environments. --- # Source: https://vitest.dev/api.md # Source: https://vitest.dev/config/browser/api.md # Source: https://vitest.dev/config/api.md --- url: /config/api.md --- # api * **Type:** `boolean | number` * **Default:** `false` * **CLI:** `--api`, `--api.port`, `--api.host`, `--api.strictPort` Listen to port and serve API for [the UI](/guide/ui) or [browser server](/guide/browser/). When set to `true`, the default port is `51204`. --- # Source: https://vitest.dev/api/advanced/artifacts.md --- url: /api/advanced/artifacts.md --- # Test Artifacts 4.0.11 ::: warning This is an advanced API. As a user, you most likely want to use [test annotations](/guide/test-annotations) to add notes or context to your tests instead. This is primarily used internally and by library authors. ::: Test artifacts allow attaching or recording structured data, files, or metadata during test execution. This is a low-level feature primarily designed for: * Internal use ([`annotate`](/guide/test-annotations) is built on top of the artifact system) * Framework authors creating custom testing tools on top of Vitest Each artifact includes: * A type discriminator which is a unique identifier for the artifact type * Custom data, can be any relevant information * Optional attachments, either files or inline content associated with the artifact * A source code location indicating where the artifact was created Vitest automatically manages attachment serialization (files are copied to [`attachmentsDir`](/config/#attachmentsdir)) and injects source location metadata, so you can focus on the data you want to record. All artifacts **must** extend from [`TestArtifactBase`](#testartifactbase) and all attachments from [`TestAttachment`](#testattachment) to be correctly handled internally. ## API ### `recordArtifact` {#recordartifact} ::: warning `recordArtifact` is an experimental API. Breaking changes might not follow SemVer, please pin Vitest's version when using it. The API surface may change based on feedback. We encourage you to try it out and share your experience with the team. ::: ```ts function recordArtifact(task: Test, artifact: Artifact): Promise ``` The `recordArtifact` function records an artifact during test execution and returns it. It expects a [task](/api/advanced/runner#tasks) as the first parameter and an object assignable to [`TestArtifact`](#testartifact) as the second. This function has to be used within a test, and the test has to still be running. Recording after test completion will throw an error. When an artifact is recorded on a test, it emits an `onTestArtifactRecord` runner event and a [`onTestCaseArtifactRecord` reporter event](/api/advanced/reporters#ontestcaseartifactrecord). To retrieve recorded artifacts from a test case, use the [`artifacts()`](/api/advanced/test-case#artifacts) method. Note: annotations, [even though they're built on top of this feature](#relationship-with-annotations), won't appear in the `task.artifacts` array for backwards compatibility reasons until the next major version. ### `TestArtifact` The `TestArtifact` type is a union containing all artifacts Vitest can produce, including custom ones. All artifacts extend from [`TestArtifactBase`](#testartifactbase) ### `TestArtifactBase` {#testartifactbase} ```ts export interface TestArtifactBase { /** File or data attachments associated with this artifact */ attachments?: TestAttachment[] /** Source location where this artifact was created */ location?: TestArtifactLocation } ``` The `TestArtifactBase` interface is the base for all test artifacts. Extend this interface when creating custom test artifacts. Vitest automatically manages the `attachments` array and injects the `location` property to indicate where the artifact was created in your test code. ### `TestAttachment` ```ts export interface TestAttachment { /** MIME type of the attachment (e.g., 'image/png', 'text/plain') */ contentType?: string /** File system path to the attachment */ path?: string /** Inline attachment content as a string or raw binary data */ body?: string | Uint8Array } ``` The `TestAttachment` interface represents a file or data attachment associated with a test artifact. Attachments can be either file-based (via `path`) or inline content (via `body`). The `contentType` helps consumers understand how to interpret the attachment data. ### `TestArtifactLocation` ```ts export interface TestArtifactLocation { /** Line number in the source file (1-indexed) */ line: number /** Column number in the line (1-indexed) */ column: number /** Path to the source file */ file: string } ``` The `TestArtifactLocation` interface represents the source code location information for a test artifact. It indicates where in the source code the artifact originated from. ### `TestArtifactRegistry` The `TestArtifactRegistry` interface is a registry for custom test artifact types. Augmenting this interface using [TypeScript's module augmentation feature](https://typescriptlang.org/docs/handbook/declaration-merging#module-augmentation) allows registering custom artifact types that tests can produce. Each custom artifact should extend [`TestArtifactBase`](#testartifactbase) and include a unique `type` discriminator property. Here are a few guidelines or best practices to follow: * Try using a `Symbol` as the **registry key** to guarantee uniqueness * The `type` property should follow the pattern `'package-name:artifact-name'`, **`'internal:'` is a reserved prefix** * Use `attachments` to include files or data; extend [`TestAttachment`](#testattachment) for custom metadata * `location` property is automatically injected ## Custom Artifacts To use and manage artifacts in a type-safe manner, you need to create its type and register it: ```ts import type { TestArtifactBase, TestAttachment } from 'vitest' interface A11yReportAttachment extends TestAttachment { contentType: 'text/html' path: string } interface AccessibilityArtifact extends TestArtifactBase { type: 'a11y:report' passed: boolean wcagLevel: 'A' | 'AA' | 'AAA' attachments: [A11yReportAttachment] } const a11yReportKey = Symbol('report') declare module 'vitest' { interface TestArtifactRegistry { [a11yReportKey]: AccessibilityArtifact } } ``` As long as the types are assignable to their bases and don't have errors, everything should work fine and you should be able to record artifacts using [`recordArtifact`](#recordartifact): ```ts async function toBeAccessible( this: MatcherState, actual: Element, wcagLevel: 'A' | 'AA' | 'AAA' = 'AA' ): AsyncExpectationResult { const report = await runAccessibilityAudit(actual, wcagLevel) await recordArtifact(this.task, { type: 'a11y:report', passed: report.violations.length === 0, wcagLevel, attachments: [{ contentType: 'text/html', path: report.path, }], }) return { pass: violations.length === 0, message: () => `Found ${report.violations.length} accessibility violation(s)` } } ``` ## Relationship with Annotations Test annotations are built on top of the artifact system. When using annotations in tests, they create `internal:annotation` artifacts under the hood. However, annotations are: * Simpler to use * Designed for end-users, not developers Use annotations if you just want to add notes to your tests. Use artifacts if you need custom data. --- # Source: https://vitest.dev/api/assert-type.md --- url: /api/assert-type.md --- # assertType ::: warning During runtime this function doesn't do anything. To [enable typechecking](/guide/testing-types#run-typechecking), don't forget to pass down `--typecheck` flag. ::: * **Type:** `(value: T): void` You can use this function as an alternative for [`expectTypeOf`](/api/expect-typeof) to easily assert that the argument type is equal to the generic provided. ```ts 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(concat('a', 'b')) assertType(concat(1, 2)) // @ts-expect-error wrong types assertType(concat('a', 2)) ``` --- # Source: https://vitest.dev/api/assert.md --- url: /api/assert.md --- # assert Vitest reexports the `assert` method from [`chai`](https://www.chaijs.com/api/assert/) for verifying invariants. ## assert * **Type:** `(expression: any, message?: string) => asserts expression` Assert that the given `expression` is truthy, otherwise the assertion fails. ```ts import { assert, test } from 'vitest' test('assert', () => { assert('foo' !== 'bar', 'foo should not be equal to bar') }) ``` ## fail * **Type:** * `(message?: string) => never` * `(actual: T, expected: T, message?: string, operator?: string) => never` Force an assertion failure. ```ts import { assert, test } from 'vitest' test('assert.fail', () => { assert.fail('error message on failure') assert.fail('foo', 'bar', 'foo is not bar', '===') }) ``` ## isOk * **Type:** `(value: T, message?: string) => asserts value` * **Alias** `ok` Assert that the given `value` is truthy. ```ts import { assert, test } from 'vitest' test('assert.isOk', () => { assert.isOk('foo', 'every truthy is ok') assert.isOk(false, 'this will fail since false is not truthy') }) ``` ## isNotOk * **Type:** `(value: T, message?: string) => void` * **Alias** `notOk` Assert that the given `value` is falsy. ```ts import { assert, test } from 'vitest' test('assert.isNotOk', () => { assert.isNotOk('foo', 'this will fail, every truthy is not ok') assert.isNotOk(false, 'this will pass since false is falsy') }) ``` ## equal * **Type:** `(actual: T, expected: T, message?: string) => void` Asserts non-strict equality (==) of `actual` and `expected`. ```ts import { assert, test } from 'vitest' test('assert.equal', () => { assert.equal(Math.sqrt(4), '2') }) ``` ## notEqual * **Type:** `(actual: T, expected: T, message?: string) => void` Asserts non-strict inequality (!=) of `actual` and `expected`. ```ts import { assert, test } from 'vitest' test('assert.equal', () => { assert.notEqual(Math.sqrt(4), 3) }) ``` ## strictEqual * **Type:** `(actual: T, expected: T, message?: string) => void` Asserts strict equality (===) of `actual` and `expected`. ```ts import { assert, test } from 'vitest' test('assert.strictEqual', () => { assert.strictEqual(Math.sqrt(4), 2) }) ``` ## deepEqual * **Type:** `(actual: T, expected: T, message?: string) => void` Asserts that `actual` is deeply equal to `expected`. ```ts import { assert, test } from 'vitest' test('assert.deepEqual', () => { assert.deepEqual({ color: 'green' }, { color: 'green' }) }) ``` ## notDeepEqual * **Type:** `(actual: T, expected: T, message?: string) => void` Assert that `actual` is not deeply equal to `expected`. ```ts import { assert, test } from 'vitest' test('assert.notDeepEqual', () => { assert.notDeepEqual({ color: 'green' }, { color: 'red' }) }) ``` ## isAbove * **Type:** `(valueToCheck: number, valueToBeAbove: number, message?: string) => void` Assert that `valueToCheck` is strictly greater than (>) `valueToBeAbove`. ```ts import { assert, test } from 'vitest' test('assert.isAbove', () => { assert.isAbove(5, 2, '5 is strictly greater than 2') }) ``` ## isAtLeast * **Type:** `(valueToCheck: number, valueToBeAtLeast: number, message?: string) => void` Assert that `valueToCheck` is greater than or equal to (>=) `valueToBeAtLeast`. ```ts import { assert, test } from 'vitest' test('assert.isAtLeast', () => { assert.isAtLeast(5, 2, '5 is greater or equal to 2') assert.isAtLeast(3, 3, '3 is greater or equal to 3') }) ``` ## isBelow * **Type:** `(valueToCheck: number, valueToBeBelow: number, message?: string) => void` Asserts `valueToCheck` is strictly less than (<) `valueToBeBelow`. ```ts import { assert, test } from 'vitest' test('assert.isBelow', () => { assert.isBelow(3, 6, '3 is strictly less than 6') }) ``` ## isAtMost * **Type:** `(valueToCheck: number, valueToBeAtMost: number, message?: string) => void` Asserts `valueToCheck` is less than or equal to (<=) `valueToBeAtMost`. ```ts import { assert, test } from 'vitest' test('assert.isAtMost', () => { assert.isAtMost(3, 6, '3 is less than or equal to 6') assert.isAtMost(4, 4, '4 is less than or equal to 4') }) ``` ## isTrue * **Type:** `(value: T, message?: string) => asserts value is true` Asserts that `value` is true. ```ts import { assert, test } from 'vitest' const testPassed = true test('assert.isTrue', () => { assert.isTrue(testPassed) }) ``` ## isNotTrue * **Type:** `(value: T, message?: string) => asserts value is Exclude` Asserts that `value` is not true. ```ts import { assert, test } from 'vitest' const testPassed = 'ok' test('assert.isNotTrue', () => { assert.isNotTrue(testPassed) }) ``` ## isFalse * **Type:** `(value: T, message?: string) => asserts value is false` Asserts that `value` is false. ```ts import { assert, test } from 'vitest' const testPassed = false test('assert.isFalse', () => { assert.isFalse(testPassed) }) ``` ## isNotFalse * **Type:** `(value: T, message?: string) => asserts value is Exclude` Asserts that `value` is not false. ```ts import { assert, test } from 'vitest' const testPassed = 'no' test('assert.isNotFalse', () => { assert.isNotFalse(testPassed) }) ``` ## isNull * **Type:** `(value: T, message?: string) => asserts value is null` Asserts that `value` is null. ```ts import { assert, test } from 'vitest' const error = null test('assert.isNull', () => { assert.isNull(error, 'error is null') }) ``` ## isNotNull * **Type:** `(value: T, message?: string) => asserts value is Exclude` Asserts that `value` is not null. ```ts import { assert, test } from 'vitest' const error = { message: 'error was occurred' } test('assert.isNotNull', () => { assert.isNotNull(error, 'error is not null but object') }) ``` ## isNaN * **Type:** `(value: T, message?: string) => void` Asserts that `value` is NaN. ```ts import { assert, test } from 'vitest' const calculation = 1 * 'vitest' test('assert.isNaN', () => { assert.isNaN(calculation, '1 * "vitest" is NaN') }) ``` ## isNotNaN * **Type:** `(value: T, message?: string) => void` Asserts that `value` is not NaN. ```ts import { assert, test } from 'vitest' const calculation = 1 * 2 test('assert.isNotNaN', () => { assert.isNotNaN(calculation, '1 * 2 is Not NaN but 2') }) ``` ## exists * **Type:** `(value: T, message?: string) => asserts value is NonNullable` Asserts that `value` is neither null nor undefined. ```ts import { assert, test } from 'vitest' const name = 'foo' test('assert.exists', () => { assert.exists(name, 'foo is neither null nor undefined') }) ``` ## notExists * **Type:** `(value: T, message?: string) => asserts value is null | undefined` Asserts that `value` is either null nor undefined. ```ts import { assert, test } from 'vitest' const foo = null const bar = undefined test('assert.notExists', () => { assert.notExists(foo, 'foo is null so not exist') assert.notExists(bar, 'bar is undefined so not exist') }) ``` ## isUndefined * **Type:** `(value: T, message?: string) => asserts value is undefined` Asserts that `value` is undefined. ```ts import { assert, test } from 'vitest' const name = undefined test('assert.isUndefined', () => { assert.isUndefined(name, 'name is undefined') }) ``` ## isDefined * **Type:** `(value: T, message?: string) => asserts value is Exclude` Asserts that `value` is not undefined. ```ts import { assert, test } from 'vitest' const name = 'foo' test('assert.isDefined', () => { assert.isDefined(name, 'name is not undefined') }) ``` ## isFunction * **Type:** `(value: T, message?: string) => void` * **Alias:** `isCallable` Asserts that `value` is a function. ```ts import { assert, test } from 'vitest' function name() { return 'foo' }; test('assert.isFunction', () => { assert.isFunction(name, 'name is function') }) ``` ## isNotFunction * **Type:** `(value: T, message?: string) => void` * **Alias:** `isNotCallable` Asserts that `value` is not a function. ```ts import { assert, test } from 'vitest' const name = 'foo' test('assert.isNotFunction', () => { assert.isNotFunction(name, 'name is not function but string') }) ``` ## isObject * **Type:** `(value: T, message?: string) => void` Asserts that `value` is an object of type Object (as revealed by Object.prototype.toString). The assertion does not match subclassed objects. ```ts import { assert, test } from 'vitest' const someThing = { color: 'red', shape: 'circle' } test('assert.isObject', () => { assert.isObject(someThing, 'someThing is object') }) ``` ## isNotObject * **Type:** `(value: T, message?: string) => void` Asserts that `value` is not an object of type Object (as revealed by Object.prototype.toString). The assertion does not match subclassed objects. ```ts import { assert, test } from 'vitest' const someThing = 'redCircle' test('assert.isNotObject', () => { assert.isNotObject(someThing, 'someThing is not object but string') }) ``` ## isArray * **Type:** `(value: T, message?: string) => void` Asserts that `value` is an array. ```ts import { assert, test } from 'vitest' const color = ['red', 'green', 'yellow'] test('assert.isArray', () => { assert.isArray(color, 'color is array') }) ``` ## isNotArray * **Type:** `(value: T, message?: string) => void` Asserts that `value` is not an array. ```ts import { assert, test } from 'vitest' const color = 'red' test('assert.isNotArray', () => { assert.isNotArray(color, 'color is not array but string') }) ``` ## isString * **Type:** `(value: T, message?: string) => void` Asserts that `value` is a string. ```ts import { assert, test } from 'vitest' const color = 'red' test('assert.isString', () => { assert.isString(color, 'color is string') }) ``` ## isNotString * **Type:** `(value: T, message?: string) => void` Asserts that `value` is not a string. ```ts import { assert, test } from 'vitest' const color = ['red', 'green', 'yellow'] test('assert.isNotString', () => { assert.isNotString(color, 'color is not string but array') }) ``` ## isNumber * **Type:** `(value: T, message?: string) => void` Asserts that `value` is a number. ```ts import { assert, test } from 'vitest' const colors = 3 test('assert.isNumber', () => { assert.isNumber(colors, 'colors is number') }) ``` ## isNotNumber * **Type:** `(value: T, message?: string) => void` Asserts that `value` is not a number. ```ts import { assert, test } from 'vitest' const colors = '3 colors' test('assert.isNotNumber', () => { assert.isNotNumber(colors, 'colors is not number but strings') }) ``` ## isFinite * **Type:** `(value: T, message?: string) => void` Asserts that `value` is a finite number (not NaN, Infinity). ```ts import { assert, test } from 'vitest' const colors = 3 test('assert.isFinite', () => { assert.isFinite(colors, 'colors is number not NaN or Infinity') }) ``` ## isBoolean * **Type:** `(value: T, message?: string) => void` Asserts that `value` is a boolean. ```ts import { assert, test } from 'vitest' const isReady = true test('assert.isBoolean', () => { assert.isBoolean(isReady, 'isReady is a boolean') }) ``` ## isNotBoolean * **Type:** `(value: T, message?: string) => void` Asserts that `value` is not a boolean. ```ts import { assert, test } from 'vitest' const isReady = 'sure' test('assert.isBoolean', () => { assert.isBoolean(isReady, 'isReady is not a boolean but string') }) ``` ## typeOf * **Type:** `(value: T, name: string, message?: string) => void` Asserts that `value`’s type is `name`, as determined by Object.prototype.toString. ```ts import { assert, test } from 'vitest' test('assert.typeOf', () => { assert.typeOf({ color: 'red' }, 'object', 'we have an object') assert.typeOf(['red', 'green'], 'array', 'we have an array') assert.typeOf('red', 'string', 'we have a string') assert.typeOf(/red/, 'regexp', 'we have a regular expression') assert.typeOf(null, 'null', 'we have a null') assert.typeOf(undefined, 'undefined', 'we have an undefined') }) ``` ## notTypeOf * **Type:** `(value: T, name: string, message?: string) => void` Asserts that `value`’s type is not `name`, as determined by Object.prototype.toString. ```ts import { assert, test } from 'vitest' test('assert.notTypeOf', () => { assert.notTypeOf('red', 'number', '"red" is not a number') }) ``` ## instanceOf * **Type:** `(value: T, constructor: Function, message?: string) => asserts value is T` Asserts that `value` is an instance of `constructor`. ```ts import { assert, test } from 'vitest' function Person(name) { this.name = name } const foo = new Person('foo') class Tea { constructor(name) { this.name = name } } const coffee = new Tea('coffee') test('assert.instanceOf', () => { assert.instanceOf(foo, Person, 'foo is an instance of Person') assert.instanceOf(coffee, Tea, 'coffee is an instance of Tea') }) ``` ## notInstanceOf * **Type:** `(value: T, constructor: Function, message?: string) => asserts value is Exclude` Asserts that `value` is not an instance of `constructor`. ```ts import { assert, test } from 'vitest' function Person(name) { this.name = name } const foo = new Person('foo') class Tea { constructor(name) { this.name = name } } const coffee = new Tea('coffee') test('assert.instanceOf', () => { assert.instanceOf(foo, Tea, 'foo is not an instance of Tea') }) ``` ## include * **Type:** * `(haystack: string, needle: string, message?: string) => void` * `(haystack: readonly T[] | ReadonlySet | ReadonlyMap, needle: T, message?: string) => void` * `(haystack: WeakSet, needle: T, message?: string) => void` * `(haystack: T, needle: Partial, message?: string) => void` Asserts that `haystack` includes `needle`. Can be used to assert the inclusion of a value in an array, a substring in a string, or a subset of properties in an object. ```ts import { assert, test } from 'vitest' test('assert.include', () => { assert.include([1, 2, 3], 2, 'array contains value') assert.include('foobar', 'foo', 'string contains substring') assert.include({ foo: 'bar', hello: 'universe' }, { foo: 'bar' }, 'object contains property') }) ``` ## notInclude * **Type:** * `(haystack: string, needle: string, message?: string) => void` * `(haystack: readonly T[] | ReadonlySet | ReadonlyMap, needle: T, message?: string) => void` * `(haystack: WeakSet, needle: T, message?: string) => void` * `(haystack: T, needle: Partial, message?: string) => void` Asserts that `haystack` does not include `needle`. It can be used to assert the absence of a value in an array, a substring in a string, or a subset of properties in an object. ```ts import { assert, test } from 'vitest' test('assert.notInclude', () => { assert.notInclude([1, 2, 3], 4, 'array doesn\'t contain 4') assert.notInclude('foobar', 'baz', 'foobar doesn\'t contain baz') assert.notInclude({ foo: 'bar', hello: 'universe' }, { foo: 'baz' }, 'object doesn\'t contain property') }) ``` ## deepInclude * **Type:** * `(haystack: string, needle: string, message?: string) => void` * `(haystack: readonly T[] | ReadonlySet | ReadonlyMap, needle: T, message?: string) => void` * `(haystack: T, needle: T extends WeakSet ? never : Partial, message?: string) => void` Asserts that `haystack` includes `needle`. Can be used to assert the inclusion of a value in an array or a subset of properties in an object. Deep equality is used. ```ts import { assert, test } from 'vitest' const obj1 = { a: 1 } const obj2 = { b: 2 } test('assert.deepInclude', () => { assert.deepInclude([obj1, obj2], { a: 1 }) assert.deepInclude({ foo: obj1, bar: obj2 }, { foo: { a: 1 } }) }) ``` ## notDeepInclude * **Type:** * `(haystack: string, needle: string, message?: string) => void` * `(haystack: readonly T[] | ReadonlySet | ReadonlyMap, needle: T, message?: string) => void` * `(haystack: T, needle: T extends WeakSet ? never : Partial, message?: string) => void` Asserts that `haystack` does not include `needle`. It can be used to assert the absence of a value in an array or a subset of properties in an object. Deep equality is used. ```ts import { assert, test } from 'vitest' const obj1 = { a: 1 } const obj2 = { b: 2 } test('assert.notDeepInclude', () => { assert.notDeepInclude([obj1, obj2], { a: 10 }) assert.notDeepInclude({ foo: obj1, bar: obj2 }, { foo: { a: 10 } }) }) ``` ## nestedInclude * **Type:** `(haystack: any, needle: any, message?: string) => void` Asserts that `haystack` includes `needle`. Can be used to assert the inclusion of a subset of properties in an object. Enables the use of dot- and bracket-notation for referencing nested properties. ‘\[]’ and ‘.’ in property names can be escaped using double backslashes. ```ts import { assert, test } from 'vitest' test('assert.nestedInclude', () => { assert.nestedInclude({ '.a': { b: 'x' } }, { '\\.a.[b]': 'x' }) assert.nestedInclude({ a: { '[b]': 'x' } }, { 'a.\\[b\\]': 'x' }) }) ``` ## notNestedInclude * **Type:** `(haystack: any, needle: any, message?: string) => void` Asserts that `haystack` does not include `needle`. Can be used to assert the inclusion of a subset of properties in an object. Enables the use of dot- and bracket-notation for referencing nested properties. ‘\[]’ and ‘.’ in property names can be escaped using double backslashes. ```ts import { assert, test } from 'vitest' test('assert.nestedInclude', () => { assert.notNestedInclude({ '.a': { b: 'x' } }, { '\\.a.b': 'y' }) assert.notNestedInclude({ a: { '[b]': 'x' } }, { 'a.\\[b\\]': 'y' }) }) ``` ## deepNestedInclude * **Type:** `(haystack: any, needle: any, message?: string) => void` Asserts that `haystack` includes `needle`. Can be used to assert the inclusion of a subset of properties in an object while checking for deep equality. Enables the use of dot- and bracket-notation for referencing nested properties. ‘\[]’ and ‘.’ in property names can be escaped using double backslashes. ```ts import { assert, test } from 'vitest' test('assert.deepNestedInclude', () => { assert.deepNestedInclude({ a: { b: [{ x: 1 }] } }, { 'a.b[0]': { x: 1 } }) assert.deepNestedInclude({ '.a': { '[b]': { x: 1 } } }, { '\\.a.\\[b\\]': { x: 1 } }) }) ``` ## notDeepNestedInclude * **Type:** `(haystack: any, needle: any, message?: string) => void` Asserts that `haystack` not includes `needle`. Can be used to assert the absence of a subset of properties in an object while checking for deep equality. Enables the use of dot- and bracket-notation for referencing nested properties. ‘\[]’ and ‘.’ in property names can be escaped using double backslashes. ```ts import { assert, test } from 'vitest' test('assert.notDeepNestedInclude', () => { assert.notDeepNestedInclude({ a: { b: [{ x: 1 }] } }, { 'a.b[0]': { y: 1 } }) assert.notDeepNestedInclude({ '.a': { '[b]': { x: 1 } } }, { '\\.a.\\[b\\]': { y: 2 } }) }) ``` ## ownInclude * **Type:** `(haystack: any, needle: any, message?: string) => void` Asserts that `haystack` includes `needle`. Can be used to assert the inclusion of a subset of properties in an object while ignoring inherited properties. ```ts import { assert, test } from 'vitest' test('assert.ownInclude', () => { assert.ownInclude({ a: 1 }, { a: 1 }) }) ``` ## notOwnInclude * **Type:** `(haystack: any, needle: any, message?: string) => void` Asserts that `haystack` includes `needle`. Can be used to assert the absence of a subset of properties in an object while ignoring inherited properties. ```ts import { assert, test } from 'vitest' const obj1 = { b: 2 } const obj2 = object.create(obj1) obj2.a = 1 test('assert.notOwnInclude', () => { assert.notOwnInclude(obj2, { b: 2 }) }) ``` ## deepOwnInclude * **Type:** `(haystack: any, needle: any, message?: string) => void` Asserts that `haystack` includes `needle`. Can be used to assert the inclusion of a subset of properties in an object while ignoring inherited properties and checking for deep equality. ```ts import { assert, test } from 'vitest' test('assert.deepOwnInclude', () => { assert.deepOwnInclude({ a: { b: 2 } }, { a: { b: 2 } }) }) ``` ## notDeepOwnInclude * **Type:** `(haystack: any, needle: any, message?: string) => void` Asserts that `haystack` not includes `needle`. Can be used to assert the absence of a subset of properties in an object while ignoring inherited properties and checking for deep equality. ```ts import { assert, test } from 'vitest' test('assert.notDeepOwnInclude', () => { assert.notDeepOwnInclude({ a: { b: 2 } }, { a: { c: 3 } }) }) ``` ## match * **Type:** `(value: string, regexp: RegExp, message?: string) => void` Asserts that `value` matches the regular expression `regexp`. ```ts import { assert, test } from 'vitest' test('assert.match', () => { assert.match('foobar', /^foo/, 'regexp matches') }) ``` ## notMatch * **Type:** `(value: string, regexp: RegExp, message?: string) => void` Asserts that `value` does not matches the regular expression `regexp`. ```ts import { assert, test } from 'vitest' test('assert.notMatch', () => { assert.notMatch('foobar', /^foo/, 'regexp does not match') }) ``` ## property * **Type:** `(object: T, property: string, message?: string) => void` Asserts that `object` has a direct or inherited property named by `property` ```ts import { assert, test } from 'vitest' test('assert.property', () => { assert.property({ tea: { green: 'matcha' } }, 'tea') assert.property({ tea: { green: 'matcha' } }, 'toString') }) ``` ## notProperty * **Type:** `(object: T, property: string, message?: string) => void` Asserts that `object` does not have a direct or inherited property named by `property` ```ts import { assert, test } from 'vitest' test('assert.notProperty', () => { assert.notProperty({ tea: { green: 'matcha' } }, 'coffee') }) ``` ## propertyVal * **Type:** `(object: T, property: string, value: V, message?: string) => void` Asserts that `object` has a direct or inherited property named by `property` with a value given by `value`. Uses a strict equality check (===). ```ts import { assert, test } from 'vitest' test('assert.notPropertyVal', () => { assert.propertyVal({ tea: 'is good' }, 'tea', 'is good') }) ``` ## notPropertyVal * **Type:** `(object: T, property: string, value: V, message?: string) => void` Asserts that `object` does not have a direct or inherited property named by `property` with a value given by `value`. Uses a strict equality check (===). ```ts import { assert, test } from 'vitest' test('assert.notPropertyVal', () => { assert.notPropertyVal({ tea: 'is good' }, 'tea', 'is bad') assert.notPropertyVal({ tea: 'is good' }, 'coffee', 'is good') }) ``` ## deepPropertyVal * **Type:** `(object: T, property: string, value: V, message?: string) => void` Asserts that `object` has a direct or inherited property named by `property` with a value given by `value`. Uses a deep equality check. ```ts import { assert, test } from 'vitest' test('assert.deepPropertyVal', () => { assert.deepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'matcha' }) }) ``` ## notDeepPropertyVal * **Type:** `(object: T, property: string, value: V, message?: string) => void` Asserts that `object` does not have a direct or inherited property named by `property` with a value given by `value`. Uses a deep equality check. ```ts import { assert, test } from 'vitest' test('assert.deepPropertyVal', () => { assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { black: 'matcha' }) assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'oolong' }) assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'coffee', { green: 'matcha' }) }) ``` ## nestedProperty * **Type:** `(object: T, property: string, message?: string) => void` Asserts that `object` has a direct or inherited property named by `property`, which can be a string using dot- and bracket-notation for nested reference. ```ts import { assert, test } from 'vitest' test('assert.deepPropertyVal', () => { assert.nestedProperty({ tea: { green: 'matcha' } }, 'tea.green') }) ``` ## notNestedProperty * **Type:** `(object: T, property: string, message?: string) => void` Asserts that `object` does not have a direct or inherited property named by `property`, which can be a string using dot- and bracket-notation for nested reference. ```ts import { assert, test } from 'vitest' test('assert.deepPropertyVal', () => { assert.notNestedProperty({ tea: { green: 'matcha' } }, 'tea.oolong') }) ``` ## nestedPropertyVal * **Type:** `(object: T, property: string, value: any, message?: string) => void` Asserts that `object` has a property named by `property` with value given by `value`. `property` can use dot- and bracket-notation for nested reference. Uses a strict equality check (===). ```ts import { assert, test } from 'vitest' test('assert.nestedPropertyVal', () => { assert.nestedPropertyVal({ tea: { green: 'matcha' } }, 'tea.green', 'matcha') }) ``` ## notNestedPropertyVal * **Type:** `(object: T, property: string, value: any, message?: string) => void` Asserts that `object` does not have a property named by `property` with value given by `value`. `property` can use dot- and bracket-notation for nested reference. Uses a strict equality check (===). ```ts import { assert, test } from 'vitest' test('assert.notNestedPropertyVal', () => { assert.notNestedPropertyVal({ tea: { green: 'matcha' } }, 'tea.green', 'konacha') assert.notNestedPropertyVal({ tea: { green: 'matcha' } }, 'coffee.green', 'matcha') }) ``` ## deepNestedPropertyVal * **Type:** `(object: T, property: string, value: any, message?: string) => void` Asserts that `object` has a property named by `property` with a value given by `value`. `property` can use dot- and bracket-notation for nested reference. Uses a deep equality check (===). ```ts import { assert, test } from 'vitest' test('assert.notNestedPropertyVal', () => { assert.notNestedPropertyVal({ tea: { green: 'matcha' } }, 'tea.green', 'konacha') assert.notNestedPropertyVal({ tea: { green: 'matcha' } }, 'coffee.green', 'matcha') }) ``` ## notDeepNestedPropertyVal * **Type:** `(object: T, property: string, value: any, message?: string) => void` Asserts that `object` does not have a property named by `property` with value given by `value`. `property` can use dot- and bracket-notation for nested reference. Uses a deep equality check. ```ts import { assert, test } from 'vitest' test('assert.notDeepNestedPropertyVal', () => { assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { oolong: 'yum' }) assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { matcha: 'yuck' }) assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.black', { matcha: 'yum' }) }) ``` ## lengthOf * **Type:** `(object: T, length: number, message?: string) => void` Asserts that `object` has a `length` or `size` with the expected value. ```ts import { assert, test } from 'vitest' test('assert.lengthOf', () => { assert.lengthOf([1, 2, 3], 3, 'array has length of 3') assert.lengthOf('foobar', 6, 'string has length of 6') assert.lengthOf(new Set([1, 2, 3]), 3, 'set has size of 3') assert.lengthOf(new Map([['a', 1], ['b', 2], ['c', 3]]), 3, 'map has size of 3') }) ``` ## hasAnyKeys * **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void` Asserts that `object` has at least one of the `keys` provided. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys. ```ts import { assert, test } from 'vitest' test('assert.hasAnyKeys', () => { assert.hasAnyKeys({ foo: 1, bar: 2, baz: 3 }, ['foo', 'iDontExist', 'baz']) assert.hasAnyKeys({ foo: 1, bar: 2, baz: 3 }, { foo: 30, iDontExist: 99, baz: 1337 }) assert.hasAnyKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value']]), [{ foo: 1 }, 'key']) assert.hasAnyKeys(new Set([{ foo: 'bar' }, 'anotherKey']), [{ foo: 'bar' }, 'anotherKey']) }) ``` ## hasAllKeys * **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void` Asserts that `object` has all and only all of the `keys` provided. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys. ```ts import { assert, test } from 'vitest' test('assert.hasAllKeys', () => { assert.hasAllKeys({ foo: 1, bar: 2, baz: 3 }, ['foo', 'bar', 'baz']) assert.hasAllKeys({ foo: 1, bar: 2, baz: 3 }, { foo: 30, bar: 99, baz: 1337 }) assert.hasAllKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value']]), [{ foo: 1 }, 'key']) assert.hasAllKeys(new Set([{ foo: 'bar' }, 'anotherKey'], [{ foo: 'bar' }, 'anotherKey'])) }) ``` ## containsAllKeys * **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void` Asserts that `object` has all of the `keys` provided but may have more keys not listed. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys. ```ts import { assert, test } from 'vitest' test('assert.containsAllKeys', () => { assert.containsAllKeys({ foo: 1, bar: 2, baz: 3 }, ['foo', 'baz']) assert.containsAllKeys({ foo: 1, bar: 2, baz: 3 }, ['foo', 'bar', 'baz']) assert.containsAllKeys({ foo: 1, bar: 2, baz: 3 }, { foo: 30, baz: 1337 }) assert.containsAllKeys({ foo: 1, bar: 2, baz: 3 }, { foo: 30, bar: 99, baz: 1337 }) assert.containsAllKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value']]), [{ foo: 1 }]) assert.containsAllKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value']]), [{ foo: 1 }, 'key']) assert.containsAllKeys(new Set([{ foo: 'bar' }, 'anotherKey'], [{ foo: 'bar' }])) assert.containsAllKeys(new Set([{ foo: 'bar' }, 'anotherKey'], [{ foo: 'bar' }, 'anotherKey'])) }) ``` ## doesNotHaveAnyKeys * **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void` Asserts that `object` has none of the `keys` provided. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys. ```ts import { assert, test } from 'vitest' test('assert.doesNotHaveAnyKeys', () => { assert.doesNotHaveAnyKeys({ foo: 1, bar: 2, baz: 3 }, ['one', 'two', 'example']) assert.doesNotHaveAnyKeys({ foo: 1, bar: 2, baz: 3 }, { one: 1, two: 2, example: 'foo' }) assert.doesNotHaveAnyKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value']]), [{ one: 'two' }, 'example']) assert.doesNotHaveAnyKeys(new Set([{ foo: 'bar' }, 'anotherKey'], [{ one: 'two' }, 'example'])) }) ``` ## doesNotHaveAllKeys * **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void` Asserts that `object` does not have at least one of the `keys` provided. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys. ```ts import { assert, test } from 'vitest' test('assert.hasAnyKeys', () => { assert.doesNotHaveAnyKeys({ foo: 1, bar: 2, baz: 3 }, ['one', 'two', 'example']) assert.doesNotHaveAnyKeys({ foo: 1, bar: 2, baz: 3 }, { one: 1, two: 2, example: 'foo' }) assert.doesNotHaveAnyKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value']]), [{ one: 'two' }, 'example']) assert.doesNotHaveAnyKeys(new Set([{ foo: 'bar' }, 'anotherKey']), [{ one: 'two' }, 'example']) }) ``` ## hasAnyDeepKeys * **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void` Asserts that `object` has at least one of the `keys` provided. Since Sets and Maps can have objects as keys you can use this assertion to perform a deep comparison. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys. ```ts import { assert, test } from 'vitest' test('assert.hasAnyDeepKeys', () => { assert.hasAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2]]), { one: 'one' }) assert.hasAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2]]), [{ one: 'one' }, { two: 'two' }]) assert.hasAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo']]), [{ one: 'one' }, { two: 'two' }]) assert.hasAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), { one: 'one' }) assert.hasAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { three: 'three' }]) assert.hasAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { two: 'two' }]) }) ``` ## hasAllDeepKeys * **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void` Asserts that `object` has all and only all of the `keys` provided. Since Sets and Maps can have objects as keys you can use this assertion to perform a deep comparison. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys. ```ts import { assert, test } from 'vitest' test('assert.hasAnyDeepKeys', () => { assert.hasAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne']]), { one: 'one' }) assert.hasAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo']]), [{ one: 'one' }, { two: 'two' }]) assert.hasAllDeepKeys(new Set([{ one: 'one' }]), { one: 'one' }) assert.hasAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { two: 'two' }]) }) ``` ## containsAllDeepKeys * **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void` Asserts that `object` contains all of the `keys` provided. Since Sets and Maps can have objects as keys you can use this assertion to perform a deep comparison. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys. ```ts import { assert, test } from 'vitest' test('assert.containsAllDeepKeys', () => { assert.containsAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2]]), { one: 'one' }) assert.containsAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo']]), [{ one: 'one' }, { two: 'two' }]) assert.containsAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), { one: 'one' }) assert.containsAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { two: 'two' }]) }) ``` ## doesNotHaveAnyDeepKeys * **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void` Asserts that `object` has none of the `keys` provided. Since Sets and Maps can have objects as keys you can use this assertion to perform a deep comparison. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys. ```ts import { assert, test } from 'vitest' test('assert.doesNotHaveAnyDeepKeys', () => { assert.doesNotHaveAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2]]), { thisDoesNot: 'exist' }) assert.doesNotHaveAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo']]), [{ twenty: 'twenty' }, { fifty: 'fifty' }]) assert.doesNotHaveAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), { twenty: 'twenty' }) assert.doesNotHaveAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ twenty: 'twenty' }, { fifty: 'fifty' }]) }) ``` ## doesNotHaveAllDeepKeys * **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void` Asserts that `object` does not have at least one of the `keys` provided. Since Sets and Maps can have objects as keys you can use this assertion to perform a deep comparison. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys. ```ts import { assert, test } from 'vitest' test('assert.doesNotHaveAllDeepKeys', () => { assert.doesNotHaveAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2]]), { thisDoesNot: 'exist' }) assert.doesNotHaveAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo']]), [{ twenty: 'twenty' }, { one: 'one' }]) assert.doesNotHaveAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), { twenty: 'twenty' }) assert.doesNotHaveAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { fifty: 'fifty' }]) }) ``` ## throws * **Type:** * `(fn: () => void, errMsgMatcher?: RegExp | string, ignored?: any, message?: string) => void` * `(fn: () => void, errorLike?: ErrorConstructor | Error | null, errMsgMatcher?: RegExp | string | null, message?: string) => void` * **Alias:** * `throw` * `Throw` If `errorLike` is an Error constructor, asserts that `fn` will throw an error that is an instance of `errorLike`. If errorLike is an Error instance, asserts that the error thrown is the same instance as `errorLike`. If `errMsgMatcher` is provided, it also asserts that the error thrown will have a message matching `errMsgMatcher`. ```ts import { assert, test } from 'vitest' test('assert.throws', () => { assert.throws(fn, 'Error thrown must have this msg') assert.throws(fn, /Error thrown must have a msg that matches this/) assert.throws(fn, ReferenceError) assert.throws(fn, errorInstance) assert.throws(fn, ReferenceError, 'Error thrown must be a ReferenceError and have this msg') assert.throws(fn, errorInstance, 'Error thrown must be the same errorInstance and have this msg') assert.throws(fn, ReferenceError, /Error thrown must be a ReferenceError and match this/) assert.throws(fn, errorInstance, /Error thrown must be the same errorInstance and match this/) }) ``` ## doesNotThrow * **Type:** `(fn: () => void, errMsgMatcher?: RegExp | string, ignored?: any, message?: string) => void` * **Type:** `(fn: () => void, errorLike?: ErrorConstructor | Error | null, errMsgMatcher?: RegExp | string | null, message?: string) => void` If `errorLike` is an Error constructor, asserts that `fn` will not throw an error that is an instance of `errorLike`. If errorLike is an Error instance, asserts that the error thrown is not the same instance as `errorLike`. If `errMsgMatcher` is provided, it also asserts that the error thrown will not have a message matching `errMsgMatcher`. ```ts import { assert, test } from 'vitest' test('assert.doesNotThrow', () => { assert.doesNotThrow(fn, 'Any Error thrown must not have this message') assert.doesNotThrow(fn, /Any Error thrown must not match this/) assert.doesNotThrow(fn, Error) assert.doesNotThrow(fn, errorInstance) assert.doesNotThrow(fn, Error, 'Error must not have this message') assert.doesNotThrow(fn, errorInstance, 'Error must not have this message') assert.doesNotThrow(fn, Error, /Error must not match this/) assert.doesNotThrow(fn, errorInstance, /Error must not match this/) }) ``` ## operator * **Type:** `(val1: OperatorComparable, operator: Operator, val2: OperatorComparable, message?: string) => void` Compare `val1` and `val2` using `operator`. ```ts import { assert, test } from 'vitest' test('assert.operator', () => { assert.operator(1, '<', 2, 'everything is ok') }) ``` ## closeTo * **Type:** `(actual: number, expected: number, delta: number, message?: string) => void` * **Alias:** `approximately` Asserts that the `actual` is equal `expected`, to within a +/- `delta` range. ```ts import { assert, test } from 'vitest' test('assert.closeTo', () => { assert.closeTo(1.5, 1, 0.5, 'numbers are close') }) ``` ## sameMembers * **Type:** `(set1: T[], set2: T[], message?: string) => void` Asserts that `set1` and `set2` have the same members in any order. Uses a strict equality check (===). ```ts import { assert, test } from 'vitest' test('assert.sameMembers', () => { assert.sameMembers([1, 2, 3], [2, 1, 3], 'same members') }) ``` ## notSameMembers * **Type:** `(set1: T[], set2: T[], message?: string) => void` Asserts that `set1` and `set2` don't have the same members in any order. Uses a strict equality check (===). ```ts import { assert, test } from 'vitest' test('assert.sameMembers', () => { assert.notSameMembers([1, 2, 3], [5, 1, 3], 'not same members') }) ``` ## sameDeepMembers * **Type:** `(set1: T[], set2: T[], message?: string) => void` Asserts that `set1` and `set2` have the same members in any order. Uses a deep equality check. ```ts import { assert, test } from 'vitest' test('assert.sameDeepMembers', () => { assert.sameDeepMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }, { c: 3 }], 'same deep members') }) ``` ## notSameDeepMembers * **Type:** `(set1: T[], set2: T[], message?: string) => void` Asserts that `set1` and `set2` don’t have the same members in any order. Uses a deep equality check. ```ts import { assert, test } from 'vitest' test('assert.sameDeepMembers', () => { assert.sameDeepMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }, { c: 3 }], 'same deep members') }) ``` ## sameOrderedMembers * **Type:** `(set1: T[], set2: T[], message?: string) => void` Asserts that `set1` and `set2` have the same members in the same order. Uses a strict equality check (===). ```ts import { assert, test } from 'vitest' test('assert.sameOrderedMembers', () => { assert.sameOrderedMembers([1, 2, 3], [1, 2, 3], 'same ordered members') }) ``` ## notSameOrderedMembers * **Type:** `(set1: T[], set2: T[], message?: string) => void` Asserts that `set1` and `set2` have the same members in the same order. Uses a strict equality check (===). ```ts import { assert, test } from 'vitest' test('assert.notSameOrderedMembers', () => { assert.notSameOrderedMembers([1, 2, 3], [2, 1, 3], 'not same ordered members') }) ``` ## sameDeepOrderedMembers * **Type:** `(set1: T[], set2: T[], message?: string) => void` Asserts that `set1` and `set2` have the same members in the same order. Uses a deep equality check. ```ts import { assert, test } from 'vitest' test('assert.sameDeepOrderedMembers', () => { assert.sameDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ a: 1 }, { b: 2 }, { c: 3 }], 'same deep ordered members') }) ``` ## notSameDeepOrderedMembers * **Type:** `(set1: T[], set2: T[], message?: string) => void` Asserts that `set1` and `set2` don’t have the same members in the same order. Uses a deep equality check. ```ts import { assert, test } from 'vitest' test('assert.notSameDeepOrderedMembers', () => { assert.notSameDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ a: 1 }, { b: 2 }, { z: 5 }], 'not same deep ordered members') assert.notSameDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }, { c: 3 }], 'not same deep ordered members') }) ``` ## includeMembers * **Type:** `(superset: T[], subset: T[], message?: string) => void` Asserts that `subset` is included in `superset` in any order. Uses a strict equality check (===). Duplicates are ignored. ```ts import { assert, test } from 'vitest' test('assert.includeMembers', () => { assert.includeMembers([1, 2, 3], [2, 1, 2], 'include members') }) ``` ## notIncludeMembers * **Type:** `(superset: T[], subset: T[], message?: string) => void` Asserts that `subset` isn't included in `superset` in any order. Uses a strict equality check (===). Duplicates are ignored. ```ts import { assert, test } from 'vitest' test('assert.notIncludeMembers', () => { assert.notIncludeMembers([1, 2, 3], [5, 1], 'not include members') }) ``` ## includeDeepMembers * **Type:** `(superset: T[], subset: T[], message?: string) => void` Asserts that `subset` is included in `superset` in any order. Uses a deep equality check. Duplicates are ignored. ```ts import { assert, test } from 'vitest' test('assert.includeDeepMembers', () => { assert.includeDeepMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }, { b: 2 }], 'include deep members') }) ``` ## notIncludeDeepMembers * **Type:** `(superset: T[], subset: T[], message?: string) => void` Asserts that `subset` isn’t included in `superset` in any order. Uses a deep equality check. Duplicates are ignored. ```ts import { assert, test } from 'vitest' test('assert.notIncludeDeepMembers', () => { assert.notIncludeDeepMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { f: 5 }], 'not include deep members') }) ``` ## includeOrderedMembers * **Type:** `(superset: T[], subset: T[], message?: string) => void` Asserts that `subset` is included in `superset` in the same order beginning with the first element in `superset`. Uses a strict equality check (===). ```ts import { assert, test } from 'vitest' test('assert.includeOrderedMembers', () => { assert.includeOrderedMembers([1, 2, 3], [1, 2], 'include ordered members') }) ``` ## notIncludeOrderedMembers * **Type:** `(superset: T[], subset: T[], message?: string) => void` Asserts that `subset` isn't included in `superset` in the same order beginning with the first element in `superset`. Uses a strict equality check (===). ```ts import { assert, test } from 'vitest' test('assert.notIncludeOrderedMembers', () => { assert.notIncludeOrderedMembers([1, 2, 3], [2, 1], 'not include ordered members') assert.notIncludeOrderedMembers([1, 2, 3], [2, 3], 'not include ordered members') }) ``` ## includeDeepOrderedMembers * **Type:** `(superset: T[], subset: T[], message?: string) => void` Asserts that `subset` is included in `superset` in the same order beginning with the first element in `superset`. Uses a deep equality check. ```ts import { assert, test } from 'vitest' test('assert.includeDeepOrderedMembers', () => { assert.includeDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ a: 1 }, { b: 2 }], 'include deep ordered members') }) ``` ## notIncludeDeepOrderedMembers * **Type:** `(superset: T[], subset: T[], message?: string) => void` Asserts that `subset` isn’t included in `superset` in the same order beginning with the first element in superset. Uses a deep equality check. ```ts import { assert, test } from 'vitest' test('assert.includeDeepOrderedMembers', () => { assert.notIncludeDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ a: 1 }, { f: 5 }], 'not include deep ordered members') assert.notIncludeDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }], 'not include deep ordered members') assert.notIncludeDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { c: 3 }], 'not include deep ordered members') }) ``` ## oneOf * **Type:** `(inList: T, list: T[], message?: string) => void` Asserts that non-object, non-array value `inList` appears in the flat array `list`. ```ts import { assert, test } from 'vitest' test('assert.oneOf', () => { assert.oneOf(1, [2, 1], 'Not found in list') }) ``` ## changes * **Type:** `(modifier: Function, object: T, property: string, message?: string) => void` Asserts that a `modifier` changes the `object` of a `property`. ```ts import { assert, test } from 'vitest' test('assert.changes', () => { const obj = { val: 10 } function fn() { obj.val = 22 }; assert.changes(fn, obj, 'val') }) ``` ## changesBy * **Type:** `(modifier: Function, object: T, property: string, change: number, message?: string) => void` Asserts that a `modifier` changes the `object` of a `property` by a `change`. ```ts import { assert, test } from 'vitest' test('assert.changesBy', () => { const obj = { val: 10 } function fn() { obj.val += 2 }; assert.changesBy(fn, obj, 'val', 2) }) ``` ## doesNotChange * **Type:** `(modifier: Function, object: T, property: string, message?: string) => void` Asserts that a `modifier` does not changes the `object` of a `property`. ```ts import { assert, test } from 'vitest' test('assert.doesNotChange', () => { const obj = { val: 10 } function fn() { obj.val += 2 }; assert.doesNotChange(fn, obj, 'val', 2) }) ``` ## changesButNotBy * **Type:** `(modifier: Function, object: T, property: string, change:number, message?: string) => void` Asserts that a `modifier` does not change the `object` of a `property` or of a `modifier` return value by a `change`. ```ts import { assert, test } from 'vitest' test('assert.changesButNotBy', () => { const obj = { val: 10 } function fn() { obj.val += 10 }; assert.changesButNotBy(fn, obj, 'val', 5) }) ``` ## increases * **Type:** `(modifier: Function, object: T, property: string, message?: string) => void` Asserts that a `modifier` increases a numeric `object`'s `property`. ```ts import { assert, test } from 'vitest' test('assert.increases', () => { const obj = { val: 10 } function fn() { obj.val = 13 }; assert.increases(fn, obj, 'val') }) ``` ## increasesBy * **Type:** `(modifier: Function, object: T, property: string, change: number, message?: string) => void` Asserts that a `modifier` increases a numeric `object`'s `property` or a `modifier` return value by an `change`. ```ts import { assert, test } from 'vitest' test('assert.increasesBy', () => { const obj = { val: 10 } function fn() { obj.val += 10 }; assert.increasesBy(fn, obj, 'val', 10) }) ``` ## doesNotIncrease * **Type:** `(modifier: Function, object: T, property: string, message?: string) => void` Asserts that a `modifier` does not increases a numeric `object`'s `property`. ```ts import { assert, test } from 'vitest' test('assert.doesNotIncrease', () => { const obj = { val: 10 } function fn() { obj.val = 8 } assert.doesNotIncrease(fn, obj, 'val') }) ``` ## increasesButNotBy * **Type:** `(modifier: Function, object: T, property: string, change: number, message?: string) => void` Asserts that a `modifier` does not increases a numeric `object`'s `property` or a `modifier` return value by an `change`. ```ts import { assert, test } from 'vitest' test('assert.increasesButNotBy', () => { const obj = { val: 10 } function fn() { obj.val += 15 }; assert.increasesButNotBy(fn, obj, 'val', 10) }) ``` ## decreases * **Type:** `(modifier: Function, object: T, property: string, message?: string) => void` Asserts that a `modifier` decreases a numeric `object`'s `property`. ```ts import { assert, test } from 'vitest' test('assert.decreases', () => { const obj = { val: 10 } function fn() { obj.val = 5 }; assert.decreases(fn, obj, 'val') }) ``` ## decreasesBy * **Type:** `(modifier: Function, object: T, property: string, change: number, message?: string) => void` Asserts that a `modifier` decreases a numeric `object`'s `property` or a `modifier` return value by a `change`. ```ts import { assert, test } from 'vitest' test('assert.decreasesBy', () => { const obj = { val: 10 } function fn() { obj.val -= 5 }; assert.decreasesBy(fn, obj, 'val', 5) }) ``` ## doesNotDecrease * **Type:** `(modifier: Function, object: T, property: string, message?: string) => void` Asserts that a `modifier` dose not decrease a numeric `object`'s `property`. ```ts import { assert, test } from 'vitest' test('assert.doesNotDecrease', () => { const obj = { val: 10 } function fn() { obj.val = 15 } assert.doesNotDecrease(fn, obj, 'val') }) ``` ## doesNotDecreaseBy * **Type:** `(modifier: Function, object: T, property: string, change: number, message?: string) => void` Asserts that a `modifier` does not decrease a numeric `object`'s `property` or a `modifier` return value by a `change`. ```ts import { assert, test } from 'vitest' test('assert.doesNotDecreaseBy', () => { const obj = { val: 10 } function fn() { obj.val = 5 }; assert.doesNotDecreaseBy(fn, obj, 'val', 1) }) ``` ## decreasesButNotBy * **Type:** `(modifier: Function, object: T, property: string, change: number, message?: string) => void` Asserts that a `modifier` does not decrease a numeric `object`'s `property` or a `modifier` return value by a `change`. ```ts import { assert, test } from 'vitest' test('assert.decreasesButNotBy', () => { const obj = { val: 10 } function fn() { obj.val = 5 }; assert.decreasesButNotBy(fn, obj, 'val', 1) }) ``` ## ifError * **Type:** `(object: T, message?: string) => void` Asserts if `object` is not a false value, and throws if it is a true value. This is added to allow for chai to be a drop-in replacement for Node’s assert class. ```ts import { assert, test } from 'vitest' test('assert.ifError', () => { const err = new Error('I am a custom error') assert.ifError(err) // Rethrows err! }) ``` ## isExtensible * **Type:** `(object: T, message?: string) => void` * **Alias:** `extensible` Asserts that `object` is extensible (can have new properties added to it). ```ts import { assert, test } from 'vitest' test('assert.isExtensible', () => { assert.isExtensible({}) }) ``` ## isNotExtensible * **Type:** `(object: T, message?: string) => void` * **Alias:** `notExtensible` Asserts that `object` is not extensible (can not have new properties added to it). ```ts import { assert, test } from 'vitest' test('assert.isNotExtensible', () => { const nonExtensibleObject = Object.preventExtensions({}) const sealedObject = Object.seal({}) const frozenObject = Object.freeze({}) assert.isNotExtensible(nonExtensibleObject) assert.isNotExtensible(sealedObject) assert.isNotExtensible(frozenObject) }) ``` ## isSealed * **Type:** `(object: T, message?: string) => void` * **Alias:** `sealed` Asserts that `object` is sealed (cannot have new properties added to it and its existing properties cannot be removed). ```ts import { assert, test } from 'vitest' test('assert.isSealed', () => { const sealedObject = Object.seal({}) const frozenObject = Object.seal({}) assert.isSealed(sealedObject) assert.isSealed(frozenObject) }) ``` ## isNotSealed * **Type:** `(object: T, message?: string) => void` * **Alias:** `notSealed` Asserts that `object` is not sealed (can have new properties added to it and its existing properties can be removed). ```ts import { assert, test } from 'vitest' test('assert.isNotSealed', () => { assert.isNotSealed({}) }) ``` ## isFrozen * **Type:** `(object: T, message?: string) => void` * **Alias:** `frozen` Asserts that object is frozen (cannot have new properties added to it and its existing properties cannot be modified). ```ts import { assert, test } from 'vitest' test('assert.isFrozen', () => { const frozenObject = Object.freeze({}) assert.frozen(frozenObject) }) ``` ## isNotFrozen * **Type:** `(object: T, message?: string) => void` * **Alias:** `notFrozen` Asserts that `object` is not frozen (can have new properties added to it and its existing properties can be modified). ```ts import { assert, test } from 'vitest' test('assert.isNotFrozen', () => { assert.isNotFrozen({}) }) ``` ## isEmpty * **Type:** `(target: T, message?: string) => void` * **Alias:** `empty` Asserts that the `target` does not contain any values. For arrays and strings, it checks the length property. For Map and Set instances, it checks the size property. For non-function objects, it gets the count of its own enumerable string keys. ```ts import { assert, test } from 'vitest' test('assert.isEmpty', () => { assert.isEmpty([]) assert.isEmpty('') assert.isEmpty(new Map()) assert.isEmpty({}) }) ``` ## isNotEmpty * **Type:** `(object: T, message?: string) => void` * **Alias:** `notEmpty` Asserts that the `target` contains values. For arrays and strings, it checks the length property. For Map and Set instances, it checks the size property. For non-function objects, it gets the count of its own enumerable string keys. ```ts import { assert, test } from 'vitest' test('assert.isNotEmpty', () => { assert.isNotEmpty([1, 2]) assert.isNotEmpty('34') assert.isNotEmpty(new Set([5, 6])) assert.isNotEmpty({ key: 7 }) }) ``` --- # Source: https://vitest.dev/api/browser/assertions.md --- url: /api/browser/assertions.md --- # Assertion API Vitest provides a wide range of DOM assertions out of the box forked from [`@testing-library/jest-dom`](https://github.com/testing-library/jest-dom) library with the added support for locators and built-in retry-ability. ::: tip TypeScript Support If you are using [TypeScript](/guide/browser/#typescript) or want to have correct type hints in `expect`, make sure you have `vitest/browser` referenced somewhere. If you never imported from there, you can add a `reference` comment in any file that's covered by your `tsconfig.json`: ```ts /// ``` ::: Tests in the browser might fail inconsistently due to their asynchronous nature. Because of this, it is important to have a way to guarantee that assertions succeed even if the condition is delayed (by a timeout, network request, or animation, for example). For this purpose, Vitest provides retriable assertions out of the box via the [`expect.poll`](/api/expect#poll) and `expect.element` APIs: ```ts import { expect, test } from 'vitest' import { page } from 'vitest/browser' test('error banner is rendered', async () => { triggerError() // This creates a locator that will try to find the element // when any of its methods are called. // This call by itself doesn't check the existence of the element. const banner = page.getByRole('alert', { name: /error/i, }) // Vitest provides `expect.element` with built-in retry-ability // It will repeatedly check that the element exists in the DOM and that // the content of `element.textContent` is equal to "Error!" // until all the conditions are met await expect.element(banner).toHaveTextContent('Error!') }) ``` We recommend to always use `expect.element` when working with `page.getBy*` locators to reduce test flakiness. Note that `expect.element` accepts a second option: ```ts interface ExpectPollOptions { // The interval to retry the assertion for in milliseconds // Defaults to "expect.poll.interval" config option interval?: number // Time to retry the assertion for in milliseconds // Defaults to "expect.poll.timeout" config option timeout?: number // The message printed when the assertion fails message?: string } ``` ::: tip `expect.element` is a shorthand for `expect.poll(() => element)` and works in exactly the same way. `toHaveTextContent` and all other assertions are still available on a regular `expect` without a built-in retry-ability mechanism: ```ts // will fail immediately if .textContent is not `'Error!'` expect(banner).toHaveTextContent('Error!') ``` ::: ## toBeDisabled ```ts function toBeDisabled(): Promise ``` Allows you to check whether an element is disabled from the user's perspective. Matches if the element is a form control and the `disabled` attribute is specified on this element or the element is a descendant of a form element with a `disabled` attribute. Note that only native control elements such as HTML `button`, `input`, `select`, `textarea`, `option`, `optgroup` can be disabled by setting "disabled" attribute. "disabled" attribute on other elements is ignored, unless it's a custom element. ```html ``` ```ts await expect.element(getByTestId('button')).toBeDisabled() // ✅ await expect.element(getByTestId('button')).not.toBeDisabled() // ❌ ``` ## toBeEnabled ```ts function toBeEnabled(): Promise ``` Allows you to check whether an element is not disabled from the user's perspective. Works like [`not.toBeDisabled()`](#tobedisabled). Use this matcher to avoid double negation in your tests. ```html ``` ```ts await expect.element(getByTestId('button')).toBeEnabled() // ✅ await expect.element(getByTestId('button')).not.toBeEnabled() // ❌ ``` ## toBeEmptyDOMElement ```ts function toBeEmptyDOMElement(): Promise ``` This allows you to assert whether an element has no visible content for the user. It ignores comments but will fail if the element contains white-space. ```html ``` ```ts await expect.element(getByTestId('empty')).toBeEmptyDOMElement() await expect.element(getByTestId('not-empty')).not.toBeEmptyDOMElement() await expect.element( getByTestId('with-whitespace') ).not.toBeEmptyDOMElement() ``` ## toBeInTheDocument ```ts function toBeInTheDocument(): Promise ``` Assert whether an element is present in the document or not. ```html ``` ```ts await expect.element(getByTestId('svg-element')).toBeInTheDocument() await expect.element(getByTestId('does-not-exist')).not.toBeInTheDocument() ``` ::: warning This matcher does not find detached elements. The element must be added to the document to be found by `toBeInTheDocument`. If you desire to search in a detached element, please use: [`toContainElement`](#tocontainelement). ::: ## toBeInvalid ```ts function toBeInvalid(): Promise ``` This allows you to check if an element, is currently invalid. An element is invalid if it has an [`aria-invalid` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-invalid) with no value or a value of `"true"`, or if the result of [`checkValidity()`](https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation) is `false`. ```html
``` ```ts await expect.element(getByTestId('no-aria-invalid')).not.toBeInvalid() await expect.element(getByTestId('aria-invalid')).toBeInvalid() await expect.element(getByTestId('aria-invalid-value')).toBeInvalid() await expect.element(getByTestId('aria-invalid-false')).not.toBeInvalid() await expect.element(getByTestId('valid-form')).not.toBeInvalid() await expect.element(getByTestId('invalid-form')).toBeInvalid() ``` ## toBeRequired ```ts function toBeRequired(): Promise ``` This allows you to check if a form element is currently required. An element is required if it is having a `required` or `aria-required="true"` attribute. ```html
``` ```ts await expect.element(getByTestId('required-input')).toBeRequired() await expect.element(getByTestId('aria-required-input')).toBeRequired() await expect.element(getByTestId('conflicted-input')).toBeRequired() await expect.element(getByTestId('aria-not-required-input')).not.toBeRequired() await expect.element(getByTestId('optional-input')).not.toBeRequired() await expect.element(getByTestId('unsupported-type')).not.toBeRequired() await expect.element(getByTestId('select')).toBeRequired() await expect.element(getByTestId('textarea')).toBeRequired() await expect.element(getByTestId('supported-role')).not.toBeRequired() await expect.element(getByTestId('supported-role-aria')).toBeRequired() ``` ## toBeValid ```ts function toBeValid(): Promise ``` This allows you to check if the value of an element, is currently valid. An element is valid if it has no [`aria-invalid` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-invalid) or an attribute value of "false". The result of [`checkValidity()`](https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation) must also be `true` if it's a form element. ```html
``` ```ts await expect.element(getByTestId('no-aria-invalid')).toBeValid() await expect.element(getByTestId('aria-invalid')).not.toBeValid() await expect.element(getByTestId('aria-invalid-value')).not.toBeValid() await expect.element(getByTestId('aria-invalid-false')).toBeValid() await expect.element(getByTestId('valid-form')).toBeValid() await expect.element(getByTestId('invalid-form')).not.toBeValid() ``` ## toBeVisible ```ts function toBeVisible(): Promise ``` This allows you to check if an element is currently visible to the user. Element is considered visible when it has non-empty bounding box and does not have `visibility:hidden` computed style. Note that according to this definition: * Elements of zero size **are not** considered visible. * Elements with `display:none` **are not** considered visible. * Elements with `opacity:0` **are** considered visible. To check that at least one element from the list is visible, use `locator.first()`. ```ts // A specific element is visible. await expect.element(page.getByText('Welcome')).toBeVisible() // At least one item in the list is visible. await expect.element(page.getByTestId('todo-item').first()).toBeVisible() // At least one of the two elements is visible, possibly both. await expect.element( page.getByRole('button', { name: 'Sign in' }) .or(page.getByRole('button', { name: 'Sign up' })) .first() ).toBeVisible() ``` ## toBeInViewport 4.0.0 {#tobeinviewport} ```ts function toBeInViewport(options: { ratio?: number }): Promise ``` This allows you to check if an element is currently in viewport with [IntersectionObserver API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). You can pass `ratio` argument as option, which means the minimal ratio of the element should be in viewport. `ratio` should be in 0~1. ```ts // A specific element is in viewport. await expect.element(page.getByText('Welcome')).toBeInViewport() // 50% of a specific element should be in viewport await expect.element(page.getByText('To')).toBeInViewport({ ratio: 0.5 }) // Full of a specific element should be in viewport await expect.element(page.getByText('Vitest')).toBeInViewport({ ratio: 1 }) ``` ## toContainElement ```ts function toContainElement(element: HTMLElement | SVGElement | Locator | null): Promise ``` This allows you to assert whether an element contains another element as a descendant or not. ```html ``` ```ts const ancestor = getByTestId('ancestor') const descendant = getByTestId('descendant') const nonExistantElement = getByTestId('does-not-exist') await expect.element(ancestor).toContainElement(descendant) await expect.element(descendant).not.toContainElement(ancestor) await expect.element(ancestor).not.toContainElement(nonExistantElement) ``` ## toContainHTML ```ts function toContainHTML(htmlText: string): Promise ``` Assert whether a string representing a HTML element is contained in another element. The string should contain valid html, and not any incomplete html. ```html ``` ```ts // These are valid usages await expect.element(getByTestId('parent')).toContainHTML('') await expect.element(getByTestId('parent')).toContainHTML('') await expect.element(getByTestId('parent')).not.toContainHTML('
') // These won't work await expect.element(getByTestId('parent')).toContainHTML('data-testid="child"') await expect.element(getByTestId('parent')).toContainHTML('data-testid') await expect.element(getByTestId('parent')).toContainHTML('
') ``` ::: warning Chances are you probably do not need to use this matcher. We encourage testing from the perspective of how the user perceives the app in a browser. That's why testing against a specific DOM structure is not advised. It could be useful in situations where the code being tested renders html that was obtained from an external source, and you want to validate that that html code was used as intended. It should not be used to check DOM structure that you control. Please, use [`toContainElement`](#tocontainelement) instead. ::: ## toHaveAccessibleDescription ```ts function toHaveAccessibleDescription(description?: string | RegExp): Promise ``` This allows you to assert that an element has the expected [accessible description](https://w3c.github.io/accname/). You can pass the exact string of the expected accessible description, or you can make a partial match passing a regular expression, or by using [`expect.stringContaining`](/api/expect#expect-stringcontaining) or [`expect.stringMatching`](/api/expect#expect-stringmatching). ```html Start About User profile pic Company logo The logo of Our Company Company logo ``` ```ts await expect.element(getByTestId('link')).toHaveAccessibleDescription() await expect.element(getByTestId('link')).toHaveAccessibleDescription('A link to start over') await expect.element(getByTestId('link')).not.toHaveAccessibleDescription('Home page') await expect.element(getByTestId('extra-link')).not.toHaveAccessibleDescription() await expect.element(getByTestId('avatar')).not.toHaveAccessibleDescription() await expect.element(getByTestId('logo')).not.toHaveAccessibleDescription('Company logo') await expect.element(getByTestId('logo')).toHaveAccessibleDescription( 'The logo of Our Company', ) await expect.element(getByTestId('logo2')).toHaveAccessibleDescription( 'The logo of Our Company', ) ``` ## toHaveAccessibleErrorMessage ```ts function toHaveAccessibleErrorMessage(message?: string | RegExp): Promise ``` This allows you to assert that an element has the expected [accessible error message](https://w3c.github.io/aria/#aria-errormessage). You can pass the exact string of the expected accessible error message. Alternatively, you can perform a partial match by passing a regular expression or by using [`expect.stringContaining`](/api/expect#expect-stringcontaining) or [`expect.stringMatching`](/api/expect#expect-stringmatching). ```html ``` ```ts // Inputs with Valid Error Messages await expect.element(getByRole('textbox', { name: 'Has Error' })).toHaveAccessibleErrorMessage() await expect.element(getByRole('textbox', { name: 'Has Error' })).toHaveAccessibleErrorMessage( 'This field is invalid', ) await expect.element(getByRole('textbox', { name: 'Has Error' })).toHaveAccessibleErrorMessage( /invalid/i, ) await expect.element( getByRole('textbox', { name: 'Has Error' }), ).not.toHaveAccessibleErrorMessage('This field is absolutely correct!') // Inputs without Valid Error Messages await expect.element( getByRole('textbox', { name: 'No Error Attributes' }), ).not.toHaveAccessibleErrorMessage() await expect.element( getByRole('textbox', { name: 'Not Invalid' }), ).not.toHaveAccessibleErrorMessage() ``` ## toHaveAccessibleName ```ts function toHaveAccessibleName(name?: string | RegExp): Promise ``` This allows you to assert that an element has the expected [accessible name](https://w3c.github.io/accname/). It is useful, for instance, to assert that form elements and buttons are properly labelled. You can pass the exact string of the expected accessible name, or you can make a partial match passing a regular expression, or by using [`expect.stringContaining`](/api/expect#expect-stringcontaining) or [`expect.stringMatching`](/api/expect#expect-stringmatching). ```html Test alt Test title

Test content

``` ```ts const button = getByTestId('ok-button') await expect.element(button).toHaveAttribute('disabled') await expect.element(button).toHaveAttribute('type', 'submit') await expect.element(button).not.toHaveAttribute('type', 'button') await expect.element(button).toHaveAttribute( 'type', expect.stringContaining('sub') ) await expect.element(button).toHaveAttribute( 'type', expect.not.stringContaining('but') ) ``` ## toHaveClass ```ts function toHaveClass(...classNames: string[], options?: { exact: boolean }): Promise function toHaveClass(...classNames: (string | RegExp)[]): Promise ``` This allows you to check whether the given element has certain classes within its `class` attribute. You must provide at least one class, unless you are asserting that an element does not have any classes. The list of class names may include strings and regular expressions. Regular expressions are matched against each individual class in the target element, and it is NOT matched against its full `class` attribute value as whole. ::: warning Note that you cannot use `exact: true` option when only regular expressions are provided. ::: ```html ``` ```ts const deleteButton = getByTestId('delete-button') const noClasses = getByTestId('no-classes') await expect.element(deleteButton).toHaveClass('extra') await expect.element(deleteButton).toHaveClass('btn-danger btn') await expect.element(deleteButton).toHaveClass(/danger/, 'btn') await expect.element(deleteButton).toHaveClass('btn-danger', 'btn') await expect.element(deleteButton).not.toHaveClass('btn-link') await expect.element(deleteButton).not.toHaveClass(/link/) // ⚠️ regexp matches against individual classes, not the whole classList await expect.element(deleteButton).not.toHaveClass(/btn extra/) // the element has EXACTLY a set of classes (in any order) await expect.element(deleteButton).toHaveClass('btn-danger extra btn', { exact: true }) // if it has more than expected it is going to fail await expect.element(deleteButton).not.toHaveClass('btn-danger extra', { exact: true }) await expect.element(noClasses).not.toHaveClass() ``` ## toHaveFocus ```ts function toHaveFocus(): Promise ``` This allows you to assert whether an element has focus or not. ```html
``` ```ts const input = page.getByTestId('element-to-focus') input.element().focus() await expect.element(input).toHaveFocus() input.element().blur() await expect.element(input).not.toHaveFocus() ``` ## toHaveFormValues ```ts function toHaveFormValues(expectedValues: Record): Promise ``` This allows you to check if a form or fieldset contains form controls for each given name, and having the specified value. ::: tip It is important to stress that this matcher can only be invoked on a [form](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement) or a [fieldset](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFieldSetElement) element. This allows it to take advantage of the [`.elements`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements) property in `form` and `fieldset` to reliably fetch all form controls within them. This also avoids the possibility that users provide a container that contains more than one `form`, thereby intermixing form controls that are not related, and could even conflict with one another. ::: This matcher abstracts away the particularities with which a form control value is obtained depending on the type of form control. For instance, `` elements have a `value` attribute, but `` elements return the value as a **number**, instead of a string. * `` elements: * if there's a single one with the given `name` attribute, it is treated as a **boolean**, returning `true` if the checkbox is checked, `false` if unchecked. * if there's more than one checkbox with the same `name` attribute, they are all treated collectively as a single form control, which returns the value as an **array** containing all the values of the selected checkboxes in the collection. * `` elements are all grouped by the `name` attribute, and such a group treated as a single form control. This form control returns the value as a **string** corresponding to the `value` attribute of the selected radio button within the group. * `` elements return the value as a **string**. This also applies to `` elements having any other possible `type` attribute that's not explicitly covered in different rules above (e.g. `search`, `email`, `date`, `password`, `hidden`, etc.) * `` elements return the value as an **array** containing all the values of the [selected options](https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/selectedOptions). * ` ``` ```ts const input = page.getByLabelText('First name') const textarea = page.getByLabelText('Description') const selectSingle = page.getByLabelText('Fruit') const selectMultiple = page.getByLabelText('Fruits') await expect.element(input).toHaveDisplayValue('Luca') await expect.element(input).toHaveDisplayValue(/Luc/) await expect.element(textarea).toHaveDisplayValue('An example description here.') await expect.element(textarea).toHaveDisplayValue(/example/) await expect.element(selectSingle).toHaveDisplayValue('Select a fruit...') await expect.element(selectSingle).toHaveDisplayValue(/Select/) await expect.element(selectMultiple).toHaveDisplayValue([/Avocado/, 'Banana']) ``` ## toBeChecked ```ts function toBeChecked(): Promise ``` This allows you to check whether the given element is checked. It accepts an `input` of type `checkbox` or `radio` and elements with a `role` of `checkbox`, `radio` or `switch` with a valid `aria-checked` attribute of `"true"` or `"false"`. ```html
``` ```ts const inputCheckboxChecked = getByTestId('input-checkbox-checked') const inputCheckboxUnchecked = getByTestId('input-checkbox-unchecked') const ariaCheckboxChecked = getByTestId('aria-checkbox-checked') const ariaCheckboxUnchecked = getByTestId('aria-checkbox-unchecked') await expect.element(inputCheckboxChecked).toBeChecked() await expect.element(inputCheckboxUnchecked).not.toBeChecked() await expect.element(ariaCheckboxChecked).toBeChecked() await expect.element(ariaCheckboxUnchecked).not.toBeChecked() const inputRadioChecked = getByTestId('input-radio-checked') const inputRadioUnchecked = getByTestId('input-radio-unchecked') const ariaRadioChecked = getByTestId('aria-radio-checked') const ariaRadioUnchecked = getByTestId('aria-radio-unchecked') await expect.element(inputRadioChecked).toBeChecked() await expect.element(inputRadioUnchecked).not.toBeChecked() await expect.element(ariaRadioChecked).toBeChecked() await expect.element(ariaRadioUnchecked).not.toBeChecked() const ariaSwitchChecked = getByTestId('aria-switch-checked') const ariaSwitchUnchecked = getByTestId('aria-switch-unchecked') await expect.element(ariaSwitchChecked).toBeChecked() await expect.element(ariaSwitchUnchecked).not.toBeChecked() ``` ## toBePartiallyChecked ```typescript function toBePartiallyChecked(): Promise ``` This allows you to check whether the given element is partially checked. It accepts an `input` of type `checkbox` and elements with a `role` of `checkbox` with a `aria-checked="mixed"`, or `input` of type `checkbox` with `indeterminate` set to `true` ```html
``` ```ts const ariaCheckboxMixed = getByTestId('aria-checkbox-mixed') const inputCheckboxChecked = getByTestId('input-checkbox-checked') const inputCheckboxUnchecked = getByTestId('input-checkbox-unchecked') const ariaCheckboxChecked = getByTestId('aria-checkbox-checked') const ariaCheckboxUnchecked = getByTestId('aria-checkbox-unchecked') const inputCheckboxIndeterminate = getByTestId('input-checkbox-indeterminate') await expect.element(ariaCheckboxMixed).toBePartiallyChecked() await expect.element(inputCheckboxChecked).not.toBePartiallyChecked() await expect.element(inputCheckboxUnchecked).not.toBePartiallyChecked() await expect.element(ariaCheckboxChecked).not.toBePartiallyChecked() await expect.element(ariaCheckboxUnchecked).not.toBePartiallyChecked() inputCheckboxIndeterminate.element().indeterminate = true await expect.element(inputCheckboxIndeterminate).toBePartiallyChecked() ``` ## toHaveRole ```ts function toHaveRole(role: ARIARole): Promise ``` This allows you to assert that an element has the expected [role](https://www.w3.org/TR/html-aria/#docconformance). This is useful in cases where you already have access to an element via some query other than the role itself, and want to make additional assertions regarding its accessibility. The role can match either an explicit role (via the `role` attribute), or an implicit one via the [implicit ARIA semantics](https://www.w3.org/TR/html-aria/#docconformance). ```html
Continue About Invalid link ``` ```ts await expect.element(getByTestId('button')).toHaveRole('button') await expect.element(getByTestId('button-explicit')).toHaveRole('button') await expect.element(getByTestId('button-explicit-multiple')).toHaveRole('button') await expect.element(getByTestId('button-explicit-multiple')).toHaveRole('switch') await expect.element(getByTestId('link')).toHaveRole('link') await expect.element(getByTestId('link-invalid')).not.toHaveRole('link') await expect.element(getByTestId('link-invalid')).toHaveRole('generic') ``` ::: warning Roles are matched literally by string equality, without inheriting from the ARIA role hierarchy. As a result, querying a superclass role like `checkbox` will not include elements with a subclass role like `switch`. Also note that unlike `testing-library`, Vitest ignores all custom roles except the first valid one, following Playwright's behaviour: ```jsx
await expect.element(getByTestId('switch')).toHaveRole('switch') // ✅ await expect.element(getByTestId('switch')).toHaveRole('alert') // ❌ ``` ::: ## toHaveSelection ```ts function toHaveSelection(selection?: string): Promise ``` This allows to assert that an element has a [text selection](https://developer.mozilla.org/en-US/docs/Web/API/Selection). This is useful to check if text or part of the text is selected within an element. The element can be either an input of type text, a textarea, or any other element that contains text, such as a paragraph, span, div etc. ::: warning The expected selection is a string, it does not allow to check for selection range indices. ::: ```html

prev

text selected text

next

``` ```ts getByTestId('text').element().setSelectionRange(5, 13) await expect.element(getByTestId('text')).toHaveSelection('selected') getByTestId('textarea').element().setSelectionRange(0, 5) await expect.element('textarea').toHaveSelection('text ') const selection = document.getSelection() const range = document.createRange() selection.removeAllRanges() selection.empty() selection.addRange(range) // selection of child applies to the parent as well range.selectNodeContents(getByTestId('child').element()) await expect.element(getByTestId('child')).toHaveSelection('selected') await expect.element(getByTestId('parent')).toHaveSelection('selected') // selection that applies from prev all, parent text before child, and part child. range.setStart(getByTestId('prev').element(), 0) range.setEnd(getByTestId('child').element().childNodes[0], 3) await expect.element(queryByTestId('prev')).toHaveSelection('prev') await expect.element(queryByTestId('child')).toHaveSelection('sel') await expect.element(queryByTestId('parent')).toHaveSelection('text sel') await expect.element(queryByTestId('next')).not.toHaveSelection() // selection that applies from part child, parent text after child and part next. range.setStart(getByTestId('child').element().childNodes[0], 3) range.setEnd(getByTestId('next').element().childNodes[0], 2) await expect.element(queryByTestId('child')).toHaveSelection('ected') await expect.element(queryByTestId('parent')).toHaveSelection('ected text') await expect.element(queryByTestId('prev')).not.toHaveSelection() await expect.element(queryByTestId('next')).toHaveSelection('ne') ``` ## toMatchScreenshot experimental {#tomatchscreenshot} ```ts function toMatchScreenshot( options?: ScreenshotMatcherOptions, ): Promise function toMatchScreenshot( name?: string, options?: ScreenshotMatcherOptions, ): Promise ``` ::: tip The `toMatchScreenshot` assertion can be configured globally in your [Vitest config](/config/browser/expect#tomatchscreenshot). ::: This assertion allows you to perform visual regression testing by comparing screenshots of elements or pages against stored reference images. When differences are detected beyond the configured threshold, the test fails. To help identify the changes, the assertion generates: * The actual screenshot captured during the test * The expected reference screenshot * A diff image highlighting the differences (when possible) ::: warning Screenshots Stability The assertion automatically retries taking screenshots until two consecutive captures yield the same result. This helps reduce flakiness caused by animations, loading states, or other dynamic content. You can control this behavior with the `timeout` option. However, browser rendering can vary across: * Different browsers and browser versions * Operating systems (Windows, macOS, Linux) * Screen resolutions and pixel densities * GPU drivers and hardware acceleration * Font rendering and system fonts It is recommended to read the [Visual Regression Testing guide](/guide/browser/visual-regression-testing) to implement this testing strategy efficiently. ::: ::: tip When a screenshot comparison fails due to **intentional changes**, you can update the reference screenshot by pressing the `u` key in watch mode, or by running tests with the `-u` or `--update` flags. ::: ```html ``` ```ts // basic usage, auto-generates screenshot name await expect.element(getByTestId('button')).toMatchScreenshot() // with custom name await expect.element(getByTestId('button')).toMatchScreenshot('fancy-button') // with options await expect.element(getByTestId('button')).toMatchScreenshot({ comparatorName: 'pixelmatch', comparatorOptions: { allowedMismatchedPixelRatio: 0.01, }, }) // with both name and options await expect.element(getByTestId('button')).toMatchScreenshot('fancy-button', { comparatorName: 'pixelmatch', comparatorOptions: { allowedMismatchedPixelRatio: 0.01, }, }) ``` ### Options * `comparatorName: "pixelmatch" = "pixelmatch"` The name of the algorithm/library used for comparing images. Currently, [`"pixelmatch"`](https://github.com/mapbox/pixelmatch) is the only supported comparator. * `comparatorOptions: object` These options allow changing the behavior of the comparator. What properties can be set depends on the chosen comparator algorithm. Vitest has set default values out of the box, but they can be overridden. * [`"pixelmatch"` options](#pixelmatch-comparator-options) ::: warning **Always explicitly set `comparatorName` to get proper type inference for `comparatorOptions`**. Without it, TypeScript won't know which options are valid: ```ts // ❌ TypeScript can't infer the correct options await expect.element(button).toMatchScreenshot({ comparatorOptions: { // might error when new comparators are added allowedMismatchedPixelRatio: 0.01, }, }) // ✅ TypeScript knows these are pixelmatch options await expect.element(button).toMatchScreenshot({ comparatorName: 'pixelmatch', comparatorOptions: { allowedMismatchedPixelRatio: 0.01, }, }) ``` ::: * `screenshotOptions: object` The same options allowed by [`locator.screenshot()`](/api/browser/locators.html#screenshot), except for: * `'base64'` * `'path'` * `'save'` * `'type'` * `timeout: number = 5_000` Time to wait until a stable screenshot is found. Setting this value to `0` disables the timeout, but if a stable screenshot can't be determined the process will not end. #### `"pixelmatch"` comparator options The following options are available when using the `"pixelmatch"` comparator: * `allowedMismatchedPixelRatio: number | undefined = undefined` The maximum allowed ratio of differing pixels between the captured screenshot and the reference image. Must be a value between `0` and `1`. For example, `allowedMismatchedPixelRatio: 0.02` means the test will pass if up to 2% of pixels differ, but fail if more than 2% differ. * `allowedMismatchedPixels: number | undefined = undefined` The maximum number of pixels that are allowed to differ between the captured screenshot and the stored reference image. If set to `undefined`, any non-zero difference will cause the test to fail. For example, `allowedMismatchedPixels: 10` means the test will pass if 10 or fewer pixels differ, but fail if 11 or more differ. * `threshold: number = 0.1` Acceptable perceived color difference between the same pixel in two images. Value ranges from `0` (strict) to `1` (very lenient). Lower values mean small differences will be detected. The comparison uses the [YIQ color space](https://en.wikipedia.org/wiki/YIQ). * `includeAA: boolean = false` If `true`, disables detection and ignoring of anti-aliased pixels. * `alpha: number = 0.1` Blending level of unchanged pixels in the diff image. Ranges from `0` (white) to `1` (original brightness). * `aaColor: [r: number, g: number, b: number] = [255, 255, 0]` Color used for anti-aliased pixels in the diff image. * `diffColor: [r: number, g: number, b: number] = [255, 0, 0]` Color used for differing pixels in the diff image. * `diffColorAlt: [r: number, g: number, b: number] | undefined = undefined` Optional alternative color for dark-on-light differences, to help show what's added vs. removed. If not set, `diffColor` is used for all differences. * `diffMask: boolean = false` If `true`, shows only the diff as a mask on a transparent background, instead of overlaying it on the original image. Anti-aliased pixels won't be shown (if detected). ::: warning When both `allowedMismatchedPixels` and `allowedMismatchedPixelRatio` are set, the more restrictive value is used. For example, if you allow 100 pixels or 2% ratio, and your image has 10,000 pixels, the effective limit would be 100 pixels instead of 200. ::: --- # Source: https://vitest.dev/config/attachmentsdir.md --- url: /config/attachmentsdir.md --- # attachmentsDir * **Type:** `string` * **Default:** `'.vitest-attachments'` Directory path for storing attachments created by [`context.annotate`](/guide/test-context#annotate) relative to the project root. --- # Source: https://vitest.dev/config/bail.md --- url: /config/bail.md --- # bail * **Type:** `number` * **Default:** `0` * **CLI**: `--bail=` Stop test execution when given number of tests have failed. By default Vitest will run all of your test cases even if some of them fail. This may not be desired for CI builds where you are only interested in 100% successful builds and would like to stop test execution as early as possible when test failures occur. The `bail` option can be used to speed up CI runs by preventing it from running more tests when failures have occurred. --- # Source: https://vitest.dev/config/benchmark.md --- url: /config/benchmark.md --- # benchmark {#benchmark} * **Type:** `{ include?, exclude?, ... }` Options used when running `vitest bench`. ## benchmark.include * **Type:** `string[]` * **Default:** `['**/*.{bench,benchmark}.?(c|m)[jt]s?(x)']` Include globs for benchmark test files ## benchmark.exclude * **Type:** `string[]` * **Default:** `['node_modules', 'dist', '.idea', '.git', '.cache']` Exclude globs for benchmark test files ## benchmark.includeSource * **Type:** `string[]` * **Default:** `[]` Include globs for in-source benchmark test files. This option is similar to [`includeSource`](#includesource). When defined, Vitest will run all matched files with `import.meta.vitest` inside. ## benchmark.reporters * **Type:** `Arrayable` * **Default:** `'default'` Custom reporter for output. Can contain one or more built-in report names, reporter instances, and/or paths to custom reporters. ## benchmark.outputFile Deprecated in favor of `benchmark.outputJson`. ## benchmark.outputJson {#benchmark-outputJson} * **Type:** `string | undefined` * **Default:** `undefined` A file path to store the benchmark result, which can be used for `--compare` option later. For example: ```sh # save main branch's result git checkout main vitest bench --outputJson main.json # change a branch and compare against main git checkout feature vitest bench --compare main.json ``` ## benchmark.compare {#benchmark-compare} * **Type:** `string | undefined` * **Default:** `undefined` A file path to a previous benchmark result to compare against current runs. --- # Source: https://vitest.dev/config/browser.md # Source: https://vitest.dev/guide/browser.md --- url: /guide/browser.md --- # Browser Mode {#browser-mode} This page provides information about the browser mode feature in the Vitest API, which allows you to run your tests in the browser natively, providing access to browser globals like window and document. ::: tip If you are looking for documentation for `expect`, `vi` or any general API like test projects or type testing, refer to the ["Getting Started" guide](/guide/). ::: ## Installation For easier setup, you can use `vitest init browser` command to install required dependencies and create browser configuration. ::: code-group ```bash [npm] npx vitest init browser ``` ```bash [yarn] yarn exec vitest init browser ``` ```bash [pnpm] pnpx vitest init browser ``` ```bash [bun] bunx vitest init browser ``` ::: ### Manual Installation You can also install packages manually. Vitest always requires a provider to be defined. You can chose either [`preview`](/config/browser/preview), [`playwright`](/config/browser/playwright) or [`webdriverio`](/config/browser/webdriverio). If you want to just preview how your tests look, you can use the `preview` provider: ::: code-group ```bash [npm] npm install -D vitest @vitest/browser-preview ``` ```bash [yarn] yarn add -D vitest @vitest/browser-preview ``` ```bash [pnpm] pnpm add -D vitest @vitest/browser-preview ``` ```bash [bun] bun add -D vitest @vitest/browser-preview ``` ::: ::: warning However, to run tests in CI you need to install either [`playwright`](https://npmjs.com/package/playwright) or [`webdriverio`](https://www.npmjs.com/package/webdriverio). We also recommend switching to either one of them for testing locally instead of using the default `preview` provider since it relies on simulating events instead of using Chrome DevTools Protocol. If you don't already use one of these tools, we recommend starting with Playwright because it supports parallel execution, which makes your tests run faster. ::: tabs key:provider \== Playwright [Playwright](https://npmjs.com/package/playwright) is a framework for Web Testing and Automation. ::: code-group ```bash [npm] npm install -D vitest @vitest/browser-playwright ``` ```bash [yarn] yarn add -D vitest @vitest/browser-playwright ``` ```bash [pnpm] pnpm add -D vitest @vitest/browser-playwright ``` ```bash [bun] bun add -D vitest @vitest/browser-playwright ``` \== WebdriverIO [WebdriverIO](https://www.npmjs.com/package/webdriverio) allows you to run tests locally using the WebDriver protocol. ::: code-group ```bash [npm] npm install -D vitest @vitest/browser-webdriverio ``` ```bash [yarn] yarn add -D vitest @vitest/browser-webdriverio ``` ```bash [pnpm] pnpm add -D vitest @vitest/browser-webdriverio ``` ```bash [bun] bun add -D vitest @vitest/browser-webdriverio ``` ::: ## Configuration To activate browser mode in your Vitest configuration, set the `browser.enabled` field to `true` in your Vitest configuration file. Here is an example configuration using the browser field: ```ts [vitest.config.ts] import { defineConfig } from 'vitest/config' import { playwright } from '@vitest/browser-playwright' export default defineConfig({ test: { browser: { provider: playwright(), enabled: true, // at least one instance is required instances: [ { browser: 'chromium' }, ], }, } }) ``` ::: info Vitest assigns port `63315` to avoid conflicts with the development server, allowing you to run both in parallel. You can change that with the [`browser.api`](/config/#browser-api) option. The CLI does not print the Vite server URL automatically. You can press "b" to print the URL when running in watch mode. ::: If you have not used Vite before, make sure you have your framework's plugin installed and specified in the config. Some frameworks might require extra configuration to work - check their Vite related documentation to be sure. ::: code-group ```ts [react] import { defineConfig } from 'vitest/config' import react from '@vitejs/plugin-react' import { playwright } from '@vitest/browser-playwright' export default defineConfig({ plugins: [react()], test: { browser: { enabled: true, provider: playwright(), instances: [ { browser: 'chromium' }, ], } } }) ``` ```ts [vue] import { defineConfig } from 'vitest/config' import { playwright } from '@vitest/browser-playwright' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], test: { browser: { enabled: true, provider: playwright(), instances: [ { browser: 'chromium' }, ], } } }) ``` ```ts [svelte] import { defineConfig } from 'vitest/config' import { svelte } from '@sveltejs/vite-plugin-svelte' import { playwright } from '@vitest/browser-playwright' export default defineConfig({ plugins: [svelte()], test: { browser: { enabled: true, provider: playwright(), instances: [ { browser: 'chromium' }, ], } } }) ``` ```ts [solid] import { defineConfig } from 'vitest/config' import solidPlugin from 'vite-plugin-solid' import { playwright } from '@vitest/browser-playwright' export default defineConfig({ plugins: [solidPlugin()], test: { browser: { enabled: true, provider: playwright(), instances: [ { browser: 'chromium' }, ], } } }) ``` ```ts [marko] import { defineConfig } from 'vitest/config' import marko from '@marko/vite' import { playwright } from '@vitest/browser-playwright' export default defineConfig({ plugins: [marko()], test: { browser: { enabled: true, provider: playwright(), instances: [ { browser: 'chromium' }, ], } } }) ``` ```ts [qwik] import { defineConfig } from 'vitest/config' import { qwikVite } from '@builder.io/qwik/optimizer' import { playwright } from '@vitest/browser-playwright' // optional, run the tests in SSR mode import { testSSR } from 'vitest-browser-qwik/ssr-plugin' export default defineConfig({ plugins: [testSSR(), qwikVite()], test: { browser: { enabled: true, provider: playwright(), instances: [{ browser: 'chromium' }] }, }, }) ``` ::: If you need to run some tests using Node-based runner, you can define a [`projects`](/guide/projects) option with separate configurations for different testing strategies: {#projects-config} ```ts [vitest.config.ts] import { defineConfig } from 'vitest/config' import { playwright } from '@vitest/browser-playwright' export default defineConfig({ test: { projects: [ { test: { // an example of file based convention, // you don't have to follow it include: [ 'tests/unit/**/*.{test,spec}.ts', 'tests/**/*.unit.{test,spec}.ts', ], name: 'unit', environment: 'node', }, }, { test: { // an example of file based convention, // you don't have to follow it include: [ 'tests/browser/**/*.{test,spec}.ts', 'tests/**/*.browser.{test,spec}.ts', ], name: 'browser', browser: { enabled: true, provider: playwright(), instances: [ { browser: 'chromium' }, ], }, }, }, ], }, }) ``` ## Browser Option Types The browser option in Vitest depends on the provider. Vitest will fail, if you pass `--browser` and don't specify its name in the config file. Available options: * `webdriverio` supports these browsers: * `firefox` * `chrome` * `edge` * `safari` * `playwright` supports these browsers: * `firefox` * `webkit` * `chromium` ## Browser Compatibility Vitest uses [Vite dev server](https://vitejs.dev/guide/#browser-support) to run your tests, so we only support features specified in the [`esbuild.target`](https://vitejs.dev/config/shared-options.html#esbuild) option (`esnext` by default). By default, Vite targets browsers which support the native [ES Modules](https://caniuse.com/es6-module), native [ESM dynamic import](https://caniuse.com/es6-module-dynamic-import), and [`import.meta`](https://caniuse.com/mdn-javascript_operators_import_meta). On top of that, we utilize [`BroadcastChannel`](https://caniuse.com/?search=BroadcastChannel) to communicate between iframes: * Chrome >=87 * Firefox >=78 * Safari >=15.4 * Edge >=88 ## Running Tests When you specify a browser name in the browser option, Vitest will try to run the specified browser using `preview` by default, and then run the tests there. If you don't want to use `preview`, you can configure the custom browser provider by using `browser.provider` option. To specify a browser using the CLI, use the `--browser` flag followed by the browser name, like this: ```sh npx vitest --browser=chromium ``` Or you can provide browser options to CLI with dot notation: ```sh npx vitest --browser.headless ``` ::: warning Since Vitest 3.2, if you don't have the `browser` option in your config but specify the `--browser` flag, Vitest will fail because it can't assume that config is meant for the browser and not Node.js tests. ::: By default, Vitest will automatically open the browser UI for development. Your tests will run inside an iframe in the center. You can configure the viewport by selecting the preferred dimensions, calling `page.viewport` inside the test, or setting default values in [the config](/config/#browser-viewport). ## Headless Headless mode is another option available in the browser mode. In headless mode, the browser runs in the background without a user interface, which makes it useful for running automated tests. The headless option in Vitest can be set to a boolean value to enable or disable headless mode. When using headless mode, Vitest won't open the UI automatically. If you want to continue using the UI but have tests run headlessly, you can install the [`@vitest/ui`](/guide/ui) package and pass the `--ui` flag when running Vitest. Here's an example configuration enabling headless mode: ```ts [vitest.config.ts] import { defineConfig } from 'vitest/config' import { playwright } from '@vitest/browser-playwright' export default defineConfig({ test: { browser: { provider: playwright(), enabled: true, headless: true, }, } }) ``` You can also set headless mode using the `--browser.headless` flag in the CLI, like this: ```sh npx vitest --browser.headless ``` In this case, Vitest will run in headless mode using the Chrome browser. ::: warning Headless mode is not available by default. You need to use either [`playwright`](https://npmjs.com/package/playwright) or [`webdriverio`](https://www.npmjs.com/package/webdriverio) providers to enable this feature. ::: ## Examples By default, you don't need any external packages to work with the Browser Mode: ```js [example.test.js] import { expect, test } from 'vitest' import { page } from 'vitest/browser' import { render } from './my-render-function.js' test('properly handles form inputs', async () => { render() // mount DOM elements // Asserts initial state. await expect.element(page.getByText('Hi, my name is Alice')).toBeInTheDocument() // Get the input DOM node by querying the associated label. const usernameInput = page.getByLabelText(/username/i) // Type the name into the input. This already validates that the input // is filled correctly, no need to check the value manually. await usernameInput.fill('Bob') await expect.element(page.getByText('Hi, my name is Bob')).toBeInTheDocument() }) ``` However, Vitest also provides packages to render components for several popular frameworks out of the box: * [`vitest-browser-vue`](https://github.com/vitest-dev/vitest-browser-vue) to render [vue](https://vuejs.org) components * [`vitest-browser-svelte`](https://github.com/vitest-dev/vitest-browser-svelte) to render [svelte](https://svelte.dev) components * [`vitest-browser-react`](https://github.com/vitest-dev/vitest-browser-react) to render [react](https://react.dev) components * [`vitest-browser-angular`](https://github.com/vitest-community/vitest-browser-angular) to render [Angular](https://angular.dev) components Community packages are available for other frameworks: * [`vitest-browser-lit`](https://github.com/EskiMojo14/vitest-browser-lit) to render [lit](https://lit.dev) components * [`vitest-browser-preact`](https://github.com/JoviDeCroock/vitest-browser-preact) to render [preact](https://preactjs.com) components * [`vitest-browser-qwik`](https://github.com/kunai-consulting/vitest-browser-qwik) to render [qwik](https://qwik.dev) components If your framework is not represented, feel free to create your own package - it is a simple wrapper around the framework renderer and `page.elementLocator` API. We will add a link to it on this page. Make sure it has a name starting with `vitest-browser-`. Besides rendering components and locating elements, you will also need to make assertions. Vitest forks the [`@testing-library/jest-dom`](https://github.com/testing-library/jest-dom) library to provide a wide range of DOM assertions out of the box. Read more at the [Assertions API](/api/browser/assertions). ```ts import { expect } from 'vitest' import { page } from 'vitest/browser' // element is rendered correctly await expect.element(page.getByText('Hello World')).toBeInTheDocument() ``` Vitest exposes a [Context API](/api/browser/context) with a small set of utilities that might be useful to you in tests. For example, if you need to make an interaction, like clicking an element or typing text into an input, you can use `userEvent` from `vitest/browser`. Read more at the [Interactivity API](/api/browser/interactivity). ```ts import { page, userEvent } from 'vitest/browser' await userEvent.fill(page.getByLabelText(/username/i), 'Alice') // or just locator.fill await page.getByLabelText(/username/i).fill('Alice') ``` ::: code-group ```ts [vue] import { render } from 'vitest-browser-vue' import Component from './Component.vue' test('properly handles v-model', async () => { const screen = render(Component) // Asserts initial state. await expect.element(screen.getByText('Hi, my name is Alice')).toBeInTheDocument() // Get the input DOM node by querying the associated label. const usernameInput = screen.getByLabelText(/username/i) // Type the name into the input. This already validates that the input // is filled correctly, no need to check the value manually. await usernameInput.fill('Bob') await expect.element(screen.getByText('Hi, my name is Bob')).toBeInTheDocument() }) ``` ```ts [svelte] import { render } from 'vitest-browser-svelte' import { expect, test } from 'vitest' import Greeter from './greeter.svelte' test('greeting appears on click', async () => { const screen = render(Greeter, { name: 'World' }) const button = screen.getByRole('button') await button.click() const greeting = screen.getByText(/hello world/iu) await expect.element(greeting).toBeInTheDocument() }) ``` ```tsx [react] import { render } from 'vitest-browser-react' import Fetch from './fetch' test('loads and displays greeting', async () => { // Render a React element into the DOM const screen = render() await screen.getByText('Load Greeting').click() // wait before throwing an error if it cannot find an element const heading = screen.getByRole('heading') // assert that the alert message is correct await expect.element(heading).toHaveTextContent('hello there') await expect.element(screen.getByRole('button')).toBeDisabled() }) ``` ```ts [lit] import { render } from 'vitest-browser-lit' import { html } from 'lit' import './greeter-button' test('greeting appears on click', async () => { const screen = render(html``) const button = screen.getByRole('button') await button.click() const greeting = screen.getByText(/hello world/iu) await expect.element(greeting).toBeInTheDocument() }) ``` ```tsx [preact] import { render } from 'vitest-browser-preact' import { createElement } from 'preact' import Greeting from '.Greeting' test('greeting appears on click', async () => { const screen = render() const button = screen.getByRole('button') await button.click() const greeting = screen.getByText(/hello world/iu) await expect.element(greeting).toBeInTheDocument() }) ``` ```tsx [qwik] import { render } from 'vitest-browser-qwik' import Greeting from './greeting' test('greeting appears on click', async () => { // renderSSR and renderHook are also available const screen = render() const button = screen.getByRole('button') await button.click() const greeting = screen.getByText(/hello world/iu) await expect.element(greeting).toBeInTheDocument() }) ``` ::: Vitest doesn't support all frameworks out of the box, but you can use external tools to run tests with these frameworks. We also encourage the community to create their own `vitest-browser` wrappers - if you have one, feel free to add it to the examples above. For unsupported frameworks, we recommend using `testing-library` packages: * [`@solidjs/testing-library`](https://testing-library.com/docs/solid-testing-library/intro) to render [solid](https://www.solidjs.com) components * [`@marko/testing-library`](https://testing-library.com/docs/marko-testing-library/intro) to render [marko](https://markojs.com) components You can also see more examples in [`browser-examples`](https://github.com/vitest-tests/browser-examples) repository. ::: warning `testing-library` provides a package `@testing-library/user-event`. We do not recommend using it directly because it simulates events instead of actually triggering them - instead, use [`userEvent`](/api/browser/interactivity) imported from `vitest/browser` that uses Chrome DevTools Protocol or Webdriver (depending on the provider) under the hood. ::: ::: code-group ```tsx [solid] // based on @testing-library/solid API // https://testing-library.com/docs/solid-testing-library/api import { render } from '@testing-library/solid' it('uses params', async () => { const App = () => ( <> (

Id: {useParams()?.id}

)} />

Start

} /> ) const { baseElement } = render(() => , { location: 'ids/1234' }) const screen = page.elementLocator(baseElement) await expect.screen(screen.getByText('Id: 1234')).toBeInTheDocument() }) ``` ```ts [marko] // based on @testing-library/marko API // https://testing-library.com/docs/marko-testing-library/api import { render, screen } from '@marko/testing-library' import Greeting from './greeting.marko' test('renders a message', async () => { const { baseElement } = await render(Greeting, { name: 'Marko' }) const screen = page.elementLocator(baseElement) await expect.element(screen.getByText(/Marko/)).toBeInTheDocument() expect(container.firstChild).toMatchInlineSnapshot(`

Hello, Marko!

`) }) ``` ::: ## Limitations ### Thread Blocking Dialogs When using Vitest Browser, it's important to note that thread blocking dialogs like `alert` or `confirm` cannot be used natively. This is because they block the web page, which means Vitest cannot continue communicating with the page, causing the execution to hang. In such situations, Vitest provides default mocks with default returned values for these APIs. This ensures that if the user accidentally uses synchronous popup web APIs, the execution would not hang. However, it's still recommended for the user to mock these web APIs for a better experience. Read more in [Mocking](/guide/mocking). ### Spying on Module Exports Browser Mode uses the browser's native ESM support to serve modules. The module namespace object is sealed and can't be reconfigured, unlike in Node.js tests where Vitest can patch the Module Runner. This means you can't call `vi.spyOn` on an imported object: ```ts import { vi } from 'vitest' import * as module from './module.js' vi.spyOn(module, 'method') // ❌ throws an error ``` To bypass this limitation, Vitest supports `{ spy: true }` option in `vi.mock('./module.js')`. This will automatically spy on every export in the module without replacing them with fake ones. ```ts import { vi } from 'vitest' import * as module from './module.js' vi.mock('./module.js', { spy: true }) vi.mocked(module.method).mockImplementation(() => { // ... }) ``` However, the only way to mock exported *variables* is to export a method that will change the internal value: ::: code-group ```js [module.js] export let MODE = 'test' export function changeMode(newMode) { MODE = newMode } ``` ```js [module.test.ts] import { expect } from 'vitest' import { changeMode, MODE } from './module.js' changeMode('production') expect(MODE).toBe('production') ``` ::: --- # Source: https://vitest.dev/config/cache.md --- url: /config/cache.md --- # cache * **Type**: `false` * **CLI**: `--no-cache`, `--cache=false` Use this option if you want to disable the cache feature. At the moment Vitest stores cache for test results to run the longer and failed tests first. The cache directory is controlled by the Vite's [`cacheDir`](https://vitejs.dev/config/shared-options.html#cachedir) option: ```ts import { defineConfig } from 'vitest/config' export default defineConfig({ cacheDir: 'custom-folder/.vitest' }) ``` You can limit the directory only for Vitest by using `process.env.VITEST`: ```ts import { defineConfig } from 'vitest/config' export default defineConfig({ cacheDir: process.env.VITEST ? 'custom-folder/.vitest' : undefined }) ``` --- # Source: https://vitest.dev/config/chaiconfig.md --- url: /config/chaiconfig.md --- # chaiConfig * **Type:** `{ includeStack?, showDiff?, truncateThreshold? }` * **Default:** `{ includeStack: false, showDiff: true, truncateThreshold: 40 }` Equivalent to [Chai config](https://github.com/chaijs/chai/blob/4.x.x/lib/chai/config.js). ## chaiConfig.includeStack * **Type:** `boolean` * **Default:** `false` Influences whether stack trace is included in Assertion error message. Default of false suppresses stack trace in the error message. ## chaiConfig.showDiff * **Type:** `boolean` * **Default:** `true` Influences whether or not the `showDiff` flag should be included in the thrown AssertionErrors. `false` will always be `false`; `true` will be true when the assertion has requested a diff to be shown. ## chaiConfig.truncateThreshold * **Type:** `number` * **Default:** `40` Sets length threshold for actual and expected values in assertion errors. If this threshold is exceeded, for example for large data structures, the value is replaced with something like `[ Array(3) ]` or `{ Object (prop1, prop2) }`. Set it to `0` if you want to disable truncating altogether. This config option affects truncating values in `test.each` titles and inside the assertion error message. --- # Source: https://vitest.dev/guide/mocking/classes.md --- url: /guide/mocking/classes.md --- # Mocking Classes You can mock an entire class with a single [`vi.fn`](/api/vi#fn) call. ```ts class Dog { name: string constructor(name: string) { this.name = name } static getType(): string { return 'animal' } greet = (): string => { return `Hi! My name is ${this.name}!` } speak(): string { return 'bark!' } isHungry() {} feed() {} } ``` We can re-create this class with `vi.fn` (or `vi.spyOn().mockImplementation()`): ```ts const Dog = vi.fn(class { static getType = vi.fn(() => 'mocked animal') constructor(name) { this.name = name } greet = vi.fn(() => `Hi! My name is ${this.name}!`) speak = vi.fn(() => 'loud bark!') feed = vi.fn() }) ``` ::: warning If a non-primitive is returned from the constructor function, that value will become the result of the new expression. In this case the `[[Prototype]]` may not be correctly bound: ```ts const CorrectDogClass = vi.fn(function (name) { this.name = name }) const IncorrectDogClass = vi.fn(name => ({ name })) const Marti = new CorrectDogClass('Marti') const Newt = new IncorrectDogClass('Newt') Marti instanceof CorrectDogClass // ✅ true Newt instanceof IncorrectDogClass // ❌ false! ``` If you are mocking classes, prefer the class syntax over the function. ::: ::: tip WHEN TO USE? Generally speaking, you would re-create a class like this inside the module factory if the class is re-exported from another module: ```ts import { Dog } from './dog.js' vi.mock(import('./dog.js'), () => { const Dog = vi.fn(class { feed = vi.fn() // ... other mocks }) return { Dog } }) ``` This method can also be used to pass an instance of a class to a function that accepts the same interface: ```ts [src/feed.ts] function feed(dog: Dog) { // ... } ``` ```ts [tests/dog.test.ts] import { expect, test, vi } from 'vitest' import { feed } from '../src/feed.js' const Dog = vi.fn(class { feed = vi.fn() }) test('can feed dogs', () => { const dogMax = new Dog('Max') feed(dogMax) expect(dogMax.feed).toHaveBeenCalled() expect(dogMax.isHungry()).toBe(false) }) ``` ::: Now, when we create a new instance of the `Dog` class its `speak` method (alongside `feed` and `greet`) is already mocked: ```ts const Cooper = new Dog('Cooper') Cooper.speak() // loud bark! Cooper.greet() // Hi! My name is Cooper! // you can use built-in assertions to check the validity of the call expect(Cooper.speak).toHaveBeenCalled() expect(Cooper.greet).toHaveBeenCalled() const Max = new Dog('Max') // methods are not shared between instances if you assigned them directly expect(Max.speak).not.toHaveBeenCalled() expect(Max.greet).not.toHaveBeenCalled() ``` We can reassign the return value for a specific instance: ```ts const dog = new Dog('Cooper') // "vi.mocked" is a type helper, since // TypeScript doesn't know that Dog is a mocked class, // it wraps any function in a Mock type // without validating if the function is a mock vi.mocked(dog.speak).mockReturnValue('woof woof') dog.speak() // woof woof ``` To mock the property, we can use the `vi.spyOn(dog, 'name', 'get')` method. This makes it possible to use spy assertions on the mocked property: ```ts const dog = new Dog('Cooper') const nameSpy = vi.spyOn(dog, 'name', 'get').mockReturnValue('Max') expect(dog.name).toBe('Max') expect(nameSpy).toHaveBeenCalledTimes(1) ``` ::: tip You can also spy on getters and setters using the same method. ::: ::: danger Using classes with `vi.fn()` was introduced in Vitest 4. Previously, you had to use `function` and `prototype` inheritence directly. See [v3 guide](https://v3.vitest.dev/guide/mocking.html#classes). ::: --- # Source: https://vitest.dev/config/clearmocks.md --- url: /config/clearmocks.md --- # clearMocks * **Type:** `boolean` * **Default:** `false` Should Vitest automatically call [`vi.clearAllMocks()`](/api/vi#vi-clearallmocks) before each test. This will clear mock history without affecting mock implementations. ```js [vitest.config.js] import { defineConfig } from 'vitest/config' export default defineConfig({ test: { clearMocks: true, }, }) ``` --- # Source: https://vitest.dev/guide/cli.md --- url: /guide/cli.md --- # Command Line Interface ## Commands ### `vitest` Start Vitest in the current directory. Will enter the watch mode in development environment and run mode in CI (or non-interactive terminal) automatically. You can pass an additional argument as the filter of the test files to run. For example: ```bash vitest foobar ``` Will run only the test file that contains `foobar` in their paths. This filter only checks inclusion and doesn't support regexp or glob patterns (unless your terminal processes it before Vitest receives the filter). Since Vitest 3, you can also specify the test by filename and line number: ```bash $ vitest basic/foo.test.ts:10 ``` ::: warning Note that Vitest requires the full filename for this feature to work. It can be relative to the current working directory or an absolute file path. ```bash $ vitest basic/foo.js:10 # ✅ $ vitest ./basic/foo.js:10 # ✅ $ vitest /users/project/basic/foo.js:10 # ✅ $ vitest foo:10 # ❌ $ vitest ./basic/foo:10 # ❌ ``` At the moment Vitest also doesn't support ranges: ```bash $ vitest basic/foo.test.ts:10, basic/foo.test.ts:25 # ✅ $ vitest basic/foo.test.ts:10-25 # ❌ ``` ::: ### `vitest run` Perform a single run without watch mode. ### `vitest watch` Run all test suites but watch for changes and rerun tests when they change. Same as calling `vitest` without an argument. Will fallback to `vitest run` in CI or when stdin is not a TTY (non-interactive environment). ### `vitest dev` Alias to `vitest watch`. ### `vitest related` Run only tests that cover a list of source files. Works with static imports (e.g., `import('./index.js')` or `import index from './index.js`), but not the dynamic ones (e.g., `import(filepath)`). All files should be relative to root folder. Useful to run with [`lint-staged`](https://github.com/okonet/lint-staged) or with your CI setup. ```bash vitest related /src/index.ts /src/hello-world.js ``` ::: tip Don't forget that Vitest runs with enabled watch mode by default. If you are using tools like `lint-staged`, you should also pass `--run` option, so that command can exit normally. ```js [.lintstagedrc.js] export default { '*.{js,ts}': 'vitest related --run', } ``` ::: ### `vitest bench` Run only [benchmark](/guide/features.html#benchmarking) tests, which compare performance results. ### `vitest init` `vitest init ` can be used to setup project configuration. At the moment, it only supports [`browser`](/guide/browser/) value: ```bash vitest init browser ``` ### `vitest list` `vitest list` command inherits all `vitest` options to print the list of all matching tests. This command ignores `reporters` option. By default, it will print the names of all tests that matched the file filter and name pattern: ```shell vitest list filename.spec.ts -t="some-test" ``` ```txt describe > some-test describe > some-test > test 1 describe > some-test > test 2 ``` You can pass down `--json` flag to print tests in JSON format or save it in a separate file: ```bash vitest list filename.spec.ts -t="some-test" --json=./file.json ``` If `--json` flag doesn't receive a value, it will output the JSON into stdout. You also can pass down `--filesOnly` flag to print the test files only: ```bash vitest list --filesOnly ``` ```txt tests/test1.test.ts tests/test2.test.ts ``` ## Options ::: tip Vitest supports both camel case and kebab case for CLI arguments. For example, `--passWithNoTests` and `--pass-with-no-tests` will both work (`--no-color` and `--inspect-brk` are the exceptions). Vitest also supports different ways of specifying the value: `--reporter dot` and `--reporter=dot` are both valid. If option supports an array of values, you need to pass the option multiple times: ``` vitest --reporter=dot --reporter=default ``` Boolean options can be negated with `no-` prefix. Specifying the value as `false` also works: ``` vitest --no-api vitest --api=false ``` ::: ### root * **CLI:** `-r, --root ` * **Config:** [root](/config/root) Root path ### config * **CLI:** `-c, --config ` Path to config file ### update * **CLI:** `-u, --update` * **Config:** [update](/config/update) Update snapshot ### watch * **CLI:** `-w, --watch` * **Config:** [watch](/config/watch) Enable watch mode ### testNamePattern * **CLI:** `-t, --testNamePattern ` * **Config:** [testNamePattern](/config/testnamepattern) Run tests with full names matching the specified regexp pattern ### dir * **CLI:** `--dir ` * **Config:** [dir](/config/dir) Base directory to scan for the test files ### ui * **CLI:** `--ui` Enable UI ### open * **CLI:** `--open` * **Config:** [open](/config/open) Open UI automatically (default: `!process.env.CI`) ### api.port * **CLI:** `--api.port [port]` Specify server port. Note if the port is already being used, Vite will automatically try the next available port so this may not be the actual port the server ends up listening on. If true will be set to `51204` ### api.host * **CLI:** `--api.host [host]` Specify which IP addresses the server should listen on. Set this to `0.0.0.0` or `true` to listen on all addresses, including LAN and public addresses ### api.strictPort * **CLI:** `--api.strictPort` Set to true to exit if port is already in use, instead of automatically trying the next available port ### silent * **CLI:** `--silent [value]` * **Config:** [silent](/config/silent) Silent console output from tests. Use `'passed-only'` to see logs from failing tests only. ### hideSkippedTests * **CLI:** `--hideSkippedTests` Hide logs for skipped tests ### reporters * **CLI:** `--reporter ` * **Config:** [reporters](/config/reporters) Specify reporters (default, blob, verbose, dot, json, tap, tap-flat, junit, tree, hanging-process, github-actions) ### outputFile * **CLI:** `--outputFile ` * **Config:** [outputFile](/config/outputfile) Write test results to a file when supporter reporter is also specified, use cac's dot notation for individual outputs of multiple reporters (example: `--outputFile.tap=./tap.txt`) ### coverage.provider * **CLI:** `--coverage.provider ` * **Config:** [coverage.provider](/config/coverage#coverage-provider) Select the tool for coverage collection, available values are: "v8", "istanbul" and "custom" ### coverage.enabled * **CLI:** `--coverage.enabled` * **Config:** [coverage.enabled](/config/coverage#coverage-enabled) Enables coverage collection. Can be overridden using the `--coverage` CLI option (default: `false`) ### coverage.include * **CLI:** `--coverage.include ` * **Config:** [coverage.include](/config/coverage#coverage-include) Files included in coverage as glob patterns. May be specified more than once when using multiple patterns. By default only files covered by tests are included. ### coverage.exclude * **CLI:** `--coverage.exclude ` * **Config:** [coverage.exclude](/config/coverage#coverage-exclude) Files to be excluded in coverage. May be specified more than once when using multiple extensions. ### coverage.clean * **CLI:** `--coverage.clean` * **Config:** [coverage.clean](/config/coverage#coverage-clean) Clean coverage results before running tests (default: true) ### coverage.cleanOnRerun * **CLI:** `--coverage.cleanOnRerun` * **Config:** [coverage.cleanOnRerun](/config/coverage#coverage-cleanonrerun) Clean coverage report on watch rerun (default: true) ### coverage.reportsDirectory * **CLI:** `--coverage.reportsDirectory ` * **Config:** [coverage.reportsDirectory](/config/coverage#coverage-reportsdirectory) Directory to write coverage report to (default: ./coverage) ### coverage.reporter * **CLI:** `--coverage.reporter ` * **Config:** [coverage.reporter](/config/coverage#coverage-reporter) Coverage reporters to use. Visit [`coverage.reporter`](/config/#coverage-reporter) for more information (default: `["text", "html", "clover", "json"]`) ### coverage.reportOnFailure * **CLI:** `--coverage.reportOnFailure` * **Config:** [coverage.reportOnFailure](/config/coverage#coverage-reportonfailure) Generate coverage report even when tests fail (default: `false`) ### coverage.allowExternal * **CLI:** `--coverage.allowExternal` * **Config:** [coverage.allowExternal](/config/coverage#coverage-allowexternal) Collect coverage of files outside the project root (default: `false`) ### coverage.skipFull * **CLI:** `--coverage.skipFull` * **Config:** [coverage.skipFull](/config/coverage#coverage-skipfull) Do not show files with 100% statement, branch, and function coverage (default: `false`) ### coverage.thresholds.100 * **CLI:** `--coverage.thresholds.100` * **Config:** [coverage.thresholds.100](/config/coverage#coverage-thresholds-100) Shortcut to set all coverage thresholds to 100 (default: `false`) ### coverage.thresholds.perFile * **CLI:** `--coverage.thresholds.perFile` * **Config:** [coverage.thresholds.perFile](/config/coverage#coverage-thresholds-perfile) Check thresholds per file. See `--coverage.thresholds.lines`, `--coverage.thresholds.functions`, `--coverage.thresholds.branches` and `--coverage.thresholds.statements` for the actual thresholds (default: `false`) ### coverage.thresholds.autoUpdate * **CLI:** `--coverage.thresholds.autoUpdate ` * **Config:** [coverage.thresholds.autoUpdate](/config/coverage#coverage-thresholds-autoupdate) Update threshold values: "lines", "functions", "branches" and "statements" to configuration file when current coverage is above the configured thresholds (default: `false`) ### coverage.thresholds.lines * **CLI:** `--coverage.thresholds.lines ` Threshold for lines. Visit [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) for more information. This option is not available for custom providers ### coverage.thresholds.functions * **CLI:** `--coverage.thresholds.functions ` Threshold for functions. Visit [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) for more information. This option is not available for custom providers ### coverage.thresholds.branches * **CLI:** `--coverage.thresholds.branches ` Threshold for branches. Visit [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) for more information. This option is not available for custom providers ### coverage.thresholds.statements * **CLI:** `--coverage.thresholds.statements ` Threshold for statements. Visit [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) for more information. This option is not available for custom providers ### coverage.ignoreClassMethods * **CLI:** `--coverage.ignoreClassMethods ` * **Config:** [coverage.ignoreClassMethods](/config/coverage#coverage-ignoreclassmethods) Array of class method names to ignore for coverage. Visit [istanbuljs](https://github.com/istanbuljs/nyc#ignoring-methods) for more information. This option is only available for the istanbul providers (default: `[]`) ### coverage.processingConcurrency * **CLI:** `--coverage.processingConcurrency ` * **Config:** [coverage.processingConcurrency](/config/coverage#coverage-processingconcurrency) Concurrency limit used when processing the coverage results. (default min between 20 and the number of CPUs) ### coverage.customProviderModule * **CLI:** `--coverage.customProviderModule ` * **Config:** [coverage.customProviderModule](/config/coverage#coverage-customprovidermodule) Specifies the module name or path for the custom coverage provider module. Visit [Custom Coverage Provider](/guide/coverage#custom-coverage-provider) for more information. This option is only available for custom providers ### coverage.watermarks.statements * **CLI:** `--coverage.watermarks.statements ` High and low watermarks for statements in the format of `,` ### coverage.watermarks.lines * **CLI:** `--coverage.watermarks.lines ` High and low watermarks for lines in the format of `,` ### coverage.watermarks.branches * **CLI:** `--coverage.watermarks.branches ` High and low watermarks for branches in the format of `,` ### coverage.watermarks.functions * **CLI:** `--coverage.watermarks.functions ` High and low watermarks for functions in the format of `,` ### mode * **CLI:** `--mode ` * **Config:** [mode](/config/mode) Override Vite mode (default: `test` or `benchmark`) ### isolate * **CLI:** `--isolate` * **Config:** [isolate](/config/isolate) Run every test file in isolation. To disable isolation, use `--no-isolate` (default: `true`) ### globals * **CLI:** `--globals` * **Config:** [globals](/config/globals) Inject apis globally ### dom * **CLI:** `--dom` Mock browser API with happy-dom ### browser.enabled * **CLI:** `--browser.enabled` * **Config:** [browser.enabled](/config/browser/enabled) Run tests in the browser. Equivalent to `--browser.enabled` (default: `false`) ### browser.name * **CLI:** `--browser.name ` Run all tests in a specific browser. Some browsers are only available for specific providers (see `--browser.provider`). ### browser.headless * **CLI:** `--browser.headless` * **Config:** [browser.headless](/config/browser/headless) Run the browser in headless mode (i.e. without opening the GUI (Graphical User Interface)). If you are running Vitest in CI, it will be enabled by default (default: `process.env.CI`) ### browser.api.port * **CLI:** `--browser.api.port [port]` * **Config:** [browser.api.port](/config/browser/api#api-port) Specify server port. Note if the port is already being used, Vite will automatically try the next available port so this may not be the actual port the server ends up listening on. If true will be set to `63315` ### browser.api.host * **CLI:** `--browser.api.host [host]` * **Config:** [browser.api.host](/config/browser/api#api-host) Specify which IP addresses the server should listen on. Set this to `0.0.0.0` or `true` to listen on all addresses, including LAN and public addresses ### browser.api.strictPort * **CLI:** `--browser.api.strictPort` * **Config:** [browser.api.strictPort](/config/browser/api#api-strictport) Set to true to exit if port is already in use, instead of automatically trying the next available port ### browser.isolate * **CLI:** `--browser.isolate` * **Config:** [browser.isolate](/config/browser/isolate) Run every browser test file in isolation. To disable isolation, use `--browser.isolate=false` (default: `true`) ### browser.ui * **CLI:** `--browser.ui` * **Config:** [browser.ui](/config/browser/ui) Show Vitest UI when running tests (default: `!process.env.CI`) ### browser.fileParallelism * **CLI:** `--browser.fileParallelism` Should browser test files run in parallel. Use `--browser.fileParallelism=false` to disable (default: `true`) ### browser.connectTimeout * **CLI:** `--browser.connectTimeout ` * **Config:** [browser.connectTimeout](/config/browser/connecttimeout) If connection to the browser takes longer, the test suite will fail (default: `60_000`) ### browser.trackUnhandledErrors * **CLI:** `--browser.trackUnhandledErrors` * **Config:** [browser.trackUnhandledErrors](/config/browser/trackunhandlederrors) Control if Vitest catches uncaught exceptions so they can be reported (default: `true`) ### browser.trace * **CLI:** `--browser.trace ` * **Config:** [browser.trace](/config/browser/trace) Enable trace view mode. Supported: "on", "off", "on-first-retry", "on-all-retries", "retain-on-failure". ### pool * **CLI:** `--pool ` * **Config:** [pool](/config/pool) Specify pool, if not running in the browser (default: `forks`) ### execArgv * **CLI:** `--execArgv
}> ) // Initially working await expect.element(getByText('Component working fine')).toBeInTheDocument() // Trigger error rerender( Something went wrong
}> ) // Error boundary should catch it await expect.element(getByText('Something went wrong')).toBeInTheDocument() }) ``` ### Testing Accessibility ```tsx test('Modal component is accessible', async () => { const { getByRole, getByLabelText } = render( ) // Test focus management - modal should receive focus when opened // This is crucial for screen reader users to know a modal opened const modal = getByRole('dialog') await expect.element(modal).toHaveFocus() // Test ARIA attributes - these provide semantic information to screen readers await expect.element(modal).toHaveAttribute('aria-labelledby') // Links to title element await expect.element(modal).toHaveAttribute('aria-modal', 'true') // Indicates modal behavior // Test keyboard navigation - Escape key should close modal // This is required by ARIA authoring practices await userEvent.keyboard('{Escape}') // expect.element auto-retries until modal is removed await expect.element(modal).not.toBeInTheDocument() // Test focus trap - tab navigation should cycle within modal // This prevents users from tabbing to content behind the modal const firstInput = getByLabelText(/username/i) const lastButton = getByRole('button', { name: /save/i }) // Use click to focus on the first input, then test tab navigation await firstInput.click() await userEvent.keyboard('{Shift>}{Tab}{/Shift}') // Shift+Tab goes backwards await expect.element(lastButton).toHaveFocus() // Should wrap to last element }) ``` ## Debugging Component Tests ### 1. Use Browser Dev Tools Browser Mode runs tests in real browsers, giving you access to full developer tools. When tests fail, you can: * **Open browser dev tools** during test execution (F12 or right-click → Inspect) * **Set breakpoints** in your test code or component code * **Inspect the DOM** to see the actual rendered output * **Check console errors** for JavaScript errors or warnings * **Monitor network requests** to debug API calls For headful mode debugging, add `headless: false` to your browser config temporarily. ### 2. Add Debug Statements Use strategic logging to understand test failures: ```tsx test('debug form validation', async () => { render() const submitButton = page.getByRole('button', { name: /submit/i }) await submitButton.click() // Debug: Check if element exists with different query const errorElement = page.getByText('Email is required') console.log('Error element found:', errorElement.length) await expect.element(errorElement).toBeInTheDocument() }) ``` ### 3. Inspect Rendered Output When components don't render as expected, investigate systematically: **Use Vitest's browser UI:** * Run tests with browser mode enabled * Open the browser URL shown in the terminal to see tests running * Visual inspection helps identify CSS issues, layout problems, or missing elements **Test element queries:** ```tsx // Debug why elements can't be found const button = page.getByRole('button', { name: /submit/i }) console.log('Button count:', button.length) // Should be 1 // Try alternative queries if the first one fails if (button.length === 0) { console.log('All buttons:', page.getByRole('button').length) console.log('By test ID:', page.getByTestId('submit-btn').length) } ``` ### 4. Verify Selectors Selector issues are common causes of test failures. Debug them systematically: **Check accessible names:** ```tsx // If getByRole fails, check what roles/names are available const buttons = page.getByRole('button').all() for (const button of buttons) { // Use element() to get the DOM element and access native properties const element = button.element() const accessibleName = element.getAttribute('aria-label') || element.textContent console.log(`Button: "${accessibleName}"`) } ``` **Test different query strategies:** ```tsx // Multiple ways to find the same element using .or for auto-retrying const submitButton = page.getByRole('button', { name: /submit/i }) // By accessible name .or(page.getByTestId('submit-button')) // By test ID .or(page.getByText('Submit')) // By exact text // Note: Vitest doesn't have page.locator(), use specific getBy* methods instead ``` **Common selector debugging patterns:** ```tsx test('debug element queries', async () => { render() // Check if element is visible and enabled const emailInput = page.getByLabelText(/email/i) await expect.element(emailInput).toBeVisible() // Will show if element is visible and print DOM if not }) ``` ### 5. Debugging Async Issues Component tests often involve timing issues: ```tsx test('debug async component behavior', async () => { render() // expect.element will automatically retry and show helpful error messages await expect.element(page.getByText('John Doe')).toBeInTheDocument() }) ``` ## Migration from Other Testing Frameworks ### From Jest + Testing Library Most Jest + Testing Library tests work with minimal changes: ```ts // Before (Jest) import { render, screen } from '@testing-library/react' // [!code --] // After (Vitest) import { render } from 'vitest-browser-react' // [!code ++] ``` ### Key Differences * Use `await expect.element()` instead of `expect()` for DOM assertions * Use `vitest/browser` for user interactions instead of `@testing-library/user-event` * Browser Mode provides real browser environment for accurate testing ## Learn More * [Browser Mode Documentation](/guide/browser/) * [Assertion API](/api/browser/assertions) * [Interactivity API](/api/browser/interactivity) * [Example Repository](https://github.com/vitest-tests/browser-examples) --- # Source: https://vitest.dev/config.md --- url: /config.md --- # Configuring Vitest If you are using Vite and have a `vite.config` file, Vitest will read it to match with the plugins and setup as your Vite app. If you want to have a different configuration for testing or your main app doesn't rely on Vite specifically, you could either: * Create `vitest.config.ts`, which will have the higher priority and will **override** the configuration from `vite.config.ts` (Vitest supports all conventional JS and TS extensions, but doesn't support `json`) - it means all options in your `vite.config` will be **ignored** * Pass `--config` option to CLI, e.g. `vitest --config ./path/to/vitest.config.ts` * Use `process.env.VITEST` or `mode` property on `defineConfig` (will be set to `test`/`benchmark` if not overridden with `--mode`) to conditionally apply different configuration in `vite.config.ts`. Note that like any other environment variable, `VITEST` is also exposed on `import.meta.env` in your tests To configure `vitest` itself, add `test` property in your Vite config. You'll also need to add a reference to Vitest types using a [triple slash command](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html#-reference-types-) at the top of your config file, if you are importing `defineConfig` from `vite` itself. If you are not using `vite`, add `defineConfig` imported from `vitest/config` to your config file: ```js [vitest.config.js] import { defineConfig } from 'vitest/config' export default defineConfig({ test: { // ... Specify options here. }, }) ``` If you have a `vite` config already, you can add `/// ` to include the `test` types: ```js [vite.config.js] /// import { defineConfig } from 'vite' export default defineConfig({ test: { // ... Specify options here. }, }) ``` You can retrieve Vitest's default options to expand them if needed: ```js [vitest.config.js] import { configDefaults, defineConfig } from 'vitest/config' export default defineConfig({ test: { exclude: [...configDefaults.exclude, 'packages/template/*'], }, }) ``` When using a separate `vitest.config.js`, you can also extend Vite's options from another config file if needed: ```js [vitest.config.js] import { defineConfig, mergeConfig } from 'vitest/config' import viteConfig from './vite.config' export default mergeConfig(viteConfig, defineConfig({ test: { exclude: ['packages/template/*'], }, })) ``` If your Vite config is defined as a function, you can define the config like this: ```js [vitest.config.js] import { defineConfig, mergeConfig } from 'vitest/config' import viteConfig from './vite.config' export default defineConfig(configEnv => mergeConfig( viteConfig(configEnv), defineConfig({ test: { exclude: ['packages/template/*'], }, }) )) ``` Since Vitest uses Vite config, you can also use any configuration option from [Vite](https://vitejs.dev/config/). For example, `define` to define global variables, or `resolve.alias` to define aliases - these options should be defined on the top level, *not* within a `test` property. Configuration options that are not supported inside a [project](/guide/projects) config have icon next to them. This means they can only be set in the root Vitest config. --- # Source: https://vitest.dev/config/browser/connecttimeout.md --- url: /config/browser/connecttimeout.md --- # browser.connectTimeout * **Type:** `number` * **Default:** `60_000` The timeout in milliseconds. If connection to the browser takes longer, the test suite will fail. ::: info This is the time it should take for the browser to establish the WebSocket connection with the Vitest server. In normal circumstances, this timeout should never be reached. ::: --- # Source: https://vitest.dev/api/browser/context.md --- url: /api/browser/context.md --- # Context API Vitest exposes a context module via `vitest/browser` entry point. As of 2.0, it exposes a small set of utilities that might be useful to you in tests. ## `userEvent` ::: tip The `userEvent` API is explained in detail at [Interactivity API](/api/browser/interactivity). ::: ```ts /** * Handler for user interactions. The support is implemented by the browser provider (`playwright` or `webdriverio`). * If used with `preview` provider, fallbacks to simulated events via `@testing-library/user-event`. * @experimental */ export const userEvent: { setup: () => UserEvent cleanup: () => Promise click: (element: Element, options?: UserEventClickOptions) => Promise dblClick: (element: Element, options?: UserEventDoubleClickOptions) => Promise tripleClick: (element: Element, options?: UserEventTripleClickOptions) => Promise selectOptions: ( element: Element, values: HTMLElement | HTMLElement[] | string | string[], options?: UserEventSelectOptions, ) => Promise keyboard: (text: string) => Promise type: (element: Element, text: string, options?: UserEventTypeOptions) => Promise clear: (element: Element) => Promise tab: (options?: UserEventTabOptions) => Promise hover: (element: Element, options?: UserEventHoverOptions) => Promise unhover: (element: Element, options?: UserEventHoverOptions) => Promise fill: (element: Element, text: string, options?: UserEventFillOptions) => Promise dragAndDrop: (source: Element, target: Element, options?: UserEventDragAndDropOptions) => Promise } ``` ## `commands` ::: tip This API is explained in detail at [Commands API](/api/browser/commands). ::: ```ts /** * Available commands for the browser. * A shortcut to `server.commands`. */ export const commands: BrowserCommands ``` ## `page` The `page` export provides utilities to interact with the current `page`. ::: warning While it exposes some utilities from Playwright's `page`, it is not the same object. Since the browser context is evaluated in the browser, your tests don't have access to Playwright's `page` because it runs on the server. Use [Commands API](/api/browser/commands) if you need to have access to Playwright's `page` object. ::: ```ts export const page: { /** * Change the size of iframe's viewport. */ viewport(width: number, height: number): Promise /** * Make a screenshot of the test iframe or a specific element. * @returns Path to the screenshot file or path and base64. */ screenshot(options: Omit & { base64: true }): Promise<{ path: string base64: string }> screenshot(options?: ScreenshotOptions): Promise /** * Extend default `page` object with custom methods. */ extend(methods: Partial): BrowserPage /** * Wrap an HTML element in a `Locator`. When querying for elements, the search will always return this element. */ elementLocator(element: Element): Locator /** * The iframe locator. This is a document locator that enters the iframe body * and works similarly to the `page` object. * **Warning:** At the moment, this is supported only by the `playwright` provider. */ frameLocator(iframeElement: Locator): FrameLocator /** * Locator APIs. See its documentation for more details. */ getByRole(role: ARIARole | string, options?: LocatorByRoleOptions): Locator getByLabelText(text: string | RegExp, options?: LocatorOptions): Locator getByTestId(text: string | RegExp): Locator getByAltText(text: string | RegExp, options?: LocatorOptions): Locator getByPlaceholder(text: string | RegExp, options?: LocatorOptions): Locator getByText(text: string | RegExp, options?: LocatorOptions): Locator getByTitle(text: string | RegExp, options?: LocatorOptions): Locator } ``` ::: tip The `getBy*` API is explained at [Locators API](/api/browser/locators). ::: ::: warning WARNING 3.2.0 Note that `screenshot` will always return a base64 string if `save` is set to `false`. The `path` is also ignored in that case. ::: ### frameLocator ```ts function frameLocator(iframeElement: Locator): FrameLocator ``` The `frameLocator` method returns a `FrameLocator` instance that can be used to find elements inside the iframe. The frame locator is similar to `page`. It does not refer to the Iframe HTML element, but to the iframe's document. ```ts const frame = page.frameLocator( page.getByTestId('iframe') ) await frame.getByText('Hello World').click() // ✅ await frame.click() // ❌ Not available ``` ::: danger IMPORTANT At the moment, the `frameLocator` method is only supported by the `playwright` provider. The interactive methods (like `click` or `fill`) are always available on elements within the iframe, but assertions with `expect.element` require the iframe to have the [same-origin policy](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy). ::: ## `cdp` ```ts function cdp(): CDPSession ``` The `cdp` export returns the current Chrome DevTools Protocol session. It is mostly useful to library authors to build tools on top of it. ::: warning CDP session works only with `playwright` provider and only when using `chromium` browser. You can read more about it in playwright's [`CDPSession`](https://playwright.dev/docs/api/class-cdpsession) documentation. ::: ```ts export const cdp: () => CDPSession ``` ## `server` The `server` export represents the Node.js environment where the Vitest server is running. It is mostly useful for debugging or limiting your tests based on the environment. ```ts export const server: { /** * Platform the Vitest server is running on. * The same as calling `process.platform` on the server. */ platform: Platform /** * Runtime version of the Vitest server. * The same as calling `process.version` on the server. */ version: string /** * Name of the browser provider. */ provider: string /** * Name of the current browser. */ browser: string /** * Available commands for the browser. */ commands: BrowserCommands /** * Serialized test config. */ config: SerializedConfig } ``` ## `utils` Utility functions useful for custom render libraries. ```ts export const utils: { /** * This is simillar to calling `page.elementLocator`, but it returns only * locator selectors. */ getElementLocatorSelectors(element: Element): LocatorSelectors /** * Prints prettified HTML of an element. */ debug( el?: Element | Locator | null | (Element | Locator)[], maxLength?: number, options?: PrettyDOMOptions, ): void /** * Returns prettified HTML of an element. */ prettyDOM( dom?: Element | Locator | undefined | null, maxLength?: number, prettyFormatOptions?: PrettyDOMOptions, ): string /** * Configures default options of `prettyDOM` and `debug` functions. * This will also affect `vitest-browser-{framework}` package. * @experimental */ configurePrettyDOM(options: StringifyOptions): void /** * Creates "Cannot find element" error. Useful for custom locators. */ getElementError(selector: string, container?: Element): Error } ``` --- # Source: https://vitest.dev/guide/coverage.md # Source: https://vitest.dev/config/coverage.md --- url: /config/coverage.md --- # coverage {#coverage} You can use [`v8`](/guide/coverage.html#v8-provider), [`istanbul`](/guide/coverage.html#istanbul-provider) or [a custom coverage solution](/guide/coverage#custom-coverage-provider) for coverage collection. You can provide coverage options to CLI with dot notation: ```sh npx vitest --coverage.enabled --coverage.provider=istanbul ``` ::: warning If you are using coverage options with dot notation, don't forget to specify `--coverage.enabled`. Do not provide a single `--coverage` option in that case. ::: ## coverage.provider * **Type:** `'v8' | 'istanbul' | 'custom'` * **Default:** `'v8'` * **CLI:** `--coverage.provider=` Use `provider` to select the tool for coverage collection. ## coverage.enabled * **Type:** `boolean` * **Default:** `false` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.enabled`, `--coverage.enabled=false` Enables coverage collection. Can be overridden using `--coverage` CLI option. ## coverage.include * **Type:** `string[]` * **Default:** Files that were imported during test run * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.include=`, `--coverage.include= --coverage.include=` List of files included in coverage as glob patterns. By default only files covered by tests are included. It is recommended to pass file extensions in the pattern. See [Including and excluding files from coverage report](/guide/coverage.html#including-and-excluding-files-from-coverage-report) for examples. ## coverage.exclude * **Type:** `string[]` * **Default:** : `[]` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.exclude=`, `--coverage.exclude= --coverage.exclude=` List of files excluded from coverage as glob patterns. See [Including and excluding files from coverage report](/guide/coverage.html#including-and-excluding-files-from-coverage-report) for examples. ## coverage.clean * **Type:** `boolean` * **Default:** `true` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.clean`, `--coverage.clean=false` Clean coverage results before running tests ## coverage.cleanOnRerun * **Type:** `boolean` * **Default:** `true` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.cleanOnRerun`, `--coverage.cleanOnRerun=false` Clean coverage report on watch rerun. Set to `false` to preserve coverage results from previous run in watch mode. ## coverage.reportsDirectory * **Type:** `string` * **Default:** `'./coverage'` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.reportsDirectory=` ::: warning Vitest will delete this directory before running tests if `coverage.clean` is enabled (default value). ::: Directory to write coverage report to. To preview the coverage report in the output of [HTML reporter](/guide/reporters.html#html-reporter), this option must be set as a sub-directory of the html report directory (for example `./html/coverage`). ## coverage.reporter * **Type:** `string | string[] | [string, {}][]` * **Default:** `['text', 'html', 'clover', 'json']` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.reporter=`, `--coverage.reporter= --coverage.reporter=` Coverage reporters to use. See [istanbul documentation](https://istanbul.js.org/docs/advanced/alternative-reporters/) for detailed list of all reporters. See [`@types/istanbul-reporter`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/276d95e4304b3670eaf6e8e5a7ea9e265a14e338/types/istanbul-reports/index.d.ts) for details about reporter specific options. The reporter has three different types: * A single reporter: `{ reporter: 'html' }` * Multiple reporters without options: `{ reporter: ['html', 'json'] }` * A single or multiple reporters with reporter options: ```ts { reporter: [ ['lcov', { 'projectRoot': './src' }], ['json', { 'file': 'coverage.json' }], ['text'] ] } ``` You can also pass custom coverage reporters. See [Guide - Custom Coverage Reporter](/guide/coverage#custom-coverage-reporter) for more information. ```ts { reporter: [ // Specify reporter using name of the NPM package '@vitest/custom-coverage-reporter', ['@vitest/custom-coverage-reporter', { someOption: true }], // Specify reporter using local path '/absolute/path/to/custom-reporter.cjs', ['/absolute/path/to/custom-reporter.cjs', { someOption: true }], ] } ``` You can check your coverage report in Vitest UI: check [Vitest UI Coverage](/guide/coverage#vitest-ui) for more details. ## coverage.reportOnFailure {#coverage-reportonfailure} * **Type:** `boolean` * **Default:** `false` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.reportOnFailure`, `--coverage.reportOnFailure=false` Generate coverage report even when tests fail. ## coverage.allowExternal * **Type:** `boolean` * **Default:** `false` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.allowExternal`, `--coverage.allowExternal=false` Collect coverage of files outside the [project `root`](#root). ## coverage.excludeAfterRemap * **Type:** `boolean` * **Default:** `false` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.excludeAfterRemap`, `--coverage.excludeAfterRemap=false` Apply exclusions again after coverage has been remapped to original sources. This is useful when your source files are transpiled and may contain source maps of non-source files. Use this option when you are seeing files that show up in report even if they match your `coverage.exclude` patterns. ## coverage.skipFull * **Type:** `boolean` * **Default:** `false` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.skipFull`, `--coverage.skipFull=false` Do not show files with 100% statement, branch, and function coverage. ## coverage.thresholds Options for coverage thresholds. If a threshold is set to a positive number, it will be interpreted as the minimum percentage of coverage required. For example, setting the lines threshold to `90` means that 90% of lines must be covered. If a threshold is set to a negative number, it will be treated as the maximum number of uncovered items allowed. For example, setting the lines threshold to `-10` means that no more than 10 lines may be uncovered. ```ts { coverage: { thresholds: { // Requires 90% function coverage functions: 90, // Require that no more than 10 lines are uncovered lines: -10, } } } ``` ### coverage.thresholds.lines * **Type:** `number` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.thresholds.lines=` Global threshold for lines. ### coverage.thresholds.functions * **Type:** `number` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.thresholds.functions=` Global threshold for functions. ### coverage.thresholds.branches * **Type:** `number` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.thresholds.branches=` Global threshold for branches. ### coverage.thresholds.statements * **Type:** `number` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.thresholds.statements=` Global threshold for statements. ### coverage.thresholds.perFile * **Type:** `boolean` * **Default:** `false` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.thresholds.perFile`, `--coverage.thresholds.perFile=false` Check thresholds per file. ### coverage.thresholds.autoUpdate * **Type:** `boolean | function` * **Default:** `false` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.thresholds.autoUpdate=` Update all threshold values `lines`, `functions`, `branches` and `statements` to configuration file when current coverage is better than the configured thresholds. This option helps to maintain thresholds when coverage is improved. You can also pass a function for formatting the updated threshold values: ```ts { coverage: { thresholds: { // Update thresholds without decimals autoUpdate: (newThreshold) => Math.floor(newThreshold), // 95.85 -> 95 functions: 95, } } } ``` ### coverage.thresholds.100 * **Type:** `boolean` * **Default:** `false` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.thresholds.100`, `--coverage.thresholds.100=false` Sets global thresholds to 100. Shortcut for `--coverage.thresholds.lines 100 --coverage.thresholds.functions 100 --coverage.thresholds.branches 100 --coverage.thresholds.statements 100`. ### coverage.thresholds\[glob-pattern] * **Type:** `{ statements?: number functions?: number branches?: number lines?: number }` * **Default:** `undefined` * **Available for providers:** `'v8' | 'istanbul'` Sets thresholds for files matching the glob pattern. ::: tip NOTE Vitest counts all files, including those covered by glob-patterns, into the global coverage thresholds. This is different from Jest behavior. ::: ```ts { coverage: { thresholds: { // Thresholds for all files functions: 95, branches: 70, // Thresholds for matching glob pattern 'src/utils/**.ts': { statements: 95, functions: 90, branches: 85, lines: 80, }, // Files matching this pattern will only have lines thresholds set. // Global thresholds are not inherited. '**/math.ts': { lines: 100, } } } } ``` ### coverage.thresholds\[glob-pattern].100 * **Type:** `boolean` * **Default:** `false` * **Available for providers:** `'v8' | 'istanbul'` Sets thresholds to 100 for files matching the glob pattern. ```ts { coverage: { thresholds: { // Thresholds for all files functions: 95, branches: 70, // Thresholds for matching glob pattern 'src/utils/**.ts': { 100: true }, '**/math.ts': { 100: true } } } } ``` ## coverage.ignoreClassMethods * **Type:** `string[]` * **Default:** `[]` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.ignoreClassMethods=` Set to array of class method names to ignore for coverage. See [istanbul documentation](https://github.com/istanbuljs/nyc#ignoring-methods) for more information. ## coverage.watermarks * **Type:** ```ts { statements?: [number, number], functions?: [number, number], branches?: [number, number], lines?: [number, number] } ``` * **Default:** ```ts { statements: [50, 80], functions: [50, 80], branches: [50, 80], lines: [50, 80] } ``` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.watermarks.statements=50,80`, `--coverage.watermarks.branches=50,80` Watermarks for statements, lines, branches and functions. See [istanbul documentation](https://github.com/istanbuljs/nyc#high-and-low-watermarks) for more information. ## coverage.processingConcurrency * **Type:** `boolean` * **Default:** `Math.min(20, os.availableParallelism?.() ?? os.cpus().length)` * **Available for providers:** `'v8' | 'istanbul'` * **CLI:** `--coverage.processingConcurrency=` Concurrency limit used when processing the coverage results. ## coverage.customProviderModule * **Type:** `string` * **Available for providers:** `'custom'` * **CLI:** `--coverage.customProviderModule=` Specifies the module name or path for the custom coverage provider module. See [Guide - Custom Coverage Provider](/guide/coverage#custom-coverage-provider) for more information. --- # Source: https://vitest.dev/config/css.md --- url: /config/css.md --- # css * **Type**: `boolean | { include?, exclude?, modules? }` Configure if CSS should be processed. When excluded, CSS files will be replaced with empty strings to bypass the subsequent processing. CSS Modules will return a proxy to not affect runtime. ::: warning This option is not applied to [browser tests](/guide/browser/). ::: ## css.include * **Type**: `RegExp | RegExp[]` * **Default**: `[]` RegExp pattern for files that should return actual CSS and will be processed by Vite pipeline. :::tip To process all CSS files, use `/.+/`. ::: ## css.exclude * **Type**: `RegExp | RegExp[]` * **Default**: `[]` RegExp pattern for files that will return an empty CSS file. ## css.modules * **Type**: `{ classNameStrategy? }` * **Default**: `{}` ### css.modules.classNameStrategy * **Type**: `'stable' | 'scoped' | 'non-scoped'` * **Default**: `'stable'` If you decide to process CSS files, you can configure if class names inside CSS modules should be scoped. You can choose one of the options: * `stable`: class names will be generated as `_${name}_${hashedFilename}`, which means that generated class will stay the same, if CSS content is changed, but will change, if the name of the file is modified, or file is moved to another folder. This setting is useful, if you use snapshot feature. * `scoped`: class names will be generated as usual, respecting `css.modules.generateScopedName` method, if you have one and CSS processing is enabled. By default, filename will be generated as `_${name}_${hash}`, where hash includes filename and content of the file. * `non-scoped`: class names will not be hashed. ::: warning By default, Vitest exports a proxy, bypassing CSS Modules processing. If you rely on CSS properties on your classes, you have to enable CSS processing using `include` option. ::: --- # Source: https://vitest.dev/config/dangerouslyignoreunhandlederrors.md --- url: /config/dangerouslyignoreunhandlederrors.md --- # dangerouslyIgnoreUnhandledErrors * **Type**: `boolean` * **Default**: `false` * **CLI:** * `--dangerouslyIgnoreUnhandledErrors` * `--dangerouslyIgnoreUnhandledErrors=false` If this option is set to `true`, Vitest will not fail the test run if there are unhandled errors. Note that built-in reporters will still report them. If you want to filter out certain errors conditionally, use [`onUnhandledError`](/config/onunhandlederror) callback instead. ## Example ```js [vitest.config.js] import { defineConfig } from 'vitest/config' export default defineConfig({ test: { dangerouslyIgnoreUnhandledErrors: true, }, }) ``` --- # Source: https://vitest.dev/guide/mocking/dates.md --- url: /guide/mocking/dates.md --- # Mocking Dates Sometimes you need to be in control of the date to ensure consistency when testing. Vitest uses [`@sinonjs/fake-timers`](https://github.com/sinonjs/fake-timers) package for manipulating timers, as well as system date. You can find more about the specific API in detail [here](/api/vi#vi-setsystemtime). ## Example ```js import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' const businessHours = [9, 17] function purchase() { const currentHour = new Date().getHours() const [open, close] = businessHours if (currentHour > open && currentHour < close) { return { message: 'Success' } } return { message: 'Error' } } describe('purchasing flow', () => { beforeEach(() => { // tell vitest we use mocked time vi.useFakeTimers() }) afterEach(() => { // restoring date after each test run vi.useRealTimers() }) it('allows purchases within business hours', () => { // set hour within business hours const date = new Date(2000, 1, 1, 13) vi.setSystemTime(date) // access Date.now() will result in the date set above expect(purchase()).toEqual({ message: 'Success' }) }) it('disallows purchases outside of business hours', () => { // set hour outside business hours const date = new Date(2000, 1, 1, 19) vi.setSystemTime(date) // access Date.now() will result in the date set above expect(purchase()).toEqual({ message: 'Error' }) }) }) ``` --- # Source: https://vitest.dev/guide/debugging.md --- url: /guide/debugging.md --- # Debugging :::tip When debugging tests you might want to use following options: * [`--test-timeout=0`](/guide/cli#testtimeout) to prevent tests from timing out when stopping at breakpoints * [`--no-file-parallelism`](/guide/cli#fileparallelism) to prevent test files from running parallel ::: ## VS Code Quick way to debug tests in VS Code is via `JavaScript Debug Terminal`. Open a new `JavaScript Debug Terminal` and run `npm run test` or `vitest` directly. *this works with any code run in Node, so will work with most JS testing frameworks* ![image](https://user-images.githubusercontent.com/5594348/212169143-72bf39ce-f763-48f5-822a-0c8b2e6a8484.png) You can also add a dedicated launch configuration to debug a test file in VS Code: ```json { // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Debug Current Test File", "autoAttachChildProcesses": true, "skipFiles": ["/**", "**/node_modules/**"], "program": "${workspaceRoot}/node_modules/vitest/vitest.mjs", "args": ["run", "${relativeFile}"], "smartStep": true, "console": "integratedTerminal" } ] } ``` Then in the debug tab, ensure 'Debug Current Test File' is selected. You can then open the test file you want to debug and press F5 to start debugging. ### Browser mode To debug [Vitest Browser Mode](/guide/browser/index.md), pass `--inspect` or `--inspect-brk` in CLI or define it in your Vitest configuration: ::: code-group ```bash [CLI] vitest --inspect-brk --browser --no-file-parallelism ``` ```ts [vitest.config.js] import { defineConfig } from 'vitest/config' import { playwright } from '@vitest/browser-playwright' export default defineConfig({ test: { inspectBrk: true, fileParallelism: false, browser: { provider: playwright(), instances: [{ browser: 'chromium' }] }, }, }) ``` ::: By default Vitest will use port `9229` as debugging port. You can overwrite it with by passing value in `--inspect-brk`: ```bash vitest --inspect-brk=127.0.0.1:3000 --browser --no-file-parallelism ``` Use following [VSCode Compound configuration](https://code.visualstudio.com/docs/editor/debugging#_compound-launch-configurations) for launching Vitest and attaching debugger in the browser: ```json { "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Run Vitest Browser", "program": "${workspaceRoot}/node_modules/vitest/vitest.mjs", "console": "integratedTerminal", "args": ["--inspect-brk", "--browser", "--no-file-parallelism"] }, { "type": "chrome", "request": "attach", "name": "Attach to Vitest Browser", "port": 9229 } ], "compounds": [ { "name": "Debug Vitest Browser", "configurations": ["Attach to Vitest Browser", "Run Vitest Browser"], "stopAll": true } ] } ``` ## IntelliJ IDEA Create a [vitest](https://www.jetbrains.com/help/idea/vitest.html#createRunConfigVitest) run configuration. Use the following settings to run all tests in debug mode: Setting | Value \--- | --- Working directory | `/path/to/your-project-root` Then run this configuration in debug mode. The IDE will stop at JS/TS breakpoints set in the editor. ## Node Inspector, e.g. Chrome DevTools Vitest also supports debugging tests without IDEs. However this requires that tests are not run parallel. Use one of the following commands to launch Vitest. ```sh # To run in a single worker vitest --inspect-brk --no-file-parallelism # To run in browser mode vitest --inspect-brk --browser --no-file-parallelism ``` Once Vitest starts it will stop execution and wait for you to open developer tools that can connect to [Node.js inspector](https://nodejs.org/en/docs/guides/debugging-getting-started/). You can use Chrome DevTools for this by opening `chrome://inspect` on browser. In watch mode you can keep the debugger open during test re-runs by using the `--isolate false` options. --- # Source: https://vitest.dev/config/deps.md --- url: /config/deps.md --- # deps * **Type:** `{ optimizer?, ... }` Handling for dependencies resolution. ## deps.optimizer {#deps-optimizer} * **Type:** `{ ssr?, client? }` * **See also:** [Dep Optimization Options](https://vitejs.dev/config/dep-optimization-options.html) Enable dependency optimization. If you have a lot of tests, this might improve their performance. When Vitest encounters the external library listed in `include`, it will be bundled into a single file using esbuild and imported as a whole module. This is good for several reasons: * Importing packages with a lot of imports is expensive. By bundling them into one file we can save a lot of time * Importing UI libraries is expensive because they are not meant to run inside Node.js * Your `alias` configuration is now respected inside bundled packages * Code in your tests is running closer to how it's running in the browser Be aware that only packages in `deps.optimizer?.[mode].include` option are bundled (some plugins populate this automatically, like Svelte). You can read more about available options in [Vite](https://vitejs.dev/config/dep-optimization-options.html) docs (Vitest doesn't support `disable` and `noDiscovery` options). By default, Vitest uses `optimizer.client` for `jsdom` and `happy-dom` environments, and `optimizer.ssr` for `node` and `edge` environments. This options also inherits your `optimizeDeps` configuration (for web Vitest will extend `optimizeDeps`, for ssr - `ssr.optimizeDeps`). If you redefine `include`/`exclude` option in `deps.optimizer` it will extend your `optimizeDeps` when running tests. Vitest automatically removes the same options from `include`, if they are listed in `exclude`. ::: tip You will not be able to edit your `node_modules` code for debugging, since the code is actually located in your `cacheDir` or `test.cache.dir` directory. If you want to debug with `console.log` statements, edit it directly or force rebundling with `deps.optimizer?.[mode].force` option. ::: ### deps.optimizer.{mode}.enabled * **Type:** `boolean` * **Default:** `false` Enable dependency optimization. ## deps.client {#deps-client} * **Type:** `{ transformAssets?, ... }` Options that are applied to external files when the environment is set to `client`. By default, `jsdom` and `happy-dom` use `client` environment, while `node` and `edge` environments use `ssr`, so these options will have no affect on files inside those environments. Usually, files inside `node_modules` are externalized, but these options also affect files in [`server.deps.external`](#server-deps-external). ### deps.client.transformAssets * **Type:** `boolean` * **Default:** `true` Should Vitest process assets (.png, .svg, .jpg, etc) files and resolve them like Vite does in the browser. This module will have a default export equal to the path to the asset, if no query is specified. ::: warning At the moment, this option only works with [`vmThreads`](#vmthreads) and [`vmForks`](#vmforks) pools. ::: ### deps.client.transformCss * **Type:** `boolean` * **Default:** `true` Should Vitest process CSS (.css, .scss, .sass, etc) files and resolve them like Vite does in the browser. If CSS files are disabled with [`css`](#css) options, this option will just silence `ERR_UNKNOWN_FILE_EXTENSION` errors. ::: warning At the moment, this option only works with [`vmThreads`](#vmthreads) and [`vmForks`](#vmforks) pools. ::: ### deps.client.transformGlobPattern * **Type:** `RegExp | RegExp[]` * **Default:** `[]` Regexp pattern to match external files that should be transformed. By default, files inside `node_modules` are externalized and not transformed, unless it's CSS or an asset, and corresponding option is not disabled. ::: warning At the moment, this option only works with [`vmThreads`](#vmthreads) and [`vmForks`](#vmforks) pools. ::: ## deps.interopDefault * **Type:** `boolean` * **Default:** `true` Interpret CJS module's default as named exports. Some dependencies only bundle CJS modules and don't use named exports that Node.js can statically analyze when a package is imported using `import` syntax instead of `require`. When importing such dependencies in Node environment using named exports, you will see this error: ``` import { read } from 'fs-jetpack'; ^^^^ SyntaxError: Named export 'read' not found. The requested module 'fs-jetpack' is a CommonJS module, which may not support all module.exports as named exports. CommonJS modules can always be imported via the default export. ``` Vitest doesn't do static analysis, and cannot fail before your running code, so you will most likely see this error when running tests, if this feature is disabled: ``` TypeError: createAsyncThunk is not a function TypeError: default is not a function ``` By default, Vitest assumes you are using a bundler to bypass this and will not fail, but you can disable this behaviour manually, if your code is not processed. ## deps.moduleDirectories * **Type:** `string[]` * **Default**: `['node_modules']` A list of directories that should be treated as module directories. This config option affects the behavior of [`vi.mock`](/api/vi#vi-mock): when no factory is provided and the path of what you are mocking matches one of the `moduleDirectories` values, Vitest will try to resolve the mock by looking for a `__mocks__` folder in the [root](#root) of the project. This option will also affect if a file should be treated as a module when externalizing dependencies. By default, Vitest imports external modules with native Node.js bypassing Vite transformation step. Setting this option will *override* the default, if you wish to still search `node_modules` for packages include it along with any other options: ```ts import { defineConfig } from 'vitest/config' export default defineConfig({ test: { deps: { moduleDirectories: ['node_modules', path.resolve('../../packages')], } }, }) ``` --- # Source: https://vitest.dev/config/diff.md --- url: /config/diff.md --- # diff * **Type:** `string` * **CLI:** `--diff=` `DiffOptions` object or a path to a module which exports `DiffOptions`. Useful if you want to customize diff display. For example, as a config object: ```ts import { defineConfig } from 'vitest/config' import c from 'picocolors' export default defineConfig({ test: { diff: { aIndicator: c.bold('--'), bIndicator: c.bold('++'), omitAnnotationLines: true, }, }, }) ``` Or as a module: :::code-group ```ts [vitest.config.js] import { defineConfig } from 'vitest/config' export default defineConfig({ test: { diff: './vitest.diff.ts', }, }) ``` ```ts [vitest.diff.ts] import type { DiffOptions } from 'vitest' import c from 'picocolors' export default { aIndicator: c.bold('--'), bIndicator: c.bold('++'), omitAnnotationLines: true, } satisfies DiffOptions ``` ::: ## diff.expand * **Type**: `boolean` * **Default**: `true` * **CLI:** `--diff.expand=false` Expand all common lines. ## diff.truncateThreshold * **Type**: `number` * **Default**: `0` * **CLI:** `--diff.truncateThreshold=` The maximum length of diff result to be displayed. Diffs above this threshold will be truncated. Truncation won't take effect with default value 0. ## diff.truncateAnnotation * **Type**: `string` * **Default**: `'... Diff result is truncated'` * **CLI:** `--diff.truncateAnnotation=` Annotation that is output at the end of diff result if it's truncated. ## diff.truncateAnnotationColor * **Type**: `DiffOptionsColor = (arg: string) => string` * **Default**: `noColor = (string: string): string => string` Color of truncate annotation, default is output with no color. ## diff.printBasicPrototype * **Type**: `boolean` * **Default**: `false` Print basic prototype `Object` and `Array` in diff output ## diff.maxDepth * **Type**: `number` * **Default**: `20` (or `8` when comparing different types) Limit the depth to recurse when printing nested objects --- # Source: https://vitest.dev/config/dir.md --- url: /config/dir.md --- # dir * **Type:** `string` * **CLI:** `--dir=` * **Default:** same as `root` Base directory to scan for the test files. You can specify this option to speed up test discovery if your root covers the whole project --- # Source: https://vitest.dev/config/disableconsoleintercept.md --- url: /config/disableconsoleintercept.md --- # disableConsoleIntercept * **Type:** `boolean` * **CLI:** `--disableConsoleIntercept` * **Default:** `false` By default, Vitest automatically intercepts console logging during tests for extra formatting of test file, test title, etc. This is also required for console log preview on Vitest UI. However, disabling such interception might help when you want to debug a code with normal synchronous terminal console logging. ::: warning This option has no effect on [browser tests](/guide/browser/) since Vitest preserves original logging in browser devtools. ::: --- # Source: https://vitest.dev/config/browser/enabled.md --- url: /config/browser/enabled.md --- # browser.enabled * **Type:** `boolean` * **Default:** `false` * **CLI:** `--browser`, `--browser.enabled=false` Enabling this flag makes Vitest run all tests in a [browser](/guide/browser/) by default. If you are configuring other browser options via the CLI, you can use `--browser.enabled` alongside them instead of `--browser`: ```sh vitest --browser.enabled --browser.headless ``` ::: warning To enable [Browser Mode](/guide/browser/), you must also specify the [`provider`](/config/browser/provider) and at least one [`instance`](/config/browser/instances). Available providers: * [playwright](/config/browser/playwright) * [webdriverio](/config/browser/webdriverio) * [preview](/config/browser/preview) ::: ## Example ```js{7} [vitest.config.js] import { defineConfig } from 'vitest/config' import { playwright } from '@vitest/browser-playwright' export default defineConfig({ test: { browser: { enabled: true, provider: playwright(), instances: [ { browser: 'chromium' }, ], }, }, }) ``` If you use TypeScript, the `browser` field in `instances` provides autocompletion based on your provider. --- # Source: https://vitest.dev/config/env.md --- url: /config/env.md --- # env * **Type:** `Partial` Environment variables available on `process.env` and `import.meta.env` during tests. These variables will not be available in the main process (in `globalSetup`, for example). --- # Source: https://vitest.dev/guide/environment.md # Source: https://vitest.dev/config/environment.md --- url: /config/environment.md --- # environment * **Type:** `'node' | 'jsdom' | 'happy-dom' | 'edge-runtime' | string` * **Default:** `'node'` * **CLI:** `--environment=` The environment that will be used for testing. The default environment in Vitest is a Node.js environment. If you are building a web application, you can use browser-like environment through either [`jsdom`](https://github.com/jsdom/jsdom) or [`happy-dom`](https://github.com/capricorn86/happy-dom) instead. If you are building edge functions, you can use [`edge-runtime`](https://edge-runtime.vercel.app/packages/vm) environment ::: tip You can also use [Browser Mode](/guide/browser/) to run integration or unit tests in the browser without mocking the environment. ::: To define custom options for your environment, use [`environmentOptions`](/config/environmentoptions). By adding a `@vitest-environment` docblock or comment at the top of the file, you can specify another environment to be used for all tests in that file: Docblock style: ```js /** * @vitest-environment jsdom */ test('use jsdom in this test file', () => { const element = document.createElement('div') expect(element).not.toBeNull() }) ``` Comment style: ```js // @vitest-environment happy-dom test('use happy-dom in this test file', () => { const element = document.createElement('div') expect(element).not.toBeNull() }) ``` For compatibility with Jest, there is also a `@jest-environment`: ```js /** * @jest-environment jsdom */ test('use jsdom in this test file', () => { const element = document.createElement('div') expect(element).not.toBeNull() }) ``` You can also define a custom environment. When non-builtin environment is used, Vitest will try to load the file if it's relative or absolute, or a package `vitest-environment-${name}`, if the name is a bare specifier. The custom environment file should export an object with the shape of `Environment`: ```ts [environment.js] import type { Environment } from 'vitest' export default { name: 'custom', viteEnvironment: 'ssr', setup() { // custom setup return { teardown() { // called after all tests with this env have been run } } } } ``` ::: tip The `viteEnvironment` field corresponde to the environment defined by the [Vite Environment API](https://vite.dev/guide/api-environment#environment-api). By default, Vite exposes `client` (for the browser) and `ssr` (for the server) environments. ::: Vitest also exposes `builtinEnvironments` through `vitest/environments` entry, in case you just want to extend it. You can read more about extending environments in [our guide](/guide/environment). ::: tip jsdom environment exposes `jsdom` global variable equal to the current [JSDOM](https://github.com/jsdom/jsdom) instance. If you want TypeScript to recognize it, you can add `vitest/jsdom` to your `tsconfig.json` when you use this environment: ```json [tsconfig.json] { "compilerOptions": { "types": ["vitest/jsdom"] } } ``` ::: --- # Source: https://vitest.dev/config/environmentoptions.md --- url: /config/environmentoptions.md --- # environmentOptions * **Type:** `Record<'jsdom' | 'happyDOM' | string, unknown>` * **Default:** `{}` These options are passed to the setup method of the current [environment](/config/environment). By default, you can configure options only for `jsdom` and `happyDOM` when you use them as your test environment. ## Example ```js [vitest.config.js] import { defineConfig } from 'vitest/config' export default defineConfig({ test: { environmentOptions: { jsdom: { url: 'http://localhost:3000', }, happyDOM: { width: 300, height: 400, }, }, }, }) ``` ::: warning Options are scoped to their environment. For example, put jsdom options under the `jsdom` key and happy-dom options under the `happyDOM` key. This lets you mix multiple environments within the same project. ::: --- # Source: https://vitest.dev/config/exclude.md --- url: /config/exclude.md --- # exclude * **Type:** `string[]` * **Default:** `['**/node_modules/**', '**/.git/**']` * **CLI:** `vitest --exclude "**/excluded-file" --exclude "*/other-files/*.js"` A list of [glob patterns](https://superchupu.dev/tinyglobby/comparison) that should be excluded from your test files. These patterns are resolved relative to the [`root`](/config/root) ([`process.cwd()`](https://nodejs.org/api/process.html#processcwd) by default). Vitest uses the [`tinyglobby`](https://www.npmjs.com/package/tinyglobby) package to resolve the globs. ::: warning This option does not affect coverage. If you need to remove certain files from the coverage report, use [`coverage.exclude`](/config/coverage#exclude). This is the only option that doesn't override your configuration if you provide it with a CLI flag. All glob patterns added via `--exclude` flag will be added to the config's `exclude`. ::: ## Example ```js import { defineConfig } from 'vitest/config' export default defineConfig({ test: { exclude: [ '**/node_modules/**', '**/dist/**', './temp/**', ], }, }) ``` ::: tip Although the CLI `exclude` option is additive, manually setting `exclude` in your config will replace the default value. To extend the default `exclude` patterns, use `configDefaults` from `vitest/config`: ```js{6} import { configDefaults, defineConfig } from 'vitest/config' export default defineConfig({ test: { exclude: [ ...configDefaults.exclude, 'packages/template/*', './temp/**', ], }, }) ``` ::: --- # Source: https://vitest.dev/config/execargv.md --- url: /config/execargv.md --- # execArgv * **Type:** `string[]` * **Default:** `[]` Pass additional arguments to `node` in the runner worker. See [Command-line API | Node.js](https://nodejs.org/docs/latest/api/cli.html) for more information. :::warning Be careful when using, it as some options may crash worker, e.g. `--prof`, `--title`. See https://github.com/nodejs/node/issues/41103. ::: --- # Source: https://vitest.dev/config/expandsnapshotdiff.md --- url: /config/expandsnapshotdiff.md --- # expandSnapshotDiff * **Type:** `boolean` * **CLI:** `--expandSnapshotDiff`, `--expand-snapshot-diff` * **Default:** `false` Show full diff when snapshot fails instead of a patch. --- # Source: https://vitest.dev/api/expect-typeof.md --- url: /api/expect-typeof.md --- # expectTypeOf ::: warning During runtime this function doesn't do anything. To [enable typechecking](/guide/testing-types#run-typechecking), don't forget to pass down `--typecheck` flag. ::: * **Type:** `(a: unknown) => ExpectTypeOf` ## not * **Type:** `ExpectTypeOf` You can negate all assertions, using `.not` property. ## toEqualTypeOf * **Type:** `(expected: T) => void` This matcher will check if the types are fully equal to each other. This matcher will not fail if two objects have different values, but the same type. It will fail however if an object is missing a property. ```ts import { expectTypeOf } from 'vitest' expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>() expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 1 }) expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 2 }) expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>() ``` ## toMatchTypeOf * **Type:** `(expected: T) => void` ::: warning DEPRECATED This matcher has been deprecated since expect-type v1.2.0. Use [`toExtend`](#toextend) instead. ::: This matcher checks if expect type extends provided type. It is different from `toEqual` and is more similar to [expect's](/api/expect) `toMatchObject()`. With this matcher, you can check if an object “matches” a type. ```ts import { expectTypeOf } from 'vitest' expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf({ a: 1 }) expectTypeOf().toMatchTypeOf() expectTypeOf().not.toMatchTypeOf() ``` ## toExtend * **Type:** `(expected: T) => void` This matcher checks if expect type extends provided type. It is different from `toEqual` and is more similar to [expect's](/api/expect) `toMatchObject()`. With this matcher, you can check if an object "matches" a type. ```ts import { expectTypeOf } from 'vitest' expectTypeOf({ a: 1, b: 1 }).toExtend({ a: 1 }) expectTypeOf().toExtend() expectTypeOf().not.toExtend() ``` ## toMatchObjectType * **Type:** `() => void` This matcher performs a strict check on object types, ensuring that the expected type matches the provided object type. It's stricter than [`toExtend`](#toextend) and is the recommended choice when working with object types as it's more likely to catch issues like readonly properties. ```ts import { expectTypeOf } from 'vitest' expectTypeOf({ a: 1, b: 2 }).toMatchObjectType<{ a: number }>() // preferred expectTypeOf({ a: 1, b: 2 }).toExtend<{ a: number }>() // works but less strict // Supports nested object checking const user = { name: 'John', address: { city: 'New York', zip: '10001' } } expectTypeOf(user).toMatchObjectType<{ name: string; address: { city: string } }>() ``` ::: warning This matcher only works with plain object types. It will fail for union types and other complex types. For those cases, use [`toExtend`](#toextend) instead. ::: ## extract * **Type:** `ExpectTypeOf` You can use `.extract` to narrow down types for further testing. ```ts import { expectTypeOf } from 'vitest' type ResponsiveProp = T | T[] | { xs?: T; sm?: T; md?: T } interface CSSProperties { margin?: string; padding?: string } function getResponsiveProp(_props: T): ResponsiveProp { return {} } const cssProperties: CSSProperties = { margin: '1px', padding: '2px' } expectTypeOf(getResponsiveProp(cssProperties)) .extract<{ xs?: any }>() // extracts the last type from a union .toEqualTypeOf<{ xs?: CSSProperties; sm?: CSSProperties; md?: CSSProperties }>() expectTypeOf(getResponsiveProp(cssProperties)) .extract() // extracts an array from a union .toEqualTypeOf() ``` ::: warning If no type is found in the union, `.extract` will return `never`. ::: ## exclude * **Type:** `ExpectTypeOf` You can use `.exclude` to remove types from a union for further testing. ```ts import { expectTypeOf } from 'vitest' type ResponsiveProp = T | T[] | { xs?: T; sm?: T; md?: T } interface CSSProperties { margin?: string; padding?: string } function getResponsiveProp(_props: T): ResponsiveProp { return {} } const cssProperties: CSSProperties = { margin: '1px', padding: '2px' } expectTypeOf(getResponsiveProp(cssProperties)) .exclude() .exclude<{ xs?: unknown }>() // or just .exclude() .toEqualTypeOf() ``` ::: warning If no type is found in the union, `.exclude` will return `never`. ::: ## returns * **Type:** `ExpectTypeOf` You can use `.returns` to extract return value of a function type. ```ts import { expectTypeOf } from 'vitest' expectTypeOf(() => {}).returns.toBeVoid() expectTypeOf((a: number) => [a, a]).returns.toEqualTypeOf([1, 2]) ``` ::: warning If used on a non-function type, it will return `never`, so you won't be able to chain it with other matchers. ::: ## parameters * **Type:** `ExpectTypeOf` You can extract function arguments with `.parameters` to perform assertions on its value. Parameters are returned as an array. ```ts import { expectTypeOf } from 'vitest' type NoParam = () => void type HasParam = (s: string) => void expectTypeOf().parameters.toEqualTypeOf<[]>() expectTypeOf().parameters.toEqualTypeOf<[string]>() ``` ::: warning If used on a non-function type, it will return `never`, so you won't be able to chain it with other matchers. ::: ::: tip You can also use [`.toBeCallableWith`](#tobecallablewith) matcher as a more expressive assertion. ::: ## parameter * **Type:** `(nth: number) => ExpectTypeOf` You can extract a certain function argument with `.parameter(number)` call to perform other assertions on it. ```ts import { expectTypeOf } from 'vitest' function foo(a: number, b: string) { return [a, b] } expectTypeOf(foo).parameter(0).toBeNumber() expectTypeOf(foo).parameter(1).toBeString() ``` ::: warning If used on a non-function type, it will return `never`, so you won't be able to chain it with other matchers. ::: ## constructorParameters * **Type:** `ExpectTypeOf` You can extract constructor parameters as an array of values and perform assertions on them with this method. ```ts import { expectTypeOf } from 'vitest' expectTypeOf(Date).constructorParameters.toEqualTypeOf<[] | [string | number | Date]>() ``` ::: warning If used on a non-function type, it will return `never`, so you won't be able to chain it with other matchers. ::: ::: tip You can also use [`.toBeConstructibleWith`](#tobeconstructiblewith) matcher as a more expressive assertion. ::: ## instance * **Type:** `ExpectTypeOf` This property gives access to matchers that can be performed on an instance of the provided class. ```ts import { expectTypeOf } from 'vitest' expectTypeOf(Date).instance.toHaveProperty('toISOString') ``` ::: warning If used on a non-function type, it will return `never`, so you won't be able to chain it with other matchers. ::: ## items * **Type:** `ExpectTypeOf` You can get array item type with `.items` to perform further assertions. ```ts import { expectTypeOf } from 'vitest' expectTypeOf([1, 2, 3]).items.toEqualTypeOf() expectTypeOf([1, 2, 3]).items.not.toEqualTypeOf() ``` ## resolves * **Type:** `ExpectTypeOf` This matcher extracts resolved value of a `Promise`, so you can perform other assertions on it. ```ts import { expectTypeOf } from 'vitest' async function asyncFunc() { return 123 } expectTypeOf(asyncFunc).returns.resolves.toBeNumber() expectTypeOf(Promise.resolve('string')).resolves.toBeString() ``` ::: warning If used on a non-promise type, it will return `never`, so you won't be able to chain it with other matchers. ::: ## guards * **Type:** `ExpectTypeOf` This matcher extracts guard value (e.g., `v is number`), so you can perform assertions on it. ```ts import { expectTypeOf } from 'vitest' function isString(v: any): v is string { return typeof v === 'string' } expectTypeOf(isString).guards.toBeString() ``` ::: warning Returns `never`, if the value is not a guard function, so you won't be able to chain it with other matchers. ::: ## asserts * **Type:** `ExpectTypeOf` This matcher extracts assert value (e.g., `assert v is number`), so you can perform assertions on it. ```ts import { expectTypeOf } from 'vitest' function assertNumber(v: any): asserts v is number { if (typeof v !== 'number') { throw new TypeError('Nope !') } } expectTypeOf(assertNumber).asserts.toBeNumber() ``` ::: warning Returns `never`, if the value is not an assert function, so you won't be able to chain it with other matchers. ::: ## toBeAny * **Type:** `() => void` With this matcher you can check, if provided type is `any` type. If the type is too specific, the test will fail. ```ts import { expectTypeOf } from 'vitest' expectTypeOf().toBeAny() expectTypeOf({} as any).toBeAny() expectTypeOf('string').not.toBeAny() ``` ## toBeUnknown * **Type:** `() => void` This matcher checks, if provided type is `unknown` type. ```ts import { expectTypeOf } from 'vitest' expectTypeOf().toBeUnknown() expectTypeOf({} as unknown).toBeUnknown() expectTypeOf('string').not.toBeUnknown() ``` ## toBeNever * **Type:** `() => void` This matcher checks, if provided type is a `never` type. ```ts import { expectTypeOf } from 'vitest' expectTypeOf().toBeNever() expectTypeOf((): never => {}).returns.toBeNever() ``` ## toBeFunction * **Type:** `() => void` This matcher checks, if provided type is a `function`. ```ts import { expectTypeOf } from 'vitest' expectTypeOf(42).not.toBeFunction() expectTypeOf((): never => {}).toBeFunction() ``` ## toBeObject * **Type:** `() => void` This matcher checks, if provided type is an `object`. ```ts import { expectTypeOf } from 'vitest' expectTypeOf(42).not.toBeObject() expectTypeOf({}).toBeObject() ``` ## toBeArray * **Type:** `() => void` This matcher checks, if provided type is `Array`. ```ts import { expectTypeOf } from 'vitest' expectTypeOf(42).not.toBeArray() expectTypeOf([]).toBeArray() expectTypeOf([1, 2]).toBeArray() expectTypeOf([{}, 42]).toBeArray() ``` ## toBeString * **Type:** `() => void` This matcher checks, if provided type is a `string`. ```ts import { expectTypeOf } from 'vitest' expectTypeOf(42).not.toBeString() expectTypeOf('').toBeString() expectTypeOf('a').toBeString() ``` ## toBeBoolean * **Type:** `() => void` This matcher checks, if provided type is `boolean`. ```ts import { expectTypeOf } from 'vitest' expectTypeOf(42).not.toBeBoolean() expectTypeOf(true).toBeBoolean() expectTypeOf().toBeBoolean() ``` ## toBeVoid * **Type:** `() => void` This matcher checks, if provided type is `void`. ```ts import { expectTypeOf } from 'vitest' expectTypeOf(() => {}).returns.toBeVoid() expectTypeOf().toBeVoid() ``` ## toBeSymbol * **Type:** `() => void` This matcher checks, if provided type is a `symbol`. ```ts import { expectTypeOf } from 'vitest' expectTypeOf(Symbol(1)).toBeSymbol() expectTypeOf().toBeSymbol() ``` ## toBeNull * **Type:** `() => void` This matcher checks, if provided type is `null`. ```ts import { expectTypeOf } from 'vitest' expectTypeOf(null).toBeNull() expectTypeOf().toBeNull() expectTypeOf(undefined).not.toBeNull() ``` ## toBeUndefined * **Type:** `() => void` This matcher checks, if provided type is `undefined`. ```ts import { expectTypeOf } from 'vitest' expectTypeOf(undefined).toBeUndefined() expectTypeOf().toBeUndefined() expectTypeOf(null).not.toBeUndefined() ``` ## toBeNullable * **Type:** `() => void` This matcher checks, if you can use `null` or `undefined` with provided type. ```ts import { expectTypeOf } from 'vitest' expectTypeOf().toBeNullable() expectTypeOf().toBeNullable() expectTypeOf().toBeNullable() ``` ## toBeCallableWith * **Type:** `() => void` This matcher ensures you can call provided function with a set of parameters. ```ts import { expectTypeOf } from 'vitest' type NoParam = () => void type HasParam = (s: string) => void expectTypeOf().toBeCallableWith() expectTypeOf().toBeCallableWith('some string') ``` ::: warning If used on a non-function type, it will return `never`, so you won't be able to chain it with other matchers. ::: ## toBeConstructibleWith * **Type:** `() => void` This matcher ensures you can create a new instance with a set of constructor parameters. ```ts import { expectTypeOf } from 'vitest' expectTypeOf(Date).toBeConstructibleWith(new Date()) expectTypeOf(Date).toBeConstructibleWith('01-01-2000') ``` ::: warning If used on a non-function type, it will return `never`, so you won't be able to chain it with other matchers. ::: ## toHaveProperty * **Type:** `(property: K) => ExpectTypeOf` This matcher checks if a property exists on the provided object. If it exists, it also returns the same set of matchers for the type of this property, so you can chain assertions one after another. ```ts import { expectTypeOf } from 'vitest' const obj = { a: 1, b: '' } expectTypeOf(obj).toHaveProperty('a') expectTypeOf(obj).not.toHaveProperty('c') expectTypeOf(obj).toHaveProperty('a').toBeNumber() expectTypeOf(obj).toHaveProperty('b').toBeString() expectTypeOf(obj).toHaveProperty('a').not.toBeString() ``` ## branded * **Type:** `ExpectTypeOf` You can use `.branded` to allow type assertions to succeed for types that are semantically equivalent but differ in representation. ```ts import { expectTypeOf } from 'vitest' // Without .branded, this fails even though the types are effectively the same expectTypeOf<{ a: { b: 1 } & { c: 1 } }>().toEqualTypeOf<{ a: { b: 1; c: 1 } }>() // With .branded, the assertion succeeds expectTypeOf<{ a: { b: 1 } & { c: 1 } }>().branded.toEqualTypeOf<{ a: { b: 1; c: 1 } }>() ``` ::: warning This helper comes at a performance cost and can cause the TypeScript compiler to 'give up' if used with excessively deep types. Use it sparingly and only when necessary. ::: --- # Source: https://vitest.dev/api/expect.md # Source: https://vitest.dev/config/browser/expect.md # Source: https://vitest.dev/config/expect.md --- url: /config/expect.md --- # expect * **Type:** `ExpectOptions` ## expect.requireAssertions * **Type:** `boolean` * **Default:** `false` The same as calling [`expect.hasAssertions()`](/api/expect#expect-hasassertions) at the start of every test. This makes sure that no test will pass accidentally. ::: tip This only works with Vitest's `expect`. If you use `assert` or `.should` assertions, they will not count, and your test will fail due to the lack of expect assertions. You can change the value of this by calling `vi.setConfig({ expect: { requireAssertions: false } })`. The config will be applied to every subsequent `expect` call until the `vi.resetConfig` is called manually. ::: ::: warning When you run tests with `sequence.concurrent` and `expect.requireAssertions` set to `true`, you should use [local expect](/guide/test-context.html#expect) instead of the global one. Otherwise, this may cause false negatives in [some situations (#8469)](https://github.com/vitest-dev/vitest/issues/8469). ::: ## expect.poll Global configuration options for [`expect.poll`](/api/expect#poll). These are the same options you can pass down to `expect.poll(condition, options)`. ### expect.poll.interval * **Type:** `number` * **Default:** `50` Polling interval in milliseconds ### expect.poll.timeout * **Type:** `number` * **Default:** `1000` Polling timeout in milliseconds --- # Source: https://vitest.dev/config/experimental.md --- url: /config/experimental.md --- # experimental ## experimental.fsModuleCache 4.0.11 {#experimental-fsmodulecache} ::: tip FEEDBACK Please, leave feedback regarding this feature in a [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions/9221). ::: * **Type:** `boolean` * **Default:** `false` Enabling this option allows Vitest to keep cached modules on the file system, making tests run faster between reruns. You can delete the old cache by running [`vitest --clearCache`](/guide/cli#clearcache). ::: warning BROWSER SUPPORT At the moment, this option does not affect [the browser](/guide/browser/). ::: You can debug if your modules are cached by running vitest with a `DEBUG=vitest:cache:fs` environment variable: ```shell DEBUG=vitest:cache:fs vitest --experimental.fsModuleCache ``` ### Known Issues Vitest creates persistent file hash based on file content, its id, vite's environment configuration and coverage status. Vitest tries to use as much information it has about the configuration, but it is still incomplete. At the moment, it is not possible to track your plugin options because there is no standard interface for it. If you have a plugin that relies on things outside the file content or the public configuration (like reading another file or a folder), it's possible that the cache will get stale. To workaround that, you can define a [cache key generator](/api/advanced/plugin#definecachekeygenerator) to specify dynamic option or to opt-out of caching for that module: ```js [vitest.config.js] import { defineConfig } from 'vitest/config' export default defineConfig({ plugins: [ { name: 'vitest-cache', configureVitest({ experimental_defineCacheKeyGenerator }) { experimental_defineCacheKeyGenerator(({ id, sourceCode }) => { // never cache this id if (id.includes('do-not-cache')) { return false } // cache this file based on the value of a dynamic variable if (sourceCode.includes('myDynamicVar')) { return process.env.DYNAMIC_VAR_VALUE } }) } } ], test: { experimental: { fsModuleCache: true, }, }, }) ``` If you are a plugin author, consider defining a [cache key generator](/api/advanced/plugin#definecachekeygenerator) in your plugin if it can be registered with different options that affect the transform result. On the other hand, if your plugin should not affect the cache key, you can opt-out by setting `api.vitest.experimental.ignoreFsModuleCache` to `true`: ```js [vitest.config.js] import { defineConfig } from 'vitest/config' export default defineConfig({ plugins: [ { name: 'vitest-cache', api: { vitest: { experimental: { ignoreFsModuleCache: true, }, }, }, }, ], test: { experimental: { fsModuleCache: true, }, }, }) ``` Note that you can still define the cache key generator even the plugin opt-out of module caching. ## experimental.fsModuleCachePath 4.0.11 {#experimental-fsmodulecachepath} * **Type:** `string` * **Default:** `'node_modules/.experimental-vitest-cache'` Directory where the file system cache is located. By default, Vitest will try to find the workspace root and store the cache inside the `node_modules` folder. The root is based on your package manager's lockfile (for example, `.package-lock.json`, `.yarn-state.yml`, `.pnpm/lock.yaml` and so on). At the moment, Vitest ignores the [test.cache.dir](/config/cache) or [cacheDir](https://vite.dev/config/shared-options#cachedir) options completely and creates a separate folder. ## experimental.openTelemetry 4.0.11 {#experimental-opentelemetry} ::: tip FEEDBACK Please, leave feedback regarding this feature in a [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions/9222). ::: * **Type:** ```ts interface OpenTelemetryOptions { enabled: boolean /** * A path to a file that exposes an OpenTelemetry SDK for Node.js. */ sdkPath?: string /** * A path to a file that exposes an OpenTelemetry SDK for the browser. */ browserSdkPath?: string } ``` * **Default:** `{ enabled: false }` This option controls [OpenTelemetry](https://opentelemetry.io/) support. Vitest imports the SDK file in the main thread and before every test file, if `enabled` is set to `true`. ::: danger PERFORMANCE CONCERNS OpenTelemetry may significantly impact Vitest performance; enable it only for local debugging. ::: You can use a [custom service](/guide/open-telemetry) together with Vitest to pinpoint which tests or files are slowing down your test suite. For browser mode, see the [Browser Mode](/guide/open-telemetry#browser-mode) section of the OpenTelemetry guide. An `sdkPath` is resolved relative to the [`root`](/config/root) of the project and should point to a module that exposes a started SDK instance as a default export. For example: ::: code-group ```js [otel.js] import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node' import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto' import { NodeSDK } from '@opentelemetry/sdk-node' const sdk = new NodeSDK({ serviceName: 'vitest', traceExporter: new OTLPTraceExporter(), instrumentations: [getNodeAutoInstrumentations()], }) sdk.start() export default sdk ``` ```js [vitest.config.js] import { defineConfig } from 'vitest/config' export default defineConfig({ test: { experimental: { openTelemetry: { enabled: true, sdkPath: './otel.js', }, }, }, }) ``` ::: ::: warning It's important that Node can process `sdkPath` content because it is not transformed by Vitest. See [the guide](/guide/open-telemetry) on how to work with OpenTelemetry inside of Vitest. ::: ## experimental.printImportBreakdown 4.0.15 {#experimental-printimportbreakdown} ::: tip FEEDBACK Please, leave feedback regarding this feature in a [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions/9224). ::: * **Type:** `boolean` * **Default:** `false` Show import duration breakdown after tests have finished running. This option only works with [`default`](/guide/reporters#default), [`verbose`](/guide/reporters#verbose), or [`tree`](/guide/reporters#tree) reporters. * Self: the time it took to import the module, excluding static imports; * Total: the time it took to import the module, including static imports. Note that this does not include `transform` time of the current module. Note that if the file path is too long, Vitest will truncate it at the start until it fits 45 character limit. ::: info [Vitest UI](/guide/ui#import-breakdown) shows a breakdown of imports automatically if at least one file took longer than 500 milliseconds to load. You can manually set this option to `false` to disable this. ::: --- # Source: https://vitest.dev/guide/extending-matchers.md --- url: /guide/extending-matchers.md --- # Extending Matchers Since Vitest is compatible with both Chai and Jest, you can use either the `chai.use` API or `expect.extend`, whichever you prefer. This guide will explore extending matchers with `expect.extend`. If you are interested in Chai's API, check [their guide](https://www.chaijs.com/guide/plugins/). To extend default matchers, call `expect.extend` with an object containing your matchers. ```ts expect.extend({ toBeFoo(received, expected) { const { isNot } = this return { // do not alter your "pass" based on isNot. Vitest does it for you pass: received === 'foo', message: () => `${received} is${isNot ? ' not' : ''} foo` } } }) ``` If you are using TypeScript, you can extend default `Assertion` interface in an ambient declaration file (e.g: `vitest.d.ts`) with the code below: ::: code-group ```ts [3.2.0] import 'vitest' interface CustomMatchers { toBeFoo: () => R } declare module 'vitest' { interface Matchers extends CustomMatchers {} } ``` ```ts [3.0.0] import 'vitest' interface CustomMatchers { toBeFoo: () => R } declare module 'vitest' { interface Assertion extends CustomMatchers {} interface AsymmetricMatchersContaining extends CustomMatchers {} } ``` ::: ::: tip Since Vitest 3.2, you can extend the `Matchers` interface to have type-safe assertions in `expect.extend`, `expect().*`, and `expect.*` methods at the same time. Previously, you had to define separate interfaces for each of them. ::: ::: warning Don't forget to include the ambient declaration file in your `tsconfig.json`. ::: The return value of a matcher should be compatible with the following interface: ```ts interface ExpectationResult { pass: boolean message: () => string // If you pass these, they will automatically appear inside a diff when // the matcher does not pass, so you don't need to print the diff yourself actual?: unknown expected?: unknown } ``` ::: warning If you create an asynchronous matcher, don't forget to `await` the result (`await expect('foo').toBeFoo()`) in the test itself:: ```ts expect.extend({ async toBeAsyncAssertion() { // ... } }) await expect().toBeAsyncAssertion() ``` ::: The first argument inside a matcher's function is the received value (the one inside `expect(received)`). The rest are arguments passed directly to the matcher. Matcher function has access to `this` context with the following properties: ### `isNot` Returns true, if matcher was called on `not` (`expect(received).not.toBeFoo()`). ### `promise` If matcher was called on `resolved/rejected`, this value will contain the name of modifier. Otherwise, it will be an empty string. ### `equals` This is a utility function that allows you to compare two values. It will return `true` if values are equal, `false` otherwise. This function is used internally for almost every matcher. It supports objects with asymmetric matchers by default. ### `utils` This contains a set of utility functions that you can use to display messages. `this` context also contains information about the current test. You can also get it by calling `expect.getState()`. The most useful properties are: ### `currentTestName` Full name of the current test (including describe block). ### `task` 4.0.11 {#task} Contains a reference to [the `Test` runner task](/api/advanced/runner#tasks) when available. ::: warning When using the global `expect` with concurrent tests, `this.task` is `undefined`. Use `context.expect` instead to ensure `task` is available in custom matchers. ::: ### `testPath` Path to the current test. --- # Source: https://vitest.dev/config/faketimers.md --- url: /config/faketimers.md --- # fakeTimers * **Type:** `FakeTimerInstallOpts` Options that Vitest will pass down to [`@sinon/fake-timers`](https://www.npmjs.com/package/@sinonjs/fake-timers) when using [`vi.useFakeTimers()`](/api/vi#vi-usefaketimers). ## fakeTimers.now * **Type:** `number | Date` * **Default:** `Date.now()` Installs fake timers with the specified Unix epoch. ## fakeTimers.toFake * **Type:** `('setTimeout' | 'clearTimeout' | 'setImmediate' | 'clearImmediate' | 'setInterval' | 'clearInterval' | 'Date' | 'nextTick' | 'hrtime' | 'requestAnimationFrame' | 'cancelAnimationFrame' | 'requestIdleCallback' | 'cancelIdleCallback' | 'performance' | 'queueMicrotask')[]` * **Default:** everything available globally except `nextTick` and `queueMicrotask` An array with names of global methods and APIs to fake. To only mock `setTimeout()` and `nextTick()`, specify this property as `['setTimeout', 'nextTick']`. Mocking `nextTick` is not supported when running Vitest inside `node:child_process` by using `--pool=forks`. NodeJS uses `process.nextTick` internally in `node:child_process` and hangs when it is mocked. Mocking `nextTick` is supported when running Vitest with `--pool=threads`. ## fakeTimers.loopLimit * **Type:** `number` * **Default:** `10_000` The maximum number of timers that will be run when calling [`vi.runAllTimers()`](/api/vi#vi-runalltimers). ## fakeTimers.shouldAdvanceTime * **Type:** `boolean` * **Default:** `false` Tells @sinonjs/fake-timers to increment mocked time automatically based on the real system time shift (e.g. the mocked time will be incremented by 20ms for every 20ms change in the real system time). ## fakeTimers.advanceTimeDelta * **Type:** `number` * **Default:** `20` Relevant only when using with `shouldAdvanceTime: true`. increment mocked time by advanceTimeDelta ms every advanceTimeDelta ms change in the real system time. ## fakeTimers.shouldClearNativeTimers * **Type:** `boolean` * **Default:** `true` Tells fake timers to clear "native" (i.e. not fake) timers by delegating to their respective handlers. When disabled, it can lead to potentially unexpected behavior if timers existed prior to starting fake timers session. --- # Source: https://vitest.dev/guide/features.md --- url: /guide/features.md --- # Features ## Shared Config between Test, Dev and Build Vite's config, transformers, resolvers, and plugins. Use the same setup from your app to run the tests. Learn more at [Configuring Vitest](/guide/#configuring-vitest). ## Watch Mode ```bash $ vitest ``` When you modify your source code or the test files, Vitest smartly searches the module graph and only reruns the related tests, just like how HMR works in Vite! `vitest` starts in `watch mode` **by default in development environment** and `run mode` in CI environment (when `process.env.CI` presents) smartly. You can use `vitest watch` or `vitest run` to explicitly specify the desired mode. Start Vitest with the `--standalone` flag to keep it running in the background. It won't run any tests until they change. Vitest will not run tests if the source code is changed until the test that imports the source has been run ## Common Web Idioms Out-Of-The-Box Out-of-the-box ES Module / TypeScript / JSX support / PostCSS ## Threads By default Vitest runs test files in [multiple processes](/guide/parallelism) using [`node:child_process`](https://nodejs.org/api/child_process.html), allowing tests to run simultaneously. If you want to speed up your test suite even further, consider enabling `--pool=threads` to run tests using [`node:worker_threads`](https://nodejs.org/api/worker_threads.html) (beware that some packages might not work with this setup). To run tests in a single thread or process, see [`fileParallelism`](/config/#fileParallelism). Vitest also isolates each file's environment so env mutations in one file don't affect others. Isolation can be disabled by passing `--no-isolate` to the CLI (trading correctness for run performance). ## Test Filtering Vitest provides many ways to narrow down the tests to run in order to speed up testing so you can focus on development. Learn more about [Test Filtering](/guide/filtering). ## Running Tests Concurrently Use `.concurrent` in consecutive tests to start them in parallel. ```ts import { describe, it } from 'vitest' // The two tests marked with concurrent will be started in parallel describe('suite', () => { it('serial test', async () => { /* ... */ }) it.concurrent('concurrent test 1', async ({ expect }) => { /* ... */ }) it.concurrent('concurrent test 2', async ({ expect }) => { /* ... */ }) }) ``` If you use `.concurrent` on a suite, every test in it will be started in parallel. ```ts import { describe, it } from 'vitest' // All tests within this suite will be started in parallel describe.concurrent('suite', () => { it('concurrent test 1', async ({ expect }) => { /* ... */ }) it('concurrent test 2', async ({ expect }) => { /* ... */ }) it.concurrent('concurrent test 3', async ({ expect }) => { /* ... */ }) }) ``` You can also use `.skip`, `.only`, and `.todo` with concurrent suites and tests. Read more in the [API Reference](/api/#test-concurrent). ::: warning When running concurrent tests, Snapshots and Assertions must use `expect` from the local [Test Context](/guide/test-context) to ensure the right test is detected. ::: ## Snapshot [Jest-compatible](https://jestjs.io/docs/snapshot-testing) snapshot support. ```ts import { expect, it } from 'vitest' it('renders correctly', () => { const result = render() expect(result).toMatchSnapshot() }) ``` Learn more at [Snapshot](/guide/snapshot). ## Chai and Jest `expect` Compatibility [Chai](https://www.chaijs.com/) is built-in for assertions with [Jest `expect`](https://jestjs.io/docs/expect)-compatible APIs. Notice that if you are using third-party libraries that add matchers, setting [`test.globals`](/config/#globals) to `true` will provide better compatibility. ## Mocking [Tinyspy](https://github.com/tinylibs/tinyspy) is built-in for mocking with `jest`-compatible APIs on `vi` object. ```ts import { expect, vi } from 'vitest' const fn = vi.fn() fn('hello', 1) expect(vi.isMockFunction(fn)).toBe(true) expect(fn.mock.calls[0]).toEqual(['hello', 1]) fn.mockImplementation((arg: string) => arg) fn('world', 2) expect(fn.mock.results[1].value).toBe('world') ``` Vitest supports both [happy-dom](https://github.com/capricorn86/happy-dom) or [jsdom](https://github.com/jsdom/jsdom) for mocking DOM and browser APIs. They don't come with Vitest, you will need to install them separately: ::: code-group ```bash [happy-dom] $ npm i -D happy-dom ``` ```bash [jsdom] $ npm i -D jsdom ``` ::: After that, change the `environment` option in your config file: ```ts [vitest.config.ts] import { defineConfig } from 'vitest/config' export default defineConfig({ test: { environment: 'happy-dom', // or 'jsdom', 'node' }, }) ``` Learn more at [Mocking](/guide/mocking). ## Coverage Vitest supports Native code coverage via [`v8`](https://v8.dev/blog/javascript-code-coverage) and instrumented code coverage via [`istanbul`](https://istanbul.js.org/). ```json [package.json] { "scripts": { "test": "vitest", "coverage": "vitest run --coverage" } } ``` Learn more at [Coverage](/guide/coverage). ## In-Source Testing Vitest also provides a way to run tests within your source code along with the implementation, similar to [Rust's module tests](https://doc.rust-lang.org/book/ch11-03-test-organization.html#the-tests-module-and-cfgtest). This makes the tests share the same closure as the implementations and able to test against private states without exporting. Meanwhile, it also brings the feedback loop closer for development. ```ts [src/index.ts] // the implementation export function add(...args: number[]): number { return args.reduce((a, b) => a + b, 0) } // in-source test suites if (import.meta.vitest) { const { it, expect } = import.meta.vitest it('add', () => { expect(add()).toBe(0) expect(add(1)).toBe(1) expect(add(1, 2, 3)).toBe(6) }) } ``` Learn more at [In-source testing](/guide/in-source). ## Benchmarking Experimental {#benchmarking} You can run benchmark tests with [`bench`](/api/#bench) function via [Tinybench](https://github.com/tinylibs/tinybench) to compare performance results. ```ts [sort.bench.ts] import { bench, describe } from 'vitest' describe('sort', () => { bench('normal', () => { const x = [1, 5, 4, 2, 3] x.sort((a, b) => { return a - b }) }) bench('reverse', () => { const x = [1, 5, 4, 2, 3] x.reverse().sort((a, b) => { return a - b }) }) }) ``` ## Type Testing Experimental {#type-testing} You can [write tests](/guide/testing-types) to catch type regressions. Vitest comes with [`expect-type`](https://github.com/mmkal/expect-type) package to provide you with a similar and easy to understand API. ```ts [types.test-d.ts] import { assertType, expectTypeOf, test } from 'vitest' import { mount } from './mount.js' test('my types work properly', () => { expectTypeOf(mount).toBeFunction() expectTypeOf(mount).parameter(0).toExtend<{ name: string }>() // @ts-expect-error name is a string assertType(mount({ name: 42 })) }) ``` ## Sharding Run tests on different machines using [`--shard`](/guide/cli#shard) and [`--reporter=blob`](/guide/reporters#blob-reporter) flags. All test and coverage results can be merged at the end of your CI pipeline using `--merge-reports` command: ```bash vitest --shard=1/2 --reporter=blob --coverage vitest --shard=2/2 --reporter=blob --coverage vitest --merge-reports --reporter=junit --coverage ``` See [`Improving Performance | Sharding`](/guide/improving-performance#sharding) for more information. ## Environment Variables Vitest exclusively autoloads environment variables prefixed with `VITE_` from `.env` files to maintain compatibility with frontend-related tests, adhering to [Vite's established convention](https://vitejs.dev/guide/env-and-mode.html#env-files). To load every environmental variable from `.env` files anyway, you can use `loadEnv` method imported from `vite`: ```ts [vitest.config.ts] import { loadEnv } from 'vite' import { defineConfig } from 'vitest/config' export default defineConfig(({ mode }) => ({ test: { // mode defines what ".env.{mode}" file to choose if exists env: loadEnv(mode, process.cwd(), ''), }, })) ``` ## Unhandled Errors By default, Vitest catches and reports all [unhandled rejections](https://developer.mozilla.org/en-US/docs/Web/API/Window/unhandledrejection_event), [uncaught exceptions](https://nodejs.org/api/process.html#event-uncaughtexception) (in Node.js) and [error](https://developer.mozilla.org/en-US/docs/Web/API/Window/error_event) events (in the [browser](/guide/browser/)). You can disable this behaviour by catching them manually. Vitest assumes the callback is handled by you and won't report the error. ::: code-group ```ts [setup.node.js] // in Node.js process.on('unhandledRejection', () => { // your own handler }) process.on('uncaughtException', () => { // your own handler }) ``` ```ts [setup.browser.js] // in the browser window.addEventListener('error', () => { // your own handler }) window.addEventListener('unhandledrejection', () => { // your own handler }) ``` ::: Alternatively, you can also ignore reported errors with a [`dangerouslyIgnoreUnhandledErrors`](/config/#dangerouslyignoreunhandlederrors) option. Vitest will still report them, but they won't affect the test result (exit code won't be changed). If you need to test that error was not caught, you can create a test that looks like this: ```ts test('my function throws uncaught error', async ({ onTestFinished }) => { const unhandledRejectionListener = vi.fn() process.on('unhandledRejection', unhandledRejectionListener) onTestFinished(() => { process.off('unhandledRejection', unhandledRejectionListener) }) callMyFunctionThatRejectsError() await expect.poll(unhandledRejectionListener).toHaveBeenCalled() }) ``` --- # Source: https://vitest.dev/guide/mocking/file-system.md --- url: /guide/mocking/file-system.md --- # Mocking the File System Mocking the file system ensures that the tests do not depend on the actual file system, making the tests more reliable and predictable. This isolation helps in avoiding side effects from previous tests. It allows for testing error conditions and edge cases that might be difficult or impossible to replicate with an actual file system, such as permission issues, disk full scenarios, or read/write errors. Vitest doesn't provide any file system mocking API out of the box. You can use `vi.mock` to mock the `fs` module manually, but it's hard to maintain. Instead, we recommend using [`memfs`](https://www.npmjs.com/package/memfs) to do that for you. `memfs` creates an in-memory file system, which simulates file system operations without touching the actual disk. This approach is fast and safe, avoiding any potential side effects on the real file system. ## Example To automatically redirect every `fs` call to `memfs`, you can create `__mocks__/fs.cjs` and `__mocks__/fs/promises.cjs` files at the root of your project: ::: code-group ```ts [__mocks__/fs.cjs] // we can also use `import`, but then // every export should be explicitly defined const { fs } = require('memfs') module.exports = fs ``` ```ts [__mocks__/fs/promises.cjs] // we can also use `import`, but then // every export should be explicitly defined const { fs } = require('memfs') module.exports = fs.promises ``` ::: ```ts [read-hello-world.js] import { readFileSync } from 'node:fs' export function readHelloWorld(path) { return readFileSync(path, 'utf-8') } ``` ```ts [hello-world.test.js] import { beforeEach, expect, it, vi } from 'vitest' import { fs, vol } from 'memfs' import { readHelloWorld } from './read-hello-world.js' // tell vitest to use fs mock from __mocks__ folder // this can be done in a setup file if fs should always be mocked vi.mock('node:fs') vi.mock('node:fs/promises') beforeEach(() => { // reset the state of in-memory fs vol.reset() }) it('should return correct text', () => { const path = '/hello-world.txt' fs.writeFileSync(path, 'hello world') const text = readHelloWorld(path) expect(text).toBe('hello world') }) it('can return a value multiple times', () => { // you can use vol.fromJSON to define several files vol.fromJSON( { './dir1/hw.txt': 'hello dir1', './dir2/hw.txt': 'hello dir2', }, // default cwd '/tmp', ) expect(readHelloWorld('/tmp/dir1/hw.txt')).toBe('hello dir1') expect(readHelloWorld('/tmp/dir2/hw.txt')).toBe('hello dir2') }) ``` --- # Source: https://vitest.dev/config/fileparallelism.md --- url: /config/fileparallelism.md --- # fileParallelism * **Type:** `boolean` * **Default:** `true` * **CLI:** `--no-file-parallelism`, `--fileParallelism=false` Should all test files run in parallel. Setting this to `false` will override `maxWorkers` option to `1`. ::: tip This option doesn't affect tests running in the same file. If you want to run those in parallel, use `concurrent` option on [describe](/api/#describe-concurrent) or via [a config](#sequence-concurrent). ::: --- # Source: https://vitest.dev/guide/filtering.md --- url: /guide/filtering.md --- # Test Filtering Filtering, timeouts, concurrent for suite and tests ## CLI You can use CLI to filter test files by name: ```bash $ vitest basic ``` Will only execute test files that contain `basic`, e.g. ``` basic.test.ts basic-foo.test.ts basic/foo.test.ts ``` You can also use the `-t, --testNamePattern ` option to filter tests by full name. This can be helpful when you want to filter by the name defined within a file rather than the filename itself. Since Vitest 3, you can also specify the test by filename and line number: ```bash $ vitest basic/foo.test.ts:10 ``` ::: warning Note that Vitest requires the full filename for this feature to work. It can be relative to the current working directory or an absolute file path. ```bash $ vitest basic/foo.js:10 # ✅ $ vitest ./basic/foo.js:10 # ✅ $ vitest /users/project/basic/foo.js:10 # ✅ $ vitest foo:10 # ❌ $ vitest ./basic/foo:10 # ❌ ``` At the moment Vitest also doesn't support ranges: ```bash $ vitest basic/foo.test.ts:10, basic/foo.test.ts:25 # ✅ $ vitest basic/foo.test.ts:10-25 # ❌ ``` ::: ## Specifying a Timeout You can optionally pass a timeout in milliseconds as a third argument to tests. The default is [5 seconds](/config/#testtimeout). ```ts import { test } from 'vitest' test('name', async () => { /* ... */ }, 1000) ``` Hooks also can receive a timeout, with the same 5 seconds default. ```ts import { beforeAll } from 'vitest' beforeAll(async () => { /* ... */ }, 1000) ``` ## Skipping Suites and Tests Use `.skip` to avoid running certain suites or tests ```ts import { assert, describe, it } from 'vitest' describe.skip('skipped suite', () => { it('test', () => { // Suite skipped, no error assert.equal(Math.sqrt(4), 3) }) }) describe('suite', () => { it.skip('skipped test', () => { // Test skipped, no error assert.equal(Math.sqrt(4), 3) }) }) ``` ## Selecting Suites and Tests to Run Use `.only` to only run certain suites or tests ```ts import { assert, describe, it } from 'vitest' // Only this suite (and others marked with only) are run describe.only('suite', () => { it('test', () => { assert.equal(Math.sqrt(4), 3) }) }) describe('another suite', () => { it('skipped test', () => { // Test skipped, as tests are running in Only mode assert.equal(Math.sqrt(4), 3) }) it.only('test', () => { // Only this test (and others marked with only) are run assert.equal(Math.sqrt(4), 2) }) }) ``` Run Vitest with a file filter and a line number: ```shell vitest ./test/example.test.ts:5 ``` ```ts:line-numbers import { assert, describe, it } from 'vitest' describe('suite', () => { // Run only this test it('test', () => { assert.equal(Math.sqrt(4), 3) }) }) ``` ## Unimplemented Suites and Tests Use `.todo` to stub suites and tests that should be implemented ```ts import { describe, it } from 'vitest' // An entry will be shown in the report for this suite describe.todo('unimplemented suite') // An entry will be shown in the report for this test describe('suite', () => { it.todo('unimplemented test') }) ``` --- # Source: https://vitest.dev/config/forcereruntriggers.md --- url: /config/forcereruntriggers.md --- # forceRerunTriggers * **Type**: `string[]` * **Default:** `['**/package.json/**', '**/vitest.config.*/**', '**/vite.config.*/**']` Glob pattern of file paths that will trigger the whole suite rerun. When paired with the `--changed` argument will run the whole test suite if the trigger is found in the git diff. Useful if you are testing calling CLI commands, because Vite cannot construct a module graph: ```ts test('execute a script', async () => { // Vitest cannot rerun this test, if content of `dist/index.js` changes await execa('node', ['dist/index.js']) }) ``` ::: tip Make sure that your files are not excluded by [`server.watch.ignored`](https://vitejs.dev/config/server-options.html#server-watch). ::: --- # Source: https://vitest.dev/guide/mocking/functions.md --- url: /guide/mocking/functions.md --- # Mocking Functions Mocking functions can be split up into two different categories: spying and mocking. If you need to observe the behaviour of a method on an object, you can use [`vi.spyOn()`](/api/vi#vi-spyon) to create a spy that tracks calls to that method. If you need to pass down a custom function implementation as an argument or create a new mocked entity, you can use [`vi.fn()`](/api/vi#vi-fn) to create a mock function. Both `vi.spyOn` and `vi.fn` share the same methods. ## Example ```js import { afterEach, describe, expect, it, vi } from 'vitest' const messages = { items: [ { message: 'Simple test message', from: 'Testman' }, // ... ], addItem(item) { messages.items.push(item) messages.callbacks.forEach(callback => callback(item)) }, onItem(callback) { messages.callbacks.push(callback) }, getLatest, // can also be a `getter or setter if supported` } function getLatest(index = messages.items.length - 1) { return messages.items[index] } it('should get the latest message with a spy', () => { const spy = vi.spyOn(messages, 'getLatest') expect(spy.getMockName()).toEqual('getLatest') expect(messages.getLatest()).toEqual( messages.items[messages.items.length - 1], ) expect(spy).toHaveBeenCalledTimes(1) spy.mockImplementationOnce(() => 'access-restricted') expect(messages.getLatest()).toEqual('access-restricted') expect(spy).toHaveBeenCalledTimes(2) }) it('passing down the mock', () => { const callback = vi.fn() messages.onItem(callback) messages.addItem({ message: 'Another test message', from: 'Testman' }) expect(callback).toHaveBeenCalledWith({ message: 'Another test message', from: 'Testman', }) }) ``` --- # Source: https://vitest.dev/guide/mocking/globals.md # Source: https://vitest.dev/config/globals.md --- url: /config/globals.md --- # globals * **Type:** `boolean` * **Default:** `false` * **CLI:** `--globals`, `--no-globals`, `--globals=false` By default, `vitest` does not provide global APIs for explicitness. If you prefer to use the APIs globally like Jest, you can pass the `--globals` option to CLI or add `globals: true` in the config. ```js import { defineConfig } from 'vitest/config' export default defineConfig({ test: { globals: true, }, }) ``` ::: tip Note that some libraries, e.g., `@testing-library/react`, rely on globals being present to perform auto cleanup. ::: To get TypeScript working with the global APIs, add `vitest/globals` to the `types` field in your `tsconfig.json`: ```json [tsconfig.json] { "compilerOptions": { "types": ["vitest/globals"] } } ``` If you have redefined your [`typeRoots`](https://www.typescriptlang.org/tsconfig/#typeRoots) to include additional types in your compilation, you will need to add back the `node_modules` to make `vitest/globals` discoverable: ```json [tsconfig.json] { "compilerOptions": { "typeRoots": ["./types", "./node_modules/@types", "./node_modules"], "types": ["vitest/globals"] } } ``` --- # Source: https://vitest.dev/config/globalsetup.md --- url: /config/globalsetup.md --- # globalSetup * **Type:** `string | string[]` Path to global setup files relative to project [root](/config/root). A global setup file can either export named functions `setup` and `teardown` or a `default` function that returns a teardown function: ::: code-group ```js [exports] export function setup(project) { console.log('setup') } export function teardown() { console.log('teardown') } ``` ```js [default] export default function setup(project) { console.log('setup') return function teardown() { console.log('teardown') } } ``` ::: Note that the `setup` method and a `default` function receive a [test project](/api/advanced/test-project) as the first argument. The global setup is called before the test workers are created and only if there is at least one test queued, and teardown is called after all test files have finished running. In [watch mode](/config/watch), the teardown is called before the process is exited instead. If you need to reconfigure your setup before the test rerun, you can use [`onTestsRerun`](#handling-test-reruns) hook instead. Multiple global setup files are possible. `setup` and `teardown` are executed sequentially with teardown in reverse order. ::: danger Beware that the global setup is running in a different global scope before test workers are even created, so your tests don't have access to global variables defined here. However, you can pass down serializable data to tests via [`provide`](/config/provide) method and read them in your tests via `inject` imported from `vitest`: :::code-group ```ts [example.test.ts] import { inject } from 'vitest' inject('wsPort') === 3000 ``` ```ts [globalSetup.ts] import type { TestProject } from 'vitest/node' export default function setup(project: TestProject) { project.provide('wsPort', 3000) } declare module 'vitest' { export interface ProvidedContext { wsPort: number } } ``` If you need to execute code in the same process as tests, use [`setupFiles`](/config/setupfiles) instead, but note that it runs before every test file. ::: ### Handling Test Reruns You can define a custom callback function to be called when Vitest reruns tests. The test 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 [globalSetup.ts] import type { TestProject } from 'vitest/node' export default function setup(project: TestProject) { project.onTestsRerun(async () => { await restartDb() }) } ``` --- # Source: https://vitest.dev/guide.md --- url: /guide.md --- # Getting Started ## Overview Vitest (pronounced as *"veetest"*) is a next generation testing framework powered by Vite. You can learn more about the rationale behind the project in the [Why Vitest](/guide/why) section. ## Trying Vitest Online You can try Vitest online on [StackBlitz](https://vitest.new). It runs Vitest directly in the browser, and it is almost identical to the local setup but doesn't require installing anything on your machine. ## Adding Vitest to Your Project Learn how to install by Video ::: code-group ```bash [npm] npm install -D vitest ``` ```bash [yarn] yarn add -D vitest ``` ```bash [pnpm] pnpm add -D vitest ``` ```bash [bun] bun add -D vitest ``` ::: :::tip Vitest requires Vite >=v6.0.0 and Node >=v20.0.0 ::: It is recommended that you install a copy of `vitest` in your `package.json`, using one of the methods listed above. However, if you would prefer to run `vitest` directly, you can use `npx vitest` (the `npx` tool comes with npm and Node.js). The `npx` tool will execute the specified command. By default, `npx` will first check if the command exists in the local project's binaries. If it is not found there, `npx` will look in the system's `$PATH` and execute it if found. If the command is not found in either location, `npx` will install it in a temporary location prior to execution. ## Writing Tests As an example, we will write a simple test that verifies the output of a function that adds two numbers. ```js [sum.js] export function sum(a, b) { return a + b } ``` ```js [sum.test.js] import { expect, test } from 'vitest' import { sum } from './sum.js' test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3) }) ``` ::: tip By default, tests must contain `.test.` or `.spec.` in their file name. ::: Next, in order to execute the test, add the following section to your `package.json`: ```json [package.json] { "scripts": { "test": "vitest" } } ``` Finally, run `npm run test`, `yarn test` or `pnpm test`, depending on your package manager, and Vitest will print this message: ```txt ✓ sum.test.js (1) ✓ adds 1 + 2 to equal 3 Test Files 1 passed (1) Tests 1 passed (1) Start at 02:15:44 Duration 311ms ``` ::: warning If you are using Bun as your package manager, make sure to use `bun run test` command instead of `bun test`, otherwise Bun will run its own test runner. ::: Learn more about the usage of Vitest, see the [API](/api/) section. ## Configuring Vitest One of the main advantages of Vitest is its unified configuration with Vite. If present, `vitest` will read your root `vite.config.ts` to match with the plugins and setup as your Vite app. For example, your Vite [resolve.alias](https://vitejs.dev/config/shared-options.html#resolve-alias) and [plugins](https://vitejs.dev/guide/using-plugins.html) configuration will work out-of-the-box. If you want a different configuration during testing, you can: * Create `vitest.config.ts`, which will have the higher priority * Pass `--config` option to CLI, e.g. `vitest --config ./path/to/vitest.config.ts` * Use `process.env.VITEST` or `mode` property on `defineConfig` (will be set to `test` if not overridden) to conditionally apply different configuration in `vite.config.ts`. Note that like any other environment variable, `VITEST` is also exposed on `import.meta.env` in your tests Vitest supports the same extensions for your configuration file as Vite does: `.js`, `.mjs`, `.cjs`, `.ts`, `.cts`, `.mts`. Vitest does not support `.json` extension. If you are not using Vite as your build tool, you can configure Vitest using the `test` property in your config file: ```ts [vitest.config.ts] import { defineConfig } from 'vitest/config' export default defineConfig({ test: { // ... }, }) ``` ::: tip Even if you do not use Vite yourself, Vitest relies heavily on it for its transformation pipeline. For that reason, you can also configure any property described in [Vite documentation](https://vitejs.dev/config/). ::: If you are already using Vite, add `test` property in your Vite config. You'll also need to add a reference to Vitest types using a [triple slash directive](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html#-reference-types-) at the top of your config file. ```ts [vite.config.ts] /// import { defineConfig } from 'vite' export default defineConfig({ test: { // ... }, }) ``` See the list of config options in the [Config Reference](../config/) ::: warning If you decide to have two separate config files for Vite and Vitest, make sure to define the same Vite options in your Vitest config file since it will override your Vite file, not extend it. You can also use `mergeConfig` method from `vite` or `vitest/config` entries to merge Vite config with Vitest config: :::code-group ```ts [vitest.config.mjs] import { defineConfig, mergeConfig } from 'vitest/config' import viteConfig from './vite.config.mjs' export default mergeConfig(viteConfig, defineConfig({ test: { // ... }, })) ``` ```ts [vite.config.mjs] import { defineConfig } from 'vite' import Vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [Vue()], }) ``` However, we recommend using the same file for both Vite and Vitest, instead of creating two separate files. ::: ## Projects Support Run different project configurations inside the same project with [Test Projects](/guide/projects). You can define a list of files and folders that define your projects in `vitest.config` file. ```ts [vitest.config.ts] import { defineConfig } from 'vitest/config' export default defineConfig({ test: { projects: [ // you can use a list of glob patterns to define your projects // Vitest expects a list of config files // or directories where there is a config file 'packages/*', 'tests/*/vitest.config.{e2e,unit}.ts', // you can even run the same tests, // but with different configs in the same "vitest" process { test: { name: 'happy-dom', root: './shared_tests', environment: 'happy-dom', setupFiles: ['./setup.happy-dom.ts'], }, }, { test: { name: 'node', root: './shared_tests', environment: 'node', setupFiles: ['./setup.node.ts'], }, }, ], }, }) ``` ## Command Line Interface In a project where Vitest is installed, you can use the `vitest` binary in your npm scripts, or run it directly with `npx vitest`. Here are the default npm scripts in a scaffolded Vitest project: ```json [package.json] { "scripts": { "test": "vitest", "coverage": "vitest run --coverage" } } ``` To run tests once without watching for file changes, use `vitest run`. You can specify additional CLI options like `--port` or `--https`. For a full list of CLI options, run `npx vitest --help` in your project. Learn more about the [Command Line Interface](/guide/cli) ## Automatic Dependency Installation Vitest will prompt you to install certain dependencies if they are not already installed. You can disable this behavior by setting the `VITEST_SKIP_INSTALL_CHECKS=1` environment variable. ## IDE Integrations We also provided an official extension for Visual Studio Code to enhance your testing experience with Vitest. [Install from VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=vitest.explorer) Learn more about [IDE Integrations](/guide/ide) ## Examples | Example | Source | Playground | |---|---|---| | `basic` | [GitHub](https://github.com/vitest-dev/vitest/tree/main/examples/basic) | [Play Online](https://stackblitz.com/fork/github/vitest-dev/vitest/tree/main/examples/basic?initialPath=__vitest__/) | | `fastify` | [GitHub](https://github.com/vitest-dev/vitest/tree/main/examples/fastify) | [Play Online](https://stackblitz.com/fork/github/vitest-dev/vitest/tree/main/examples/fastify?initialPath=__vitest__/) | | `in-source-test` | [GitHub](https://github.com/vitest-dev/vitest/tree/main/examples/in-source-test) | [Play Online](https://stackblitz.com/fork/github/vitest-dev/vitest/tree/main/examples/in-source-test?initialPath=__vitest__/) | | `lit` | [GitHub](https://github.com/vitest-dev/vitest/tree/main/examples/lit) | [Play Online](https://stackblitz.com/fork/github/vitest-dev/vitest/tree/main/examples/lit?initialPath=__vitest__/) | | `vue` | [GitHub](https://github.com/vitest-tests/browser-examples/tree/main/examples/vue) | [Play Online](https://stackblitz.com/fork/github/vitest-tests/browser-examples/tree/main/examples/vue?initialPath=__vitest__/) | | `marko` | [GitHub](https://github.com/vitest-tests/browser-examples/tree/main/examples/marko) | [Play Online](https://stackblitz.com/fork/github/vitest-tests/browser-examples/tree/main/examples/marko?initialPath=__vitest__/) | | `preact` | [GitHub](https://github.com/vitest-tests/browser-examples/tree/main/examples/preact) | [Play Online](https://stackblitz.com/fork/github/vitest-tests/browser-examples/tree/main/examples/preact?initialPath=__vitest__/) | | `qwik`| [Github](https://github.com/vitest-tests/browser-examples/tree/main/examples/qwik) | [Play Online](https://stackblitz.com/fork/github/vitest-tests/browser-examples/tree/main/examples/qwik?initialPath=__vitest__/) | | `react` | [GitHub](https://github.com/vitest-tests/browser-examples/tree/main/examples/react) | [Play Online](https://stackblitz.com/fork/github/vitest-tests/browser-examples/tree/main/examples/react?initialPath=__vitest__/) | | `solid` | [GitHub](https://github.com/vitest-tests/browser-examples/tree/main/examples/solid) | [Play Online](https://stackblitz.com/fork/github/vitest-tests/browser-examples/tree/main/examples/solid?initialPath=__vitest__/) | | `svelte` | [GitHub](https://github.com/vitest-tests/browser-examples/tree/main/examples/svelte) | [Play Online](https://stackblitz.com/fork/github/vitest-tests/browser-examples/tree/main/examples/svelte?initialPath=__vitest__/) | | `profiling` | [GitHub](https://github.com/vitest-dev/vitest/tree/main/examples/profiling) | Not Available | | `typecheck` | [GitHub](https://github.com/vitest-dev/vitest/tree/main/examples/typecheck) | [Play Online](https://stackblitz.com/fork/github/vitest-dev/vitest/tree/main/examples/typecheck?initialPath=__vitest__/) | | `projects` | [GitHub](https://github.com/vitest-dev/vitest/tree/main/examples/projects) | [Play Online](https://stackblitz.com/fork/github/vitest-dev/vitest/tree/main/examples/projects?initialPath=__vitest__/) | ## Projects using Vitest * [unocss](https://github.com/unocss/unocss) * [unplugin-auto-import](https://github.com/antfu/unplugin-auto-import) * [unplugin-vue-components](https://github.com/antfu/unplugin-vue-components) * [vue](https://github.com/vuejs/core) * [vite](https://github.com/vitejs/vite) * [vitesse](https://github.com/antfu/vitesse) * [vitesse-lite](https://github.com/antfu/vitesse-lite) * [fluent-vue](https://github.com/demivan/fluent-vue) * [vueuse](https://github.com/vueuse/vueuse) * [milkdown](https://github.com/Saul-Mirone/milkdown) * [gridjs-svelte](https://github.com/iamyuu/gridjs-svelte) * [spring-easing](https://github.com/okikio/spring-easing) * [bytemd](https://github.com/bytedance/bytemd) * [faker](https://github.com/faker-js/faker) * [million](https://github.com/aidenybai/million) * [Vitamin](https://github.com/wtchnm/Vitamin) * [neodrag](https://github.com/PuruVJ/neodrag) * [svelte-multiselect](https://github.com/janosh/svelte-multiselect) * [iconify](https://github.com/iconify/iconify) * [tdesign-vue-next](https://github.com/Tencent/tdesign-vue-next) * [cz-git](https://github.com/Zhengqbbb/cz-git) ## Using Unreleased Commits Each commit on main branch and a PR with a `cr-tracked` label are published to [pkg.pr.new](https://github.com/stackblitz-labs/pkg.pr.new). You can install it by `npm i https://pkg.pr.new/vitest@{commit}`. If you want to test your own modification locally, you can build and link it yourself ([pnpm](https://pnpm.io/) is required): ```bash git clone https://github.com/vitest-dev/vitest.git cd vitest pnpm install cd packages/vitest pnpm run build pnpm link --global # you can use your preferred package manager for this step ``` Then go to the project where you are using Vitest and run `pnpm link --global vitest` (or the package manager that you used to link `vitest` globally). ## Community If you have questions or need help, reach out to the community at [Discord](https://chat.vitest.dev) and [GitHub Discussions](https://github.com/vitest-dev/vitest/discussions). --- # Source: https://vitest.dev/config/browser/headless.md --- url: /config/browser/headless.md --- # browser.headless * **Type:** `boolean` * **Default:** `process.env.CI` * **CLI:** `--browser.headless`, `--browser.headless=false` Run the browser in a `headless` mode. If you are running Vitest in CI, it will be enabled by default. --- # Source: https://vitest.dev/config/hideskippedtests.md --- url: /config/hideskippedtests.md --- # hideSkippedTests * **Type:** `boolean` * **CLI:** `--hideSkippedTests`, `--hide-skipped-tests` * **Default:** `false` Hide logs for skipped tests --- # Source: https://vitest.dev/config/hooktimeout.md --- url: /config/hooktimeout.md --- # hookTimeout * **Type:** `number` * **Default:** `10_000` in Node.js, `30_000` if `browser.enabled` is `true` * **CLI:** `--hook-timeout=10000`, `--hookTimeout=10000` Default timeout of a hook in milliseconds. Use `0` to disable timeout completely. --- # Source: https://vitest.dev/guide/ide.md --- url: /guide/ide.md --- # IDE Integrations ## VS Code Official {#vs-code} [GitHub](https://github.com/vitest-dev/vscode) | [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=vitest.explorer) ![](https://i.ibb.co/bJCbCf2/202203292020.gif) ## JetBrains IDE WebStorm, PhpStorm, IntelliJ IDEA Ultimate, and other JetBrains IDEs come with built-in support for Vitest. [WebStorm Help](https://www.jetbrains.com/help/webstorm/vitest.html) | [IntelliJ IDEA Ultimate Help](https://www.jetbrains.com/help/idea/vitest.html) | [PhpStorm Help](https://www.jetbrains.com/help/phpstorm/vitest.html) ![Vitest WebStorm Demo](https://raw.githubusercontent.com/kricact/WS-info/main/gifs/vitest-run-all.gif) ## Wallaby.js Paid (free for OSS) Created by [The Wallaby Team](https://wallabyjs.com) [Wallaby.js](https://wallabyjs.com) runs your Vitest tests immediately as you type, highlighting results in your IDE right next to your code. [VS Code](https://marketplace.visualstudio.com/items?itemName=WallabyJs.wallaby-vscode) | [JetBrains](https://plugins.jetbrains.com/plugin/15742-wallaby) | [Visual Studio](https://marketplace.visualstudio.com/items?itemName=vs-publisher-999439.WallabyjsforVisualStudio2022) | [Sublime Text](https://packagecontrol.io/packages/Wallaby) ![Wallaby VS Code Demo](https://wallabyjs.com/assets/img/vitest_demo.gif) --- # Source: https://vitest.dev/api/advanced/import-example.md --- url: /api/advanced/import-example.md --- ```ts function import(moduleId: string): Promise ``` --- # Source: https://vitest.dev/guide/improving-performance.md --- url: /guide/improving-performance.md --- # Improving Performance ## Test Isolation By default Vitest runs every test file in an isolated environment based on the [pool](/config/#pool): * `threads` pool runs every test file in a separate [`Worker`](https://nodejs.org/api/worker_threads.html#class-worker) * `forks` pool runs every test file in a separate [forked child process](https://nodejs.org/api/child_process.html#child_processforkmodulepath-args-options) * `vmThreads` pool runs every test file in a separate [VM context](https://nodejs.org/api/vm.html#vmcreatecontextcontextobject-options), but it uses workers for parallelism This greatly increases test times, which might not be desirable for projects that don't rely on side effects and properly cleanup their state (which is usually true for projects with `node` environment). In this case disabling isolation will improve the speed of your tests. To do that, you can provide `--no-isolate` flag to the CLI or set [`test.isolate`](/config/#isolate) property in the config to `false`. ::: code-group ```bash [CLI] vitest --no-isolate ``` ```ts [vitest.config.js] import { defineConfig } from 'vitest/config' export default defineConfig({ test: { isolate: false, }, }) ``` ::: You can also disable isolation for specific files only by using `projects`: ```ts [vitest.config.js] import { defineConfig } from 'vitest/config' export default defineConfig({ test: { projects: [ { name: 'Isolated', isolate: true, // (default value) exclude: ['**.non-isolated.test.ts'], }, { name: 'Non-isolated', isolate: false, include: ['**.non-isolated.test.ts'], } ] }, }) ``` :::tip If you are using `vmThreads` pool, you cannot disable isolation. Use `threads` pool instead to improve your tests performance. ::: For some projects, it might also be desirable to disable parallelism to improve startup time. To do that, provide `--no-file-parallelism` flag to the CLI or set [`test.fileParallelism`](/config/#fileparallelism) property in the config to `false`. ::: code-group ```bash [CLI] vitest --no-file-parallelism ``` ```ts [vitest.config.js] import { defineConfig } from 'vitest/config' export default defineConfig({ test: { fileParallelism: false, }, }) ``` ::: ## Limiting Directory Search You can limit the working directory when Vitest searches for files using [`test.dir`](/config/#test-dir) option. This should make the search faster if you have unrelated folders and files in the root directory. ## Pool By default Vitest runs tests in `pool: 'forks'`. While `'forks'` pool is better for compatibility issues ([hanging process](/guide/common-errors.html#failed-to-terminate-worker) and [segfaults](/guide/common-errors.html#segfaults-and-native-code-errors)), it may be slightly slower than `pool: 'threads'` in larger projects. You can try to improve test run time by switching `pool` option in configuration: ::: code-group ```bash [CLI] vitest --pool=threads ``` ```ts [vitest.config.js] import { defineConfig } from 'vitest/config' export default defineConfig({ test: { pool: 'threads', }, }) ``` ::: ## Sharding Test sharding is a process of splitting your test suite into groups, or shards. This can be useful when you have a large test suite and multiple machines that could run subsets of that suite simultaneously. To split Vitest tests on multiple different runs, use [`--shard`](/guide/cli#shard) option with [`--reporter=blob`](/guide/reporters#blob-reporter) option: ```sh vitest run --reporter=blob --shard=1/3 # 1st machine vitest run --reporter=blob --shard=2/3 # 2nd machine vitest run --reporter=blob --shard=3/3 # 3rd machine ``` > Vitest splits your *test files*, not your test cases, into shards. If you've got 1000 test files, the `--shard=1/4` option will run 250 test files, no matter how many test cases individual files have. Collect the results stored in `.vitest-reports` directory from each machine and merge them with [`--merge-reports`](/guide/cli#merge-reports) option: ```sh vitest run --merge-reports ``` ::: details GitHub Actions example This setup is also used at https://github.com/vitest-tests/test-sharding. ```yaml # Inspired from https://playwright.dev/docs/test-sharding name: Tests on: push: branches: - main jobs: tests: runs-on: ubuntu-latest strategy: matrix: shardIndex: [1, 2, 3, 4] shardTotal: [4] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - name: Install pnpm uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 - name: Install dependencies run: pnpm i - name: Run tests run: pnpm run test --reporter=blob --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} - name: Upload blob report to GitHub Actions Artifacts if: ${{ !cancelled() }} uses: actions/upload-artifact@v4 with: name: blob-report-${{ matrix.shardIndex }} path: .vitest-reports/* include-hidden-files: true retention-days: 1 merge-reports: if: ${{ !cancelled() }} needs: [tests] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - name: Install pnpm uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 - name: Install dependencies run: pnpm i - name: Download blob reports from GitHub Actions Artifacts uses: actions/download-artifact@v4 with: path: .vitest-reports pattern: blob-report-* merge-multiple: true - name: Merge reports run: npx vitest --merge-reports ``` ::: :::tip Test sharding can also become useful on high CPU-count machines. Vitest will run only a single Vite server in its main thread. Rest of the threads are used to run test files. In a high CPU-count machine the main thread can become a bottleneck as it cannot handle all the requests coming from the threads. For example in 32 CPU machine the main thread is responsible to handle load coming from 31 test threads. To reduce the load from main thread's Vite server you can use test sharding. The load can be balanced on multiple Vite server. ```sh # Example for splitting tests on 32 CPU to 4 shards. # As each process needs 1 main thread, there's 7 threads for test runners (1+7)*4 = 32 # Use VITEST_MAX_WORKERS: VITEST_MAX_WORKERS=7 vitest run --reporter=blob --shard=1/4 & \ VITEST_MAX_WORKERS=7 vitest run --reporter=blob --shard=2/4 & \ VITEST_MAX_WORKERS=7 vitest run --reporter=blob --shard=3/4 & \ VITEST_MAX_WORKERS=7 vitest run --reporter=blob --shard=4/4 & \ wait # https://man7.org/linux/man-pages/man2/waitpid.2.html vitest run --merge-reports ``` ::: --- # Source: https://vitest.dev/guide/in-source.md --- url: /guide/in-source.md --- # In-Source Testing Vitest provides a way to run tests within your source code along side the implementation, similar to [Rust's module tests](https://doc.rust-lang.org/book/ch11-03-test-organization.html#the-tests-module-and-cfgtest). This makes the tests share the same closure as the implementations and able to test against private states without exporting. Meanwhile, it also brings a closer feedback loop for development. ::: warning This guide explains how to write tests inside your source code. If you need to write tests in separate test files, follow the ["Writing Tests" guide](/guide/#writing-tests). ::: ## Setup To get started, put a `if (import.meta.vitest)` block at the end of your source file and write some tests inside it. For example: ```ts [src/index.ts] // the implementation export function add(...args: number[]) { return args.reduce((a, b) => a + b, 0) } // in-source test suites if (import.meta.vitest) { const { it, expect } = import.meta.vitest it('add', () => { expect(add()).toBe(0) expect(add(1)).toBe(1) expect(add(1, 2, 3)).toBe(6) }) } ``` Update the `includeSource` config for Vitest to grab the files under `src/`: ```ts [vitest.config.ts] import { defineConfig } from 'vitest/config' export default defineConfig({ test: { includeSource: ['src/**/*.{js,ts}'], // [!code ++] }, }) ``` Then you can start to test! ```bash $ npx vitest ``` ## Production Build For the production build, you will need to set the `define` options in your config file, letting the bundler do the dead code elimination. For example, in Vite ```ts [vite.config.ts] /// import { defineConfig } from 'vite' export default defineConfig({ test: { includeSource: ['src/**/*.{js,ts}'], }, define: { // [!code ++] 'import.meta.vitest': 'undefined', // [!code ++] }, // [!code ++] }) ``` ### Other Bundlers ::: details Rolldown ```js [rolldown.config.js] import { defineConfig } from 'rolldown/config' export default defineConfig({ transform: { define: { // [!code ++] 'import.meta.vitest': 'undefined', // [!code ++] }, // [!code ++] }, }) ``` Learn more: [Rolldown](https://rolldown.rs/) ::: ::: details Rollup ```js [rollup.config.js] import replace from '@rollup/plugin-replace' // [!code ++] export default { plugins: [ replace({ // [!code ++] 'import.meta.vitest': 'undefined', // [!code ++] }) // [!code ++] ], // other options } ``` Learn more: [Rollup](https://rollupjs.org/) ::: ::: details unbuild ```js [build.config.js] import { defineBuildConfig } from 'unbuild' export default defineBuildConfig({ replace: { // [!code ++] 'import.meta.vitest': 'undefined', // [!code ++] }, // [!code ++] // other options }) ``` Learn more: [unbuild](https://github.com/unjs/unbuild) ::: ::: details webpack ```js [webpack.config.js] const webpack = require('webpack') module.exports = { plugins: [ new webpack.DefinePlugin({ // [!code ++] 'import.meta.vitest': 'undefined', // [!code ++] })// [!code ++] ], } ``` Learn more: [webpack](https://webpack.js.org/plugins/define-plugin/) ::: ## TypeScript To get TypeScript support for `import.meta.vitest`, add `vitest/importMeta` to your `tsconfig.json`: ```json [tsconfig.json] { "compilerOptions": { "types": [ "vitest/importMeta" // [!code ++] ] } } ``` Reference to [`examples/in-source-test`](https://github.com/vitest-dev/vitest/tree/main/examples/in-source-test) for the full example. ## Notes This feature could be useful for: * Unit testing for small-scoped functions or utilities * Prototyping * Inline Assertion It's recommended to **use separate test files instead** for more complex tests like components or E2E testing. --- # Source: https://vitest.dev/config/include-source.md --- url: /config/include-source.md --- # includeSource * **Type:** `string[]` * **Default:** `[]` A list of [glob patterns](https://superchupu.dev/tinyglobby/comparison) that match your [in-source test files](/guide/in-source). These patterns are resolved relative to the [`root`](/config/root) ([`process.cwd()`](https://nodejs.org/api/process.html#processcwd) by default). When defined, Vitest will run all matched files that have `import.meta.vitest` inside. ::: warning Vitest performs a simple text-based inclusion check on source files. If a file contains `import.meta.vitest`, even in a comment, it will be matched as an in-source test file. ::: Vitest uses the [`tinyglobby`](https://www.npmjs.com/package/tinyglobby) package to resolve the globs. ## Example ```js import { defineConfig } from 'vitest/config' export default defineConfig({ test: { includeSource: ['src/**/*.{js,ts}'], }, }) ``` Then you can write tests inside your source files: ```ts [src/index.ts] export function add(...args: number[]) { return args.reduce((a, b) => a + b, 0) } // #region in-source test suites if (import.meta.vitest) { const { it, expect } = import.meta.vitest it('add', () => { expect(add()).toBe(0) expect(add(1)).toBe(1) expect(add(1, 2, 3)).toBe(6) }) } // #endregion ``` For your production build, you need to replace the `import.meta.vitest` with `undefined`, letting the bundler do the dead code elimination. ::: code-group ```js [vite.config.ts] import { defineConfig } from 'vite' export default defineConfig({ define: { // [!code ++] 'import.meta.vitest': 'undefined', // [!code ++] }, // [!code ++] }) ``` ```js [rolldown.config.js] import { defineConfig } from 'rolldown/config' export default defineConfig({ transform: { define: { // [!code ++] 'import.meta.vitest': 'undefined', // [!code ++] }, // [!code ++] }, }) ``` ```js [rollup.config.js] import replace from '@rollup/plugin-replace' // [!code ++] export default { plugins: [ replace({ // [!code ++] 'import.meta.vitest': 'undefined', // [!code ++] }) // [!code ++] ], // other options } ``` ```js [build.config.js] import { defineBuildConfig } from 'unbuild' export default defineBuildConfig({ replace: { // [!code ++] 'import.meta.vitest': 'undefined', // [!code ++] }, // [!code ++] // other options }) ``` ```js [webpack.config.js] const webpack = require('webpack') module.exports = { plugins: [ new webpack.DefinePlugin({ // [!code ++] 'import.meta.vitest': 'undefined', // [!code ++] })// [!code ++] ], } ``` ::: ::: tip To get TypeScript support for `import.meta.vitest`, add `vitest/importMeta` to your `tsconfig.json`: ```json [tsconfig.json] { "compilerOptions": { "types": ["vitest/importMeta"] } } ``` ::: --- # Source: https://vitest.dev/config/include.md --- url: /config/include.md --- # include * **Type:** `string[]` * **Default:** `['**/*.{test,spec}.?(c|m)[jt]s?(x)']` * **CLI:** `vitest [...include]`, `vitest **/*.test.js` A list of [glob patterns](https://superchupu.dev/tinyglobby/comparison) that match your test files. These patterns are resolved relative to the [`root`](/config/root) ([`process.cwd()`](https://nodejs.org/api/process.html#processcwd) by default). Vitest uses the [`tinyglobby`](https://www.npmjs.com/package/tinyglobby) package to resolve the globs. ::: tip NOTE When using coverage, Vitest automatically adds test files `include` patterns to coverage's default `exclude` patterns. See [`coverage.exclude`](/config/coverage#exclude). ::: ## Example ```js import { defineConfig } from 'vitest/config' export default defineConfig({ test: { include: [ './test', './**/*.{test,spec}.tsx?', ], }, }) ``` Vitest provides reasonable defaults, so normally you wouldn't override them. A good example of defining `include` is for [test projects](/guide/projects): ```js{8,12} [vitest.config.js] import { defineConfig } from 'vitest/config' export default defineConfig({ test: { projects: [ { name: 'unit', include: ['./test/unit/*.test.js'], }, { name: 'e2e', include: ['./test/e2e/*.test.js'], }, ], }, }) ``` ::: warning This option will override Vitest defaults. If you just want to extend them, use `configDefaults` from `vitest/config`: ```js{6} import { configDefaults, defineConfig } from 'vitest/config' export default defineConfig({ test: { include: [ ...configDefaults.include, './test', './**/*.{test,spec}.tsx?', ], }, }) ``` ::: --- # Source: https://vitest.dev/config/includetasklocation.md --- url: /config/includetasklocation.md --- # includeTaskLocation * **Type:** `boolean` * **Default:** `false` Should `location` property be included when Vitest API receives tasks in [reporters](#reporters). If you have a lot of tests, this might cause a small performance regression. The `location` property has `column` and `line` values that correspond to the `test` or `describe` position in the original file. This option will be auto-enabled if you don't disable it explicitly, and you are running Vitest with: * [Vitest UI](/guide/ui) * or using the [Browser Mode](/guide/browser/) without [headless](/guide/browser/#headless) mode * or using [HTML Reporter](/guide/reporters#html-reporter) ::: tip This option has no effect if you do not use custom code that relies on this. ::: --- # Source: https://vitest.dev/config/browser/instances.md --- url: /config/browser/instances.md --- # browser.instances * **Type:** `BrowserConfig` * **Default:** `[]` Defines multiple browser setups. Every config has to have at least a `browser` field. You can specify most of the [project options](/config/) (not marked with a icon) and some of the `browser` options like `browser.testerHtmlPath`. ::: warning Every browser config inherits options from the root config: ```ts{3,9} [vitest.config.ts] export default defineConfig({ test: { setupFile: ['./root-setup-file.js'], browser: { enabled: true, testerHtmlPath: './custom-path.html', instances: [ { // will have both setup files: "root" and "browser" setupFile: ['./browser-setup-file.js'], // implicitly has "testerHtmlPath" from the root config // [!code warning] // testerHtmlPath: './custom-path.html', // [!code warning] }, ], }, }, }) ``` For more examples, refer to the ["Multiple Setups" guide](/guide/browser/multiple-setups). ::: List of available `browser` options: * `browser` (the name of the browser) * [`headless`](/config/browser/headless) * [`locators`](/config/browser/locators) * [`viewport`](/config/browser/viewport) * [`testerHtmlPath`](/config/browser/testerhtmlpath) * [`screenshotDirectory`](/config/browser/screenshotdirectory) * [`screenshotFailures`](/config/browser/screenshotfailures) * [`provider`](/config/browser/provider) Under the hood, Vitest transforms these instances into separate [test projects](/api/advanced/test-project) sharing a single Vite server for better caching performance. --- # Source: https://vitest.dev/api/browser/interactivity.md --- url: /api/browser/interactivity.md --- # Interactivity API Vitest implements a subset of [`@testing-library/user-event`](https://testing-library.com/docs/user-event/intro) APIs using [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/) or [webdriver](https://www.w3.org/TR/webdriver/) instead of faking events which makes the browser behaviour more reliable and consistent with how users interact with a page. ```ts import { userEvent } from 'vitest/browser' await userEvent.click(document.querySelector('.button')) ``` Almost every `userEvent` method inherits its provider options. ## userEvent.setup ```ts function setup(): UserEvent ``` Creates a new user event instance. This is useful if you need to keep the state of keyboard to press and release buttons correctly. ::: warning Unlike `@testing-library/user-event`, the default `userEvent` instance from `vitest/browser` is created once, not every time its methods are called! You can see the difference in how it works in this snippet: ```ts import { userEvent as vitestUserEvent } from 'vitest/browser' import { userEvent as originalUserEvent } from '@testing-library/user-event' await vitestUserEvent.keyboard('{Shift}') // press shift without releasing await vitestUserEvent.keyboard('{/Shift}') // releases shift await originalUserEvent.keyboard('{Shift}') // press shift without releasing await originalUserEvent.keyboard('{/Shift}') // DID NOT release shift because the state is different ``` This behaviour is more useful because we do not emulate the keyboard, we actually press the Shift, so keeping the original behaviour would cause unexpected issues when typing in the field. ::: ## userEvent.click ```ts function click( element: Element | Locator, options?: UserEventClickOptions, ): Promise ``` Click on an element. Inherits provider's options. Please refer to your provider's documentation for detailed explanation about how this method works. ```ts import { page, userEvent } from 'vitest/browser' test('clicks on an element', async () => { const logo = page.getByRole('img', { name: /logo/ }) await userEvent.click(logo) // or you can access it directly on the locator await logo.click() // With WebdriverIO, this uses either ElementClick (with no arguments) or // actions (with arguments). Use an empty object to force the use of actions. await logo.click({}) }) ``` ### Clicking with a modifier With either WebdriverIO or Playwright: ```ts await userEvent.keyboard('{Shift>}') // By using an empty object as the option, this opts in to using a chain of actions // instead of an ElementClick in webdriver. // Firefox has a bug that makes this necessary. // Follow https://bugzilla.mozilla.org/show_bug.cgi?id=1456642 to know when this // will be fixed. await userEvent.click(element, {}) await userEvent.keyboard('{/Shift}') ``` With Playwright: ```ts await userEvent.click(element, { modifiers: ['Shift'] }) ``` References: * [Playwright `locator.click` API](https://playwright.dev/docs/api/class-locator#locator-click) * [WebdriverIO `element.click` API](https://webdriver.io/docs/api/element/click/) * [testing-library `click` API](https://testing-library.com/docs/user-event/convenience/#click) ## userEvent.dblClick ```ts function dblClick( element: Element | Locator, options?: UserEventDoubleClickOptions, ): Promise ``` Triggers a double click event on an element. Please refer to your provider's documentation for detailed explanation about how this method works. ```ts import { page, userEvent } from 'vitest/browser' test('triggers a double click on an element', async () => { const logo = page.getByRole('img', { name: /logo/ }) await userEvent.dblClick(logo) // or you can access it directly on the locator await logo.dblClick() }) ``` References: * [Playwright `locator.dblclick` API](https://playwright.dev/docs/api/class-locator#locator-dblclick) * [WebdriverIO `element.doubleClick` API](https://webdriver.io/docs/api/element/doubleClick/) * [testing-library `dblClick` API](https://testing-library.com/docs/user-event/convenience/#dblClick) ## userEvent.tripleClick ```ts function tripleClick( element: Element | Locator, options?: UserEventTripleClickOptions, ): Promise ``` Triggers a triple click event on an element. Since there is no `tripleclick` in browser api, this method will fire three click events in a row, and so you must check [click event detail](https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event#usage_notes) to filter the event: `evt.detail === 3`. Please refer to your provider's documentation for detailed explanation about how this method works. ```ts import { page, userEvent } from 'vitest/browser' test('triggers a triple click on an element', async () => { const logo = page.getByRole('img', { name: /logo/ }) let tripleClickFired = false logo.addEventListener('click', (evt) => { if (evt.detail === 3) { tripleClickFired = true } }) await userEvent.tripleClick(logo) // or you can access it directly on the locator await logo.tripleClick() expect(tripleClickFired).toBe(true) }) ``` References: * [Playwright `locator.click` API](https://playwright.dev/docs/api/class-locator#locator-click): implemented via `click` with `clickCount: 3` . * [WebdriverIO `browser.action` API](https://webdriver.io/docs/api/browser/action/): implemented via actions api with `move` plus three `down + up + pause` events in a row * [testing-library `tripleClick` API](https://testing-library.com/docs/user-event/convenience/#tripleClick) ## userEvent.fill ```ts function fill( element: Element | Locator, text: string, ): Promise ``` Set a value to the `input`/`textarea`/`contenteditable` field. This will remove any existing text in the input before setting the new value. ```ts import { page, userEvent } from 'vitest/browser' test('update input', async () => { const input = page.getByRole('input') await userEvent.fill(input, 'foo') // input.value == foo await userEvent.fill(input, '{{a[[') // input.value == {{a[[ await userEvent.fill(input, '{Shift}') // input.value == {Shift} // or you can access it directly on the locator await input.fill('foo') // input.value == foo }) ``` This methods focuses the element, fills it and triggers an `input` event after filling. You can use an empty string to clear the field. ::: tip This API is faster than using [`userEvent.type`](#userevent-type) or [`userEvent.keyboard`](#userevent-keyboard), but it **doesn't support** [user-event `keyboard` syntax](https://testing-library.com/docs/user-event/keyboard) (e.g., `{Shift}{selectall}`). We recommend using this API over [`userEvent.type`](#userevent-type) in situations when you don't need to enter special characters or have granular control over keypress events. ::: References: * [Playwright `locator.fill` API](https://playwright.dev/docs/api/class-locator#locator-fill) * [WebdriverIO `element.setValue` API](https://webdriver.io/docs/api/element/setValue) * [testing-library `type` API](https://testing-library.com/docs/user-event/utility/#type) ## userEvent.keyboard ```ts function keyboard(text: string): Promise ``` The `userEvent.keyboard` allows you to trigger keyboard strokes. If any input has a focus, it will type characters into that input. Otherwise, it will trigger keyboard events on the currently focused element (`document.body` if there are no focused elements). This API supports [user-event `keyboard` syntax](https://testing-library.com/docs/user-event/keyboard). ```ts import { userEvent } from 'vitest/browser' test('trigger keystrokes', async () => { await userEvent.keyboard('foo') // translates to: f, o, o await userEvent.keyboard('{{a[[') // translates to: {, a, [ await userEvent.keyboard('{Shift}{f}{o}{o}') // translates to: Shift, f, o, o await userEvent.keyboard('{a>5}') // press a without releasing it and trigger 5 keydown await userEvent.keyboard('{a>5/}') // press a for 5 keydown and then release it }) ``` References: * [Playwright `Keyboard` API](https://playwright.dev/docs/api/class-keyboard) * [WebdriverIO `action('key')` API](https://webdriver.io/docs/api/browser/action#key-input-source) * [testing-library `type` API](https://testing-library.com/docs/user-event/utility/#type) ## userEvent.tab ```ts function tab(options?: UserEventTabOptions): Promise ``` Sends a `Tab` key event. This is a shorthand for `userEvent.keyboard('{tab}')`. ```ts import { page, userEvent } from 'vitest/browser' test('tab works', async () => { const [input1, input2] = page.getByRole('input').elements() expect(input1).toHaveFocus() await userEvent.tab() expect(input2).toHaveFocus() await userEvent.tab({ shift: true }) expect(input1).toHaveFocus() }) ``` References: * [Playwright `Keyboard` API](https://playwright.dev/docs/api/class-keyboard) * [WebdriverIO `action('key')` API](https://webdriver.io/docs/api/browser/action#key-input-source) * [testing-library `tab` API](https://testing-library.com/docs/user-event/convenience/#tab) ## userEvent.type ```ts function type( element: Element | Locator, text: string, options?: UserEventTypeOptions, ): Promise ``` ::: warning If you don't rely on [special characters](https://testing-library.com/docs/user-event/keyboard) (e.g., `{shift}` or `{selectall}`), it is recommended to use [`userEvent.fill`](#userevent-fill) instead for better performance. ::: The `type` method implements `@testing-library/user-event`'s [`type`](https://testing-library.com/docs/user-event/utility/#type) utility built on top of [`keyboard`](https://testing-library.com/docs/user-event/keyboard) API. This function allows you to type characters into an `input`/`textarea`/`contenteditable` element. It supports [user-event `keyboard` syntax](https://testing-library.com/docs/user-event/keyboard). If you just need to press characters without an input, use [`userEvent.keyboard`](#userevent-keyboard) API. ```ts import { page, userEvent } from 'vitest/browser' test('update input', async () => { const input = page.getByRole('input') await userEvent.type(input, 'foo') // input.value == foo await userEvent.type(input, '{{a[[') // input.value == foo{a[ await userEvent.type(input, '{Shift}') // input.value == foo{a[ }) ``` ::: info Vitest doesn't expose `.type` method on the locator like `input.type` because it exists only for compatibility with the `userEvent` library. Consider using `.fill` instead as it is faster. ::: References: * [Playwright `locator.press` API](https://playwright.dev/docs/api/class-locator#locator-press) * [WebdriverIO `action('key')` API](https://webdriver.io/docs/api/browser/action#key-input-source) * [testing-library `type` API](https://testing-library.com/docs/user-event/utility/#type) ## userEvent.clear ```ts function clear(element: Element | Locator, options?: UserEventClearOptions): Promise ``` This method clears the input element content. ```ts import { page, userEvent } from 'vitest/browser' test('clears input', async () => { const input = page.getByRole('input') await userEvent.fill(input, 'foo') expect(input).toHaveValue('foo') await userEvent.clear(input) // or you can access it directly on the locator await input.clear() expect(input).toHaveValue('') }) ``` References: * [Playwright `locator.clear` API](https://playwright.dev/docs/api/class-locator#locator-clear) * [WebdriverIO `element.clearValue` API](https://webdriver.io/docs/api/element/clearValue) * [testing-library `clear` API](https://testing-library.com/docs/user-event/utility/#clear) ## userEvent.selectOptions ```ts function selectOptions( element: Element | Locator, values: | HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[], options?: UserEventSelectOptions, ): Promise ``` The `userEvent.selectOptions` allows selecting a value in a `