From 6ff7972e16666361780e3ca076f8f3cdf2c91ad8 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Mon, 20 Apr 2026 09:34:15 +0200 Subject: [PATCH 1/9] fix: alias `agent` reporter to `minimal` (#10157) --- config/reporters.md | 2 +- guide/cli-generated.md | 2 +- guide/reporters.md | 15 +++++++++------ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/config/reporters.md b/config/reporters.md index 6c9b3335..2098d8f6 100644 --- a/config/reporters.md +++ b/config/reporters.md @@ -42,7 +42,7 @@ Note that the [coverage](/guide/coverage) feature uses a different [`coverage.re - [`tap-flat`](/guide/reporters#tap-flat-reporter) - [`hanging-process`](/guide/reporters#hanging-process-reporter) - [`github-actions`](/guide/reporters#github-actions-reporter) -- [`agent`](/guide/reporters#agent-reporter) +- [`minimal`](/guide/reporters#minimal-reporter) (aliased as `agent`) - [`blob`](/guide/reporters#blob-reporter) ## Example diff --git a/guide/cli-generated.md b/guide/cli-generated.md index 63353248..ac54ea5f 100644 --- a/guide/cli-generated.md +++ b/guide/cli-generated.md @@ -102,7 +102,7 @@ Hide logs for skipped tests - **CLI:** `--reporter ` - **Config:** [reporters](/config/reporters) -Specify reporters (default, agent, blob, verbose, dot, json, tap, tap-flat, junit, tree, hanging-process, github-actions) +Specify reporters (default, agent, minimal, blob, verbose, dot, json, tap, tap-flat, junit, tree, hanging-process, github-actions) ### outputFile diff --git a/guide/reporters.md b/guide/reporters.md index 72a86146..34307954 100644 --- a/guide/reporters.md +++ b/guide/reporters.md @@ -99,7 +99,7 @@ This example will write separate JSON and XML reports as well as printing a verb By default (i.e. if no reporter is specified), Vitest will display summary of running tests and their status at the bottom. Once a suite passes, its status will be reported on top of the summary. ::: tip -When Vitest detects it is running inside an AI coding agent, the [`agent`](#agent-reporter) reporter is used instead to reduce output and minimize token usage. You can override this by explicitly configuring the [`reporters`](/config/reporters) option. +When Vitest detects it is running inside an AI coding agent, the [`minimal`](#minimal-reporter) reporter is used instead to reduce output and minimize token usage. You can override this by explicitly configuring the [`reporters`](/config/reporters) option. ::: You can disable the summary by configuring the reporter: @@ -655,21 +655,24 @@ export default defineConfig({ }) ``` -### Agent Reporter +### Minimal Reporter -Outputs a minimal report optimized for AI coding assistants and LLM-based workflows. Only failed tests and their error messages are displayed. Console logs from passing tests and the summary section are suppressed to reduce token usage. +- **Alias:** `agent` -This reporter is automatically enabled when no `reporters` option is configured and Vitest detects it is running inside an AI coding agent. If you configure custom reporters, you can explicitly add `agent`: +Outputs a minimal report containing only failed tests and their error messages. Console logs from passing tests and the summary section are also suppressed. + +::: tip Agent Reporter +This reporter is well optimized for AI coding assistants and LLM-based workflows to reduce token usage. It is automatically enabled when no `reporters` option is configured and Vitest detects it is running inside an AI coding agent. If you configure custom reporters, you can explicitly add `minimal` or `agent`: :::code-group ```bash [CLI] -npx vitest --reporter=agent +npx vitest --reporter=minimal ``` ```ts [vitest.config.ts] export default defineConfig({ test: { - reporters: ['agent'] + reporters: ['minimal'] }, }) ``` From 2aae193f0f78a1bf6e7987cb80dc9950fb739a94 Mon Sep 17 00:00:00 2001 From: Bart Waardenburg Date: Mon, 20 Apr 2026 13:44:11 +0200 Subject: [PATCH 2/9] feat(coverage): istanbul to support `instrumenter` option (#10119) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ari Perkkiö --- config/coverage.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/config/coverage.md b/config/coverage.md index 8d3f2269..461466de 100644 --- a/config/coverage.md +++ b/config/coverage.md @@ -390,6 +390,46 @@ Watermarks for statements, lines, branches and functions. See [istanbul document Concurrency limit used when processing the coverage results. +## coverage.instrumenter 4.1.5 {#coverage-instrumenter} + +- **Type:** `(options: InstrumenterOptions) => CoverageInstrumenter` +- **Available for providers:** `'istanbul'` + +Factory for a custom instrumenter to use in place of the default `istanbul-lib-instrument`. Vitest calls the factory once during initialization and reuses the returned instrumenter for every file. The rest of the Istanbul pipeline (collection, merging, reporting) is unchanged. + +The factory receives an `InstrumenterOptions` object with Vitest's runtime coverage settings, and must return an object implementing the `CoverageInstrumenter` interface. Both types are exported from `vitest/node`. + + +```ts +interface InstrumenterOptions { + coverageVariable: string + coverageGlobalScope: string + coverageGlobalScopeFunc: boolean + ignoreClassMethods: string[] +} + +interface CoverageInstrumenter { + instrumentSync: (code: string, filename: string, inputSourceMap?: any) => string + lastSourceMap: () => any + lastFileCoverage: () => any +} +``` + + +```ts +import { defineConfig } from 'vitest/config' +import { createInstrumenter } from '@vitest/some-custom-instrumenter' + +export default defineConfig({ + test: { + coverage: { + provider: 'istanbul', + instrumenter: options => createInstrumenter(options), + } + } +}) +``` + ## coverage.customProviderModule - **Type:** `string` From 7d62aac530f1e35ecc2bc77594218401eefd24b4 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 21 Apr 2026 19:54:58 +0900 Subject: [PATCH 3/9] docs: update custom snapshot matcher example (#10169) --- guide/snapshot.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/guide/snapshot.md b/guide/snapshot.md index b6d0280d..371a2a7b 100644 --- a/guide/snapshot.md +++ b/guide/snapshot.md @@ -246,8 +246,8 @@ import { expect, test, Snapshots } from 'vitest' const { toMatchFileSnapshot, toMatchInlineSnapshot, toMatchSnapshot } = Snapshots expect.extend({ - toMatchTrimmedSnapshot(received: string, length: number) { - return toMatchSnapshot.call(this, received.slice(0, length)) + toMatchTrimmedSnapshot(received: string) { + return toMatchSnapshot.call(this, received.slice(0, 10)) }, toMatchTrimmedInlineSnapshot(received: string, inlineSnapshot?: string) { return toMatchInlineSnapshot.call(this, received.slice(0, 10), inlineSnapshot) @@ -258,15 +258,19 @@ expect.extend({ }) test('file snapshot', () => { + // create __snapshots__/demo.test.ts with + // > exports[`file snapshot 1`] = `"extra long"` expect('extra long string oh my gerd').toMatchTrimmedSnapshot(10) }) test('inline snapshot', () => { - expect('extra long string oh my gerd').toMatchTrimmedInlineSnapshot() + expect('super long string oh my gerd').toMatchTrimmedInlineSnapshot(`"super long"`) }) test('raw file snapshot', async () => { - await expect('extra long string oh my gerd').toMatchTrimmedFileSnapshot('./raw-file.txt') + // create raw-file.txt with: + // > crazy long + await expect('crazy long string oh my gerd').toMatchTrimmedFileSnapshot('./raw-file.txt') }) ``` From 30df941749c0ffd4dfc4cc5c8691c9770e007b83 Mon Sep 17 00:00:00 2001 From: NoiseFan Date: Tue, 21 Apr 2026 18:55:42 +0800 Subject: [PATCH 4/9] docs(typo): fix doucment's some typo (#10083) --- api/advanced/vitest.md | 2 +- api/assert.md | 4 +- api/expect.md | 34 +++++++-------- config/allowonly.md | 4 +- config/bail.md | 2 +- config/browser/provider.md | 2 +- config/cache.md | 4 +- config/coverage.md | 2 +- config/css.md | 18 ++++---- config/dangerouslyignoreunhandlederrors.md | 4 +- config/deps.md | 2 +- config/diff.md | 28 ++++++------- config/forcereruntriggers.md | 2 +- config/logheapusage.md | 4 +- config/maxconcurrency.md | 6 +-- config/mode.md | 2 +- config/onstacktrace.md | 2 +- config/passwithnotests.md | 4 +- config/pool.md | 2 +- config/resolvesnapshotpath.md | 4 +- config/runner.md | 4 +- config/sequence.md | 48 +++++++++++----------- config/slowtestthreshold.md | 6 +-- config/testnamepattern.md | 2 +- config/typecheck.md | 44 ++++++++++---------- guide/cli.md | 8 ++-- 26 files changed, 122 insertions(+), 122 deletions(-) diff --git a/api/advanced/vitest.md b/api/advanced/vitest.md index 83c2d23c..d4eed1bf 100644 --- a/api/advanced/vitest.md +++ b/api/advanced/vitest.md @@ -244,7 +244,7 @@ This method is called automatically by [`startVitest`](/guide/advanced/tests) if function standalone(): Promise ``` -- **Alias**: `init` +- **Alias:** `init` Initialize reporters and the coverage provider. This method doesn't run any tests. If the `--watch` flag is provided, Vitest will still run changed tests even if this method was not called. diff --git a/api/assert.md b/api/assert.md index a7329a2b..a10d0663 100644 --- a/api/assert.md +++ b/api/assert.md @@ -36,7 +36,7 @@ test('assert.fail', () => { ## isOk - **Type:** `(value: T, message?: string) => asserts value` -- **Alias** `ok` +- **Alias:** `ok` Assert that the given `value` is truthy. @@ -52,7 +52,7 @@ test('assert.isOk', () => { ## isNotOk - **Type:** `(value: T, message?: string) => void` -- **Alias** `notOk` +- **Alias:** `notOk` Assert that the given `value` is falsy. diff --git a/api/expect.md b/api/expect.md index 48374392..c5ac57ee 100644 --- a/api/expect.md +++ b/api/expect.md @@ -1075,7 +1075,7 @@ test('spy function', () => { ## toHaveBeenCalledTimes -- **Type**: `(amount: number) => Awaitable` +- **Type:** `(amount: number) => Awaitable` This assertion checks if a function was called a certain amount of times. Requires a spy function to be passed to `expect`. @@ -1100,7 +1100,7 @@ test('spy function called two times', () => { ## toHaveBeenCalledWith -- **Type**: `(...args: any[]) => Awaitable` +- **Type:** `(...args: any[]) => Awaitable` This assertion checks if a function was called at least once with certain parameters. Requires a spy function to be passed to `expect`. @@ -1126,7 +1126,7 @@ test('spy function', () => { ## toHaveBeenCalledBefore -- **Type**: `(mock: MockInstance, failIfNoFirstInvocation?: boolean) => Awaitable` +- **Type:** `(mock: MockInstance, failIfNoFirstInvocation?: boolean) => Awaitable` This assertion checks if a `Mock` was called before another `Mock`. @@ -1145,7 +1145,7 @@ test('calls mock1 before mock2', () => { ## toHaveBeenCalledAfter -- **Type**: `(mock: MockInstance, failIfNoFirstInvocation?: boolean) => Awaitable` +- **Type:** `(mock: MockInstance, failIfNoFirstInvocation?: boolean) => Awaitable` This assertion checks if a `Mock` was called after another `Mock`. @@ -1164,7 +1164,7 @@ test('calls mock1 after mock2', () => { ## toHaveBeenCalledExactlyOnceWith -- **Type**: `(...args: any[]) => Awaitable` +- **Type:** `(...args: any[]) => Awaitable` This assertion checks if a function was called exactly once and with certain parameters. Requires a spy function to be passed to `expect`. @@ -1188,7 +1188,7 @@ test('spy function', () => { ## toHaveBeenLastCalledWith -- **Type**: `(...args: any[]) => Awaitable` +- **Type:** `(...args: any[]) => Awaitable` This assertion checks if a function was called with certain parameters at its last invocation. Requires a spy function to be passed to `expect`. @@ -1214,7 +1214,7 @@ test('spy function', () => { ## toHaveBeenNthCalledWith -- **Type**: `(time: number, ...args: any[]) => Awaitable` +- **Type:** `(time: number, ...args: any[]) => Awaitable` This assertion checks if a function was called with certain parameters at the certain time. The count starts at 1. So, to check the second entry, you would write `.toHaveBeenNthCalledWith(2, ...)`. @@ -1241,7 +1241,7 @@ test('first call of spy function called with right params', () => { ## toHaveReturned -- **Type**: `() => Awaitable` +- **Type:** `() => Awaitable` This assertion checks if a function has successfully returned a value at least once (i.e., did not throw an error). Requires a spy function to be passed to `expect`. @@ -1265,7 +1265,7 @@ test('spy function returned a value', () => { ## toHaveReturnedTimes -- **Type**: `(amount: number) => Awaitable` +- **Type:** `(amount: number) => Awaitable` This assertion checks if a function has successfully returned a value an exact amount of times (i.e., did not throw an error). Requires a spy function to be passed to `expect`. @@ -1284,7 +1284,7 @@ test('spy function returns a value two times', () => { ## toHaveReturnedWith -- **Type**: `(returnValue: any) => Awaitable` +- **Type:** `(returnValue: any) => Awaitable` You can call this assertion to check if a function has successfully returned a value with certain parameters at least once. Requires a spy function to be passed to `expect`. @@ -1302,7 +1302,7 @@ test('spy function returns a product', () => { ## toHaveLastReturnedWith -- **Type**: `(returnValue: any) => Awaitable` +- **Type:** `(returnValue: any) => Awaitable` You can call this assertion to check if a function has successfully returned a certain value when it was last invoked. Requires a spy function to be passed to `expect`. @@ -1321,7 +1321,7 @@ test('spy function returns bananas on a last call', () => { ## toHaveNthReturnedWith -- **Type**: `(time: number, returnValue: any) => Awaitable` +- **Type:** `(time: number, returnValue: any) => Awaitable` You can call this assertion to check if a function has successfully returned a value with certain parameters on a certain call. Requires a spy function to be passed to `expect`. @@ -1342,7 +1342,7 @@ test('spy function returns bananas on second call', () => { ## toHaveResolved -- **Type**: `() => Awaitable` +- **Type:** `() => Awaitable` This assertion checks if a function has successfully resolved a value at least once (i.e., did not reject). Requires a spy function to be passed to `expect`. @@ -1368,7 +1368,7 @@ test('spy function resolved a value', async () => { ## toHaveResolvedTimes -- **Type**: `(amount: number) => Awaitable` +- **Type:** `(amount: number) => Awaitable` This assertion checks if a function has successfully resolved a value an exact amount of times (i.e., did not reject). Requires a spy function to be passed to `expect`. @@ -1389,7 +1389,7 @@ test('spy function resolved a value two times', async () => { ## toHaveResolvedWith -- **Type**: `(returnValue: any) => Awaitable` +- **Type:** `(returnValue: any) => Awaitable` You can call this assertion to check if a function has successfully resolved a certain value at least once. Requires a spy function to be passed to `expect`. @@ -1409,7 +1409,7 @@ test('spy function resolved a product', async () => { ## toHaveLastResolvedWith -- **Type**: `(returnValue: any) => Awaitable` +- **Type:** `(returnValue: any) => Awaitable` You can call this assertion to check if a function has successfully resolved a certain value when it was last invoked. Requires a spy function to be passed to `expect`. @@ -1430,7 +1430,7 @@ test('spy function resolves bananas on a last call', async () => { ## toHaveNthResolvedWith -- **Type**: `(time: number, returnValue: any) => Awaitable` +- **Type:** `(time: number, returnValue: any) => Awaitable` You can call this assertion to check if a function has successfully resolved a certain value on a specific invocation. Requires a spy function to be passed to `expect`. diff --git a/config/allowonly.md b/config/allowonly.md index 39fd8611..6c75bed7 100644 --- a/config/allowonly.md +++ b/config/allowonly.md @@ -5,8 +5,8 @@ outline: deep # allowOnly -- **Type**: `boolean` -- **Default**: `!process.env.CI` +- **Type:** `boolean` +- **Default:** `!process.env.CI` - **CLI:** `--allowOnly`, `--allowOnly=false` By default, Vitest does not permit tests marked with the [`only`](/api/test#test-only) flag in Continuous Integration (CI) environments. Conversely, in local development environments, Vitest allows these tests to run. diff --git a/config/bail.md b/config/bail.md index 27018e56..26c1fc6b 100644 --- a/config/bail.md +++ b/config/bail.md @@ -7,7 +7,7 @@ outline: deep - **Type:** `number` - **Default:** `0` -- **CLI**: `--bail=` +- **CLI:** `--bail=` Stop test execution when given number of tests have failed. diff --git a/config/browser/provider.md b/config/browser/provider.md index c5995fbf..88eee69d 100644 --- a/config/browser/provider.md +++ b/config/browser/provider.md @@ -61,7 +61,7 @@ export default defineConfig({ }) ``` -## Custom Provider advanced +## Custom Provider advanced {#custom-provider} ::: danger ADVANCED API The custom provider API is highly experimental and can change between patches. If you just need to run tests in a browser, use the [`browser.instances`](/config/browser/instances) option instead. diff --git a/config/cache.md b/config/cache.md index a480f628..2c7058e6 100644 --- a/config/cache.md +++ b/config/cache.md @@ -5,8 +5,8 @@ outline: deep # cache -- **Type**: `false` -- **CLI**: `--no-cache`, `--cache=false` +- **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. diff --git a/config/coverage.md b/config/coverage.md index 461466de..d7456831 100644 --- a/config/coverage.md +++ b/config/coverage.md @@ -65,7 +65,7 @@ See [Including and excluding files from coverage report](/guide/coverage.html#in - **Available for providers:** `'v8' | 'istanbul'` - **CLI:** `--coverage.clean`, `--coverage.clean=false` -Clean coverage results before running tests +Clean coverage results before running tests. ## coverage.cleanOnRerun diff --git a/config/css.md b/config/css.md index eb096d16..51a4e0b9 100644 --- a/config/css.md +++ b/config/css.md @@ -5,7 +5,7 @@ outline: deep # css -- **Type**: `boolean | { include?, exclude?, modules? }` +- **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. @@ -15,8 +15,8 @@ This option is not applied to [browser tests](/guide/browser/). ## css.include -- **Type**: `RegExp | RegExp[]` -- **Default**: `[]` +- **Type:** `RegExp | RegExp[]` +- **Default:** `[]` RegExp pattern for files that should return actual CSS and will be processed by Vite pipeline. @@ -26,20 +26,20 @@ To process all CSS files, use `/.+/`. ## css.exclude -- **Type**: `RegExp | RegExp[]` -- **Default**: `[]` +- **Type:** `RegExp | RegExp[]` +- **Default:** `[]` RegExp pattern for files that will return an empty CSS file. ## css.modules -- **Type**: `{ classNameStrategy? }` -- **Default**: `{}` +- **Type:** `{ classNameStrategy? }` +- **Default:** `{}` ### css.modules.classNameStrategy -- **Type**: `'stable' | 'scoped' | 'non-scoped'` -- **Default**: `'stable'` +- **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: diff --git a/config/dangerouslyignoreunhandlederrors.md b/config/dangerouslyignoreunhandlederrors.md index 54536f19..a19bf7aa 100644 --- a/config/dangerouslyignoreunhandlederrors.md +++ b/config/dangerouslyignoreunhandlederrors.md @@ -5,8 +5,8 @@ outline: deep # dangerouslyIgnoreUnhandledErrors -- **Type**: `boolean` -- **Default**: `false` +- **Type:** `boolean` +- **Default:** `false` - **CLI:** - `--dangerouslyIgnoreUnhandledErrors` - `--dangerouslyIgnoreUnhandledErrors=false` diff --git a/config/deps.md b/config/deps.md index 579544e9..15297b9d 100644 --- a/config/deps.md +++ b/config/deps.md @@ -111,7 +111,7 @@ By default, Vitest assumes you are using a bundler to bypass this and will not f ## deps.moduleDirectories - **Type:** `string[]` -- **Default**: `['node_modules']` +- **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](/config/root) of the project. diff --git a/config/diff.md b/config/diff.md index 710d66dd..39cd2653 100644 --- a/config/diff.md +++ b/config/diff.md @@ -56,16 +56,16 @@ export default { ## diff.expand -- **Type**: `boolean` -- **Default**: `true` +- **Type:** `boolean` +- **Default:** `true` - **CLI:** `--diff.expand=false` Expand all common lines. ## diff.truncateThreshold -- **Type**: `number` -- **Default**: `0` +- **Type:** `number` +- **Default:** `0` - **CLI:** `--diff.truncateThreshold=` The maximum length of diff result to be displayed. Diffs above this threshold will be truncated. @@ -73,29 +73,29 @@ Truncation won't take effect with default value 0. ## diff.truncateAnnotation -- **Type**: `string` -- **Default**: `'... Diff result is truncated'` +- **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` +- **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` +- **Type:** `boolean` +- **Default:** `false` -Print basic prototype `Object` and `Array` in diff output +Print basic prototype `Object` and `Array` in diff output. ## diff.maxDepth -- **Type**: `number` -- **Default**: `20` (or `8` when comparing different types) +- **Type:** `number` +- **Default:** `20` (or `8` when comparing different types) -Limit the depth to recurse when printing nested objects +Limit the depth to recurse when printing nested objects. diff --git a/config/forcereruntriggers.md b/config/forcereruntriggers.md index 342143e1..9dad489c 100644 --- a/config/forcereruntriggers.md +++ b/config/forcereruntriggers.md @@ -5,7 +5,7 @@ outline: deep # forceRerunTriggers -- **Type**: `string[]` +- **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. diff --git a/config/logheapusage.md b/config/logheapusage.md index a29f251c..a65df7b0 100644 --- a/config/logheapusage.md +++ b/config/logheapusage.md @@ -5,8 +5,8 @@ outline: deep # logHeapUsage -- **Type**: `boolean` -- **Default**: `false` +- **Type:** `boolean` +- **Default:** `false` - **CLI:** `--logHeapUsage`, `--logHeapUsage=false` Show heap usage after each test. Useful for debugging memory leaks. diff --git a/config/maxconcurrency.md b/config/maxconcurrency.md index deb88476..b6a707a7 100644 --- a/config/maxconcurrency.md +++ b/config/maxconcurrency.md @@ -5,9 +5,9 @@ outline: deep # maxConcurrency -- **Type**: `number` -- **Default**: `5` -- **CLI**: `--max-concurrency=10`, `--maxConcurrency=10` +- **Type:** `number` +- **Default:** `5` +- **CLI:** `--max-concurrency=10`, `--maxConcurrency=10` The maximum number of tests and hooks that can run at the same time when using `test.concurrent` or `describe.concurrent`. diff --git a/config/mode.md b/config/mode.md index 5e45a97e..a17786d5 100644 --- a/config/mode.md +++ b/config/mode.md @@ -9,4 +9,4 @@ outline: deep - **CLI:** `--mode=staging` - **Default:** `'test'` -Overrides Vite mode +Overrides Vite mode. diff --git a/config/onstacktrace.md b/config/onstacktrace.md index 3c970589..ed6a6f70 100644 --- a/config/onstacktrace.md +++ b/config/onstacktrace.md @@ -5,7 +5,7 @@ outline: deep # onStackTrace -- **Type**: `(error: Error, frame: ParsedStack) => boolean | void` +- **Type:** `(error: Error, frame: ParsedStack) => boolean | void` Apply a filtering function to each frame of each stack trace when handling errors. This does not apply to stack traces printed by [`printConsoleTrace`](/config/printconsoletrace#printconsoletrace). The first argument, `error`, is a `TestError`. diff --git a/config/passwithnotests.md b/config/passwithnotests.md index eb4bbe2e..23ae4da1 100644 --- a/config/passwithnotests.md +++ b/config/passwithnotests.md @@ -5,8 +5,8 @@ outline: deep # passWithNoTests -- **Type**: `boolean` -- **Default**: `false` +- **Type:** `boolean` +- **Default:** `false` - **CLI:** `--passWithNoTests`, `--passWithNoTests=false` Vitest will not fail, if no tests will be found. diff --git a/config/pool.md b/config/pool.md index c9449818..b98bb9fd 100644 --- a/config/pool.md +++ b/config/pool.md @@ -13,7 +13,7 @@ Pool used to run tests in. ## threads -Enable multi-threading. When using threads you are unable to use process related APIs such as `process.chdir()`. Some libraries written in native languages, such as Prisma, `bcrypt` and `canvas`, have problems when running in multiple threads and run into segfaults. In these cases it is advised to use `forks` pool instead. +Enable multi-threading. When using threads you are unable to use process related APIs such as `process.chdir()`. Some libraries written in native languages, such as `Prisma`, `bcrypt` and `canvas`, have problems when running in multiple threads and run into segfaults. In these cases it is advised to use `forks` pool instead. ## forks diff --git a/config/resolvesnapshotpath.md b/config/resolvesnapshotpath.md index c63abfd5..f3d0ca47 100644 --- a/config/resolvesnapshotpath.md +++ b/config/resolvesnapshotpath.md @@ -5,8 +5,8 @@ outline: deep # resolveSnapshotPath -- **Type**: `(testPath: string, snapExtension: string, context: { config: SerializedConfig }) => string` -- **Default**: stores snapshot files in `__snapshots__` directory +- **Type:** `(testPath: string, snapExtension: string, context: { config: SerializedConfig }) => string` +- **Default:** stores snapshot files in `__snapshots__` directory Overrides default snapshot path. For example, to store snapshots next to test files: diff --git a/config/runner.md b/config/runner.md index aaf20871..1d47b953 100644 --- a/config/runner.md +++ b/config/runner.md @@ -5,7 +5,7 @@ outline: deep # runner -- **Type**: `VitestRunnerConstructor` -- **Default**: `node`, when running tests, or `benchmark`, when running benchmarks +- **Type:** `VitestRunnerConstructor` +- **Default:** `node`, when running tests, or `benchmark`, when running benchmarks Path to a custom test runner. This is an advanced feature and should be used with custom library runners. You can read more about it in [the documentation](/api/advanced/runner). diff --git a/config/sequence.md b/config/sequence.md index 51c7276b..e55f4b82 100644 --- a/config/sequence.md +++ b/config/sequence.md @@ -5,7 +5,7 @@ outline: deep # sequence -- **Type**: `{ sequencer?, shuffle?, seed?, hooks?, setupFiles?, groupOrder }` +- **Type:** `{ sequencer?, shuffle?, seed?, hooks?, setupFiles?, groupOrder }` Options for how tests should be sorted. @@ -17,8 +17,8 @@ npx vitest --sequence.shuffle --sequence.seed=1000 ## sequence.sequencer -- **Type**: `TestSequencerConstructor` -- **Default**: `BaseSequencer` +- **Type:** `TestSequencerConstructor` +- **Default:** `BaseSequencer` A custom class that defines methods for sharding and sorting. You can extend `BaseSequencer` from `vitest/node`, if you only need to redefine one of the `sort` and `shard` methods, but both should exist. @@ -91,9 +91,9 @@ Tests in these projects will run in this order: ## sequence.shuffle -- **Type**: `boolean | { files?, tests? }` -- **Default**: `false` -- **CLI**: `--sequence.shuffle`, `--sequence.shuffle=false` +- **Type:** `boolean | { files?, tests? }` +- **Default:** `false` +- **CLI:** `--sequence.shuffle`, `--sequence.shuffle=false` If you want files and tests to run randomly, you can enable it with this option, or CLI argument [`--sequence.shuffle`](/guide/cli). @@ -101,25 +101,25 @@ Vitest usually uses cache to sort tests, so long-running tests start earlier, wh ### sequence.shuffle.files {#sequence-shuffle-files} -- **Type**: `boolean` -- **Default**: `false` -- **CLI**: `--sequence.shuffle.files`, `--sequence.shuffle.files=false` +- **Type:** `boolean` +- **Default:** `false` +- **CLI:** `--sequence.shuffle.files`, `--sequence.shuffle.files=false` Whether to randomize files, be aware that long running tests will not start earlier if you enable this option. ### sequence.shuffle.tests {#sequence-shuffle-tests} -- **Type**: `boolean` -- **Default**: `false` -- **CLI**: `--sequence.shuffle.tests`, `--sequence.shuffle.tests=false` +- **Type:** `boolean` +- **Default:** `false` +- **CLI:** `--sequence.shuffle.tests`, `--sequence.shuffle.tests=false` Whether to randomize tests. ## sequence.concurrent {#sequence-concurrent} -- **Type**: `boolean` -- **Default**: `false` -- **CLI**: `--sequence.concurrent`, `--sequence.concurrent=false` +- **Type:** `boolean` +- **Default:** `false` +- **CLI:** `--sequence.concurrent`, `--sequence.concurrent=false` If you want tests to run in parallel, you can enable it with this option, or CLI argument [`--sequence.concurrent`](/guide/cli). @@ -129,17 +129,17 @@ When you run tests with `sequence.concurrent` and `expect.requireAssertions` set ## sequence.seed -- **Type**: `number` -- **Default**: `Date.now()` -- **CLI**: `--sequence.seed=1000` +- **Type:** `number` +- **Default:** `Date.now()` +- **CLI:** `--sequence.seed=1000` Sets the randomization seed, if tests are running in random order. ## sequence.hooks -- **Type**: `'stack' | 'list' | 'parallel'` -- **Default**: `'stack'` -- **CLI**: `--sequence.hooks=` +- **Type:** `'stack' | 'list' | 'parallel'` +- **Default:** `'stack'` +- **CLI:** `--sequence.hooks=` Changes the order in which hooks are executed. @@ -153,9 +153,9 @@ This option doesn't affect [`onTestFinished`](/api/hooks#ontestfinished). It is ## sequence.setupFiles {#sequence-setupfiles} -- **Type**: `'list' | 'parallel'` -- **Default**: `'parallel'` -- **CLI**: `--sequence.setupFiles=` +- **Type:** `'list' | 'parallel'` +- **Default:** `'parallel'` +- **CLI:** `--sequence.setupFiles=` Changes the order in which setup files are executed. diff --git a/config/slowtestthreshold.md b/config/slowtestthreshold.md index 84f9594d..dc10baa2 100644 --- a/config/slowtestthreshold.md +++ b/config/slowtestthreshold.md @@ -5,8 +5,8 @@ outline: deep # slowTestThreshold -- **Type**: `number` -- **Default**: `300` -- **CLI**: `--slow-test-threshold=`, `--slowTestThreshold=` +- **Type:** `number` +- **Default:** `300` +- **CLI:** `--slow-test-threshold=`, `--slowTestThreshold=` The number of milliseconds after which a test or suite is considered slow and reported as such in the results. diff --git a/config/testnamepattern.md b/config/testnamepattern.md index 7e4b4098..c0646e5b 100644 --- a/config/testnamepattern.md +++ b/config/testnamepattern.md @@ -5,7 +5,7 @@ outline: deep # testNamePattern {#testnamepattern} -- **Type** `string | RegExp` +- **Type:** `string | RegExp` - **CLI:** `-t `, `--testNamePattern=`, `--test-name-pattern=` Run tests with full names matching the pattern. diff --git a/config/typecheck.md b/config/typecheck.md index cae1854a..4413742c 100644 --- a/config/typecheck.md +++ b/config/typecheck.md @@ -9,24 +9,24 @@ Options for configuring [typechecking](/guide/testing-types) test environment. ## typecheck.enabled {#typecheck-enabled} -- **Type**: `boolean` -- **Default**: `false` -- **CLI**: `--typecheck`, `--typecheck.enabled` +- **Type:** `boolean` +- **Default:** `false` +- **CLI:** `--typecheck`, `--typecheck.enabled` Enable typechecking alongside your regular tests. ## typecheck.only {#typecheck-only} -- **Type**: `boolean` -- **Default**: `false` -- **CLI**: `--typecheck.only` +- **Type:** `boolean` +- **Default:** `false` +- **CLI:** `--typecheck.only` Run only typecheck tests, when typechecking is enabled. When using CLI, this option will automatically enable typechecking. ## typecheck.checker -- **Type**: `'tsc' | 'vue-tsc' | string` -- **Default**: `tsc` +- **Type:** `'tsc' | 'vue-tsc' | string` +- **Default:** `tsc` What tools to use for type checking. Vitest will spawn a process with certain parameters for easier parsing, depending on the type. Checker should implement the same output format as `tsc`. @@ -39,29 +39,29 @@ You can also pass down a path to custom binary or command name that produces the ## typecheck.include -- **Type**: `string[]` -- **Default**: `['**/*.{test,spec}-d.?(c|m)[jt]s?(x)']` +- **Type:** `string[]` +- **Default:** `['**/*.{test,spec}-d.?(c|m)[jt]s?(x)']` -Glob pattern for files that should be treated as test files +Glob pattern for files that should be treated as test files. ## typecheck.exclude -- **Type**: `string[]` -- **Default**: `['**/node_modules/**', '**/dist/**', '**/cypress/**', '**/.{idea,git,cache,output,temp}/**']` +- **Type:** `string[]` +- **Default:** `['**/node_modules/**', '**/dist/**', '**/cypress/**', '**/.{idea,git,cache,output,temp}/**']` -Glob pattern for files that should not be treated as test files +Glob pattern for files that should not be treated as test files. ## typecheck.allowJs -- **Type**: `boolean` -- **Default**: `false` +- **Type:** `boolean` +- **Default:** `false` Check JS files that have `@ts-check` comment. If you have it enabled in tsconfig, this will not overwrite it. ## typecheck.ignoreSourceErrors -- **Type**: `boolean` -- **Default**: `false` +- **Type:** `boolean` +- **Default:** `false` Do not fail, if Vitest found errors outside the test files. This will not show you non-test errors at all. @@ -69,14 +69,14 @@ By default, if Vitest finds source error, it will fail test suite. ## typecheck.tsconfig -- **Type**: `string` -- **Default**: _tries to find closest tsconfig.json_ +- **Type:** `string` +- **Default:** _tries to find closest tsconfig.json_ Path to custom tsconfig, relative to the project root. ## typecheck.spawnTimeout -- **Type**: `number` -- **Default**: `10_000` +- **Type:** `number` +- **Default:** `10_000` Minimum time in milliseconds it takes to spawn the typechecker. diff --git a/guide/cli.md b/guide/cli.md index e1a16c45..01473173 100644 --- a/guide/cli.md +++ b/guide/cli.md @@ -191,8 +191,8 @@ vitest --api=false ### changed -- **Type**: `boolean | string` -- **Default**: false +- **Type:** `boolean | string` +- **Default:** false Run tests only against changed files. If no value is provided, it will run tests against uncommitted changes (including staged and unstaged). @@ -204,8 +204,8 @@ If paired with the [`forceRerunTriggers`](/config/forcereruntriggers) config opt ### shard -- **Type**: `string` -- **Default**: disabled +- **Type:** `string` +- **Default:** disabled Test suite shard to execute in a format of ``/``, where From bceb2527e6425f398aaec04fc1b3411ac2728bee Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Wed, 22 Apr 2026 13:49:32 +0900 Subject: [PATCH 5/9] refactor!: replace `loupe.inspect` with pretty-format (#9609) Co-authored-by: Claude Opus 4.6 Co-authored-by: Codex --- api/test.md | 2 +- config/chaiconfig.md | 4 +--- config/tasktitlevalueformattruncate.md | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 config/tasktitlevalueformattruncate.md diff --git a/api/test.md b/api/test.md index 4dda739e..18af801f 100644 --- a/api/test.md +++ b/api/test.md @@ -618,7 +618,7 @@ test.each` ``` ::: tip -Vitest processes `$values` with Chai `format` method. If the value is too truncated, you can increase [chaiConfig.truncateThreshold](/config/chaiconfig#chaiconfig-truncatethreshold) in your config file. +Vitest formats interpolated title values with its display formatter. If the value is too truncated, you can increase [taskTitleValueFormatTruncate](/config/tasktitlevalueformattruncate) in your config file. ::: ## test.for diff --git a/config/chaiconfig.md b/config/chaiconfig.md index 24cf085a..5a6f9b55 100644 --- a/config/chaiconfig.md +++ b/config/chaiconfig.md @@ -29,6 +29,4 @@ Influences whether or not the `showDiff` flag should be included in the thrown A - **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. +Sets length threshold for actual and expected values in assertion error messages. 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. diff --git a/config/tasktitlevalueformattruncate.md b/config/tasktitlevalueformattruncate.md new file mode 100644 index 00000000..5bb7eb88 --- /dev/null +++ b/config/tasktitlevalueformattruncate.md @@ -0,0 +1,15 @@ +--- +title: taskTitleValueFormatTruncate | Config +outline: deep +--- + +# taskTitleValueFormatTruncate {#tasktitlevalueformattruncate} + +- **Type** `number` +- **Default:** `40` + +Sets the length limit for formatted values interpolated into generated task titles. + +This affects values inserted by APIs like `test.each` and `test.for`, including both `$value` and `%` placeholder formatting. + +Set it to `0` to disable truncation. From 1f86109e54689db534e518c85a6a73daa82d5bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Perkki=C3=B6?= Date: Wed, 22 Apr 2026 07:50:28 +0300 Subject: [PATCH 6/9] feat: add `createReport` and `.vitest` report directory convention (#9993) --- api/advanced/vitest.md | 119 ++++++++++++++++++++++++++++++++++++ guide/advanced/reporters.md | 27 ++++++++ guide/index.md | 7 +++ 3 files changed, 153 insertions(+) diff --git a/api/advanced/vitest.md b/api/advanced/vitest.md index d4eed1bf..0f436591 100644 --- a/api/advanced/vitest.md +++ b/api/advanced/vitest.md @@ -687,3 +687,122 @@ Returns module's diagnostic. If [`testModule`](/api/advanced/test-module) is not ::: warning At the moment, the [browser](/guide/browser/) modules are not supported. ::: + +## createReport 5.0.0 {#createreport} + +```ts +function createReport(scope: string): Report +``` + +Creates a report that is limited to the given scope. `Report` follows Vitest's rules around [Storing artifacts on file system](/guide/advanced/reporters.html#storing-artifacts-on-file-system). + +`Report` provides collection of utilities for writing test results, temporary files and other artifacts on the file system. It's especially intended for third party integrations like custom reporters. + +All operations of `Report` are limited to given `scope`. A single report cannot interfere with other reports. Internally Vitest creates `.vitest` directory where each `scope` creates their own directory. This convention of `.vitest` directory reduces the amount of entries end-users need to specify in their `.gitignore`. + +```ts +import type { Report } from 'vitest/node' + +const scope = 'example-yaml-reporter' + +// Automatically creates `/.vitest/example-yaml-reporter/` +// directory if it does not exist already +const report: Report = vitest.createReport(scope) +``` + +### Report.root + +```ts +const root: string +``` + +The root directory for this scope. + +```ts +const report = vitest.createReport('my-json-reporter') + +// Is /.vitest/my-json-reporter +const root = report.root +``` + + +### Report.clean + +```ts +function clean(): Promise +``` + +Clean up the report directory for this scope. + +```ts +const report = vitest.createReport('my-json-reporter') + +// Removes everything inside /.vitest/my-json-reporter/ +await report.clean() +``` + +### Report.writeFile + +```ts +function writeFile( + filename: string, + content: string | Uint8Array, + encoding?: BufferEncoding +): Promise +``` + +Write a file to the report directory for this scope. By default the file will be written with UTF-8 encoding. The filename is relative to the scope directory. + +```ts +const report = vitest.createReport('my-json-reporter') + +// Writes file to .vitest/my-json-reporter/test-report.json +await report.writeFile('test-report.json', JSON.stringify(results)) +``` + +### Report.readFile + +```ts +function readFile(filename: string, encoding?: BufferEncoding): Promise +``` + +Read a file from the report directory for this scope. + +```ts +const report = vitest.createReport('my-json-reporter') + +// Reads file from .vitest/my-json-reporter/test-report.json +const content: string = await report.readFile('test-report.json') +``` + +### Report.readdir + +```ts +function readdir(): Promise +``` + +Read contents of the report directory for this scope. + +```ts +const report = vitest.createReport('my-json-reporter') + +// Reads contents from .vitest/my-json-reporter +const filenames: string[] = await report.readdir() +``` + +### Report.delete + + +```ts +function delete(filename: string): Promise +``` + +Delete a file from the report directory for this scope. + +```ts +const report = vitest.createReport('my-json-reporter') + +// Deletes file from .vitest/my-json-reporter/test-report.json +await report.delete('test-report.json') +``` + diff --git a/guide/advanced/reporters.md b/guide/advanced/reporters.md index 925e4559..c450b57e 100644 --- a/guide/advanced/reporters.md +++ b/guide/advanced/reporters.md @@ -72,6 +72,33 @@ class MyReporter implements Reporter { } ``` +## Storing artifacts on file system + +::: tip +Vitest provides [`vitest.createReport`](/api/advanced/vitest.html#createreport) that exposes collection of utilities for writing artifacts on file system conveniently. +::: + +If your custom reporter needs to store any artifacts on file system it should place them inside `.vitest` directory. This directory is a convention that Vitest reporters and third party integrations can use to co-locate their results in a single directory. This way users of your custom reporter do not need to add multiple exclusion in their `.gitignore`. Only the `.vitest` is needed. + +Reporters and other integrations should respect following rules around `.vitest` directory: + +- `.vitest` directory is placed in [the `root` of the project](/config/root) +- Reporter can create `.vitest` directory if it does not already exist +- Reporter should never remove `.vitest` directory +- Reporter should create their own directory inside `.vitest`, for example `.vitest/yaml-reporter/` +- Reporter can remove their own specific directory inside `.vitest`, for example `.vitest/yaml-reporter/` + +```ansi +.vitest +│ +├── yaml-reporter +│ ├── results.yaml +│ └── summary.yaml +│ +└── junit-reporter + └── report.xml +``` + ## Exported Reporters `vitest` comes with a few [built-in reporters](/guide/reporters) that you can use out of the box. diff --git a/guide/index.md b/guide/index.md index 21a1df20..c3ebe8c3 100644 --- a/guide/index.md +++ b/guide/index.md @@ -46,6 +46,13 @@ It is recommended that you install a copy of `vitest` in your `package.json`, us 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. +Vitest and third party integrations can use `.vitest` directory to store generated artifacts. It's recommended to add this in your `.gitignore`. + +``` sh [.gitignore] +# Vitest reports and artifacts +.vitest/ +``` + ## Writing Tests As an example, we will write a simple test that verifies the output of a function that adds two numbers. From d221c483a604318a4c303889fa7e36fe9349473a Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Thu, 23 Apr 2026 18:03:45 +0900 Subject: [PATCH 7/9] feat(browser): export aria tree utils (#10171) --- api/browser/context.md | 30 ++++++++++++++++++++++++++++++ guide/browser/aria-snapshots.md | 2 ++ 2 files changed, 32 insertions(+) diff --git a/api/browser/context.md b/api/browser/context.md index c4eee0d2..49f75e4f 100644 --- a/api/browser/context.md +++ b/api/browser/context.md @@ -270,6 +270,17 @@ export const utils: { * Creates "Cannot find element" error. Useful for custom locators. */ getElementError(selector: string, container?: Element): Error + /** + * Utilities for generating and working with ARIA trees and templates. + * @experimental + */ + aria: { + generateAriaTree(rootElement: Element): AriaNode + renderAriaTree(root: AriaNode): string + renderAriaTemplate(template: AriaTemplateNode): string + parseAriaTemplate(text: string): AriaTemplateNode + matchAriaTree(root: AriaNode, template: AriaTemplateNode): { pass: boolean; resolved: string } + } } ``` @@ -340,3 +351,22 @@ utils.configurePrettyDOM({ ::: tip This feature is inspired by Testing Library's [`defaultIgnore`](https://testing-library.com/docs/dom-testing-library/api-configuration/#defaultignore) configuration. ::: + +### aria 5.0.0 {#aria} + +The `aria` namespace exposes low-level utilities used by Vitest's ARIA snapshot matchers. + +```ts +import { utils } from 'vitest/browser' + +document.body.innerHTML = ` +

Hello, World!

+ + +` +const tree = utils.aria.generateAriaTree(document.body) +const yaml = utils.aria.renderAriaNode(tree) +console.log(yaml) +// - heading "Hello, World!" [level=1] +// - button "Visible"" +``` diff --git a/guide/browser/aria-snapshots.md b/guide/browser/aria-snapshots.md index d4dee825..d7d8ae76 100644 --- a/guide/browser/aria-snapshots.md +++ b/guide/browser/aria-snapshots.md @@ -30,6 +30,8 @@ await expect.element(page.getByRole('navigation')).toMatchAriaInlineSnapshot(` This catches accessibility regressions: missing labels, broken roles, incorrect heading levels, and more — things that DOM snapshots would miss. Even if the underlying HTML structure changes, the assertion would not fail as long as content matches semantically. +For advanced cases, you can also generate and inspect the ARIA tree through `utils.aria` from `vitest/browser`. See the [Context API](/api/browser/context#aria) for details. + ## Snapshot Workflow ARIA snapshots use the same Vitest snapshot workflow as other snapshot assertions. File snapshots, inline snapshots, `--update` / `-u`, watch mode updates, and CI snapshot behavior all work the same way. From ec964f36ce7596a023a32b8265f6019c51b32926 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Thu, 23 Apr 2026 18:12:41 +0900 Subject: [PATCH 8/9] feat(browser): support dom snapshot trace view (#10102) Co-authored-by: Claude Sonnet 4.6 Co-authored-by: Codex --- .vitepress/config.ts | 5 + config/browser/trace.md | 2 + config/browser/traceview.md | 70 ++++++++++ guide/browser/index.md | 2 + guide/browser/playwright-traces.md | 126 ++++++++++++++++++ guide/browser/trace-view.md | 191 ++++++++++++++++++---------- guide/cli-generated.md | 21 +++ public/browser/trace-view-dark.png | Bin 0 -> 199404 bytes public/browser/trace-view-light.png | Bin 0 -> 199896 bytes 9 files changed, 353 insertions(+), 64 deletions(-) create mode 100644 config/browser/traceview.md create mode 100644 guide/browser/playwright-traces.md create mode 100644 public/browser/trace-view-dark.png create mode 100644 public/browser/trace-view-light.png diff --git a/.vitepress/config.ts b/.vitepress/config.ts index 67c88513..363f27c4 100644 --- a/.vitepress/config.ts +++ b/.vitepress/config.ts @@ -806,6 +806,11 @@ export default ({ mode }: { mode: string }) => { link: '/guide/browser/trace-view', docFooterText: 'Trace View | Browser Mode', }, + { + text: 'Playwright Traces', + link: '/guide/browser/playwright-traces', + docFooterText: 'Playwright Traces | Browser Mode', + }, { text: 'ARIA Snapshots', link: '/guide/browser/aria-snapshots', diff --git a/config/browser/trace.md b/config/browser/trace.md index 51b62eba..79d1a017 100644 --- a/config/browser/trace.md +++ b/config/browser/trace.md @@ -11,6 +11,8 @@ outline: deep Capture a trace of your browser test runs. You can preview traces with [Playwright Trace Viewer](https://trace.playwright.dev/). +See [Playwright Traces](/guide/browser/playwright-traces) for the full workflow. + This options supports the following values: - `'on'` - capture trace for all tests. (not recommended as it's performance heavy) diff --git a/config/browser/traceview.md b/config/browser/traceview.md new file mode 100644 index 00000000..9d86f36c --- /dev/null +++ b/config/browser/traceview.md @@ -0,0 +1,70 @@ +--- +title: browser.traceView | Config +outline: deep +--- + +# browser.traceView 5.0.0 + +- **Type:** `boolean | { enabled?: boolean; recordCanvas?: boolean; inlineImages?: boolean }` +- **CLI:** `--browser.traceView` +- **Default:** `false` + +Enable trace-view collection for browser tests. Vitest captures DOM snapshots for browser interactions and can show them in the browser UI, Vitest UI, or HTML reporter when those surfaces are enabled — no external tools required. + +```ts +export default defineConfig({ + test: { + browser: { + traceView: true, + }, + }, +}) +``` + +Use the object form to enable additional snapshot fidelity options: + +```ts +export default defineConfig({ + test: { + browser: { + traceView: { + enabled: true, + inlineImages: true, + recordCanvas: true, + }, + }, + }, +}) +``` + +| Option | Default | Description | +| --- | --- | --- | +| `enabled` | `false` | Enables Vitest trace-view artifact collection. | +| `inlineImages` | `false` | Inlines loaded `` pixels into snapshots for more portable replay, useful in the HTML reporter. | +| `recordCanvas` | `false` | Captures canvas pixels in snapshots. | + +## browser.traceView.enabled {#traceview-enabled} + +- **Type:** `boolean` +- **Default:** `false` +- **CLI:** `--browser.traceView.enabled` + +Enables Vitest trace-view artifact collection. + +## browser.traceView.inlineImages {#traceview-inlineimages} + +- **Type:** `boolean` +- **Default:** `false` +- **CLI:** `--browser.traceView.inlineImages` + +Inlines loaded `` pixels into snapshots for more portable replay, useful in the HTML reporter. + +## browser.traceView.recordCanvas {#traceview-recordcanvas} + +- **Type:** `boolean` +- **Default:** `false` +- **CLI:** `--browser.traceView.recordCanvas` + +Captures canvas pixels in snapshots. This enables a weaker replay iframe sandbox because rrweb needs scripts to redraw canvas data. + +See [Trace View](/guide/browser/trace-view) for full documentation. diff --git a/guide/browser/index.md b/guide/browser/index.md index 990498af..d13f882c 100644 --- a/guide/browser/index.md +++ b/guide/browser/index.md @@ -330,6 +330,8 @@ Since Vitest 3.2, if you don't have the `browser` option in your config but spec 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). +For an alternative debugging model that captures DOM snapshots for every test instead of showing a live iframe, see [Trace View](/guide/browser/trace-view). + ## 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. diff --git a/guide/browser/playwright-traces.md b/guide/browser/playwright-traces.md new file mode 100644 index 00000000..165bd2bf --- /dev/null +++ b/guide/browser/playwright-traces.md @@ -0,0 +1,126 @@ +# Playwright Traces + +Vitest Browser Mode supports generating Playwright's [trace files](https://playwright.dev/docs/trace-viewer#viewing-remote-traces). To enable tracing, you need to set the [`trace`](/config/browser/trace) option in the `test.browser` configuration. + +::: warning +Generating trace files is only available when using the [Playwright provider](/config/browser/playwright). +::: + +::: code-group +```ts [vitest.config.js] +import { defineConfig } from 'vitest/config' +import { playwright } from '@vitest/browser-playwright' + +export default defineConfig({ + test: { + browser: { + provider: playwright(), + trace: 'on', + }, + }, +}) +``` +```bash [CLI] +vitest --browser.trace=on +``` +::: + +By default, Vitest will generate a trace file for each test. You can also configure it to only generate traces on test failures by setting `trace` to `'on-first-retry'`, `'on-all-retries'` or `'retain-on-failure'`. The files will be saved in `__traces__` folder next to your test files. The name of the trace includes the project name, the test name, the [`repeats`](/api/test#repeats) count and [`retry`](/api/test#retry) count: + +``` +chromium-my-test-0-0.trace.zip +^^^^^^^^ project name + ^^^^^^ test name + ^ repeat count + ^ retry count +``` + +To change the output directory, you can set the `tracesDir` option in the `test.browser.trace` configuration. This way all traces will be stored in the same directory, grouped by the test file. + +```ts [vitest.config.js] +import { defineConfig } from 'vitest/config' +import { playwright } from '@vitest/browser-playwright' + +export default defineConfig({ + test: { + browser: { + provider: playwright(), + trace: { + mode: 'on', + // the path is relative to the root of the project + tracesDir: './playwright-traces', + }, + }, + }, +}) +``` + +The traces are available in reporters as [annotations](/guide/test-annotations). For example, in the HTML reporter, you can find the link to the trace file in the test details. + +## Trace markers + +You can add explicit named markers to make the trace timeline easier to read: + +```ts +import { page } from 'vitest/browser' + +document.body.innerHTML = ` + +` + +await page.getByRole('button', { name: 'Sign in' }).mark('sign in button rendered') +``` + +Both `page.mark(name)` and `locator.mark(name)` are available. + +You can also group multiple operations under one marker with `page.mark(name, callback)`: + +```ts +await page.mark('sign in flow', async () => { + await page.getByRole('textbox', { name: 'Email' }).fill('john@example.com') + await page.getByRole('textbox', { name: 'Password' }).fill('secret') + await page.getByRole('button', { name: 'Sign in' }).click() +}) +``` + +You can also wrap reusable helpers with [`vi.defineHelper()`](/api/vi#vi-defineHelper) so trace entries point to where the helper is called, not its internals: + +```ts +import { vi } from 'vitest' +import { page } from 'vitest/browser' + +const myRender = vi.defineHelper(async (content: string) => { + document.body.innerHTML = content + await page.elementLocator(document.body).mark('render helper') +}) + +test('renders content', async () => { + await myRender('') // trace points to this line +}) +``` + +## Preview + +To open the trace file, you can use the Playwright Trace Viewer. Run the following command in your terminal: + +```bash +npx playwright show-trace "path-to-trace-file" +``` + +This will start the Trace Viewer and load the specified trace file. + +Alternatively, you can open the Trace Viewer in your browser at https://trace.playwright.dev and upload the trace file there. + +Trace Viewer showing the trace timeline and rendered component +Trace Viewer showing the trace timeline and rendered component + +## Source Location + +When you open a trace, you'll notice that Vitest groups browser interactions and links them back to the exact line in your test that triggered them. This happens automatically for: + +- `expect.element(...)` assertions +- Interactive actions like `click`, `fill`, `type`, `hover`, `selectOptions`, `upload`, `dragAndDrop`, `tab`, `keyboard`, `wheel`, and screenshots + +Under the hood, Playwright still records its own low-level action events as usual. Vitest wraps them with source-location groups so you can jump straight from the trace timeline to the relevant line in your test. + +For anything not covered automatically, you can use `page.mark()` or `locator.mark()` to add your own trace groups — see [Trace markers](#trace-markers) above. diff --git a/guide/browser/trace-view.md b/guide/browser/trace-view.md index 49346c70..42683aa8 100644 --- a/guide/browser/trace-view.md +++ b/guide/browser/trace-view.md @@ -1,79 +1,122 @@ -# Trace View +# Trace View 5.0.0 -Vitest Browser Mode supports generating Playwright's [trace files](https://playwright.dev/docs/trace-viewer#viewing-remote-traces). To enable tracing, you need to set the [`trace`](/config/browser/trace) option in the `test.browser` configuration. +`browser.traceView` records browser interactions as DOM snapshots and lets you replay them step by step in Vitest's built-in trace viewer. It is useful when the live browser view is not enough: you can inspect earlier tests, failed retries, screenshots, assertions, and user actions after the browser has already moved on. + +Trace view is additive to the current browser testing workflow. Enabling it does not force a single debugging mode. You can use it with the normal local browser UI, with a headless browser and Vitest UI, or with the HTML reporter in CI. + +::: tip Trace view, browser UI, and HTML reports + +The normal local browser mode opens the [browser UI](/config/browser/ui), where tests run in a visible iframe. This is useful while developing, but the iframe only shows the current browser state. When another test runs, the previous rendered state is gone. + +`browser.traceView` keeps a replayable record for each test. In local browser UI mode, the trace viewer appears alongside the existing live view so you can keep using the browser UI while also inspecting recorded steps. + +For static output, add the [HTML reporter](/guide/reporters#html-reporter). The same trace viewer can then be opened from the generated report, which is useful for run-mode and CI failures. -::: warning -Generating trace files is only available when using the [Playwright provider](/config/browser/playwright). ::: +::: details Looking for Playwright traces? + +This page now documents Vitest's built-in `browser.traceView` feature. The previous `browser.trace` guide for Playwright traces moved to [Playwright Traces](./playwright-traces). + +::: + +## Quick Start + +Enable trace view with the [`browser.traceView`](/config/browser/traceview) option: + ::: code-group -```ts [vitest.config.js] + +```ts [vitest.config.ts] import { defineConfig } from 'vitest/config' -import { playwright } from '@vitest/browser-playwright' export default defineConfig({ test: { browser: { - provider: playwright(), - trace: 'on', + traceView: true, }, }, }) ``` + ```bash [CLI] -vitest --browser.trace=on +vitest --browser.traceView ``` + ::: -By default, Vitest will generate a trace file for each test. You can also configure it to only generate traces on test failures by setting `trace` to `'on-first-retry'`, `'on-all-retries'` or `'retain-on-failure'`. The files will be saved in `__traces__` folder next to your test files. The name of the trace includes the project name, the test name, the [`repeats`](/api/test#repeats) count and [`retry`](/api/test#retry) count: +When `browser.traceView` is enabled, tests with recorded traces can be opened in the trace viewer from the [browser UI](/config/browser/ui), [Vitest UI](/guide/ui), and [HTML reporter](/guide/reporters#html-reporter). The viewer has two resizable panes: -``` -chromium-my-test-0-0.trace.zip -^^^^^^^^ project name - ^^^^^^ test name - ^ repeat count - ^ retry count -``` +- **Step list** (left) — every recorded action, assertion, mark, and lifecycle entry, with name, timing, selector, and source location. Failed actions and assertions are highlighted in red. +- **DOM snapshot** (right) — a reconstruction of the page at the selected step. The interacted element is highlighted in blue. -To change the output directory, you can set the `tracesDir` option in the `test.browser.trace` configuration. This way all traces will be stored in the same directory, grouped by the test file. +Selecting a step also opens its source location in the Editor tab when that location is available. -```ts [vitest.config.js] -import { defineConfig } from 'vitest/config' -import { playwright } from '@vitest/browser-playwright' +Vitest UI trace viewer showing step list and DOM snapshot +Vitest UI trace viewer showing step list and DOM snapshot -export default defineConfig({ - test: { - browser: { - provider: playwright(), - trace: { - mode: 'on', - // the path is relative to the root of the project - tracesDir: './playwright-traces', - }, - }, - }, -}) -``` +Example replay uses [Vuetify's](https://github.com/vuetifyjs/vuetify) `VDateInput` component. + + +## Common Setups + + -The traces are available in reporters as [annotations](/guide/test-annotations). For example, in the HTML reporter, you can find the link to the trace file in the test details. +`browser.traceView` records traces. The browser mode, UI, and reporter options determine where you inspect them. -## Trace markers +| Goal | Configuration | Result | +| --- | --- | --- | +| Add trace replay to the normal local browser UI | `vitest --browser.traceView` | Uses the default local headed browser UI and adds trace replay for recorded tests. | +| Debug locally with a headless browser | `vitest --browser.traceView --browser.headless --ui` | The browser runs headless, while Vitest UI shows recorded trace steps and snapshots. | +| Debug locally with a visible browser window and Vitest UI | `vitest --browser.traceView --browser.headless=false --browser.ui=false --ui` | Vitest UI shows recorded trace steps and snapshots, while tests run in a separate headed browser window. | +| Generate a static report for CI or run mode | `vitest run --browser.traceView --reporter=html` | The HTML report includes the trace viewer for recorded tests. | -You can add explicit named markers to make the trace timeline easier to read: +## Relation to Playwright Traces + +`browser.traceView` and [`browser.trace`](/config/browser/trace) are independent features: + +| | `browser.traceView` | `browser.trace` | +| ---------------------- | --------------------------------------------------------- | ---------------------------------------------- | +| Provider support | All providers (playwright, webdriverio, preview) | Playwright only | +| Viewer | Browser UI / Vitest UI / HTML reporter | Playwright Trace Viewer / trace.playwright.dev | +| Format | [rrweb](https://github.com/rrweb-io/rrweb) DOM snapshots | Playwright `.trace.zip` | +| Requires external tool | No | Yes (`npx playwright show-trace`) | + +You can enable both at the same time. See [Playwright Traces](./playwright-traces) for the `browser.trace` workflow. + +## Recorded Steps + +Trace entries are recorded automatically for: + +- `expect.element(...)` assertions +- Interactive actions like `click`, `dblClick`, `tripleClick`, `fill`, `clear`, `type`, `hover`, `selectOptions`, `upload`, `dragAndDrop`, `tab`, `keyboard`, `wheel`, and screenshots +- Test runner lifecycle event (e.g. `vitest:onAfterRetryTask` is recorded after each test and retry run) + +Each entry captures the DOM state at that point, along with timing information, the selector, and the source location that triggered it. + +Element highlighting is best-effort. Some provider-specific selectors, shadow DOM selectors, or elements that are not present in the captured snapshot may not be highlighted. + +## Custom Trace Entries + +You can insert your own named entries with `page.mark()` and `locator.mark()`: ```ts import { page } from 'vitest/browser' -document.body.innerHTML = ` - -` +await page.mark('content rendered') -await page.getByRole('button', { name: 'Sign in' }).mark('sign in button rendered') +await page.getByRole('button', { name: 'Sign in' }).mark('sign in button') ``` -Both `page.mark(name)` and `locator.mark(name)` are available. - -You can also group multiple operations under one marker with `page.mark(name, callback)`: +You can also pass a callback to `page.mark()`. Note that grouping is not currently supported — each inner action is recorded individually, and the mark entry appears at the end: ```ts await page.mark('sign in flow', async () => { @@ -83,44 +126,64 @@ await page.mark('sign in flow', async () => { }) ``` -You can also wrap reusable helpers with [`vi.defineHelper()`](/api/vi#vi-defineHelper) so trace entries point to where the helper is called, not its internals: +Use [`vi.defineHelper()`](/api/vi#vi-defineHelper) to make entries from reusable helpers point to the call site rather than the helper's internals: ```ts import { vi } from 'vitest' import { page } from 'vitest/browser' -const myRender = vi.defineHelper(async (content: string) => { - document.body.innerHTML = content - await page.elementLocator(document.body).mark('render helper') +const renderContent = vi.defineHelper(async (html: string) => { + document.body.innerHTML = html + await page.elementLocator(document.body).mark('render') }) -test('renders content', async () => { - await myRender('') // trace points to this line +test('shows button', async () => { + await renderContent('') // trace entry points here }) ``` -## Preview +## Retries and Repeats + +Each attempt — retry or repeat — is recorded as a separate trace. When a test has multiple attempts, the viewer opens the most recent one by default. You can switch between attempts in the Report tab. + +## Snapshot Fidelity + +By default, trace view captures the DOM tree, attributes, form values, same-origin readable CSS, element scroll positions, viewport size, and window scroll position. Images and canvas pixels are not inlined by default. -To open the trace file, you can use the Playwright Trace Viewer. Run the following command in your terminal: +Stylesheets are captured through the browser's CSSOM. Readable `