From bf7524bae55d3da5cca67e22d376836be5816fb9 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sat, 25 Apr 2026 20:01:43 +0900 Subject: [PATCH 01/13] fix: global `sequence.concurrent: true` with top-level `test(..., { concurrent: false })` + depreacte `sequential` test API and options (#10194) Co-authored-by: Codex Co-authored-by: Vladimir --- api/describe.md | 6 +++++- api/test.md | 10 +++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/api/describe.md b/api/describe.md index 5444a50b..2d37a4c2 100644 --- a/api/describe.md +++ b/api/describe.md @@ -230,10 +230,14 @@ describe.concurrent('suite', () => { }) ``` -## describe.sequential +## describe.sequential {#describe-sequential} - **Alias:** `suite.sequential` +::: warning DEPRECATED +Use [`concurrent: false`](/api/test#concurrent) instead when you need to override inherited or configured concurrency. +::: + `describe.sequential` in a suite marks every test as sequential. This is useful if you want to run tests in sequence within `describe.concurrent` or with the `--sequence.concurrent` command option. ```ts diff --git a/api/test.md b/api/test.md index 18af801f..7618fa19 100644 --- a/api/test.md +++ b/api/test.md @@ -223,6 +223,10 @@ Whether this test run concurrently with other concurrent tests in the suite. - **Default:** `true` - **Alias:** [`test.sequential`](#test-sequential) +::: warning DEPRECATED +Use [`concurrent: false`](#concurrent) instead when you need to override inherited or configured concurrency. +::: + Whether tests run sequentially. When both `concurrent` and `sequential` are specified, `concurrent` takes precedence. ### skip @@ -453,10 +457,14 @@ test.concurrent('test 2', async ({ expect }) => { Note that if tests are synchronous, Vitest will still run them sequentially. -## test.sequential +## test.sequential {#test-sequential} - **Alias:** `it.sequential` +::: warning DEPRECATED +Use [`concurrent: false`](#concurrent) instead when you need to override inherited or configured concurrency. +::: + `test.sequential` marks a test as sequential. This is useful if you want to run tests in sequence within `describe.concurrent` or with the `--sequence.concurrent` command option. ```ts From 8241fd0e8b125d7f5b05779dd840bd7d9a3e8986 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 26 Apr 2026 16:14:52 +0900 Subject: [PATCH 02/13] docs: document v5 migration changes for #9609 and #10170 (#10200) Co-authored-by: Codex --- guide/migration.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/guide/migration.md b/guide/migration.md index 82963564..9047317d 100644 --- a/guide/migration.md +++ b/guide/migration.md @@ -7,6 +7,54 @@ outline: deep [Migrating to Vitest 3.0](https://v3.vitest.dev/guide/migration) | [Migrating to Vitest 2.0](https://v2.vitest.dev/guide/migration) +## Migrating to Vitest 5.0 {#vitest-5} + +::: warning Work in progress +Vitest 5.0 is currently in beta. This section tracks breaking changes as they are merged and may change before the stable release. +::: + +### String Values in `$` Test Titles Are No Longer Quoted + +When interpolating string values in `test.each`, `test.for`, `describe.each`, or `describe.for` titles with the `$` syntax, Vitest no longer wraps those string values in quotes. + +This affects generated task names in reporter output, snapshots, and any tooling that matches tests by their generated title. + +```ts +test.for([{ name: 'Alice' }])('I am $name', () => {}) +// Vitest 4 → I am 'Alice' +// Vitest 5 → I am Alice +``` + +If you need quotes in the generated title, add them to the title template: + +```ts +test.for([{ name: 'Alice' }])('I am "$name"', () => {}) +// → I am "Alice" +``` + +### `chaiConfig.truncateThreshold` No Longer Controls Test Title Value Truncation + +Vitest now formats interpolated task title values with its display formatter based on `@vitest/pretty-format`, instead of Chai/loupe formatting. + +Most output should stay similar, but generated titles or assertion output involving formatted values may have small formatting differences. + +If you used `chaiConfig.truncateThreshold` to control truncation in `test.each`, `test.for`, `describe.each`, or `describe.for` titles, use `taskTitleValueFormatTruncate` instead: + +```ts [vitest.config.ts] +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + chaiConfig: { // [!code --] + truncateThreshold: 120, // [!code --] + }, // [!code --] + taskTitleValueFormatTruncate: 120, // [!code ++] + }, +}) +``` + +`chaiConfig.truncateThreshold` still controls truncation in assertion error messages. + ## Migrating to Vitest 4.0 {#vitest-4} ::: warning Prerequisites From 853e1c2700435082498bf9ef06434d2bf2bbb2d3 Mon Sep 17 00:00:00 2001 From: "Md.Sadiq" Date: Sun, 26 Apr 2026 20:00:59 +0530 Subject: [PATCH 03/13] fix!: default `attachmentsDir` from `.vitest-attachements/` to `.vitest/attachments/` (#10186) --- config/attachmentsdir.md | 2 +- guide/browser/visual-regression-testing.md | 4 ++-- guide/cli-generated.md | 2 +- guide/improving-performance.md | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/config/attachmentsdir.md b/config/attachmentsdir.md index 993fa9f8..14867d75 100644 --- a/config/attachmentsdir.md +++ b/config/attachmentsdir.md @@ -6,6 +6,6 @@ outline: deep # attachmentsDir - **Type:** `string` -- **Default:** `'.vitest-attachments'` +- **Default:** `'.vitest/attachments'` Directory path for storing attachments created by [`context.annotate`](/guide/test-context#annotate) relative to the project root. diff --git a/guide/browser/visual-regression-testing.md b/guide/browser/visual-regression-testing.md index ad088764..75a877bd 100644 --- a/guide/browser/visual-regression-testing.md +++ b/guide/browser/visual-regression-testing.md @@ -302,10 +302,10 @@ Reference screenshot: tests/__screenshots__/button.test.ts/button-chromium-darwin.png Actual screenshot: - tests/.vitest-attachments/button.test.ts/button-chromium-darwin-actual.png + tests/.vitest/attachments/button.test.ts/button-chromium-darwin-actual.png Diff image: - tests/.vitest-attachments/button.test.ts/button-chromium-darwin-diff.png + tests/.vitest/attachments/button.test.ts/button-chromium-darwin-diff.png ``` ### Understanding the diff image diff --git a/guide/cli-generated.md b/guide/cli-generated.md index 4fc81a51..abdd2dad 100644 --- a/guide/cli-generated.md +++ b/guide/cli-generated.md @@ -865,7 +865,7 @@ Collect test and suite locations in the `location` property - **CLI:** `--attachmentsDir ` - **Config:** [attachmentsDir](/config/attachmentsdir) -The directory where attachments from `context.annotate` are stored in (default: `.vitest-attachments`) +The directory where attachments from `context.annotate` are stored in (default: `.vitest/attachments`) ### run diff --git a/guide/improving-performance.md b/guide/improving-performance.md index efbbc804..baca0c6c 100644 --- a/guide/improving-performance.md +++ b/guide/improving-performance.md @@ -178,7 +178,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: blob-attachments-${{ matrix.shardIndex }} - path: .vitest-attachments/** + path: .vitest/** include-hidden-files: true retention-days: 1 @@ -209,7 +209,7 @@ jobs: - name: Download attachments from GitHub Actions Artifacts uses: actions/download-artifact@v4 with: - path: .vitest-attachments + path: .vitest pattern: blob-attachments-* merge-multiple: true From f28efd4c52f1568690be75bab14296f8c4df1350 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 27 Apr 2026 16:58:47 +0900 Subject: [PATCH 04/13] refactor!: remove `sequential` test/suite options in favor of `concurrent` (#10198) Co-authored-by: Codex --- api/describe.md | 37 +++++++++++++---------------------- api/test.md | 46 ++++++-------------------------------------- guide/migration.md | 41 ++++++++++----------------------------- guide/parallelism.md | 13 +++++++++++++ 4 files changed, 42 insertions(+), 95 deletions(-) diff --git a/api/describe.md b/api/describe.md index 2d37a4c2..f1a95f9e 100644 --- a/api/describe.md +++ b/api/describe.md @@ -208,6 +208,19 @@ describe.concurrent('suite', () => { }) ``` +Set `concurrent` to `false` to opt out of concurrency inherited from a parent suite or [`sequence.concurrent`](/config/sequence#sequence-concurrent): + +```ts +describe.concurrent('suite', () => { + test('concurrent test', async () => { /* ... */ }) + + describe('sequential suite', { concurrent: false }, () => { + test('sequential test 1', async () => { /* ... */ }) + test('sequential test 2', async () => { /* ... */ }) + }) +}) +``` + `.skip`, `.only`, and `.todo` works with concurrent suites. All the following combinations are valid: ```ts @@ -230,30 +243,6 @@ describe.concurrent('suite', () => { }) ``` -## describe.sequential {#describe-sequential} - -- **Alias:** `suite.sequential` - -::: warning DEPRECATED -Use [`concurrent: false`](/api/test#concurrent) instead when you need to override inherited or configured concurrency. -::: - -`describe.sequential` in a suite marks every test as sequential. This is useful if you want to run tests in sequence within `describe.concurrent` or with the `--sequence.concurrent` command option. - -```ts -import { describe, test } from 'vitest' - -describe.concurrent('suite', () => { - test('concurrent test 1', async () => { /* ... */ }) - test('concurrent test 2', async () => { /* ... */ }) - - describe.sequential('', () => { - test('sequential test 1', async () => { /* ... */ }) - test('sequential test 2', async () => { /* ... */ }) - }) -}) -``` - ## describe.shuffle - **Alias:** `suite.shuffle` diff --git a/api/test.md b/api/test.md index 7618fa19..670f4006 100644 --- a/api/test.md +++ b/api/test.md @@ -217,17 +217,13 @@ Prefer using non-nested meta, if possible. Whether this test run concurrently with other concurrent tests in the suite. -### sequential +Set `concurrent` to `false` to opt out of concurrency inherited from [`describe.concurrent`](/api/describe#describe-concurrent) or [`sequence.concurrent`](/config/sequence#sequence-concurrent): -- **Type:** `boolean` -- **Default:** `true` -- **Alias:** [`test.sequential`](#test-sequential) - -::: warning DEPRECATED -Use [`concurrent: false`](#concurrent) instead when you need to override inherited or configured concurrency. -::: - -Whether tests run sequentially. When both `concurrent` and `sequential` are specified, `concurrent` takes precedence. +```ts +test('runs sequentially', { concurrent: false }, async () => { + // ... +}) +``` ### skip @@ -457,36 +453,6 @@ test.concurrent('test 2', async ({ expect }) => { Note that if tests are synchronous, Vitest will still run them sequentially. -## test.sequential {#test-sequential} - -- **Alias:** `it.sequential` - -::: warning DEPRECATED -Use [`concurrent: false`](#concurrent) instead when you need to override inherited or configured concurrency. -::: - -`test.sequential` marks a test as sequential. This is useful if you want to run tests in sequence within `describe.concurrent` or with the `--sequence.concurrent` command option. - -```ts -import { describe, test } from 'vitest' - -// with config option { sequence: { concurrent: true } } -test('concurrent test 1', async () => { /* ... */ }) -test('concurrent test 2', async () => { /* ... */ }) - -test.sequential('sequential test 1', async () => { /* ... */ }) -test.sequential('sequential test 2', async () => { /* ... */ }) - -// within concurrent suite -describe.concurrent('suite', () => { - test('concurrent test 1', async () => { /* ... */ }) - test('concurrent test 2', async () => { /* ... */ }) - - test.sequential('sequential test 1', async () => { /* ... */ }) - test.sequential('sequential test 2', async () => { /* ... */ }) -}) -``` - ## test.todo - **Alias:** `it.todo` diff --git a/guide/migration.md b/guide/migration.md index 9047317d..788cf0ab 100644 --- a/guide/migration.md +++ b/guide/migration.md @@ -13,48 +13,27 @@ outline: deep Vitest 5.0 is currently in beta. This section tracks breaking changes as they are merged and may change before the stable release. ::: -### String Values in `$` Test Titles Are No Longer Quoted +### Removed `test.sequential`, `describe.sequential`, and `sequential` Options -When interpolating string values in `test.each`, `test.for`, `describe.each`, or `describe.for` titles with the `$` syntax, Vitest no longer wraps those string values in quotes. - -This affects generated task names in reporter output, snapshots, and any tooling that matches tests by their generated title. +Vitest 5.0 removes the deprecated `test.sequential`, `describe.sequential`, and `sequential` test options. Use `concurrent: false` when you need a test or suite to opt out of inherited or globally configured concurrency. ```ts -test.for([{ name: 'Alice' }])('I am $name', () => {}) -// Vitest 4 → I am 'Alice' -// Vitest 5 → I am Alice +test.sequential('example', async () => { /* ... */ }) // [!code --] +test('example', { concurrent: false }, async () => { /* ... */ }) // [!code ++] ``` -If you need quotes in the generated title, add them to the title template: - ```ts -test.for([{ name: 'Alice' }])('I am "$name"', () => {}) -// → I am "Alice" +describe.sequential('suite', () => { /* ... */ }) // [!code --] +describe('suite', { concurrent: false }, () => { /* ... */ }) // [!code ++] ``` -### `chaiConfig.truncateThreshold` No Longer Controls Test Title Value Truncation - -Vitest now formats interpolated task title values with its display formatter based on `@vitest/pretty-format`, instead of Chai/loupe formatting. - -Most output should stay similar, but generated titles or assertion output involving formatted values may have small formatting differences. - -If you used `chaiConfig.truncateThreshold` to control truncation in `test.each`, `test.for`, `describe.each`, or `describe.for` titles, use `taskTitleValueFormatTruncate` instead: - -```ts [vitest.config.ts] -import { defineConfig } from 'vitest/config' +The same replacement applies to option objects: -export default defineConfig({ - test: { - chaiConfig: { // [!code --] - truncateThreshold: 120, // [!code --] - }, // [!code --] - taskTitleValueFormatTruncate: 120, // [!code ++] - }, -}) +```ts +test('example', { sequential: true }, async () => { /* ... */ }) // [!code --] +test('example', { concurrent: false }, async () => { /* ... */ }) // [!code ++] ``` -`chaiConfig.truncateThreshold` still controls truncation in assertion error messages. - ## Migrating to Vitest 4.0 {#vitest-4} ::: warning Prerequisites diff --git a/guide/parallelism.md b/guide/parallelism.md index 4c694c3b..c273eeef 100644 --- a/guide/parallelism.md +++ b/guide/parallelism.md @@ -80,6 +80,19 @@ describe.concurrent('user API', () => { If you want *all* tests in your project to run concurrently by default, set [`sequence.concurrent`](/config/sequence#sequence-concurrent) to `true` in your config. +You can opt individual tests or suites out of inherited concurrency with `concurrent: false`: + +```ts +test('uses a shared resource', { concurrent: false }, async () => { + // ... +}) + +describe('shared resource suite', { concurrent: false }, () => { + test('step 1', async () => { /* ... */ }) + test('step 2', async () => { /* ... */ }) +}) +``` + ### Hooks with Concurrent Tests When tests run concurrently, lifecycle hooks behave differently. `beforeAll` and `afterAll` still run once for the group, but `beforeEach` and `afterEach` run for each test — potentially at the same time, since the tests themselves overlap. From 7daeb00de738d4b2e1ecc9375e687613db5d7ae4 Mon Sep 17 00:00:00 2001 From: Raul Macarie Date: Mon, 27 Apr 2026 14:06:51 +0200 Subject: [PATCH 05/13] feat(browser): provide project reference in `ToMatchScreenshotResolvePath` (#10138) Co-authored-by: Vladimir --- config/browser/expect.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/browser/expect.md b/config/browser/expect.md index dff6d64b..45c3a21a 100644 --- a/config/browser/expect.md +++ b/config/browser/expect.md @@ -118,6 +118,10 @@ receives an object with the following properties: The value provided to [`attachmentsDir`](/config/attachmentsdir), if none is provided, its default value. +- `project: TestProject` 4.1.6 + + The [`TestProject`](/api/advanced/test-project) the test belongs to. + For example, to group screenshots by browser: ```ts From 00c87ce19fbcada49c3d015f977279bbaa391224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Perkki=C3=B6?= Date: Mon, 27 Apr 2026 15:10:47 +0300 Subject: [PATCH 06/13] feat(coverage): v8 to track `node:child_process` and `node:worker_threads` contexts (#9976) --- config/coverage.md | 11 +++++++++++ guide/cli-generated.md | 7 +++++++ 2 files changed, 18 insertions(+) diff --git a/config/coverage.md b/config/coverage.md index d7456831..8f1cfb42 100644 --- a/config/coverage.md +++ b/config/coverage.md @@ -458,3 +458,14 @@ Note that setting this option does not change where coverage HTML report is gene - **CLI:** `--coverage.changed`, `--coverage.changed=` Collect coverage only for files changed since a specified commit or branch. When set to `true`, it uses staged and unstaged changes. + +## coverage.autoAttachSubprocess 5.0.0 {#coverage-autoattachsubprocess} + +- **Type:** `boolean` +- **Default:** `false` +- **Available for providers:** `'v8'` +- **CLI:** `--coverage.autoAttachSubprocess` + +Track coverage of the `node:child_process` and `node:worker_threads` spawned during test run. + +Note that this option has some performance overhead as its using [`NODE_V8_COVERAGE`](https://nodejs.org/api/cli.html#node-v8-coveragedir) internally. This triggers Node to write lots of unnecessary files on file system. diff --git a/guide/cli-generated.md b/guide/cli-generated.md index abdd2dad..db20e272 100644 --- a/guide/cli-generated.md +++ b/guide/cli-generated.md @@ -299,6 +299,13 @@ Apply exclusions again after coverage has been remapped to original sources. (de Directory of HTML coverage output to be served in UI mode and HTML reporter. +### coverage.autoAttachSubprocess + +- **CLI:** `--coverage.autoAttachSubprocess` +- **Config:** [coverage.autoAttachSubprocess](/config/coverage#coverage-autoattachsubprocess) + +Track coverage of the `node:child_process` and `node:worker_threads` spawned during test run. Supported only by `v8` provider. (default: false) + ### mode - **CLI:** `--mode ` From 6c3732e5999b7dc50edc6ebad00ffe151f18bda0 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Mon, 27 Apr 2026 15:37:28 +0200 Subject: [PATCH 07/13] refactor: inline snapshot package (#10210) --- guide/snapshot.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/guide/snapshot.md b/guide/snapshot.md index 371a2a7b..e99faccd 100644 --- a/guide/snapshot.md +++ b/guide/snapshot.md @@ -344,7 +344,7 @@ Custom serializers control how values are _rendered_ into snapshot strings, but A domain adapter implements four methods and is generic over two types — `Captured` (what the value actually is) and `Expected` (what the stored snapshot parses into): ```ts -import type { DomainMatchResult, DomainSnapshotAdapter } from '@vitest/snapshot' +import type { DomainMatchResult, DomainSnapshotAdapter } from 'vitest' const myAdapter: DomainSnapshotAdapter = { name: 'my-domain', @@ -420,7 +420,7 @@ expect(value).toMatchMyDomainInlineSnapshot(`key=value`) A minimal adapter that stores objects as `key=value` lines, with regex pattern and subset key match support ([full source](https://github.com/vitest-dev/vitest/blob/main/test/snapshots/test/fixtures/domain/basic.ts)): ```ts [kv-adapter.ts] -import type { DomainMatchResult, DomainSnapshotAdapter } from '@vitest/snapshot' +import type { DomainMatchResult, DomainSnapshotAdapter } from 'vitest' type KVCaptured = Record type KVExpected = Record From d9595487e961ee3eff6602c95c364f530c2cff88 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 28 Apr 2026 17:40:04 +0900 Subject: [PATCH 08/13] feat: expose default reporters through `configDefaults.reporters` (#10219) Co-authored-by: Claude Opus 4.7 (1M context) --- config/reporters.md | 8 ++++---- guide/reporters.md | 46 ++++++++++++++++++++++++++------------------- guide/ui.md | 2 +- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/config/reporters.md b/config/reporters.md index 2098d8f6..989ac0e2 100644 --- a/config/reporters.md +++ b/config/reporters.md @@ -14,7 +14,7 @@ interface UserConfig { type ConfigReporter = string | Reporter | [string, object?] ``` -- **Default:** [`'default'`](/guide/reporters#default-reporter) (or [['default'](/guide/reporters#default-reporter), ['github-actions'](/guide/reporters#github-actions-reporter)] when `process.env.GITHUB_ACTIONS === 'true'`) +- **Default:** [`'default'`](/guide/reporters#default-reporter). See [Default Reporters](/guide/reporters#default-reporters) for environment-specific behavior. - **CLI:** - `--reporter=tap` for a single reporter - `--reporter=verbose --reporter=github-actions` for multiple reporters @@ -49,14 +49,14 @@ Note that the [coverage](/guide/coverage) feature uses a different [`coverage.re ::: code-group ```js [vitest.config.js] -import { defineConfig } from 'vitest/config' +import { configDefaults, defineConfig } from 'vitest/config' export default defineConfig({ test: { reporters: [ - 'default', + ...configDefaults.reporters, // conditional reporter - process.env.CI ? 'github-actions' : {}, + ...(process.env.CI ? ['html'] : []), // custom reporter from npm package // options are passed down as a tuple [ diff --git a/guide/reporters.md b/guide/reporters.md index 34307954..e423ef3d 100644 --- a/guide/reporters.md +++ b/guide/reporters.md @@ -5,7 +5,7 @@ outline: deep # Reporters -Vitest provides several built-in reporters to display test output in different formats, as well as the ability to use custom reporters. You can select different reporters either by using the `--reporter` command line option, or by including a `reporters` property in your [configuration file](/config/reporters). If no reporter is specified, Vitest will use the `default` reporter as described below. +Vitest provides several built-in reporters to display test output in different formats, as well as the ability to use custom reporters. You can select different reporters either by using the `--reporter` command line option, or by including a `reporters` property in your [configuration file](/config/reporters). If no reporter is specified, Vitest [auto-selects reporters](#default-configuration) based on the environment. Using reporters via command line: @@ -38,6 +38,26 @@ export default defineConfig({ }) ``` +## Default Configuration + +When `reporters` is not configured, Vitest uses the following reporters: + +- [`default`](#default-reporter) in normal terminal runs +- [`minimal`](#minimal-reporter) when Vitest detects an AI coding agent +- [`github-actions`](#github-actions-reporter) is added when `process.env.GITHUB_ACTIONS === 'true'` + +If you configure your own reporters, the configured list replaces the default list. To add a reporter while keeping Vitest's defaults, extend `configDefaults.reporters`: + +```ts +import { configDefaults, defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + reporters: ['json', ...configDefaults.reporters], + }, +}) +``` + ## Reporter Output By default, Vitest's reporters will print their output to the terminal. When using the `json`, `html` or `junit` reporters, you can instead write your tests' output to a file by including an `outputFile` [configuration option](/config/outputfile) either in your Vite configuration file or via CLI. @@ -66,9 +86,11 @@ npx vitest --reporter=json --reporter=default ``` ```ts +import { configDefaults, defineConfig } from 'vitest/config' + export default defineConfig({ test: { - reporters: ['json', 'default'], + reporters: ['json', ...configDefaults.reporters], outputFile: './test-output.json' }, }) @@ -96,11 +118,7 @@ This example will write separate JSON and XML reports as well as printing a verb ### Default Reporter -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 [`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. -::: +The `default` reporter displays summary of running tests and their status at the bottom. Once a suite passes, its status will be reported on top of the summary. You can disable the summary by configuring the reporter: @@ -550,21 +568,11 @@ export default defineConfig({ ### GitHub Actions Reporter {#github-actions-reporter} Output [workflow commands](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-error-message) -to provide annotations for test failures. This reporter is automatically enabled when the `reporters` option is not configured and `process.env.GITHUB_ACTIONS === 'true'` (on GitHub Actions environment). +to provide annotations for test failures. This reporter is [enabled automatically](#default-configuration) when `process.env.GITHUB_ACTIONS === 'true'` (on GitHub Actions environment). GitHub Actions GitHub Actions -If you configure reporters, you need to explicitly add `github-actions`. - -```ts -export default defineConfig({ - test: { - reporters: process.env.GITHUB_ACTIONS === 'true' ? ['dot', 'github-actions'] : ['dot'], - }, -}) -``` - You can customize the file paths that are printed in [GitHub's annotation command format](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions) by using the `onWritePath` option. This is useful when running Vitest in a containerized environment, such as Docker, where the file paths may not match the paths in the GitHub Actions environment. ```ts @@ -662,7 +670,7 @@ export default defineConfig({ 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`: +This reporter is well optimized for AI coding assistants and LLM-based workflows to reduce token usage. It is [enabled automatically](#default-configuration) when Vitest detects it is running inside an AI coding agent. :::code-group ```bash [CLI] diff --git a/guide/ui.md b/guide/ui.md index 78030856..d6c15437 100644 --- a/guide/ui.md +++ b/guide/ui.md @@ -40,7 +40,7 @@ export default defineConfig({ You can check your coverage report in Vitest UI: see [Vitest UI Coverage](/guide/coverage#vitest-ui) for more details. ::: warning -If you still want to see how your tests are running in real time in the terminal, don't forget to add `default` reporter to `reporters` option: `['default', 'html']`. +If you still want to see how your tests are running in real time in the terminal, add `configDefaults.reporters` to the `reporters` option: `['html', ...configDefaults.reporters]`. ::: ::: tip From a623a2f04649c0cf08aaced982073b2d85df276f Mon Sep 17 00:00:00 2001 From: Vladimir Date: Tue, 28 Apr 2026 16:11:22 +0200 Subject: [PATCH 09/13] fix!: represent locator as an object instead of a string (#10212) --- api/browser/locators.md | 59 ++++++++++++++++++++++++++++++++++++++--- guide/migration.md | 22 +++++++++++++++ 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/api/browser/locators.md b/api/browser/locators.md index a4da5a8c..e4ae66f9 100644 --- a/api/browser/locators.md +++ b/api/browser/locators.md @@ -1051,19 +1051,70 @@ Internally, this method calls `.elements` and wraps every element using [`page.e - [See `locator.elements()`](#elements) +### serialize + +```ts +function serialize(): SerializedLocator +``` + +Returns a JSON-serializable representation of the locator. The returned object has two fields: + +- [`selector`](#selector): the provider-specific selector string used to query the element at runtime. +- `locator`: a human-readable description of the locator (e.g. `getByRole('button')`), used for error messages and tracing. Equivalent to calling [`asLocator()`](#aslocator). + +This is primarily intended for forwarding a locator to a [browser command](/api/browser/commands), which runs in Node and cannot receive a live `Locator` instance: + +```ts +import { commands, page } from 'vitest/browser' + +await commands.myCommand(page.getByRole('button').serialize()) +``` + +::: tip +Vitest automatically serializes any `Locator` argument passed to a command, so calling `serialize()` explicitly is rarely necessary. You can also use `JSON.stringify(locator)` (it calls [`toJSON`](#tojson) internally), which produces the same result. +::: + +### toJSON + +```ts +function toJSON(): SerializedLocator +``` + +Alias of [`serialize`](#serialize). Defined so that `JSON.stringify(locator)` and structured-clone-based transports return a `SerializedLocator` object. + +### asLocator + +```ts +function asLocator(): string +``` + +Returns a human-readable description of the locator using the JavaScript locator syntax (e.g. `getByRole('button', { name: 'Submit' })`). This is the same string exposed as the `locator` field of [`serialize()`](#serialize) and is used in error messages and traces. + +```ts +import { page } from 'vitest/browser' + +const button = page.getByRole('button', { name: 'Submit' }) +button.asLocator() // "getByRole('button', { name: 'Submit' })" +``` + +::: tip +Use [`selector`](#selector) when you need the provider-specific string to forward to a [browser command](/api/browser/commands). Use `asLocator()` only for diagnostic output. The returned string is not meant to be re-used to query elements. +::: + ## Properties ### selector -The `selector` is a string that will be used to locate the element by the browser provider. Playwright will use a `playwright` locator syntax while `preview` and `webdriverio` will use CSS. +The `selector` is a string that will be used to locate the element by the browser provider. Playwright will use a `playwright` locator syntax, and `preview` and `webdriverio` will use CSS. ::: danger You should not use this string in your test code. The `selector` string should only be used when working with the Commands API: ```ts [commands.ts] import type { BrowserCommand } from 'vitest/node' +import type { SerializedLocator } from '@vitest/browser' -const test: BrowserCommand = function test(context, selector) { +const test: BrowserCommand = function test(context, { selector }) { // playwright await context.iframe.locator(selector).click() // webdriverio @@ -1076,8 +1127,8 @@ import { test } from 'vitest' import { commands, page } from 'vitest/browser' test('works correctly', async () => { - await commands.test(page.getByText('Hello').selector) // ✅ - // vitest will automatically unwrap it to a string + await commands.test(page.getByText('Hello').serialize()) // ✅ + // vitest will automatically unwrap it to a SerializedLocator await commands.test(page.getByText('Hello')) // ✅ }) ``` diff --git a/guide/migration.md b/guide/migration.md index 788cf0ab..8d1dd57b 100644 --- a/guide/migration.md +++ b/guide/migration.md @@ -34,6 +34,28 @@ test('example', { sequential: true }, async () => { /* ... */ }) // [!code --] test('example', { concurrent: false }, async () => { /* ... */ }) // [!code ++] ``` +### Locators in Commands are Serialized as Objects + +Locators forwarded to [browser commands](/api/browser/commands) are now serialized as a `SerializedLocator` object instead of a bare selector string. The object exposes two fields: + +- `selector`: the provider-specific selector string (the same value commands previously received). +- `locator`: a human-readable representation of the locator (e.g. `getByRole('button')`), used for error messages and tracing. + +Update any custom commands that accept a locator to destructure `selector` from the new object: + +```ts +import type { SerializedLocator } from '@vitest/browser' +import type { BrowserCommandContext } from 'vitest/node' + +export async function customClick( + context: BrowserCommandContext, + selector: string, // [!code --] + { selector }: SerializedLocator, // [!code ++] +) { + await context.page.locator(selector).click() +} +``` + ## Migrating to Vitest 4.0 {#vitest-4} ::: warning Prerequisites From 56e853e8219086186dd3fff53af3a2c8a793e8cd Mon Sep 17 00:00:00 2001 From: Vladimir Date: Wed, 29 Apr 2026 07:20:43 +0200 Subject: [PATCH 10/13] fix!: remove deprecated entry points (#10222) --- api/advanced/runner.md | 2 +- guide/migration.md | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/api/advanced/runner.md b/api/advanced/runner.md index fb8dd451..fa41cbc8 100644 --- a/api/advanced/runner.md +++ b/api/advanced/runner.md @@ -142,7 +142,7 @@ If you don't have a custom runner or didn't define `runTest` method, Vitest will ::: ::: tip -Snapshot support and some other features depend on the runner. If you don't want to lose it, you can extend your runner from `VitestTestRunner` imported from `vitest/runners`. It also exposes `NodeBenchmarkRunner`, if you want to extend benchmark functionality. +Snapshot support and some other features depend on the runner. If you don't want to lose it, you can extend your runner from `TestRunner` imported from `vitest`. It also exposes `NodeBenchmarkRunner`, if you want to extend benchmark functionality. ::: ## Tasks diff --git a/guide/migration.md b/guide/migration.md index 8d1dd57b..45b19e63 100644 --- a/guide/migration.md +++ b/guide/migration.md @@ -56,6 +56,19 @@ export async function customClick( } ``` +### Removed Deprecated Entrypoints + +Several entry points were marked as deprecated in Vitest 4.1. This release removes them entirely. + +- `vitest/coverage`: use `vitest/node` instead +- `vitest/reporters`: use `vitest/node` instead +- `vitest/environments`: use `vitest/runtime` instead +- `vitest/snapshot`: use `vitest/runtime` instead +- `vitest/runners`: use `TestRunner` from `vitest` instead +- `vitest/suite`: use static methods on `TestRunner` from vitest instead (for example, `TestRunner.getCurrentTest()`) +- `vitest/mocker` is removed completely, use `@vitest/mocker` package directly (this was published by accident at one point and never removed) +- `vitest/internal/module-runner` is removed + ## Migrating to Vitest 4.0 {#vitest-4} ::: warning Prerequisites From ad185a835a130e727cdfb4ac909f05238364dc6a Mon Sep 17 00:00:00 2001 From: neumaennl Date: Wed, 29 Apr 2026 10:03:21 +0200 Subject: [PATCH 11/13] feat(junit-reporter): add jest-junit-compatible naming options (#10189) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: neumaennl <7926739+neumaennl@users.noreply.github.com> Co-authored-by: Martin Neumann Co-authored-by: Copilot --- guide/reporters.md | 63 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 5 deletions(-) diff --git a/guide/reporters.md b/guide/reporters.md index e423ef3d..4b800ec4 100644 --- a/guide/reporters.md +++ b/guide/reporters.md @@ -349,17 +349,70 @@ AssertionError: expected 5 to be 4 // Object.is equality ``` -The outputted XML contains nested `testsuites` and `testcase` tags. These can also be customized via reporter options `suiteName` and `classnameTemplate`. `classnameTemplate` can either be a template string or a function. +The output XML contains nested `testsuites` → `testsuite` → `testcase` tags. You can customize the reporter's behaviour with the following options: + +| Option | Description | Default | +|---|---|---| +| `suiteName` | `name` attribute of `` | `"vitest tests"` | +| `suiteNameTemplate` | Template for the `name` attribute of ``. Accepts a string with placeholders or a function. | Relative file path | +| `classnameTemplate` | Template for the `classname` attribute of ``. Accepts a string with placeholders or a function. | Relative file path | +| `titleTemplate` | Template for the `name` attribute of ``. Accepts a string with placeholders or a function. | Full test title with ancestor hierarchy | +| `ancestorSeparator` | Separator used when joining ancestor describe block names in the `{classname}` placeholder and in the default test title. | `" > "` | +| `addFileAttribute` | Add a `file` attribute to each ``. | `false` | +| `includeConsoleOutput` | Include `` / `` console output. | `true` | +| `stackTrace` | Include stack traces in `` elements. | `true` | + +The following placeholders are available for `suiteNameTemplate`: +- `{title}` – name of the first top-level `describe` block; falls back to the file basename when there is no top-level `describe` +- `{filename}` – relative file path from the root (e.g. `src/foo.test.ts`) +- `{filepath}` – absolute file path +- `{basename}` – file name without directory (e.g. `foo.test.ts`) +- `{displayName}` – Vitest project name + +The following placeholders are available for `classnameTemplate` and `titleTemplate`: +- `{classname}` – ancestor `describe` block names joined by `ancestorSeparator` (e.g. `outer > inner`) +- `{title}` – leaf test title (the string passed to `it`/`test`) +- `{suitename}` – top-level `describe` block name, empty string when the test has no enclosing `describe` +- `{filename}` – relative file path from the root +- `{filepath}` – absolute file path +- `{basename}` – file name without directory +- `{displayName}` – Vitest project name -The supported placeholders for the `classnameTemplate` option are: -- filename -- filepath +::: tip +`{filename}` follows Vitest's convention and resolves to the **relative path** from the project root (e.g. `src/foo.test.ts`). This differs from jest-junit where `{filename}` is the bare file name. Use `{basename}` to get only the file name. +::: + +```ts +export default defineConfig({ + test: { + reporters: [ + ['junit', { + suiteName: 'My Test Suite', + // Use the first top-level describe block name as the testsuite name + suiteNameTemplate: '{title}', + // classname = ancestor describe chain + classnameTemplate: '{classname}', + // name = leaf test title only (jest-junit-compatible) + titleTemplate: '{title}', + ancestorSeparator: ' > ', + }] + ] + }, +}) +``` + +Function-based templates receive all available variables and can return any string: ```ts export default defineConfig({ test: { reporters: [ - ['junit', { suiteName: 'custom suite name', classnameTemplate: 'filename:{filename} - filepath:{filepath}' }] + ['junit', { + classnameTemplate: ({ classname, filename }) => + classname ? `${filename}::${classname}` : filename, + titleTemplate: ({ suitename, title }) => + suitename ? `[${suitename}] ${title}` : title, + }] ] }, }) From facf19878b9f2907f12e998709b8f4d4c2da25cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Perkki=C3=B6?= Date: Sun, 3 May 2026 07:03:50 +0300 Subject: [PATCH 12/13] docs: clarify order of `before*` hooks cleanup functions (#10230) --- api/hooks.md | 8 ++++---- guide/lifecycle.md | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/api/hooks.md b/api/hooks.md index bae8eaa2..cd7d9126 100644 --- a/api/hooks.md +++ b/api/hooks.md @@ -34,7 +34,7 @@ beforeEach(async () => { Here, the `beforeEach` ensures that user is added for each test. -`beforeEach` can also return an optional cleanup function (equivalent to [`afterEach`](#aftereach)): +`beforeEach` can also return an optional cleanup function. It's similar to [`afterEach`](#aftereach). The only difference is that it's executed after all other `afterEach` hooks: ```ts import { beforeEach } from 'vitest' @@ -43,7 +43,7 @@ beforeEach(async () => { // called once before each test run await prepareSomething() - // clean up function, called once after each test run + // clean up function, called once after each test run, after afterEach hooks return async () => { await resetSomething() } @@ -102,7 +102,7 @@ beforeAll(async () => { Here the `beforeAll` ensures that the mock data is set up before tests run. -`beforeAll` can also return an optional cleanup function (equivalent to [`afterAll`](#afterall)): +`beforeAll` can also return an optional cleanup function. It's similar to [`afterAll`](#afterall). The only difference is that it's executed after all other `afterAll` hooks: ```ts import { beforeAll } from 'vitest' @@ -111,7 +111,7 @@ beforeAll(async () => { // called once before all tests run await startMocking() - // clean up function, called once after all tests run + // clean up function, called once after all tests run, after afterAll hooks return async () => { await stopMocking() } diff --git a/guide/lifecycle.md b/guide/lifecycle.md index 0cac2720..8b0fc3fa 100644 --- a/guide/lifecycle.md +++ b/guide/lifecycle.md @@ -137,10 +137,12 @@ The execution follows this order: - `beforeEach` hooks execute (in order defined, or based on [`sequence.hooks`](/config/sequence#sequence-hooks)) - Test function executes - `afterEach` hooks execute (reverse order by default with `sequence.hooks: 'stack'`) + - Cleanup functions returned from `beforeEach` hooks execute (reverse order by default with `sequence.hooks: 'stack'`) - [`onTestFinished`](/api/hooks#ontestfinished) callbacks run (always in reverse order) - If test failed: [`onTestFailed`](/api/hooks#ontestfailed) callbacks run - Note: if `repeats` or `retry` are set, all of these steps are executed again 6. **[`afterAll`](/api/hooks#afterall) hooks:** Run once after all tests in the suite complete +7. **Cleanup functions returned from `beforeAll` hooks:** Run once after all tests in the suite complete **Example execution flow:** @@ -162,6 +164,11 @@ describe('User API', () => { beforeAll(() => { // Runs once before all tests in this suite console.log('beforeAll') + + return function beforeAllCleanup() { + // Runs once afterAll hooks have run + console.log('beforeAllCleanup') + } }) aroundEach(async (runTest) => { @@ -174,6 +181,11 @@ describe('User API', () => { beforeEach(() => { // Runs before each test console.log('beforeEach') + + return function beforeEachCleanup() { + // Runs after afterEach hooks have run + console.log('beforeEachCleanup') + } }) test('creates user', () => { @@ -206,13 +218,16 @@ describe('User API', () => { // beforeEach // test 1 // afterEach +// beforeEachCleanup // aroundEach after // aroundEach before // beforeEach // test 2 // afterEach +// beforeEachCleanup // aroundEach after // afterAll +// beforeAllCleanup // aroundAll after ``` From 39eca163ce36055fed6a9a3e815a1a80f65edb61 Mon Sep 17 00:00:00 2001 From: noise Date: Mon, 4 May 2026 19:00:17 +0800 Subject: [PATCH 13/13] docs(cn): dissolve the conflict --- api/advanced/runner.md | 6 +--- api/browser/locators.md | 13 ++------- api/describe.md | 31 ++------------------- api/hooks.md | 24 +++------------- api/test.md | 38 +------------------------- config/attachmentsdir.md | 7 +---- config/browser/expect.md | 6 +--- config/coverage.md | 6 +--- config/reporters.md | 21 ++------------ guide/cli-generated.md | 8 ++---- guide/lifecycle.md | 18 +----------- guide/migration.md | 8 ++---- guide/reporters.md | 59 ++++------------------------------------ guide/ui.md | 6 +--- package.json | 2 +- 15 files changed, 29 insertions(+), 224 deletions(-) diff --git a/api/advanced/runner.md b/api/advanced/runner.md index d05f9fe7..b820da6c 100644 --- a/api/advanced/runner.md +++ b/api/advanced/runner.md @@ -145,11 +145,7 @@ export default class Runner { ::: ::: tip -<<<<<<< HEAD -快照支持和其他功能是依赖于测试运行器的。如果你想保留这些功能,可以从 `vitest/runners` 导入 `VitestTestRunner` 并将你的测试运行器继承该类。如果你想扩展基准测试功能,它还提供了 `NodeBenchmarkRunner`。 -======= -Snapshot support and some other features depend on the runner. If you don't want to lose it, you can extend your runner from `TestRunner` imported from `vitest`. It also exposes `NodeBenchmarkRunner`, if you want to extend benchmark functionality. ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc +快照支持和其他功能是依赖于测试运行器的。如果你想保留这些功能,可以从 `vitest` 导入 `TestRunner` 并将你的测试运行器继承该类。如果你想扩展基准测试功能,它还提供了 `NodeBenchmarkRunner`。 ::: ## Tasks {#tasks} diff --git a/api/browser/locators.md b/api/browser/locators.md index 70fcb2d9..6929c8ce 100644 --- a/api/browser/locators.md +++ b/api/browser/locators.md @@ -1052,7 +1052,7 @@ function all(): Locator[] 在内部,此方法调用 `.elements` 并使用 [`page.elementLocator`](/api/browser/context#page) 包装每个元素。 - [更多内容请参阅 `locator.elements()`](#elements) - + ### serialize ```ts @@ -1107,11 +1107,7 @@ Use [`selector`](#selector) when you need the provider-specific string to forwar ### selector -<<<<<<< HEAD `selector` 是一个字符串,将由浏览器提供程序用于定位元素。Playwright 将使用 `playwright` 定位器语法,而 `preview` 和 `webdriverio` 将使用 CSS。 -======= -The `selector` is a string that will be used to locate the element by the browser provider. Playwright will use a `playwright` locator syntax, and `preview` and `webdriverio` will use CSS. ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc ::: danger 你不应在测试代码中使用此字符串。`selector` 字符串仅应在使用 Commands API 时使用: @@ -1133,13 +1129,8 @@ import { test } from 'vitest' import { commands, page } from 'vitest/browser' test('works correctly', async () => { -<<<<<<< HEAD await commands.test(page.getByText('Hello').selector) // ✅ - // Vitest 会自动将其解包为字符串 -======= - await commands.test(page.getByText('Hello').serialize()) // ✅ - // vitest will automatically unwrap it to a SerializedLocator ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc + // Vitest 会自动将其解包为 SerializedLocator 对象 await commands.test(page.getByText('Hello')) // ✅ }) ``` diff --git a/api/describe.md b/api/describe.md index b910609c..6b358cec 100644 --- a/api/describe.md +++ b/api/describe.md @@ -207,10 +207,7 @@ describe.concurrent('suite', () => { test.concurrent('concurrent test 3', async () => { /* ... */ }) }) ``` - -<<<<<<< HEAD -`.skip`、`.only` 和 `.todo` 适用于并发测试套件。以下所有组合都有效: -======= + Set `concurrent` to `false` to opt out of concurrency inherited from a parent suite or [`sequence.concurrent`](/config/sequence#sequence-concurrent): ```ts @@ -224,8 +221,7 @@ describe.concurrent('suite', () => { }) ``` -`.skip`, `.only`, and `.todo` works with concurrent suites. All the following combinations are valid: ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc +`.skip`、`.only` 和 `.todo` 适用于并发测试套件。以下所有组合都有效: ```ts describe.concurrent(/* ... */) @@ -247,29 +243,6 @@ describe.concurrent('suite', () => { }) ``` -<<<<<<< HEAD -## describe.sequential - -- **别名:** `suite.sequential` - -测试套件中的 `describe.sequential` 会将所有测试标记为顺序执行。该特性适用于需要在 `describe.concurrent` 并发测试套件中按顺序运行测试,或使用 `--sequence.concurrent` 命令行选项。 - -```ts -import { describe, test } from 'vitest' - -describe.concurrent('suite', () => { - test('concurrent test 1', async () => { /* ... */ }) - test('concurrent test 2', async () => { /* ... */ }) - - describe.sequential('', () => { - test('sequential test 1', async () => { /* ... */ }) - test('sequential test 2', async () => { /* ... */ }) - }) -}) -``` - -======= ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc ## describe.shuffle - **别名:** `suite.shuffle` diff --git a/api/hooks.md b/api/hooks.md index fbf8904d..18d21bdd 100644 --- a/api/hooks.md +++ b/api/hooks.md @@ -34,12 +34,8 @@ beforeEach(async () => { ``` 此处,`beforeEach` 确保每个测试都会添加用户。 - -<<<<<<< HEAD -`beforeEach` 还可以返回一个可选的清理函数(等价于 [`afterEach`](#aftereach)): -======= + `beforeEach` can also return an optional cleanup function. It's similar to [`afterEach`](#aftereach). The only difference is that it's executed after all other `afterEach` hooks: ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc ```ts import { beforeEach } from 'vitest' @@ -48,11 +44,7 @@ beforeEach(async () => { // 在每次测试运行前调用一次 await prepareSomething() -<<<<<<< HEAD - // 清理函数,在每次测试运行后调用一次 -======= - // clean up function, called once after each test run, after afterEach hooks ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc + // 清理函数,在每次测试运行后调用一次,在 afterEach 钩子之后执行 return async () => { await resetSomething() } @@ -111,11 +103,7 @@ beforeAll(async () => { 此处,`beforeAll` 确保在测试运行前完成模拟数据的初始化。 -<<<<<<< HEAD -`beforeAll` 还可以返回一个可选的清理函数(等价于 [`afterAll`](#afterall)): -======= -`beforeAll` can also return an optional cleanup function. It's similar to [`afterAll`](#afterall). The only difference is that it's executed after all other `afterAll` hooks: ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc +`beforeAll` 还可以返回一个可选的清理函数(等价于 [`afterAll`](#afterall))。唯一区别在于该钩子会在所有其他 `afterAll` 钩子执行完毕后运行: ```ts import { beforeAll } from 'vitest' @@ -124,11 +112,7 @@ beforeAll(async () => { // 在所有测试运行之前调用一次 await startMocking() -<<<<<<< HEAD - // 清理函数,在所有测试运行之后调用一次 -======= - // clean up function, called once after all tests run, after afterAll hooks ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc + // 清理函数,在所有测试运行结束后调用一次,在所有 afterAll 钩子之后执行 return async () => { await stopMocking() } diff --git a/api/test.md b/api/test.md index f51f872b..4f7e5ded 100644 --- a/api/test.md +++ b/api/test.md @@ -216,22 +216,14 @@ describe( - **别名:** [`test.concurrent`](#test-concurrent) 是否与测试套件中其他并发测试并行运行。 - + Set `concurrent` to `false` to opt out of concurrency inherited from [`describe.concurrent`](/api/describe#describe-concurrent) or [`sequence.concurrent`](/config/sequence#sequence-concurrent): -<<<<<<< HEAD -- **类型:** `boolean` -- **默认值:** `true` -- **别名:** [`test.sequential`](#test-sequential) - -是否按顺序运行测试。如果同时指定了 `concurrent` 和 `sequential`,`concurrent` 优先生效。 -======= ```ts test('runs sequentially', { concurrent: false }, async () => { // ... }) ``` ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc ### skip @@ -461,34 +453,6 @@ test.concurrent('test 2', async ({ expect }) => { 注意,如果测试是同步的,Vitest 仍会按顺序运行它们。 -<<<<<<< HEAD -## test.sequential - -- **别名:** `it.sequential` - -`test.sequential` 将测试标记为顺序执行。适用于在 `describe.concurrent` 或 `--sequence.concurrent` 命令选项下按顺序运行测试的场景。 -```ts -import { describe, test } from 'vitest' - -// 配置项 { sequence: { concurrent: true } } 开启时 -test('concurrent test 1', async () => { /* ... */ }) -test('concurrent test 2', async () => { /* ... */ }) - -test.sequential('sequential test 1', async () => { /* ... */ }) -test.sequential('sequential test 2', async () => { /* ... */ }) - -// 在并发测试套件内 -describe.concurrent('suite', () => { - test('concurrent test 1', async () => { /* ... */ }) - test('concurrent test 2', async () => { /* ... */ }) - - test.sequential('sequential test 1', async () => { /* ... */ }) - test.sequential('sequential test 2', async () => { /* ... */ }) -}) -``` - -======= ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc ## test.todo - **别名:** `it.todo` diff --git a/config/attachmentsdir.md b/config/attachmentsdir.md index 8e799378..74c3d0ac 100644 --- a/config/attachmentsdir.md +++ b/config/attachmentsdir.md @@ -5,12 +5,7 @@ outline: deep # attachmentsDir -<<<<<<< HEAD - **类型:** `string` -- **默认值:** `'.vitest-attachments'` -======= -- **Type:** `string` -- **Default:** `'.vitest/attachments'` ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc +- **默认值:** `'.vitest/attachments'` 用于存储 [`context.annotate`](/guide/test-context#annotate) 所创建附件的目录路径(相对于项目根目录)。 diff --git a/config/browser/expect.md b/config/browser/expect.md index 7ae03143..cd3e2c05 100644 --- a/config/browser/expect.md +++ b/config/browser/expect.md @@ -104,15 +104,11 @@ export default defineConfig({ [`attachmentsDir`](/config/attachmentsdir) 配置项提供的值,如果未配置则使用其默认值。 -<<<<<<< HEAD -例如,以下示例按浏览器分组存储截图: -======= - `project: TestProject` 4.1.6 The [`TestProject`](/api/advanced/test-project) the test belongs to. -For example, to group screenshots by browser: ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc +例如,以下示例按浏览器分组存储截图: ```ts resolveScreenshotPath: ({ arg, browserName, ext, root, testFileName }) => diff --git a/config/coverage.md b/config/coverage.md index be7d328d..95795ff4 100644 --- a/config/coverage.md +++ b/config/coverage.md @@ -457,11 +457,8 @@ export default defineConfig({ - **可用的测试提供者:** `'v8' | 'istanbul'` - **命令行终端:** `--coverage.changed`, `--coverage.changed=` -<<<<<<< HEAD 仅收集自指定提交或分支以来更改的文件的代码覆盖率。设置为 `true` 时,使用已暂存和未暂存的更改。 -======= -Collect coverage only for files changed since a specified commit or branch. When set to `true`, it uses staged and unstaged changes. - + ## coverage.autoAttachSubprocess 5.0.0 {#coverage-autoattachsubprocess} - **Type:** `boolean` @@ -472,4 +469,3 @@ Collect coverage only for files changed since a specified commit or branch. When Track coverage of the `node:child_process` and `node:worker_threads` spawned during test run. Note that this option has some performance overhead as its using [`NODE_V8_COVERAGE`](https://nodejs.org/api/cli.html#node-v8-coveragedir) internally. This triggers Node to write lots of unnecessary files on file system. ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc diff --git a/config/reporters.md b/config/reporters.md index 8167eb76..74bded13 100644 --- a/config/reporters.md +++ b/config/reporters.md @@ -13,18 +13,11 @@ interface UserConfig { type ConfigReporter = string | Reporter | [string, object?] ``` - -<<<<<<< HEAD -- **默认值:** [`'default'`](/guide/reporters#default-reporter)(当 `process.env.GITHUB_ACTIONS === 'true'` 时为 [['default'](/guide/reporters#default-reporter), ['github-actions'](/guide/reporters#github-actions-reporter)]) -- **命令行终端:** - - `--reporter=tap` 用于单个报告器 - - `--reporter=verbose --reporter=github-actions` 用于多个报告器 -======= + - **Default:** [`'default'`](/guide/reporters#default-reporter). See [Default Reporters](/guide/reporters#default-reporters) for environment-specific behavior. - **CLI:** - `--reporter=tap` for a single reporter - `--reporter=verbose --reporter=github-actions` for multiple reporters ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc 此选项定义在 Vitest 测试运行期间可用的单个报告器或报告器列表。 @@ -61,19 +54,11 @@ import { configDefaults, defineConfig } from 'vitest/config' export default defineConfig({ test: { reporters: [ -<<<<<<< HEAD - 'default', + ...configDefaults.reporters, // 条件报告器 - process.env.CI ? 'github-actions' : {}, + ...(process.env.CI ? ['html'] : []), // 来自 npm 包的自定义报告器 // 选项将以元组形式向下传递 -======= - ...configDefaults.reporters, - // conditional reporter - ...(process.env.CI ? ['html'] : []), - // custom reporter from npm package - // options are passed down as a tuple ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc [ 'vitest-sonar-reporter', { outputFile: 'sonar-report.xml' } diff --git a/guide/cli-generated.md b/guide/cli-generated.md index fc54336b..045c7d1a 100644 --- a/guide/cli-generated.md +++ b/guide/cli-generated.md @@ -298,7 +298,7 @@ Coverage reporters to use. Visit [`coverage.reporter`](/config/coverage#coverage - **配置:** [coverage.htmlDir](/config/coverage#coverage-htmldir) UI 模式和 HTML 报告器中提供的 HTML 覆盖率输出目录。 - + ### coverage.autoAttachSubprocess - **CLI:** `--coverage.autoAttachSubprocess` @@ -872,11 +872,7 @@ Track coverage of the `node:child_process` and `node:worker_threads` spawned dur - **命令行终端:** `--attachmentsDir ` - **配置:** [attachmentsDir](/config/attachmentsdir) -<<<<<<< HEAD -`context.annotate` 方法所生成附件的存储目录 (默认值: `.vitest-attachments`) -======= -The directory where attachments from `context.annotate` are stored in (default: `.vitest/attachments`) ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc +`context.annotate` 方法所生成附件的存储目录 (默认值: `.vitest/attachments`) ### run diff --git a/guide/lifecycle.md b/guide/lifecycle.md index 7d7f15b2..4fa8b9ed 100644 --- a/guide/lifecycle.md +++ b/guide/lifecycle.md @@ -128,7 +128,6 @@ afterEach(() => { 执行顺序如下: -<<<<<<< HEAD 1. **文件级代码:** `describe` 块外的所有代码立即执行 2. **测试收集:** 处理 `describe` 块,导入测试文件时以副作用的形式注册测试 3. **[`aroundAll`](/api/hooks#aroundall) 钩子:** 包裹套件中的所有测试(须调用 `runSuite()`) @@ -138,27 +137,12 @@ afterEach(() => { - `beforeEach` 钩子执行(按定义顺序,或基于 [`sequence.hooks`](/config/sequence#sequence-hooks)) - 测试函数执行 - `afterEach` 钩子执行(默认以 `sequence.hooks: 'stack'` 倒序执行) + - Cleanup functions returned from `beforeEach` hooks execute (reverse order by default with `sequence.hooks: 'stack'`) - [`onTestFinished`](/api/hooks#ontestfinished) 回调执行(始终倒序) - 如果测试失败:[`onTestFailed`](/api/hooks#ontestfailed) 回调执行 - 注意:如果设置了 `repeats` 或 `retry`,上述所有步骤会再次执行 6. **[`afterAll`](/api/hooks#afterall) 钩子:** 套件中所有测试完成后执行一次 -======= -1. **File-level code:** All code outside `describe` blocks runs immediately -2. **Test collection:** `describe` blocks are processed, and tests are registered as side effects of importing the test file -3. **[`aroundAll`](/api/hooks#aroundall) hooks:** Wrap around all tests in the suite (must call `runSuite()`) -4. **[`beforeAll`](/api/hooks#beforeall) hooks:** Run once before any tests in the suite -5. **For each test:** - - [`aroundEach`](/api/hooks#aroundeach) hooks wrap around the test (must call `runTest()`) - - `beforeEach` hooks execute (in order defined, or based on [`sequence.hooks`](/config/sequence#sequence-hooks)) - - Test function executes - - `afterEach` hooks execute (reverse order by default with `sequence.hooks: 'stack'`) - - Cleanup functions returned from `beforeEach` hooks execute (reverse order by default with `sequence.hooks: 'stack'`) - - [`onTestFinished`](/api/hooks#ontestfinished) callbacks run (always in reverse order) - - If test failed: [`onTestFailed`](/api/hooks#ontestfailed) callbacks run - - Note: if `repeats` or `retry` are set, all of these steps are executed again -6. **[`afterAll`](/api/hooks#afterall) hooks:** Run once after all tests in the suite complete 7. **Cleanup functions returned from `beforeAll` hooks:** Run once after all tests in the suite complete ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc **执行流程示例:** diff --git a/guide/migration.md b/guide/migration.md index 02969ce6..f60aba89 100644 --- a/guide/migration.md +++ b/guide/migration.md @@ -6,10 +6,7 @@ outline: deep # 迁移指南 {#migration-guide} [迁移至 Vitest 3.0](https://v3.vitest.dev/guide/migration) | [迁移至 Vitest 2.0](https://v2.vitest.dev/guide/migration) - -<<<<<<< HEAD -## 迁移至 Vitest 4.0 {#vitest-4} -======= + ## Migrating to Vitest 5.0 {#vitest-5} ::: warning Work in progress @@ -72,8 +69,7 @@ Several entry points were marked as deprecated in Vitest 4.1. This release remov - `vitest/mocker` is removed completely, use `@vitest/mocker` package directly (this was published by accident at one point and never removed) - `vitest/internal/module-runner` is removed -## Migrating to Vitest 4.0 {#vitest-4} ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc +## 迁移至 Vitest 4.0 {#vitest-4} ::: warning 前提条件 Vitest 4.0 要求 **Vite >= 6.0.0** 和 **Node.js >= 20.0.0**。 diff --git a/guide/reporters.md b/guide/reporters.md index 3deddafc..0ab66a9c 100644 --- a/guide/reporters.md +++ b/guide/reporters.md @@ -5,11 +5,7 @@ outline: deep # 报告器 {#reporters} -<<<<<<< HEAD -Vitest 提供了几种内置报告器,以不同格式显示测试输出,以及使用自定义报告器的能力。你可以使用 `--reporter` 命令行选项,或者在你的 `outputFile` [配置选项](/config/reporters) 中加入 `reporters` 属性来选择不同的报告器。如果没有指定报告器,Vitest 将使用下文所述的默认报告器。 -======= -Vitest provides several built-in reporters to display test output in different formats, as well as the ability to use custom reporters. You can select different reporters either by using the `--reporter` command line option, or by including a `reporters` property in your [configuration file](/config/reporters). If no reporter is specified, Vitest [auto-selects reporters](#default-configuration) based on the environment. ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc +Vitest 提供了几种内置报告器,以不同格式显示测试输出,以及使用自定义报告器的能力。你可以使用 `--reporter` 命令行选项,或者在你的 `outputFile` [配置选项](/config/reporters) 中加入 `reporters` 属性来选择不同的报告器。如果未指定报告器,Vitest 将根据运行环境 [自动选择报告器](#default-configuration)。 通过命令行使用报告器: @@ -38,10 +34,7 @@ export default defineConfig({ }, }) ``` - -<<<<<<< HEAD -## 报告器输出 {#reporter-output} -======= + ## Default Configuration When `reporters` is not configured, Vitest uses the following reporters: @@ -62,8 +55,7 @@ export default defineConfig({ }) ``` -## Reporter Output ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc +## 报告器输出 {#reporter-output} 默认情况下,Vitest 的报告器会将输出打印到终端。当使用 `json` 、`html` 或 `junit` 报告器时,你可以在 Vite 配置文件中或通过 CLI 加入 `outputFile` [配置选项](/config/outputfile),将测试输出写入文件。 @@ -99,13 +91,8 @@ import { configDefaults, defineConfig } from 'vitest/config' export default defineConfig({ test: { -<<<<<<< HEAD - reporters: ['json', 'default'], - outputFile: './test-output.json', -======= reporters: ['json', ...configDefaults.reporters], outputFile: './test-output.json' ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc }, }) ``` @@ -131,16 +118,8 @@ export default defineConfig({ ## 内置报告器 {#built-in-reporters} ### 默认报告器 {#default-reporter} - -<<<<<<< HEAD -默认情况下(即如果没有指定报告器),Vitest 会在底部显示运行测试的摘要及其状态。一旦测试套件通过,其状态将被报告在摘要的顶部。 - -::: tip -当 Vitest 检测到运行在 AI 智能体编程环境中时,将自动启用 [`minimal`](#minimal-reporter) 报告器以精简输出内容并优化词元 (token) 消耗。你可以通过显式配置 [`reporters`](/config/reporters) 选项来覆盖此行为。 -::: -======= + The `default` reporter displays summary of running tests and their status at the bottom. Once a suite passes, its status will be reported on top of the summary. ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc 我们可以通过配置报告器来禁用摘要: @@ -377,14 +356,7 @@ AssertionError: expected 5 to be 4 // Object.is equality ``` - -<<<<<<< HEAD -输出的 XML 包含嵌套的 `testsuites` 和 `testcase` 标签。这些也可以通过报告选项 `suiteName` 和 `classnameTemplate` 进行自定义。`classnameTemplate` 可以是一个模板字符串或者一个函数。 - -`classnameTemplate` 选项支持的占位符有: -- filename -- filepath -======= + The output XML contains nested `testsuites` → `testsuite` → `testcase` tags. You can customize the reporter's behaviour with the following options: | Option | Description | Default | @@ -417,7 +389,6 @@ The following placeholders are available for `classnameTemplate` and `titleTempl ::: tip `{filename}` follows Vitest's convention and resolves to the **relative path** from the project root (e.g. `src/foo.test.ts`). This differs from jest-junit where `{filename}` is the bare file name. Use `{basename}` to get only the file name. ::: ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc ```ts export default defineConfig({ @@ -664,32 +635,14 @@ export default defineConfig({ ::: ### GitHub Actions 报告器 {#github-actions-reporter} - -<<<<<<< HEAD -当测试失败时输出 [工作流命令](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-error-message) 提供注解。当未配置 `reporters` 选项且 `process.env.GITHUB_ACTIONS === 'true'`(在GitHub Actions环境中)时,此报告器会自动启用。 -======= + Output [workflow commands](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-error-message) to provide annotations for test failures. This reporter is [enabled automatically](#default-configuration) when `process.env.GITHUB_ACTIONS === 'true'` (on GitHub Actions environment). ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc GitHub Actions GitHub Actions -<<<<<<< HEAD -如果已配置报告器,需显式添加 `github-actions` 添加到报告器列表中。 - -```ts -export default defineConfig({ - test: { - reporters: process.env.GITHUB_ACTIONS === 'true' ? ['dot', 'github-actions'] : ['dot'], - }, -}) -``` - -你可以使用 `onWritePath` 选项自定义以 [GitHub 注解命令格式](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions) 打印的文件路径。这在容器化环境(如 Docker)中运行 Vitest 时非常有用,因为在这些环境中文件路径可能与 GitHub Actions 环境中的路径不匹配。 -======= You can customize the file paths that are printed in [GitHub's annotation command format](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions) by using the `onWritePath` option. This is useful when running Vitest in a containerized environment, such as Docker, where the file paths may not match the paths in the GitHub Actions environment. ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc ```ts export default defineConfig({ diff --git a/guide/ui.md b/guide/ui.md index 238fe025..4813ac49 100644 --- a/guide/ui.md +++ b/guide/ui.md @@ -38,13 +38,9 @@ export default defineConfig({ ``` 你可以在 Vitest UI 中查看覆盖率报告:查看 [覆盖率 | UI 模式](/guide/coverage#vitest-ui) 了解更多详情。 - + ::: warning -<<<<<<< HEAD -如果你仍想在终端中实时查看测试的运行情况,请不要忘记将 `default` 报告器添加到 `reporters` 选项:`['default', 'html']`。 -======= If you still want to see how your tests are running in real time in the terminal, add `configDefaults.reporters` to the `reporters` option: `['html', ...configDefaults.reporters]`. ->>>>>>> facf19878b9f2907f12e998709b8f4d4c2da25cc ::: ::: tip diff --git a/package.json b/package.json index 5132bc6a..315994b5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "docs-cn", "type": "module", - "version": "4.1.4", + "version": "5.0.0-beta.1", "private": true, "packageManager": "pnpm@9.7.1", "scripts": {