diff --git a/.vitepress/components/FeaturesList.vue b/.vitepress/components/FeaturesList.vue
index dd43d850..fa581170 100644
--- a/.vitepress/components/FeaturesList.vue
+++ b/.vitepress/components/FeaturesList.vue
@@ -21,7 +21,7 @@
支持基准测试
支持套件和测试的过滤、超时、并发配置
- 支持 Projects / Workspace
+ 支持 Projects
Jest 快照功能
@@ -37,8 +37,8 @@
使用
- jsdom 或
- happy-dom
+ happy-dom 或
+ jsdom
模拟 DOM
浏览器模式:在浏览器中运行组件测试
diff --git a/.vitepress/config.ts b/.vitepress/config.ts
index f5e1e610..53d31cd2 100644
--- a/.vitepress/config.ts
+++ b/.vitepress/config.ts
@@ -296,7 +296,7 @@ export default ({ mode }: { mode: string }) => {
collapsed: false,
items: [
{
- text: '浏览器模式配置',
+ text: '浏览器配置',
link: '/guide/browser/config',
docFooterText: '浏览器模式配置 | 浏览器模式',
},
@@ -310,11 +310,6 @@ export default ({ mode }: { mode: string }) => {
link: '/guide/browser/webdriverio',
docFooterText: '配置 WebdriverIO | 浏览器模式',
},
- {
- text: 'Configuring Preview',
- link: '/guide/browser/preview',
- docFooterText: 'Configuring Preview | 浏览器模式',
- },
],
},
{
@@ -353,24 +348,9 @@ export default ({ mode }: { mode: string }) => {
collapsed: false,
items: [
{
- text: '多种设置',
+ text: '多环境配置',
link: '/guide/browser/multiple-setups',
- docFooterText: '多种设置 | 浏览器模式',
- },
- {
- text: '组件测试',
- link: '/guide/browser/component-testing',
- docFooterText: '组件测试 | 浏览器模式',
- },
- {
- text: '可视化回归测试',
- link: '/guide/browser/visual-regression-testing',
- docFooterText: '可视化回归测试 | 浏览器模式',
- },
- {
- text: '跟踪查看器',
- link: '/guide/browser/trace-view',
- docFooterText: '跟踪查看器 | 浏览器模式',
+ docFooterText: '多环境配置 | 浏览器模式',
},
],
},
@@ -567,54 +547,19 @@ function guide(): DefaultTheme.SidebarItem[] {
link: '/guide/reporters',
},
{
- text: '测试覆盖率',
+ text: '覆盖率',
link: '/guide/coverage',
},
{
- text: '测试快照',
+ text: '快照',
link: '/guide/snapshot',
},
{
- text: '模拟对象',
+ text: '模拟',
link: '/guide/mocking',
- collapsed: true,
- items: [
- {
- text: '模拟日期',
- link: '/guide/mocking/dates',
- },
- {
- text: '模拟函数',
- link: '/guide/mocking/functions',
- },
- {
- text: '模拟全局对象',
- link: '/guide/mocking/globals',
- },
- {
- text: '模拟模块',
- link: '/guide/mocking/modules',
- },
- {
- text: '模拟文件系统',
- link: '/guide/mocking/file-system',
- },
- {
- text: '模拟请求',
- link: '/guide/mocking/requests',
- },
- {
- text: '模拟计时器',
- link: '/guide/mocking/timers',
- },
- {
- text: '模拟类',
- link: '/guide/mocking/classes',
- },
- ],
},
{
- text: '并行执行',
+ text: '并行性',
link: '/guide/parallelism',
},
{
@@ -622,7 +567,7 @@ function guide(): DefaultTheme.SidebarItem[] {
link: '/guide/testing-types',
},
{
- text: 'UI模式',
+ text: 'UI 模式',
link: '/guide/ui',
},
{
@@ -633,6 +578,10 @@ function guide(): DefaultTheme.SidebarItem[] {
text: '测试上下文',
link: '/guide/test-context',
},
+ {
+ text: '测试注释',
+ link: '/guide/test-annotations',
+ },
{
text: '测试环境',
link: '/guide/environment',
@@ -659,8 +608,8 @@ function guide(): DefaultTheme.SidebarItem[] {
collapsed: false,
items: [
{
- text: '迁移到 Vitest 4.0',
- link: '/guide/migration#vitest-4',
+ text: '迁移到 Vitest 3.0',
+ link: '/guide/migration#vitest-3',
},
{
text: '从 Jest 迁移',
@@ -692,7 +641,7 @@ function api(): DefaultTheme.SidebarItem[] {
link: '/api/',
},
{
- text: 'Mocks',
+ text: 'Mock Functions',
link: '/api/mock',
},
{
diff --git a/.vitepress/scripts/cli-generator.ts b/.vitepress/scripts/cli-generator.ts
index bea3ade8..642b9aba 100644
--- a/.vitepress/scripts/cli-generator.ts
+++ b/.vitepress/scripts/cli-generator.ts
@@ -77,7 +77,7 @@ const template = options.map((option) => {
const title = option.title
const cli = option.cli
const config = skipConfig.has(title) ? '' : `[${title}](${title.includes('browser.') ? '/guide/browser/config' : '/config/'}#${title.toLowerCase().replace(/\./g, '-')})`
- return `### ${title}\n\n- **CLI:** ${cli}\n${config ? `- **Config:** ${config}\n` : ''}\n${option.description}\n`
+ return `### ${title}\n\n- **命令行终端:** ${cli}\n${config ? `- **配置:** ${config}\n` : ''}\n${option.description}\n`
}).join('\n')
writeFileSync(cliTablePath, template, 'utf-8')
diff --git a/advanced/api.md b/advanced/api.md
deleted file mode 100644
index 40abb3b4..00000000
--- a/advanced/api.md
+++ /dev/null
@@ -1,351 +0,0 @@
----
-outline: [2, 3]
----
-
-# Node API
-
-::: warning
-Vitest 暴露了实验性的私有 API。由于可能不遵循语义化版本规范(SemVer),因此可能会出现不兼容的更改,请在使用 Vitest 时锁定版本。
-:::
-
-## 启动 Vitest
-
-你可以使用 Vitest 的 Node API 开始运行 Vitest 测试:
-
-```js
-import { startVitest } from 'vitest/node'
-
-const vitest = await startVitest('test')
-
-await vitest?.close()
-```
-
-如果测试可以启动,则 `startVitest` 函数返回 `Vitest` 实例。 如果出现以下情况之一,则返回 `undefined`:
-
-- Vitest 未找到 `vite` 包 (通常与 Vitest 一起安装)
-- 如果启用了 `coverage`,并且运行模式为 "test",但并未安装 "coverage" 包(`@vitest/coverage-v8` 或 `@vitest/coverage-istanbul`)
-- 如果未安装环境包 (`jsdom`/`happy-dom`/`@edge-runtime/vm`)
-
-如果在运行期间返回 `undefined` 或者测试失败, Vitest 会将 `process.exitCode` 设置为 `1`。
-
-如果未启用监视模式,Vitest 将会调用 `close` 方法。
-
-如果启用了监视模式并且终端支持 TTY, 则 Vitest 会注册控制台快捷键。
-
-你可以将过滤器列表作为第二个参数传递下去。Vitest 将仅运行包含其文件路径中至少一个传递字符串的测试。
-
-此外,你可以使用第三个参数传递 CLI 参数,这将覆盖任何测试配置选项。
-
-或者,你可以将完整的 Vite 配置作为第四个参数传递进去,这将优先于任何其他用户定义的选项。
-
-运行测试后,您可以从 `state.getFiles` API 获取结果:
-
-```ts
-const vitest = await startVitest('test')
-
-console.log(vitest.state.getFiles()) // [{ type: 'file', ... }]
-```
-
-自 Vitest 2.1 起,建议使用["Reported Tasks" API](/advanced/reporters#reported-tasks) 和 `state.getFiles`。今后,Vitest 将直接返回这些对象:
-
-```ts
-const vitest = await startVitest('test')
-
-const [fileTask] = vitest.state.getFiles()
-const testFile = vitest.state.getReportedEntity(fileTask)
-```
-
-## 创建 Vitest
-
-你可以使用 `createVitest` 函数创建自己的 Vitest 实例. 它返回与 `startVitest` 相同的 `Vitest` 实例, 但不会启动测试,也不会验证已安装的包。
-
-```js
-import { createVitest } from 'vitest/node'
-
-const vitest = await createVitest('test', {
- watch: false,
-})
-```
-
-## parseCLI
-
-你可以使用此方法来解析 CLI 参数。它接受字符串(其中参数由单个空格分隔)或与 Vitest CLI 使用的格式相同的 CLI 参数的字符串数组。它返回一个过滤器和`选项`,你可以稍后将其传递给 `createVitest` 或 `startVitest` 方法。
-
-```ts
-import { parseCLI } from 'vitest/node'
-
-parseCLI('vitest ./files.ts --coverage --browser=chrome')
-```
-
-## Vitest
-
-Vitest 实例需要当前的测试模式。它可以是以下之一:
-
-- 运行运行时测试时为 `test`
-- 运行基准测试时为 `benchmark`
-- 运行类型测试时为 `typecheck`
-
-### 模式
-
-#### test
-
-测试模式仅会调用 `test` 或 `it` 中的函数,并在遇到 `bench` 时抛出错误。此模式使用配置中的 `include` 和 `exclude` 选项查找测试文件。
-
-#### benchmark
-
-基准测试模式会调用 `bench` 函数,并在遇到 `test` 或 `it` 时抛出错误。此模式使用配置中的 `benchmark.include` 和 `benchmark.exclude` 选项查找基准测试文件。
-
-#### typecheck
-
-类型检查模式不会*运行*测试。它仅分析类型并提供摘要信息。此模式使用配置中的 `typecheck.include` 和 `typecheck.exclude` 选项查找要分析的文件。
-
-### start
-
-你可以使用 `start` 方法运行测试或者基准测试。你还可以传递一个字符串数组以筛选测试文件。
-
-### `provide`
-
-Vitest 提供了 `provide` 方法,它是 `vitest.getRootTestProject().provide` 的简写形式。通过这个方法,你可以将值从主线程传递到测试中。所有值在存储之前都会通过 `structuredClone` 进行检查,但值本身不会被克隆。
-
-要在测试中接收值,需要从 `vitest` entrypont 导入 `inject` 方法:
-
-```ts
-import { inject } from 'vitest'
-const port = inject('wsPort') // 3000
-```
-
-为了提高类型安全性,我们鼓励您增强 `ProvidedContext` 的类型:
-
-```ts
-import { createVitest } from 'vitest/node'
-
-const vitest = await createVitest('test', {
- watch: false,
-})
-vitest.provide('wsPort', 3000)
-
-declare module 'vitest' {
- export interface ProvidedContext {
- wsPort: number
- }
-}
-```
-
-::: warning
-在技术上来说,`provide` 是 [`TestProject`](#testproject) 的一个方法,因此它受限于特定的项目。然而,所有项目都从核心项目继承了值,这使得 `vitest.provide` 成为了一种普遍的方式来向测试传递值。
-:::
-
-::: tip
-该方法同样适用于[全局配置文件](/config/#globalsetup),在无法使用公共API的情况下。
-
-```js
-export default function setup({ provide }) {
- provide('wsPort', 3000)
-}
-```
-:::
-
-## TestProject 3.0.0 {#testproject}
-
-- **别名**: `WorkspaceProject` before 3.0.0
-
-### name
-
-这个 name 是由用户指定的唯一字符串,或由 Vitest 解释得出。如果用户未提供名称,Vitest 会尝试在项目根目录加载 `package.json` 文件,并从中获取 `name` 属性作为 name 。若项目中不存在 `package.json` 文件,则 Vitest 默认使用文件夹的名字。对于内联项目,Vitest 使用数字(转换为字符串)作为 name 。
-
-::: code-group
-```ts [node.js]
-import { createVitest } from 'vitest/node'
-
-const vitest = await createVitest('test')
-vitest.projects.map(p => p.name) === [
- '@pkg/server',
- 'utils',
- '2',
- 'custom'
-]
-```
-```ts [vitest.workspace.js]
-export default [
- './packages/server', // package.json 中包含 "@pkg/server"
- './utils', // 没有 package.json 文件
- {
- // 不要自定义名称
- test: {
- pool: 'threads',
- },
- },
- {
- // 自定义名称
- test: {
- name: 'custom',
- },
- },
-]
-```
-:::
-
-### vitest
-
-`vitest` 是指全局的 [`vitest`](#vitest) 进程。
-
-### serializedConfig
-
-所有测试都会接收到的测试配置。Vitest 手动[序列化配置](https://github.com/vitest-dev/vitest/blob/main/packages/vitest/src/node/config/serializeConfig.ts),通过移除所有无法序列化的函数和属性来实现。由于这个值在测试和 Node 环境中都可用,因此它从主入口点导出。
-
-```ts
-import type { SerializedConfig } from 'vitest'
-
-const config: SerializedConfig = vitest.projects[0].serializedConfig
-```
-
-### globalConfig
-
-`vitest` 初始化时所使用的测试配置。如果这是根项目,`globalConfig` 和 `config` 将引用同一个对象。这个配置对于不能在项目级别设置的值非常有用,比如 `coverage` 或 `reporters`。
-
-```ts
-import type { ResolvedConfig } from 'vitest/node'
-
-vitest.config === vitest.projects[0].globalConfig
-```
-
-### config
-
-这是项目的解析后的测试配置。
-
-### vite
-
-这是项目的 `ViteDevServer`。每个项目都有自己的 Vite 服务器。
-
-### browser
-
-此值仅在测试运行于浏览器中时才会被设置。如果启用了 `browser`,但测试尚未运行,这将为 `undefined`。如果您需要检查项目是否支持浏览器测试,请使用 `project.isBrowserSupported()` 方法。
-
-::: warning
-这个浏览器API尚在实验阶段,并不遵循语义化(SemVer)版本控制。浏览器API将会独立于其他API进行标准化。
-:::
-
-### provide
-
-这是一种在 [`config.provide`](/config/#provide) 字段之外向测试提供自定义值的方法。所有值在存储之前都会通过 [`structuredClone`](https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone) 进行验证,但 `providedContext` 中的值本身不会被克隆。
-
-::: code-group
-```ts [node.js]
-import { createVitest } from 'vitest/node'
-
-const vitest = await createVitest('test')
-const project = vitest.projects.find(p => p.name === 'custom')
-project.provide('key', 'value')
-await vitest.start()
-```
-```ts [test.spec.js]
-import { inject } from 'vitest'
-const value = inject('key')
-```
-:::
-
-这些值可以动态提供。在测试中提供的值将在下一次运行时更新。
-
-### getProvidedContext
-
-这将返回上下文对象。每个项目也会继承由 `vitest.provide` 设置的全局上下文。
-
-```ts
-import { createVitest } from 'vitest/node'
-
-const vitest = await createVitest('test')
-vitest.provide('global', true)
-const project = vitest.projects.find(p => p.name === 'custom')
-project.provide('key', 'value')
-
-// { global: true, key: 'value' }
-const context = project.getProvidedContext()
-```
-
-::: tip
-项目上下文的值总是会覆盖全局的值。
-:::
-
-### createSpecification
-
-创建一个测试规范,该规范可用于 `vitest.runFiles`。规范将测试文件限定在特定的 `project` 和(可选的)`pool` 中。
-
-```ts
-import { resolve } from 'node:path/posix'
-import { createVitest } from 'vitest/node'
-
-const vitest = await createVitest('test')
-const project = vitest.projects[0]
-const specification = project.createSpecification(
- resolve('./basic.test.ts'),
- 'threads', // 可选覆盖
-)
-await vitest.runFiles([specification], true)
-```
-
-::: warning
-`createSpecification` 需要一个绝对文件路径。但是它不会解析文件或检查文件系统上是否存在该文件。
-:::
-
-### isRootProject
-
-检查当前项目是否为根项目。我们也可以尝试调用 `vitest.getRootTestProject()` 来获取根项目。
-
-根项目通常不运行任何测试,并且不包含在 `vitest.projects` 中,除非我们明确地将根配置包含在它们的工作空间中。
-
-根项目的主要目标是设置全局配置。实际上,`rootProject.config` 直接引用了 `rootProject.globalConfig` 和 `vitest.config`。
-
-### globTestFiles
-
-匹配所有测试文件。这个函数返回一个包含常规测试和类型检查测试的对象:
-
-```ts
-interface GlobReturn {
- /**
- * 测试符合筛选条件的文件。
- */
- testFiles: string[]
- /**
- * 与筛选器匹配的类型检查测试文件。除非 `typecheck.enabled` 为 `true`,否则将为空。
- */
- typecheckTestFiles: string[]
-}
-```
-
-::: tip
-Vitest 使用 [fast-glob](https://www.npmjs.com/package/fast-glob) 来查找测试文件。`test.dir`、`test.root`、`root` 或 `process.cwd()` 定义了 `cwd` 选项。
-
-这个方法会查看几个配置选项:
-
-- `test.include`、`test.exclude` 用于查找常规测试文件;
-- `test.includeSource`、`test.exclude` 用于查找源代码中的测试;
-- `test.typecheck.include`、`test.typecheck.exclude` 用于查找类型检查测试。
-:::
-
-### matchesTestGlob
-
-此方法用于检查文件是否为常规测试文件。它使用与 `globTestFiles` 相同的配置属性进行验证。
-
-此方法还接受第二个参数,即源代码。这用于验证文件是否为源代码中的测试。如果我们需要多次为多个项目调用此方法,建议先读取文件一次,然后直接传递源代码。
-
-```ts
-import { resolve } from 'node:path/posix'
-import { createVitest } from 'vitest/node'
-
-const vitest = await createVitest('test')
-const project = vitest.projects[0]
-
-project.matchesTestGlob(resolve('./basic.test.ts')) // true
-project.matchesTestGlob(resolve('./basic.ts')) // false
-project.matchesTestGlob(resolve('./basic.ts'), `
-if (import.meta.vitest) {
- // ...
-}
-`) // 如果设置了 `includeSource` 则为 true
-```
-
-### close
-
-关闭项目及其所有相关资源。此操作只能调用一次;关闭的承诺会被缓存,直到服务器重新启动。如果再次需要资源,请创建一个新项目。
-
-具体来说,这个方法会关闭 Vite 服务器,停止类型检查服务,如果浏览器正在运行则关闭它,删除存放源代码的临时目录,并重置提供的上下文。
diff --git a/api/assert-type.md b/api/assert-type.md
index 973b9f6c..e4f9364c 100644
--- a/api/assert-type.md
+++ b/api/assert-type.md
@@ -1,13 +1,13 @@
# assertType
-- **类型:** `(value: T): void`
-
-你可以使用此函数作为 [`expectTypeOf`](/api/expect-typeof) 的替代方法,以轻松地断言参数类型等于提供的泛型。
-
::: warning
在运行时,此函数不执行任何操作。要 [启用类型检查](/guide/testing-types#run-typechecking),不要忘记传递 `--typecheck` 标志。
:::
+- **类型:** `(value: T): void`
+
+你可以使用此函数作为 [`expectTypeOf`](/api/expect-typeof) 的替代方法,以轻松地断言参数类型等于提供的泛型。
+
```ts
import { assertType } from 'vitest'
diff --git a/api/assert.md b/api/assert.md
index 78fcd770..8f484404 100644
--- a/api/assert.md
+++ b/api/assert.md
@@ -724,11 +724,7 @@ import { assert, test } from 'vitest'
test('assert.notInclude', () => {
assert.notInclude([1, 2, 3], 4, 'array doesn\'t contain 4')
assert.notInclude('foobar', 'baz', 'foobar doesn\'t contain baz')
- assert.notInclude(
- { foo: 'bar', hello: 'universe' },
- { foo: 'baz' },
- 'object doesn\'t contain property'
- )
+ assert.notInclude({ foo: 'bar', hello: 'universe' }, { foo: 'baz' }, 'object doesn\'t contain property')
})
```
@@ -1079,16 +1075,8 @@ test('assert.nestedPropertyVal', () => {
import { assert, test } from 'vitest'
test('assert.notNestedPropertyVal', () => {
- assert.notNestedPropertyVal(
- { tea: { green: 'matcha' } },
- 'tea.green',
- 'konacha'
- )
- assert.notNestedPropertyVal(
- { tea: { green: 'matcha' } },
- 'coffee.green',
- 'matcha'
- )
+ assert.notNestedPropertyVal({ tea: { green: 'matcha' } }, 'tea.green', 'konacha')
+ assert.notNestedPropertyVal({ tea: { green: 'matcha' } }, 'coffee.green', 'matcha')
})
```
@@ -1102,16 +1090,8 @@ test('assert.notNestedPropertyVal', () => {
import { assert, test } from 'vitest'
test('assert.notNestedPropertyVal', () => {
- assert.notNestedPropertyVal(
- { tea: { green: 'matcha' } },
- 'tea.green',
- 'konacha'
- )
- assert.notNestedPropertyVal(
- { tea: { green: 'matcha' } },
- 'coffee.green',
- 'matcha'
- )
+ assert.notNestedPropertyVal({ tea: { green: 'matcha' } }, 'tea.green', 'konacha')
+ assert.notNestedPropertyVal({ tea: { green: 'matcha' } }, 'coffee.green', 'matcha')
})
```
@@ -1125,21 +1105,9 @@ test('assert.notNestedPropertyVal', () => {
import { assert, test } from 'vitest'
test('assert.notDeepNestedPropertyVal', () => {
- assert.notDeepNestedPropertyVal(
- { tea: { green: { matcha: 'yum' } } },
- 'tea.green',
- { oolong: 'yum' }
- )
- assert.notDeepNestedPropertyVal(
- { tea: { green: { matcha: 'yum' } } },
- 'tea.green',
- { matcha: 'yuck' }
- )
- assert.notDeepNestedPropertyVal(
- { tea: { green: { matcha: 'yum' } } },
- 'tea.black',
- { matcha: 'yum' }
- )
+ assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { oolong: 'yum' })
+ assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { matcha: 'yuck' })
+ assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.black', { matcha: 'yum' })
})
```
@@ -1156,15 +1124,7 @@ test('assert.lengthOf', () => {
assert.lengthOf([1, 2, 3], 3, 'array has length of 3')
assert.lengthOf('foobar', 6, 'string has length of 6')
assert.lengthOf(new Set([1, 2, 3]), 3, 'set has size of 3')
- assert.lengthOf(
- new Map([
- ['a', 1],
- ['b', 2],
- ['c', 3],
- ]),
- 3,
- 'map has size of 3'
- )
+ assert.lengthOf(new Map([['a', 1], ['b', 2], ['c', 3]]), 3, 'map has size of 3')
})
```
@@ -1179,21 +1139,9 @@ import { assert, test } from 'vitest'
test('assert.hasAnyKeys', () => {
assert.hasAnyKeys({ foo: 1, bar: 2, baz: 3 }, ['foo', 'iDontExist', 'baz'])
- assert.hasAnyKeys(
- { foo: 1, bar: 2, baz: 3 },
- { foo: 30, iDontExist: 99, baz: 1337 }
- )
- assert.hasAnyKeys(
- new Map([
- [{ foo: 1 }, 'bar'],
- ['key', 'value'],
- ]),
- [{ foo: 1 }, 'key']
- )
- assert.hasAnyKeys(new Set([{ foo: 'bar' }, 'anotherKey']), [
- { foo: 'bar' },
- 'anotherKey',
- ])
+ assert.hasAnyKeys({ foo: 1, bar: 2, baz: 3 }, { foo: 30, iDontExist: 99, baz: 1337 })
+ assert.hasAnyKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value'],]), [{ foo: 1 }, 'key'])
+ assert.hasAnyKeys(new Set([{ foo: 'bar' }, 'anotherKey']), [{ foo: 'bar' }, 'anotherKey'])
})
```
@@ -1208,20 +1156,9 @@ import { assert, test } from 'vitest'
test('assert.hasAllKeys', () => {
assert.hasAllKeys({ foo: 1, bar: 2, baz: 3 }, ['foo', 'bar', 'baz'])
- assert.hasAllKeys(
- { foo: 1, bar: 2, baz: 3 },
- { foo: 30, bar: 99, baz: 1337 }
- )
- assert.hasAllKeys(
- new Map([
- [{ foo: 1 }, 'bar'],
- ['key', 'value'],
- ]),
- [{ foo: 1 }, 'key']
- )
- assert.hasAllKeys(
- new Set([{ foo: 'bar' }, 'anotherKey'], [{ foo: 'bar' }, 'anotherKey'])
- )
+ assert.hasAllKeys({ foo: 1, bar: 2, baz: 3 }, { foo: 30, bar: 99, baz: 1337 })
+ assert.hasAllKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value'],]), [{ foo: 1 }, 'key'])
+ assert.hasAllKeys(new Set([{ foo: 'bar' }, 'anotherKey'], [{ foo: 'bar' }, 'anotherKey']))
})
```
@@ -1238,30 +1175,11 @@ test('assert.containsAllKeys', () => {
assert.containsAllKeys({ foo: 1, bar: 2, baz: 3 }, ['foo', 'baz'])
assert.containsAllKeys({ foo: 1, bar: 2, baz: 3 }, ['foo', 'bar', 'baz'])
assert.containsAllKeys({ foo: 1, bar: 2, baz: 3 }, { foo: 30, baz: 1337 })
- assert.containsAllKeys(
- { foo: 1, bar: 2, baz: 3 },
- { foo: 30, bar: 99, baz: 1337 }
- )
- assert.containsAllKeys(
- new Map([
- [{ foo: 1 }, 'bar'],
- ['key', 'value'],
- ]),
- [{ foo: 1 }]
- )
- assert.containsAllKeys(
- new Map([
- [{ foo: 1 }, 'bar'],
- ['key', 'value'],
- ]),
- [{ foo: 1 }, 'key']
- )
- assert.containsAllKeys(
- new Set([{ foo: 'bar' }, 'anotherKey'], [{ foo: 'bar' }])
- )
- assert.containsAllKeys(
- new Set([{ foo: 'bar' }, 'anotherKey'], [{ foo: 'bar' }, 'anotherKey'])
- )
+ assert.containsAllKeys({ foo: 1, bar: 2, baz: 3 }, { foo: 30, bar: 99, baz: 1337 })
+ assert.containsAllKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value'],]), [{ foo: 1 }])
+ assert.containsAllKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value'],]), [{ foo: 1 }, 'key'])
+ assert.containsAllKeys(new Set([{ foo: 'bar' }, 'anotherKey'], [{ foo: 'bar' }]))
+ assert.containsAllKeys(new Set([{ foo: 'bar' }, 'anotherKey'], [{ foo: 'bar' }, 'anotherKey']))
})
```
@@ -1275,25 +1193,10 @@ test('assert.containsAllKeys', () => {
import { assert, test } from 'vitest'
test('assert.doesNotHaveAnyKeys', () => {
- assert.doesNotHaveAnyKeys({ foo: 1, bar: 2, baz: 3 }, [
- 'one',
- 'two',
- 'example',
- ])
- assert.doesNotHaveAnyKeys(
- { foo: 1, bar: 2, baz: 3 },
- { one: 1, two: 2, example: 'foo' }
- )
- assert.doesNotHaveAnyKeys(
- new Map([
- [{ foo: 1 }, 'bar'],
- ['key', 'value'],
- ]),
- [{ one: 'two' }, 'example']
- )
- assert.doesNotHaveAnyKeys(
- new Set([{ foo: 'bar' }, 'anotherKey'], [{ one: 'two' }, 'example'])
- )
+ assert.doesNotHaveAnyKeys({ foo: 1, bar: 2, baz: 3 }, ['one', 'two', 'example',])
+ assert.doesNotHaveAnyKeys({ foo: 1, bar: 2, baz: 3 }, { one: 1, two: 2, example: 'foo' })
+ assert.doesNotHaveAnyKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value'],]), [{ one: 'two' }, 'example'])
+ assert.doesNotHaveAnyKeys(new Set([{ foo: 'bar' }, 'anotherKey'], [{ one: 'two' }, 'example']))
})
```
@@ -1307,26 +1210,10 @@ test('assert.doesNotHaveAnyKeys', () => {
import { assert, test } from 'vitest'
test('assert.hasAnyKeys', () => {
- assert.doesNotHaveAnyKeys({ foo: 1, bar: 2, baz: 3 }, [
- 'one',
- 'two',
- 'example',
- ])
- assert.doesNotHaveAnyKeys(
- { foo: 1, bar: 2, baz: 3 },
- { one: 1, two: 2, example: 'foo' }
- )
- assert.doesNotHaveAnyKeys(
- new Map([
- [{ foo: 1 }, 'bar'],
- ['key', 'value'],
- ]),
- [{ one: 'two' }, 'example']
- )
- assert.doesNotHaveAnyKeys(new Set([{ foo: 'bar' }, 'anotherKey']), [
- { one: 'two' },
- 'example',
- ])
+ assert.doesNotHaveAnyKeys({ foo: 1, bar: 2, baz: 3 }, ['one', 'two', 'example',])
+ assert.doesNotHaveAnyKeys({ foo: 1, bar: 2, baz: 3 }, { one: 1, two: 2, example: 'foo' })
+ assert.doesNotHaveAnyKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value'],]), [{ one: 'two' }, 'example'])
+ assert.doesNotHaveAnyKeys(new Set([{ foo: 'bar' }, 'anotherKey']), [{ one: 'two' }, 'example',])
})
```
@@ -1340,38 +1227,12 @@ test('assert.hasAnyKeys', () => {
import { assert, test } from 'vitest'
test('assert.hasAnyDeepKeys', () => {
- assert.hasAnyDeepKeys(
- new Map([
- [{ one: 'one' }, 'valueOne'],
- [1, 2],
- ]),
- { one: 'one' }
- )
- assert.hasAnyDeepKeys(
- new Map([
- [{ one: 'one' }, 'valueOne'],
- [1, 2],
- ]),
- [{ one: 'one' }, { two: 'two' }]
- )
- assert.hasAnyDeepKeys(
- new Map([
- [{ one: 'one' }, 'valueOne'],
- [{ two: 'two' }, 'valueTwo'],
- ]),
- [{ one: 'one' }, { two: 'two' }]
- )
- assert.hasAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), {
- one: 'one',
- })
- assert.hasAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [
- { one: 'one' },
- { three: 'three' },
- ])
- assert.hasAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [
- { one: 'one' },
- { two: 'two' },
- ])
+ assert.hasAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2],]), { one: 'one' })
+ assert.hasAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2],]), [{ one: 'one' }, { two: 'two' }])
+ assert.hasAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo'],]), [{ one: 'one' }, { two: 'two' }])
+ assert.hasAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), { one: 'one', })
+ assert.hasAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { three: 'three' },])
+ assert.hasAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { two: 'two' },])
})
```
@@ -1385,21 +1246,10 @@ test('assert.hasAnyDeepKeys', () => {
import { assert, test } from 'vitest'
test('assert.hasAnyDeepKeys', () => {
- assert.hasAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne']]), {
- one: 'one',
- })
- assert.hasAllDeepKeys(
- new Map([
- [{ one: 'one' }, 'valueOne'],
- [{ two: 'two' }, 'valueTwo'],
- ]),
- [{ one: 'one' }, { two: 'two' }]
- )
+ assert.hasAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne']]), { one: 'one', })
+ assert.hasAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo'],]), [{ one: 'one' }, { two: 'two' }])
assert.hasAllDeepKeys(new Set([{ one: 'one' }]), { one: 'one' })
- assert.hasAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [
- { one: 'one' },
- { two: 'two' },
- ])
+ assert.hasAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { two: 'two' },])
})
```
@@ -1413,27 +1263,10 @@ test('assert.hasAnyDeepKeys', () => {
import { assert, test } from 'vitest'
test('assert.containsAllDeepKeys', () => {
- assert.containsAllDeepKeys(
- new Map([
- [{ one: 'one' }, 'valueOne'],
- [1, 2],
- ]),
- { one: 'one' }
- )
- assert.containsAllDeepKeys(
- new Map([
- [{ one: 'one' }, 'valueOne'],
- [{ two: 'two' }, 'valueTwo'],
- ]),
- [{ one: 'one' }, { two: 'two' }]
- )
- assert.containsAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), {
- one: 'one',
- })
- assert.containsAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [
- { one: 'one' },
- { two: 'two' },
- ])
+ assert.containsAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2],]), { one: 'one' })
+ assert.containsAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo'],]), [{ one: 'one' }, { two: 'two' }])
+ assert.containsAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), { one: 'one', })
+ assert.containsAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { two: 'two' },])
})
```
@@ -1447,27 +1280,10 @@ test('assert.containsAllDeepKeys', () => {
import { assert, test } from 'vitest'
test('assert.doesNotHaveAnyDeepKeys', () => {
- assert.doesNotHaveAnyDeepKeys(
- new Map([
- [{ one: 'one' }, 'valueOne'],
- [1, 2],
- ]),
- { thisDoesNot: 'exist' }
- )
- assert.doesNotHaveAnyDeepKeys(
- new Map([
- [{ one: 'one' }, 'valueOne'],
- [{ two: 'two' }, 'valueTwo'],
- ]),
- [{ twenty: 'twenty' }, { fifty: 'fifty' }]
- )
- assert.doesNotHaveAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), {
- twenty: 'twenty',
- })
- assert.doesNotHaveAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [
- { twenty: 'twenty' },
- { fifty: 'fifty' },
- ])
+ assert.doesNotHaveAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2],]), { thisDoesNot: 'exist' })
+ assert.doesNotHaveAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo'],]), [{ twenty: 'twenty' }, { fifty: 'fifty' }])
+ assert.doesNotHaveAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), { twenty: 'twenty', })
+ assert.doesNotHaveAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ twenty: 'twenty' }, { fifty: 'fifty' },])
})
```
@@ -1481,27 +1297,10 @@ test('assert.doesNotHaveAnyDeepKeys', () => {
import { assert, test } from 'vitest'
test('assert.doesNotHaveAllDeepKeys', () => {
- assert.doesNotHaveAllDeepKeys(
- new Map([
- [{ one: 'one' }, 'valueOne'],
- [1, 2],
- ]),
- { thisDoesNot: 'exist' }
- )
- assert.doesNotHaveAllDeepKeys(
- new Map([
- [{ one: 'one' }, 'valueOne'],
- [{ two: 'two' }, 'valueTwo'],
- ]),
- [{ twenty: 'twenty' }, { one: 'one' }]
- )
- assert.doesNotHaveAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), {
- twenty: 'twenty',
- })
- assert.doesNotHaveAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [
- { one: 'one' },
- { fifty: 'fifty' },
- ])
+ assert.doesNotHaveAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2],]), { thisDoesNot: 'exist' })
+ assert.doesNotHaveAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo'],]), [{ twenty: 'twenty' }, { one: 'one' }])
+ assert.doesNotHaveAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), { twenty: 'twenty', })
+ assert.doesNotHaveAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { fifty: 'fifty' },])
})
```
@@ -1524,26 +1323,10 @@ test('assert.throws', () => {
assert.throws(fn, /Error thrown must have a msg that matches this/)
assert.throws(fn, ReferenceError)
assert.throws(fn, errorInstance)
- assert.throws(
- fn,
- ReferenceError,
- 'Error thrown must be a ReferenceError and have this msg'
- )
- assert.throws(
- fn,
- errorInstance,
- 'Error thrown must be the same errorInstance and have this msg'
- )
- assert.throws(
- fn,
- ReferenceError,
- /Error thrown must be a ReferenceError and match this/
- )
- assert.throws(
- fn,
- errorInstance,
- /Error thrown must be the same errorInstance and match this/
- )
+ assert.throws(fn, ReferenceError, 'Error thrown must be a ReferenceError and have this msg')
+ assert.throws(fn, errorInstance, 'Error thrown must be the same errorInstance and have this msg')
+ assert.throws(fn, ReferenceError, /Error thrown must be a ReferenceError and match this/)
+ assert.throws(fn, errorInstance, /Error thrown must be the same errorInstance and match this/)
})
```
@@ -1636,11 +1419,7 @@ test('assert.sameMembers', () => {
import { assert, test } from 'vitest'
test('assert.sameDeepMembers', () => {
- assert.sameDeepMembers(
- [{ a: 1 }, { b: 2 }, { c: 3 }],
- [{ b: 2 }, { a: 1 }, { c: 3 }],
- 'same deep members'
- )
+ assert.sameDeepMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }, { c: 3 }], 'same deep members')
})
```
@@ -1654,11 +1433,7 @@ test('assert.sameDeepMembers', () => {
import { assert, test } from 'vitest'
test('assert.sameDeepMembers', () => {
- assert.sameDeepMembers(
- [{ a: 1 }, { b: 2 }, { c: 3 }],
- [{ b: 2 }, { a: 1 }, { c: 3 }],
- 'same deep members'
- )
+ assert.sameDeepMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }, { c: 3 }], 'same deep members')
})
```
@@ -1686,11 +1461,7 @@ test('assert.sameOrderedMembers', () => {
import { assert, test } from 'vitest'
test('assert.notSameOrderedMembers', () => {
- assert.notSameOrderedMembers(
- [1, 2, 3],
- [2, 1, 3],
- 'not same ordered members'
- )
+ assert.notSameOrderedMembers([1, 2, 3], [2, 1, 3], 'not same ordered members')
})
```
@@ -1704,11 +1475,7 @@ test('assert.notSameOrderedMembers', () => {
import { assert, test } from 'vitest'
test('assert.sameDeepOrderedMembers', () => {
- assert.sameDeepOrderedMembers(
- [{ a: 1 }, { b: 2 }, { c: 3 }],
- [{ a: 1 }, { b: 2 }, { c: 3 }],
- 'same deep ordered members'
- )
+ assert.sameDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ a: 1 }, { b: 2 }, { c: 3 }], 'same deep ordered members')
})
```
@@ -1722,16 +1489,8 @@ test('assert.sameDeepOrderedMembers', () => {
import { assert, test } from 'vitest'
test('assert.notSameDeepOrderedMembers', () => {
- assert.notSameDeepOrderedMembers(
- [{ a: 1 }, { b: 2 }, { c: 3 }],
- [{ a: 1 }, { b: 2 }, { z: 5 }],
- 'not same deep ordered members'
- )
- assert.notSameDeepOrderedMembers(
- [{ a: 1 }, { b: 2 }, { c: 3 }],
- [{ b: 2 }, { a: 1 }, { c: 3 }],
- 'not same deep ordered members'
- )
+ assert.notSameDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ a: 1 }, { b: 2 }, { z: 5 }], 'not same deep ordered members')
+ assert.notSameDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }, { c: 3 }], 'not same deep ordered members')
})
```
@@ -1773,11 +1532,7 @@ test('assert.notIncludeMembers', () => {
import { assert, test } from 'vitest'
test('assert.includeDeepMembers', () => {
- assert.includeDeepMembers(
- [{ a: 1 }, { b: 2 }, { c: 3 }],
- [{ b: 2 }, { a: 1 }, { b: 2 }],
- 'include deep members'
- )
+ assert.includeDeepMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }, { b: 2 }], 'include deep members')
})
```
@@ -1791,11 +1546,7 @@ test('assert.includeDeepMembers', () => {
import { assert, test } from 'vitest'
test('assert.notIncludeDeepMembers', () => {
- assert.notIncludeDeepMembers(
- [{ a: 1 }, { b: 2 }, { c: 3 }],
- [{ b: 2 }, { f: 5 }],
- 'not include deep members'
- )
+ assert.notIncludeDeepMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { f: 5 }], 'not include deep members')
})
```
@@ -1823,16 +1574,8 @@ test('assert.includeOrderedMembers', () => {
import { assert, test } from 'vitest'
test('assert.notIncludeOrderedMembers', () => {
- assert.notIncludeOrderedMembers(
- [1, 2, 3],
- [2, 1],
- 'not include ordered members'
- )
- assert.notIncludeOrderedMembers(
- [1, 2, 3],
- [2, 3],
- 'not include ordered members'
- )
+ assert.notIncludeOrderedMembers([1, 2, 3], [2, 1], 'not include ordered members')
+ assert.notIncludeOrderedMembers([1, 2, 3], [2, 3], 'not include ordered members')
})
```
@@ -1846,11 +1589,7 @@ test('assert.notIncludeOrderedMembers', () => {
import { assert, test } from 'vitest'
test('assert.includeDeepOrderedMembers', () => {
- assert.includeDeepOrderedMembers(
- [{ a: 1 }, { b: 2 }, { c: 3 }],
- [{ a: 1 }, { b: 2 }],
- 'include deep ordered members'
- )
+ assert.includeDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ a: 1 }, { b: 2 }], 'include deep ordered members')
})
```
@@ -1864,21 +1603,9 @@ test('assert.includeDeepOrderedMembers', () => {
import { assert, test } from 'vitest'
test('assert.includeDeepOrderedMembers', () => {
- assert.notIncludeDeepOrderedMembers(
- [{ a: 1 }, { b: 2 }, { c: 3 }],
- [{ a: 1 }, { f: 5 }],
- 'not include deep ordered members'
- )
- assert.notIncludeDeepOrderedMembers(
- [{ a: 1 }, { b: 2 }, { c: 3 }],
- [{ b: 2 }, { a: 1 }],
- 'not include deep ordered members'
- )
- assert.notIncludeDeepOrderedMembers(
- [{ a: 1 }, { b: 2 }, { c: 3 }],
- [{ b: 2 }, { c: 3 }],
- 'not include deep ordered members'
- )
+ assert.notIncludeDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ a: 1 }, { f: 5 }], 'not include deep ordered members')
+ assert.notIncludeDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }], 'not include deep ordered members')
+ assert.notIncludeDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { c: 3 }], 'not include deep ordered members')
})
```
@@ -1907,9 +1634,7 @@ import { assert, test } from 'vitest'
test('assert.changes', () => {
const obj = { val: 10 }
- function fn() {
- obj.val = 22
- }
+ function fn() { obj.val = 22 };
assert.changes(fn, obj, 'val')
})
```
@@ -1925,9 +1650,7 @@ import { assert, test } from 'vitest'
test('assert.changesBy', () => {
const obj = { val: 10 }
- function fn() {
- obj.val += 2
- }
+ function fn() { obj.val += 2 };
assert.changesBy(fn, obj, 'val', 2)
})
```
@@ -1943,9 +1666,7 @@ import { assert, test } from 'vitest'
test('assert.doesNotChange', () => {
const obj = { val: 10 }
- function fn() {
- obj.val += 2
- }
+ function fn() { obj.val += 2 };
assert.doesNotChange(fn, obj, 'val', 2)
})
```
@@ -1961,9 +1682,7 @@ import { assert, test } from 'vitest'
test('assert.changesButNotBy', () => {
const obj = { val: 10 }
- function fn() {
- obj.val += 10
- }
+ function fn() { obj.val += 10 };
assert.changesButNotBy(fn, obj, 'val', 5)
})
```
@@ -1979,9 +1698,7 @@ import { assert, test } from 'vitest'
test('assert.increases', () => {
const obj = { val: 10 }
- function fn() {
- obj.val = 13
- }
+ function fn() { obj.val = 13 };
assert.increases(fn, obj, 'val')
})
```
@@ -2013,9 +1730,7 @@ import { assert, test } from 'vitest'
test('assert.doesNotIncrease', () => {
const obj = { val: 10 }
- function fn() {
- obj.val = 8
- }
+ function fn() { obj.val = 8 }
assert.doesNotIncrease(fn, obj, 'val')
})
```
@@ -2031,9 +1746,7 @@ import { assert, test } from 'vitest'
test('assert.increasesButNotBy', () => {
const obj = { val: 10 }
- function fn() {
- obj.val += 15
- }
+ function fn() { obj.val += 15 };
assert.increasesButNotBy(fn, obj, 'val', 10)
})
```
@@ -2049,9 +1762,7 @@ import { assert, test } from 'vitest'
test('assert.decreases', () => {
const obj = { val: 10 }
- function fn() {
- obj.val = 5
- }
+ function fn() { obj.val = 5 };
assert.decreases(fn, obj, 'val')
})
```
@@ -2067,9 +1778,7 @@ import { assert, test } from 'vitest'
test('assert.decreasesBy', () => {
const obj = { val: 10 }
- function fn() {
- obj.val -= 5
- }
+ function fn() { obj.val -= 5 };
assert.decreasesBy(fn, obj, 'val', 5)
})
```
@@ -2085,9 +1794,7 @@ import { assert, test } from 'vitest'
test('assert.doesNotDecrease', () => {
const obj = { val: 10 }
- function fn() {
- obj.val = 15
- }
+ function fn() { obj.val = 15 }
assert.doesNotDecrease(fn, obj, 'val')
})
```
@@ -2103,9 +1810,7 @@ import { assert, test } from 'vitest'
test('assert.doesNotDecreaseBy', () => {
const obj = { val: 10 }
- function fn() {
- obj.val = 5
- }
+ function fn() { obj.val = 5 };
assert.doesNotDecreaseBy(fn, obj, 'val', 1)
})
```
@@ -2121,9 +1826,7 @@ import { assert, test } from 'vitest'
test('assert.decreasesButNotBy', () => {
const obj = { val: 10 }
- function fn() {
- obj.val = 5
- }
+ function fn() { obj.val = 5 };
assert.decreasesButNotBy(fn, obj, 'val', 1)
})
```
diff --git a/api/expect-typeof.md b/api/expect-typeof.md
index 6f086611..02245225 100644
--- a/api/expect-typeof.md
+++ b/api/expect-typeof.md
@@ -31,9 +31,6 @@ expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>()
- **类型:** `(expected: T) => void`
-::: warning 弃用
-自 expect-type v1.2.0 版本起,此匹配器已被弃用。请改用 [`toExtend`](#toextend)。
-:::
此匹配器检查期望类型是否扩展了提供的类型。它不同于 `toEqual`,更类似于 [expect's](/api/expect) `toMatchObject()`。使用此匹配器,你可以检查对象是否“匹配”类型。
```ts
@@ -44,44 +41,6 @@ expectTypeOf().toMatchTypeOf()
expectTypeOf().not.toMatchTypeOf()
```
-## toExtend
-
-- **类型:** `(expected: T) => void`
-
-这个匹配器用于检查期望类型是否扩展了提供的类型。它与 `toEqual` 不同,更类似于 [expect](/api/expect) 的 `toMatchObject()`。使用这个匹配器,你可以检查一个对象是否"匹配"某个类型。
-
-```ts
-import { expectTypeOf } from 'vitest'
-
-expectTypeOf({ a: 1, b: 1 }).toExtend({ a: 1 })
-expectTypeOf().toExtend()
-expectTypeOf().not.toExtend()
-```
-
-## toMatchObjectType
-
-- **类型:** `() => void`
-
-这个匹配器对对象类型执行严格检查,确保期望的类型与提供的对象类型相匹配。它比 [`toExtend`](#toextend) 更严格,是在处理对象类型时的推荐选择,因为它更有可能捕获到像只读属性这样的问题。
-
-```ts
-import { expectTypeOf } from 'vitest'
-
-expectTypeOf({ a: 1, b: 2 }).toMatchObjectType<{ a: number }>() // preferred
-expectTypeOf({ a: 1, b: 2 }).toExtend<{ a: number }>() // works but less strict
-
-// 支持嵌套对象检查
-const user = {
- name: 'John',
- address: { city: 'New York', zip: '10001' }
-}
-expectTypeOf(user).toMatchObjectType<{ name: string, address: { city: string } }>()
-```
-
-::: warning
-这个匹配器只适用于普通对象类型。对于联合类型和其他复杂类型,它将会失败。对于这些情况,请改用 [`toExtend`](#toextend)。
-:::
-
## extract
- **类型:** `ExpectTypeOf`
diff --git a/api/expect.md b/api/expect.md
index 29ce3970..cacf3676 100644
--- a/api/expect.md
+++ b/api/expect.md
@@ -31,7 +31,7 @@ expect(input).to.equal(2) // chai API
expect(input).toBe(2) // jest API
```
-从技术上讲,这个示例没有使用 [`test`](/api/#test) 函数,因此在控制台中你将看到 Nodejs 错误而不是 Vitest 输出。 要了解更多关于 `test` 的信息,请阅读[测试 API 参考](/api/)。
+从技术上讲,这个示例没有使用 [`test`](/api/#test) 函数,因此在控制台中你将看到 Nodejs 错误而不是 Vitest 输出。 要了解更多关于 `test` 的信息,请阅读 [Test API](/api/)。
此外,`expect` 可以静态地使用来访问匹配器函数,稍后将会介绍。
@@ -39,36 +39,6 @@ expect(input).toBe(2) // jest API
如果表达式没有类型错误,则 `expect` 对测试类型没有影响。 如果你想使用 Vitest 作为[类型检查器](/guide/testing-types),请使用 [`expectTypeOf`](/api/expect-typeof) 或 [`assertType`](/api/assert-type) 。
:::
-## assert
-
-- **类型:** `Chai.AssertStatic`
-
-Vitest 将 Chai 的 [`assert` API](https://www.chaijs.com/api/assert/) 以 `expect.assert` 的形式重新导出。你可以在 [Assert API page](/api/assert) 页面查看支持的方法。
-
-如果你需要缩小类型范围时,这将特别有用,因为 `expect.to*` 方法不支持此功能:
-
-```ts
-interface Cat {
- __type: 'Cat'
- mew(): void
-}
-interface Dog {
- __type: 'Dog'
- bark(): void
-}
-type Animal = Cat | Dog
-
-const animal: Animal = { __type: 'Dog', bark: () => {} }
-
-expect.assert(animal.__type === 'Dog')
-// 不显示类型错误!
-expect(animal.bark()).toBeUndefined()
-```
-
-::: tip
-注意,`expect.assert` 还支持其他缩小类型的方法(如:`assert.isDefined`,`assert.exists`等)。
-:::
-
## soft
- **类型:** `ExpectStatic & (actual: any) => Assertions`
@@ -330,32 +300,6 @@ test('we don\'t have apples', () => {
})
```
-## toBeNullable
-
-- **类型:** `() => Awaitable`
-
-`toBeNullable` simply asserts if something is nullable (`null` or `undefined`).
-
-```ts
-import { expect, test } from 'vitest'
-
-function apples() {
- return null
-}
-
-function bananas() {
- return null
-}
-
-test('we don\'t have apples', () => {
- expect(apples()).toBeNullable()
-})
-
-test('we don\'t have bananas', () => {
- expect(bananas()).toBeNullable()
-})
-```
-
## toBeNaN
- **类型:** `() => Awaitable`
@@ -1335,7 +1279,7 @@ test('spy function returns bananas on second call', async () => {
- **类型:** `(predicate: (value: any) => boolean) => Awaitable`
-该断言检查一个值是否满足「某个谓词/certain predicate」。
+该断言检查一个值是否满足某个谓词(certain predicate)。
```ts
import { describe, expect, it } from 'vitest'
@@ -1746,7 +1690,7 @@ declare module 'vitest' {
:::
:::tip
-如果想了解更多信息,请查看 [扩展断言 (Matchers) 指南](/guide/extending-matchers)。
+如果想了解更多信息,请查看 [扩展断言](/guide/extending-matchers)。
:::
## expect.addEqualityTesters {#expect-addequalitytesters}
diff --git a/api/index.md b/api/index.md
index fb1ad821..466632cd 100644
--- a/api/index.md
+++ b/api/index.md
@@ -35,7 +35,7 @@ interface TestOptions {
当测试函数返回一个 promise 时,运行器会等待它解析结束收集异步的结果。如果 promise 被拒绝,测试就会失败。
::: tip
-在 Jest 中,`TestFunction` 也可以是 `(done: DoneCallback) => void` 类型。如果使用这种形式,测试将在调用 `done` 之前不会结束。也可以使用 `async` 函数来实现相同的效果,请参阅[迁移指南中的回调完成部分](/guide/migration#回调完成)。
+在 Jest 中,`TestFunction` 也可以是 `(done: DoneCallback) => void` 类型。如果使用这种形式,测试将在调用 `done` 之前不会结束。也可以使用 `async` 函数来实现相同的效果,请参阅 [迁移指南中的回调完成部分](/guide/migration.html#done-callback)。
:::
@@ -108,7 +108,7 @@ test('heavy test', { skip: true, timeout: 10_000 }, () => {
`test` 定义了一组相关的期望。 它接收测试名称和保存测试期望的函数。
-或者,我们可以提供超时(以毫秒为单位)来指定终止前等待的时间。 默认为 5 秒,可以通过 [testTimeout](/config/#testtimeout) 进行全局配置
+或者,我们可以提供超时(以毫秒为单位)来指定终止前等待的时间。 默认为 5 秒,可以通过 [testTimeout](/config/#testtimeout) 进行全局配置。
```ts
import { expect, test } from 'vitest'
@@ -123,7 +123,7 @@ test('should work as expected', () => {
- **类型:** `>(fixtures: Fixtures): TestAPI`
- **别名:** `it.extend`
-使用 `test.extend` 来使用自定义的 fixtures 扩展测试上下文。这将返回一个新的 `test`,它也是可扩展的,因此可以根据需要扩展更多的 fixtures 或覆盖现有的 fixtures。有关更多信息,请参阅[扩展测试上下文](/guide/test-context.html#test-extend)。
+使用 `test.extend` 来使用自定义的 fixtures 扩展测试上下文。这将返回一个新的 `test`,它也是可扩展的,因此可以根据需要扩展更多的 fixtures 或覆盖现有的 fixtures。有关更多信息,请参阅 [扩展测试上下文](/guide/test-context.html#test-extend)。
```ts
import { expect, test } from 'vitest'
@@ -176,7 +176,7 @@ test('skipped test', (context) => {
})
```
-自 Vitest 3.1 起,如果你无法提前确定是否跳过,可以把条件直接作为第一个参数传给 `skip 方法:
+自 Vitest 3.1 起,如果你无法提前确定是否跳过,可以把条件直接作为第一个参数传给 `skip` 方法:
```ts
import { assert, test } from 'vitest'
@@ -206,7 +206,7 @@ test.skipIf(isDev)('prod only test', () => {
```
::: warning
-在将 Vitest 用作[类型检查器](/guide/testing-types)时,不能使用此语法。
+在将 Vitest 用作 [类型检查器](/guide/testing-types) 时,不能使用此语法。
:::
### test.runIf
@@ -227,7 +227,7 @@ test.runIf(isDev)('dev only test', () => {
```
::: warning
-在将 Vitest 用作[类型检查器](/guide/testing-types)时,不能使用此语法。
+在将 Vitest 用作 [类型检查器](/guide/testing-types) 时,不能使用此语法。
:::
### test.only
@@ -248,7 +248,7 @@ test.only('test', () => {
})
```
-有时,只运行某个文件中的 "测试",而忽略整个 测试套件 中的所有其他测试是非常有用的,因为这些测试会污染输出。
+有时,只运行某个文件中的 "测试",而忽略整个测试套件中的所有其他测试是非常有用的,因为这些测试会污染输出。
为此,请使用包含相关测试的特定文件运行 `vitest`。
@@ -289,7 +289,7 @@ test.only.concurrent(/* ... */) // or test.concurrent.only(/* ... */)
test.todo.concurrent(/* ... */) // or test.concurrent.todo(/* ... */)
```
-运行并发测试时,快照和断言必须使用本地[测试上下文](/guide/test-context.md)中的 `expect`,以确保检测到正确的测试。
+运行并发测试时,快照和断言必须使用本地 [测试上下文](/guide/test-context.md) 中的 `expect`,以确保检测到正确的测试。
```ts
test.concurrent('test 1', async ({ expect }) => {
@@ -301,12 +301,13 @@ test.concurrent('test 2', async ({ expect }) => {
```
::: warning
-在将 Vitest 用作[类型检查器](/guide/testing-types)时,不能使用此语法。
+在将 Vitest 用作 [类型检查器](/guide/testing-types) 时,不能使用此语法。
:::
### test.sequential
- **类型:** `(name: string | Function, fn: TestFunction, timeout?: number) => void`
+- **别名:** `it.sequential`
`test.sequential` 标记一个测试为顺序测试。如果要在 `describe.concurrent` 中或使用 `--sequence.concurrent` 命令选项按顺序运行测试,这一点非常有用。
@@ -314,35 +315,19 @@ test.concurrent('test 2', async ({ expect }) => {
import { describe, test } from 'vitest'
// 使用配置选项 `{ sequence: { concurrent: true } }`
-test('concurrent test 1', async () => {
- /* ... */
-})
-test('concurrent test 2', async () => {
- /* ... */
-})
+test('concurrent test 1', async () => { /* ... */ })
+test('concurrent test 2', async () => { /* ... */ })
-test.sequential('sequential test 1', async () => {
- /* ... */
-})
-test.sequential('sequential 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('concurrent test 1', async () => { /* ... */ })
+ test('concurrent test 2', async () => { /* ... */ })
- test.sequential('sequential test 1', async () => {
- /* ... */
- })
- test.sequential('sequential test 2', async () => {
- /* ... */
- })
+ test.sequential('sequential test 1', async () => { /* ... */ })
+ test.sequential('sequential test 2', async () => { /* ... */ })
})
```
@@ -360,7 +345,6 @@ test.todo('unimplemented test')
### test.fails
-- **类型:** `(name: string | Function, fn: TestFunction, timeout?: number) => void`
- **别名:** `it.fails`
使用 `test.fails` 明确表示断言将失败。
@@ -377,7 +361,7 @@ test.fails('fail test', async () => {
```
::: warning
-在将 Vitest 用作[类型检查器](/guide/testing-types)时,不能使用此语法。
+在将 Vitest 用作 [类型检查器](/guide/testing-types) 时,不能使用此语法。
:::
### test.each
@@ -487,7 +471,7 @@ Vitest 使用 chai `format` 方法处理 `$values`。如果数值太短,可以
:::
::: warning
-在将 Vitest 用作[类型检查器](/guide/testing-types)时,不能使用此语法。
+在将 Vitest 用作 [类型检查器](/guide/testing-types) 时,不能使用此语法。
:::
### test.for
@@ -504,8 +488,8 @@ test.each([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
-])('add(%i, %i) -> %i', (a, b, expected) => {
// [!code --]
+])('add(%i, %i) -> %i', (a, b, expected) => {
expect(a + b).toBe(expected)
})
@@ -514,8 +498,8 @@ test.for([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
-])('add(%i, %i) -> %i', ([a, b, expected]) => {
// [!code ++]
+])('add(%i, %i) -> %i', ([a, b, expected]) => {
expect(a + b).toBe(expected)
})
```
@@ -856,6 +840,7 @@ describe('numberToCurrency', () => {
### describe.skip
- **类型:** `(name: string | Function, fn: TestFunction, options?: number | TestOptions) => void`
+- **别名:** `suite.skip`
在套件中使用 `describe.skip` 可避免运行特定的 describe 块。
@@ -873,6 +858,7 @@ describe.skip('skipped suite', () => {
### describe.skipIf
- **类型:** `(condition: any) => void`
+- **别名:** `suite.skipIf`
在某些情况下,可能会在不同的环境下多次运行套件,其中一些测试套件可能是特定于环境的。可以使用 `describe.skipIf` 来跳过条件为真时的套件,而不是使用 `if` 来封装套件。
@@ -893,6 +879,7 @@ describe.skipIf(isDev)('prod only test suite', () => {
### describe.runIf
- **类型:** `(condition: any) => void`
+- **别名:** `suite.runIf`
与 [describe.skipIf](#describe-skipif) 相反。
@@ -931,11 +918,9 @@ describe('other suite', () => {
})
```
-为了做到这一点,请使用包含相关测试的特定文件来运行 `vitest`。
-
有时,只运行某个文件中的测试套件,而忽略整个测试套件中的所有其他测试是非常有用的,因为这些测试会污染输出。
-要做到这一点,请在包含相关测试的特定文件中运行 `vitest`。
+为了做到这一点,请使用包含相关测试的特定文件来运行 `vitest`。
```
# vitest interesting.test.ts
@@ -978,7 +963,7 @@ describe.only.concurrent(/* ... */) // 或 describe.concurrent.only(/* ... */)
describe.todo.concurrent(/* ... */) // 或 describe.concurrent.todo(/* ... */)
```
-运行并发测试时,快照和断言必须使用本地[测试上下文](/guide/test-context.md)中的 `expect` ,以确保检测到正确的测试。
+运行并发测试时,快照和断言必须使用本地 [测试上下文](/guide/test-context.md) 中的 `expect` ,以确保检测到正确的测试。
```ts
describe.concurrent('suite', () => {
@@ -992,12 +977,13 @@ describe.concurrent('suite', () => {
```
::: warning
-在将 Vitest 用作[类型检查器](/guide/testing-types)时,不能使用此语法。
+在将 Vitest 用作 [类型检查器](/guide/testing-types) 时,不能使用此语法。
:::
### describe.sequential
- **类型:** `(name: string | Function, fn: TestFunction, options?: number | TestOptions) => void`
+- **别名:** `suite.sequential`
测试套件中的 `describe.sequential` 会将每个测试标记为顺序测试。如果需要在 `describe.concurrent` 中或使用 `--sequence.concurrent` 命令选项按顺序运行测试,这一点非常有用。
@@ -1005,20 +991,12 @@ describe.concurrent('suite', () => {
import { describe, test } from 'vitest'
describe.concurrent('suite', () => {
- test('concurrent test 1', async () => {
- /* ... */
- })
- test('concurrent test 2', async () => {
- /* ... */
- })
+ test('concurrent test 1', async () => { /* ... */ })
+ test('concurrent test 2', async () => { /* ... */ })
describe.sequential('', () => {
- test('sequential test 1', async () => {
- /* ... */
- })
- test('sequential test 2', async () => {
- /* ... */
- })
+ test('sequential test 1', async () => { /* ... */ })
+ test('sequential test 2', async () => { /* ... */ })
})
})
```
@@ -1026,6 +1004,7 @@ describe.concurrent('suite', () => {
### describe.shuffle
- **类型:** `(name: string | Function, fn: TestFunction, options?: number | TestOptions) => void`
+- **别名:** `suite.shuffle`
Vitest 通过 CLI 标志 [`--sequence.shuffle`](/guide/cli) 或配置选项 [`sequence.shuffle`](/config/#sequence-shuffle),提供了一种以随机顺序运行所有测试的方法,但如果只想让测试套件的一部分以随机顺序运行测试,可以用这个标志来标记它。
@@ -1034,48 +1013,35 @@ import { describe, test } from 'vitest'
// 或 `describe('suite', { shuffle: true }, ...)`
describe.shuffle('suite', () => {
- test('random test 1', async () => {
- /* ... */
- })
- test('random test 2', async () => {
- /* ... */
- })
- test('random test 3', async () => {
- /* ... */
- })
+ test('random test 1', async () => { /* ... */ })
+ test('random test 2', async () => { /* ... */ })
+ test('random test 3', async () => { /* ... */ })
// `shuffle` 是继承的
describe('still random', () => {
- test('random 4.1', async () => {
- /* ... */
- })
- test('random 4.2', async () => {
- /* ... */
- })
+ test('random 4.1', async () => { /* ... */ })
+ test('random 4.2', async () => { /* ... */ })
})
// 禁用内部的 shuffle
describe('not random', { shuffle: false }, () => {
- test('in order 5.1', async () => {
- /* ... */
- })
- test('in order 5.2', async () => {
- /* ... */
- })
+ test('in order 5.1', async () => { /* ... */ })
+ test('in order 5.2', async () => { /* ... */ })
})
})
// 顺序取决于配置中的 `sequence.seed` 选项(默认为 `Date.now()`)
```
-`.skip`、`.only`和`.todo`适用于随机测试套件。
+`.skip`、 `.only` 和 `.todo` 适用于随机测试套件。
::: warning
-在将 Vitest 用作[类型检查器](/guide/testing-types)时,不能使用此语法。
+在将 Vitest 用作 [类型检查器](/guide/testing-types) 时,不能使用此语法。
:::
### describe.todo
- **类型:** `(name: string | Function) => void`
+- **别名:** `suite.todo`
使用 `describe.todo` 来暂存待以后实施的套件。测试报告中会显示一个条目,这样就能知道还有多少测试需要执行。
@@ -1087,6 +1053,7 @@ describe.todo('unimplemented suite')
### describe.each
- **类型:** `(cases: ReadonlyArray, ...args: any[]): (name: string | Function, fn: (...args: T[]) => void, options?: number | TestOptions) => void`
+- **别名:** `suite.each`
::: tip
虽然 `describe.each` 是为了兼容 Jest 提供的,
@@ -1140,7 +1107,7 @@ describe.each`
```
::: warning
-在将 Vitest 用作[类型检查器](/guide/testing-types)时,不能使用此语法。
+在将 Vitest 用作 [类型检查器](/guide/testing-types) 时,不能使用此语法。
:::
### describe.for
diff --git a/api/mock.md b/api/mock.md
index 036d9cea..70f93cec 100644
--- a/api/mock.md
+++ b/api/mock.md
@@ -1,6 +1,6 @@
-# Mocks
+# Mock Functions
-用 `vi.fn` 即可创建 mock 函数或类,并全程记录其调用情况;若想监控已存在对象上的某个属性,则改用 `vi.spyOn`。
+我们可以使用 `vi.fn` 方法创建一个 mock 函数来跟踪其执行情况。如果要跟踪已创建对象上的方法,可以使用 `vi.spyOn` 方法:
```js
import { vi } from 'vitest'
@@ -18,10 +18,10 @@ market.getApples()
getApplesSpy.mock.calls.length === 1
```
-要验证 mock 的行为,请通过 [`expect`](/api/expect) 调用类似 [`toHaveBeenCalled`](/api/expect#tohavebeencalled) 的断言方法;以下 API 参考汇总了所有可用来操控 mock 的属性和方法。
+我们应该在 [`expect`](/api/expect) 上使用 mock 断言(例如 [`toHaveBeenCalled`](/api/expect#tohavebeencalled) )来断言 mock 结果。在这里我们介绍了用于操作 mock 行为的可用属性和方法。
::: tip
-The custom function implementation in the types below is marked with a generic ``.
+下列类型中的自定义函数实现通过泛型 `` 标记。
:::
## getMockImplementation
@@ -42,7 +42,7 @@ function getMockImplementation(): T | undefined
function getMockName(): string
```
-此方法返回由 `.mockName(name)` 为 mock 指定的名称。`vi.fn()` 创建的替身默认返回 `'vi.fn()'`; `vi.spyOn` 生成的 spy 则沿用被监视方法的原始名称。
+使用它来返回使用 `.mockName(name)` 方法分配给 mock 对象的名称。默认情况下,它将返回 `vi.fn()`。
## mockClear
@@ -215,7 +215,7 @@ await asyncMock() // 抛出 Error<'Async error'>
function mockReset(): Mock
```
-该方法会先执行与 [`mockClear`](#mockClear) 相同的清理,再重置 mock 的实现,并一并清除所有一次性(once)设定。
+执行与 `mockClear` 相同的操作,并将内部实现设置为空函数(调用时返回 undefined)。这也会重置所有 “once” 实现。它对于将 mock 完全重置为其默认状态很有用。
注意:
@@ -378,37 +378,6 @@ fn.mock.calls
]
```
-:::warning 对象按引用存储。
-请注意,Vitest 在 `mock` 状态的所有属性中始终按引用保存对象。一旦你的代码修改了这些属性,诸如 [`.toHaveBeenCalledWith`](/api/expect#tohavebeencalledwith) 之类的断言便可能无法通过:
-
-```ts
-const argument = {
- value: 0,
-}
-const fn = vi.fn()
-fn(argument) // { value: 0 }
-
-argument.value = 10
-
-expect(fn).toHaveBeenCalledWith({ value: 0 }) // [!code --]
-
-// 相等性检查是针对原始参数进行的,
-// 但是,该参数的属性在调用和断言之间发生了更改。
-expect(fn).toHaveBeenCalledWith({ value: 10 }) // [!code ++]
-```
-
-此时,可先自行克隆该参数:
-
-```ts{6}
-const calledArguments = []
-const fn = vi.fn((arg) => {
- calledArguments.push(structuredClone(arg))
-})
-
-expect(calledArguments[0]).toEqual({ value: 0 })
-```
-:::
-
## mock.lastCall
```ts
@@ -491,11 +460,6 @@ fn.mock.results
## mock.settledResults
```ts
-interface MockSettledResultIncomplete {
- type: 'incomplete'
- value: undefined
-}
-
interface MockSettledResultFulfilled {
type: 'fulfilled'
value: T
@@ -509,16 +473,13 @@ interface MockSettledResultRejected {
export type MockSettledResult
= | MockSettledResultFulfilled
| MockSettledResultRejected
- | MockSettledResultIncomplete
const settledResults: MockSettledResult>>[]
```
-该数组按顺序记录了函数每次被调用后最终兑现或拒绝的值。
-
-若函数返回的是非 Promise ,实际值会原封不动地保留,但状态仍被标记为 `fulfilled` 或 `rejected`。
+包含函数中 `resolved` 或 `rejected` 的所有值的数组。
-在结果出来前,对应的 `settledResult` 类型始终为 `incomplete`。
+如果函数从未 resolved 或 rejected ,则此数组将为空。
```js
const fn = vi.fn().mockResolvedValueOnce('result')
diff --git a/api/vi.md b/api/vi.md
index a2860833..221a80fe 100644
--- a/api/vi.md
+++ b/api/vi.md
@@ -4,33 +4,20 @@ outline: deep
# Vi
-Vitest 通过其 `vi` 辅助工具提供实用功能来帮助你。可以全局访问它(当启用 [globals 配置](/config/#globals) 时),也可以直接从 `vitest` 中导入:
+Vitest 通过 `vi` 工具函数提供实用功能。可以全局访问它(当启用 [globals 配置](/config/#globals) 时),也可以直接从 `vitest` 中导入:
```js
import { vi } from 'vitest'
```
-## 模拟模块 {#mock-modules}
+## Mock Modules
本节介绍在 [模拟模块](/guide/mocking#modules) 时可以使用的 API。请注意,Vitest 不支持模拟使用 `require()` 导入的模块。
### vi.mock
-```ts
-interface MockOptions {
- spy?: boolean
-}
-
-interface MockFactory {
- (importOriginal: () => T): unknown
-}
-
-function mock(path: string, factory?: MockOptions | MockFactory): void
-function mock(
- module: Promise,
- factory?: MockOptions | MockFactory
-): void
-```
+- **类型**: `(path: string, factory?: MockOptions | ((importOriginal: () => unknown) => unknown)) => void`
+- **类型**: `(path: Promise, factory?: MockOptions | ((importOriginal: () => T) => T | Promise)) => void`
用另一个模块替换提供的 `path` 中的所有导入模块。我们可以在路径内使用配置的 Vite 别名。对 `vi.mock` 的调用是悬挂式的,因此在何处调用并不重要。它总是在所有导入之前执行。如果需要在其作用域之外引用某些变量,可以在 [`vi.hoisted`](/api/vi#vi-hoisted)中定义它们,并在 `vi.mock` 中引用它们。
@@ -44,6 +31,8 @@ Vitest 不会模拟 [setup file](/config/#setupfiles) 中导入的模块,因
如果定义了 `factory` 函数,所有导入都将返回其结果。Vitest 只调用一次 factory,并缓存所有后续导入的结果,直到 [`vi.unmock`](#vi-unmock) 或 [`vi.doUnmock`](#vi-dounmock) 被调用。
+与 `jest` 不同, 该工厂函数是可以异步的。你可以通过 [`vi.importActual`](#vi-importactual) 或传入工厂函数作为首个参数的工具方法,在内部获取原始模块。
+
我们还可以提供一个具有 `spy` 属性的对象,而不是工厂函数。如果 `spy` 为 `true`,则 Vitest 将照常自动模拟模块,但不会覆盖导出的实现。如果我们只想断言导出的方法已被另一种方法正确调用,这将非常有用。
```ts
@@ -59,7 +48,6 @@ expect(result).toBe(3)
expect(calculator).toHaveBeenCalledWith(1, 2)
expect(calculator).toHaveReturned(3)
```
-
Vitest 还在 `vi.mock` 和 `vi.doMock` 方法中支持 module promise 而非字符串,以获得更好的集成开发环境支持。当文件被移动时,路径会被更新,`importOriginal` 也会自动继承类型。使用此签名还将强制工厂返回类型与原始模块兼容(但每次导出都是可选的)。
```ts
@@ -119,7 +107,7 @@ vi.mock('./path/to/module.js', () => {
return {
default: { myDefaultKey: vi.fn() },
namedExport: vi.fn(),
- // ...
+ // etc...
}
})
```
@@ -143,11 +131,11 @@ vi.mock('./path/to/module.js', () => {
如果在没有提供工厂或选项的测试文件中调用 `vi.mock` ,它会在 `__mocks__` 文件夹中找到一个文件作为模块使用:
```ts [increment.test.js]
+import { vi } from 'vitest'
+
// axios 是 `__mocks__/axios.js` 默认导出项
import axios from 'axios'
-import { vi } from 'vitest'
-
// increment 是 `src/__mocks__/increment.js` 具名导出
import { increment } from '../increment.js'
@@ -162,20 +150,12 @@ axios.get(`/apples/${increment(1)}`)
请注意,如果不调用 `vi.mock` ,模块**不会**被自动模拟。要复制 Jest 的自动锁定行为,可以在 [`setupFiles`](/config/#setupfiles) 中为每个所需的模块调用 `vi.mock` 。
:::
-如果没有提供 `__mocks__` 文件夹或未提供工厂函数,Vitest 将导入原始模块并自动模拟其所有导出。有关应用的规则,请参阅[算法](/guide/mocking/modules#automocking-algorithm)。
+如果没有提供 `__mocks__` 文件夹或工厂,Vitest 将导入原始模块并自动模拟其所有输出。有关应用的规则,请参阅 [模块](/guide/mocking#automocking-algorithm)。
### vi.doMock
-```ts
-function doMock(
- path: string,
- factory?: MockOptions | MockFactory
-): void
-function doMock(
- module: Promise,
- factory?: MockOptions | MockFactory
-): void
-```
+- **类型**: `(path: string, factory?: MockOptions | ((importOriginal: () => unknown) => unknown)) => void`
+- **类型**: `(path: Promise, factory?: MockOptions | ((importOriginal: () => T) => T | Promise)) => void`
与 [`vi.mock`](#vi-mock) 相同,但它不会被移动到文件顶部,因此我们可以引用全局文件作用域中的变量。模块的下一个 [动态导入](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) 将被模拟。
@@ -224,16 +204,8 @@ test('importing the next module imports mocked one', async () => {
### vi.mocked
-```ts
-function mocked(
- object: T,
- deep?: boolean
-): MaybeMockedDeep
-function mocked(
- object: T,
- options?: { partial?: boolean, deep?: boolean }
-): MaybePartiallyMockedDeep
-```
+- **类型**: `(obj: T, deep?: boolean) => MaybeMockedDeep`
+- **类型**: `(obj: T, options?: { partial?: boolean; deep?: boolean }) => MaybePartiallyMockedDeep`
TypeScript 的类型助手。只返回传入的对象。
@@ -270,9 +242,7 @@ test('mock return value with only partially correct typing', async () => {
### vi.importActual
-```ts
-function importActual(path: string): Promise
-```
+- **类型**: `(path: string) => Promise`
导入模块,绕过模块是否应被模拟的所有检查。如果我们想部分模拟模块,这一点很有用。
@@ -286,25 +256,19 @@ vi.mock('./example.js', async () => {
### vi.importMock
-```ts
-function importMock(path: string): Promise>
-```
+- **类型**: `(path: string) => Promise>`
-导入模块并模拟其所有属性(包括嵌套属性)。遵循与 [`vi.mock`](#vi-mock) 相同的规则。有关应用的规则,请参阅[算法](/guide/mocking/modules#automocking-algorithm)。
+导入模块并模拟其所有属性(包括嵌套属性)。遵循与 [`vi.mock`](#vi-mock) 相同的规则。有关应用的规则,请参阅 [模块](/guide/mocking#automocking-algorithm)。
### vi.unmock
-```ts
-function unmock(path: string | Promise): void
-```
+- **类型**: `(path: string | Promise) => void`
从模拟注册表中删除模块。所有导入调用都将返回原始模块,即使该模块之前已被模拟。该调用会被移动到文件顶端,因此只会解除在 `setupFiles` 中定义的模块。
### vi.doUnmock
-```ts
-function doUnmock(path: string | Promise): void
-```
+- **类型**: `(path: string | Promise) => void`
与 [`vi.unmock`](#vi-unmock) 相同,但不会移动到文件顶端。下一次导入模块时,将导入原始模块而非 mock。这不会解除先前导入的模块。
@@ -343,9 +307,7 @@ unmockedIncrement(30) === 31
### vi.resetModules
-```ts
-function resetModules(): Vitest
-```
+- **类型**: `() => Vitest`
通过清除所有模块的缓存来重置模块注册表。这样就可以在重新导入模块时对模块进行重新评估。顶层导入无法重新评估。这可能有助于隔离测试之间存在本地状态冲突的模块。
@@ -376,10 +338,6 @@ test('module has old state', async () => {
### vi.dynamicImportSettled
-```ts
-function dynamicImportSettled(): Promise
-```
-
等待加载所有导入模块。如果有同步调用开始导入一个模块,而如果不这样做就无法等待,那么它就很有用。
```ts
@@ -405,15 +363,13 @@ test('operations are resolved', async () => {
该方法还将在导入解析后等待下一个 `setTimeout` 跟他挂钩,因此所有同步操作都应在解析时完成。
:::
-## 模拟函数和对象
+## 模拟函数和对象 {#mocking-functions-and-objects}
本节介绍如何使用 [method mock](/api/mock) 替换环境变量和全局变量。
### vi.fn
-```ts
-function fn(fn?: Procedure | Constructable): Mock
-```
+- **类型:** `(fn?: Function) => Mock`
创建函数的监视程序,但也可以不创建监视程序。每次调用函数时,它都会存储调用参数、返回值和实例。此外,我们还可以使用 [methods](/api/mock) 操纵它的行为。
如果没有给出函数,调用 mock 时将返回 `undefined`。
@@ -433,32 +389,17 @@ expect(res).toBe(5)
expect(getApples).toHaveNthReturnedWith(2, 5)
```
-`vi.fn` 同样支持传入 class 作为参数:
-
-```ts
-const Cart = vi.fn(
- class {
- get = () => 0
- }
-)
-
-const cart = new Cart()
-expect(Cart).toHaveBeenCalled()
-```
-
### vi.mockObject 3.2.0
-```ts
-function mockObject(value: T): MaybeMockedDeep
-```
+- **Type:** `(value: T) => MaybeMockedDeep`
-它与 `vi.mock()` 模拟模块相同,深层模拟给定对象的属性和方法。详见[自动模拟](/guide/mocking.html#automocking-algorithm)。
+它与 `vi.mock()` 模拟模块相同,深层模拟给定对象的属性和方法。详见 [自动模拟](/guide/mocking#automocking-algorithm)。
```ts
const original = {
simple: () => 'value',
nested: {
- method: () => 'real',
+ method: () => 'real'
},
prop: 'foo',
}
@@ -475,69 +416,30 @@ expect(mocked.simple()).toBe('mocked')
expect(mocked.nested.method()).toBe('mocked nested')
```
-就像 `vi.mock()` 一样,可以传递 `{ spy: true }` 作为第二个参数,以保持函数实现:
-
-```ts
-const spied = vi.mockObject(original, { spy: true })
-expect(spied.simple()).toBe('value')
-expect(spied.simple).toHaveBeenCalled()
-expect(spied.simple.mock.results[0]).toEqual({
- type: 'return',
- value: 'value',
-})
-```
-
### vi.isMockFunction
-```ts
-function isMockFunction(fn: unknown): asserts fn is Mock
-```
+- **类型:** `(fn: Function) => boolean`
检查给定参数是否为 mock 函数。如果使用的是 TypeScript ,它还会缩小参数类型的范围。
### vi.clearAllMocks
-```ts
-function clearAllMocks(): Vitest
-```
-
对所有 spies 调用 [`.mockClear()`](/api/mock#mockclear)。
这将清除模拟的历史记录,但不影响模拟的实现。
### vi.resetAllMocks
-```ts
-function resetAllMocks(): Vitest
-```
-
对所有 spies 调用 [`.mockReset()`](/api/mock#mockreset)。
这将清除模拟的历史记录,并将每个模拟的实现重置为其原始状态。
### vi.restoreAllMocks
-```ts
-function restoreAllMocks(): Vitest
-```
-
-该方法会一次性恢复所有由 [`vi.spyOn`](#vi-spyon) 创建的 spy 的原始实现。
-
-一旦完成还原,即可重新对其进行监视。
-
-::: warning
-该方法同样不会触及 [automocking](/guide/mocking/modules#mocking-a-module) 期间生成的任何 mock。
-
-注意:与 [`mock.mockRestore`](/api/mock#mockrestore) 不同,`vi.restoreAllMocks` 既不会清空调用历史,也不会重置 mock 的实现。
-:::
+对所有 spies 调用 [`.mockRestore()`](/api/mock#mockrestore)。
+这将清除模拟的历史记录,恢复所有原始模拟实现,并恢复被监视对象的原始描述符。
### vi.spyOn
-```ts
-function spyOn(
- object: T,
- key: K,
- accessor?: 'get' | 'set'
-): Mock
-```
+- **类型:** `(object: T, method: K, accessType?: 'get' | 'set') => MockInstance`
创建与 [`vi.fn()`](#vi-fn) 类似的对象的方法或 getter/setter 的监听(spy) 。它会返回一个 [mock 函数](/api/mock) 。
@@ -556,36 +458,6 @@ expect(spy).toHaveBeenCalled()
expect(spy).toHaveReturnedWith(1)
```
-若被监视的方法为类定义,则 mock 实现必须使用 `function` 或 `class` 关键字。
-
-```ts {12-14,16-20}
-const cart = {
- Apples: class Apples {
- getApples() {
- return 42
- }
- },
-}
-
-const spy = vi
- .spyOn(cart, 'Apples')
- .mockImplementation(() => ({ getApples: () => 0 })) // [!code --]
- // 使用函数关键字
- .mockImplementation(function () {
- this.getApples = () => 0
- })
- // 使用自定义类
- .mockImplementation(
- class MockApples {
- getApples() {
- return 0
- }
- }
- )
-```
-
-如果传入箭头函数, mock 被调用时将抛出 [` is not a constructor` 错误](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Not_a_constructor)。
-
::: tip
若运行环境支持 [显式资源管理](https://github.com/tc39/proposal-explicit-resource-management) ,可将 `const` 替换为 `using`。离开当前块级作用域时,系统会自动对被 mock 的函数调用 `mockRestore`,特别适用于已打 spy 的方法。
@@ -595,13 +467,12 @@ it('calls console.log', () => {
debug('message')
expect(spy).toHaveBeenCalled()
})
-// console.log 在此处还原
+// console.log is restored here
```
-
:::
::: tip
-在每个测试后,于 [`afterEach`](/api/#aftereach) 中调用 [`vi.restoreAllMocks`](#vi-restoreallmocks) 或开启配置项 [`test.restoreMocks`](/config/#restoreMocks),即可将所有方法还原为原始实现。此操作会恢复其 [对象描述符](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty),除非重新对其进行 spy ,否则无法再次修改方法实现。
+你可以在 [`afterEach`](/api/#aftereach)(或启用 [`test.restoreMocks`](/config/#restoreMocks) )中调用 [`vi.restoreAllMocks`](#vi-restoreallmocks) ,将所有方法还原为原始实现。这将还原原始的 [object descriptor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) ,因此无法更改方法的实现:
```ts
const cart = {
@@ -614,7 +485,7 @@ console.log(cart.getApples()) // 10
vi.restoreAllMocks()
console.log(cart.getApples()) // 42
spy.mockReturnValue(10)
-console.log(cart.getApples()) // 仍然为 42!
+console.log(cart.getApples()) // still 42!
```
:::
@@ -638,12 +509,7 @@ expect(calculator).toHaveReturned(3)
### vi.stubEnv {#vi-stubenv}
-```ts
-function stubEnv(
- name: T,
- value: T extends 'PROD' | 'DEV' | 'SSR' ? boolean : string | undefined
-): Vitest
-```
+- **类型:** `(name: T, value: T extends "PROD" | "DEV" | "SSR" ? boolean : string | undefined) => Vitest`
更改 `process.env` 和 `import.meta.env` 中环境变量的值。我们可以调用 `vi.unstubAllEnvs` 恢复其值。
@@ -678,9 +544,7 @@ import.meta.env.MODE = 'test'
### vi.unstubAllEnvs {#vi-unstuballenvs}
-```ts
-function unstubAllEnvs(): Vitest
-```
+- **类型:** `() => Vitest`
恢复通过 `vi.stubEnv` 更改的所有 `import.meta.env` 和 `process.env` 值。首次调用时,Vitest 会记住并保存原始值,直到再次调用 `unstubAllEnvs`。
@@ -709,9 +573,7 @@ import.meta.env.NODE_ENV === 'development'
### vi.stubGlobal
-```ts
-function stubGlobal(name: string | number | symbol, value: unknown): Vitest
-```
+- **类型:** `(name: string | number | symbol, value: unknown) => Vitest`
更改全局变量的值。我们可以调用 `vi.unstubAllGlobals` 恢复其原始值。
@@ -729,7 +591,7 @@ window.innerWidth === 100
```
:::tip
-我们也可以通过简单地将其赋值给 `globalThis` 或 `window`(如果你正在使用 `jsdom` 或 `happy-dom` 环境)来更改该值,但无法使用 `vi.unstubAllGlobals` 恢复原始值:
+我们也可以通过简单地将其赋值给 `globalThis` 或 `window`(如果我们使用的是 `jsdom` 或 `happy-dom` 环境)来更改该值,但无法使用 `vi.unstubAllGlobals` 恢复原始值:
```ts
globalThis.innerWidth = 100
@@ -741,11 +603,9 @@ window.innerWidth = 100
### vi.unstubAllGlobals {#vi-unstuballglobals}
-```ts
-function unstubAllGlobals(): Vitest
-```
+- **类型:** `() => Vitest`
-恢复 `globalThis` / `global`(和 `window` / `top` / `self` / `parent `,如果我们使用的是 `jsdom` 或 `happy-dom` 环境)上所有被 `vi.stubGlobal` 更改过的全局值。第一次调用时,Vitest 会记住并保存原始值,直到再次调用 `unstubAllGlobals`。
+恢复 `globalThis`/`global`(和 `window`/`top`/`self`/`parent`,如果我们使用的是 `jsdom` 或 `happy-dom` 环境)上所有被 `vi.stubGlobal` 更改过的全局值。第一次调用时,Vitest 会记住并保存原始值,直到再次调用 `unstubAllGlobals`。
```ts
import { vi } from 'vitest'
@@ -772,13 +632,11 @@ IntersectionObserver === undefined
## Fake Timers
-本节介绍如何使用 [fake timers](/guide/mocking/timers) 。
+本节介绍如何使用 [模拟计时器](/guide/mocking#timers)。
### vi.advanceTimersByTime
-```ts
-function advanceTimersByTime(ms: number): Vitest
-```
+- **类型:** `(ms: number) => Vitest`
该方法将调用每个启动的定时器,直到超过指定的毫秒数或队列为空(以先到者为准)。
@@ -795,9 +653,7 @@ vi.advanceTimersByTime(150)
### vi.advanceTimersByTimeAsync
-```ts
-function advanceTimersByTimeAsync(ms: number): Promise
-```
+- **类型:** `(ms: number) => Promise`
该方法将调用每个已启动的定时器,直到超过指定的毫秒数或队列为空(以先到者为准)。这将包括异步设置的计时器。
@@ -814,9 +670,7 @@ await vi.advanceTimersByTimeAsync(150)
### vi.advanceTimersToNextTimer
-```ts
-function advanceTimersToNextTimer(): Vitest
-```
+- **类型:** `() => Vitest`
将调用下一个可用的定时器。在每次调用定时器之间进行断言非常有用。我们可以调用它来管理自己的定时器。
@@ -831,9 +685,7 @@ vi.advanceTimersToNextTimer() // 输出: 1
### vi.advanceTimersToNextTimerAsync
-```ts
-function advanceTimersToNextTimerAsync(): Promise
-```
+- **类型:** `() => Promise`
如果定时器是异步设置的,则会调用下一个可用的定时器并等待解决。在每次调用定时器之间进行断言非常有用。
@@ -848,11 +700,9 @@ await vi.advanceTimersToNextTimerAsync() // log: 2
await vi.advanceTimersToNextTimerAsync() // log: 3
```
-### vi.advanceTimersToNextFrame
+### vi.advanceTimersToNextFrame 2.1.0 {#vi-advancetimerstonextframe}
-```ts
-function advanceTimersToNextFrame(): Vitest
-```
+- **类型:** `() => Vitest`
与 [`vi.advanceTimersByTime`](https://vitest.dev/api/vi#vi-advancetimersbytime) 类似,但会将计时器推进当前使用 `requestAnimationFrame` 安排的回调执行所需的毫秒数。
@@ -870,49 +720,35 @@ expect(frameRendered).toBe(true)
### vi.getTimerCount
-```ts
-function getTimerCount(): number
-```
+- **类型:** `() => number`
获取等待计时器的数量。
### vi.clearAllTimers
-```ts
-function clearAllTimers(): void
-```
-
-立即取消所有已排程的计时器,使其不再执行。
+删除所有计划运行的计时器。这些定时器今后将不再运行。
### vi.getMockedSystemTime
-```ts
-function getMockedSystemTime(): Date | null
-```
+- **类型**: `() => Date | null`
返回模拟的当前日期。如果没有模拟日期,该方法将返回 `null`。
### vi.getRealSystemTime
-```ts
-function getRealSystemTime(): number
-```
+- **类型**: `() => number`
使用 `vi.useFakeTimers` 时,会模拟 `Date.now` 调用。如果需要以毫秒为单位获取实时时间,可以调用此函数。
### vi.runAllTicks
-```ts
-function runAllTicks(): Vitest
-```
+- **类型:** `() => Vitest`
调用由 `process.nextTick` 排在队列中的每个微任务。这也将运行所有自己安排的微任务。
### vi.runAllTimers
-```ts
-function runAllTimers(): Vitest
-```
+- **类型:** `() => Vitest`
该方法将调用每个已经启动的定时器,直到定时器队列为空。这意味着在 `runAllTimers` 期间调用的每个定时器都会被触发。如果时间间隔为无限,则会在尝试 10000 次后触发(可使用 [`fakeTimers.loopLimit`](/config/#faketimers-looplimit) 进行配置)。
@@ -935,9 +771,7 @@ vi.runAllTimers()
### vi.runAllTimersAsync
-```ts
-function runAllTimersAsync(): Promise
-```
+- **类型:** `() => Promise`
该方法将异步调用每个已启动的定时器,直到定时器队列为空。这意味着在 `runAllTimersAsync` 期间调用的每个定时器都会被触发,即使是异步定时器。如果我们有一个无限的时间间隔、
会在尝试 10000 次后抛出(可使用 [`fakeTimers.loopLimit`](/config/#faketimers-looplimit) )。
@@ -954,9 +788,7 @@ await vi.runAllTimersAsync()
### vi.runOnlyPendingTimers
-```ts
-function runOnlyPendingTimers(): Vitest
-```
+- **类型:** `() => Vitest`
此方法将调用 [`vi.useFakeTimers`](#vii-usefaketimers) 调用后启动的所有计时器。它不会调用在调用期间启动的任何计时器。
@@ -971,9 +803,7 @@ vi.runOnlyPendingTimers()
### vi.runOnlyPendingTimersAsync
-```ts
-function runOnlyPendingTimersAsync(): Promise
-```
+- **类型:** `() => Promise`
此方法将异步调用 [`vi.useFakeTimers`](#vi-usefaketimers) 调用后启动的每个定时器,即使是异步定时器。它不会触发任何在调用期间启动的定时器。
@@ -1000,13 +830,11 @@ await vi.runOnlyPendingTimersAsync()
### vi.setSystemTime
-```ts
-function setSystemTime(date: string | number | Date): Vitest
-```
+- **类型**: `(date: string | number | Date) => void`
如果启用了伪计时器,此方法将模拟用户更改系统时钟(将影响与日期相关的 API,如 `hrtime` 、`performance.now` 或 `new Date()` ),但不会触发任何计时器。如果未启用假定时器,该方法将仅模拟 `Date.*` 调用。
-如果我们需要测试任何依赖于当前日期的内容 -- 例如在代码中调用 [luxon](https://github.com/moment/luxon/) --则非常有用。
+适用于需要测试依赖当前日期的场景,例如代码中的 [Luxon](https://github.com/moment/luxon/) 库调用。
接受与 `Date` 相同的字符串和数字参数。
@@ -1023,9 +851,7 @@ vi.useRealTimers()
### vi.useFakeTimers
-```ts
-function useFakeTimers(config?: FakeTimerInstallOpts): Vitest
-```
+- **类型:** `(config?: FakeTimerInstallOpts) => Vitest`
要启用模拟定时器,需要调用此方法。在调用 [`vi.useRealTimers()`](#vi-userealtimers) 之前,它将封装所有对定时器的进一步调用(如 `setTimeout` 、`setInterval` 、`clearTimeout` 、`clearInterval` 、`setImmediate` 、`clearImmediate` 和 `Date`)。
@@ -1040,32 +866,23 @@ function useFakeTimers(config?: FakeTimerInstallOpts): Vitest
### vi.isFakeTimers {#vi-isfaketimers}
-```ts
-function isFakeTimers(): boolean
-```
+- **类型:** `() => boolean`
-如果启用了假计时器,则返回 `true` 。
+如果启用了模拟计时器,则返回 `true` 。
### vi.useRealTimers
-```ts
-function useRealTimers(): Vitest
-```
+- **类型:** `() => Vitest`
当定时器用完后,我们可以调用此方法将模拟的计时器返回到其原始实现。之前调度的计时器都将被丢弃。
-## 辅助函数{#miscellaneous}
+## Miscellaneous
Vitest 提供的一组有用的辅助函数。
### vi.waitFor {#vi-waitfor}
-```ts
-function waitFor(
- callback: WaitForCallback,
- options?: number | WaitForOptions
-): Promise
-```
+- **类型:** `(callback: WaitForCallback, options?: number | WaitForOptions) => Promise`
等待回调成功执行。如果回调抛出错误或返回拒绝的承诺,它将继续等待,直到成功或超时。
@@ -1126,20 +943,15 @@ test('Element exists in a DOM', async () => {
})
```
-一旦通过 `vi.useFakeTimers` 启用假计时器,`vi.waitFor` 将在每次轮询时自动调用 `vi.advanceTimersByTime(interval)` 推进时间。
+如果使用了 `vi.useFakeTimers` , `vi.waitFor` 会在每次检查回调中自动调用 `vi.advanceTimersByTime(interval)` 。
-### vi.waitUntil {#vi-waituntil}
+### vi.waitUntil
-```ts
-function waitUntil(
- callback: WaitUntilCallback,
- options?: number | WaitUntilOptions
-): Promise
-```
+- **类型:** `(callback: WaitUntilCallback, options?: number | WaitUntilOptions) => Promise`
-与 `vi.waitFor` 类似,但若回调抛出错误会立即中断并给出报错;若回调返回假值,则持续轮询直至返回真值。适用于“先等某物出现再行动”的场景。
+这与 `vi.waitFor` 类似,但如果回调抛出任何错误,执行将立即中断并收到一条错误信息。如果回调返回虚假值(falsy) ,下一次检查将继续,直到返回真实值(truthy) 。这在需要等待某项内容存在后再执行下一步时非常有用。
-下面的示例,我们可以使用 `vi.waitUntil` 等待元素出现在页面上,然后再对该元素进行操作。
+请看下面的示例。我们可以使用 `vi.waitUntil` 等待元素出现在页面上,然后对元素进行操作。
```ts
import { expect, test, vi } from 'vitest'
@@ -1149,17 +961,15 @@ test('Element render correctly', async () => {
timeout: 500, // 默认为 1000
interval: 20, // 默认为 50
})
- expect(element).toBeInstanceOf(HTMLElement)
+
+ // 对元素执行操作
+ expect(element.querySelector('.element-child')).toBeTruthy()
})
```
-如果使用了 `vi.useFakeTimers` , `vi.waitFor` 会在每次检查回调中自动调用 `vi.advanceTimersByTime(interval)` 。
-
### vi.hoisted {#vi-hoisted}
-```ts
-function hoisted(factory: () => T): T
-```
+- **类型**: `(factory: () => T) => T`
ES 模块中的所有静态 `import` 语句都被提升到文件顶部,因此在导入之前定义的任何代码都将在导入评估之后执行。
@@ -1187,9 +997,7 @@ import { value } from './some/module.js'
```ts
import { value } from './some/module.js'
-vi.hoisted(() => {
- value
-}) // 抛出一个错误 // [!code warning]
+vi.hoisted(() => { value }) // 抛出一个错误 // [!code warning]
```
此代码将产生错误:
@@ -1238,9 +1046,7 @@ const json = await vi.hoisted(async () => {
### vi.setConfig
-```ts
-function setConfig(config: RuntimeOptions): void
-```
+- **类型**: `RuntimeConfig`
更新当前测试文件的配置。此方法只会影响当前测试文件的配置选项:
@@ -1265,8 +1071,6 @@ vi.setConfig({
### vi.resetConfig
-```ts
-function resetConfig(): void
-```
+- **类型**: `RuntimeConfig`
如果之前调用过 [`vi.setConfig`](#vi-setconfig) ,则会将配置重置为原始状态。
diff --git a/config/index.md b/config/index.md
index 9acd9040..11e1e275 100644
--- a/config/index.md
+++ b/config/index.md
@@ -2,7 +2,7 @@
outline: deep
---
-# 配置索引 {#configuring-vitest}
+# 配置 Vitest {#configuring-vitest}
如果我们正在使用 Vite 并且拥有一个 `vite.config` 文件,Vitest 会读取它来匹配我们的 Vite 应用的插件和设置。如果我们想要为测试配置不同的设置,或者我们的并不特别依赖于 Vite,我们我们可以选择:
@@ -12,7 +12,7 @@ outline: deep
要配置 Vitest 本身,请在我们的 Vite 配置中添加 `test` 属性。如果我们是从 `vite` 本身导入 `defineConfig`,我们还需要在配置文件顶部使用[三斜杠指令](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html#-reference-types-)添加对 Vitest 类型引用。
-::: details Open Config Examples
+::: details 打开配置示例
使用 `vite` 中的 `defineConfig` 时使用以下步骤:
```ts [vite.config.js]
@@ -104,7 +104,7 @@ export default defineConfig({
})
```
-由于 Vitest 使用 Vite 的配置,我们也可以使用 [Vite](https://vitejs.dev/config/) 中的任何配置选项。例如,使用 `define` 来定义全局变量,或者使用 `resolve.alias` 来定义别名——这些选项应该在顶级定义,而不是在 `test` 属性内部。
+由于 Vitest 使用 Vite 的配置,我们也可以使用 [Vite](https://vitejs.dev/config/) 中的任何配置选项。例如,使用 `define` 来定义全局变量,或者使用 `resolve.alias` 来定义别名,这些选项应该在顶级定义,而不是在 `test` 属性内部。
在 [项目](/guide/projects) 配置里不被支持的选项,会在旁边标注 。这表示这些选项只能在 Vitest 的根配置中进行设置。
:::
@@ -113,6 +113,7 @@ export default defineConfig({
- **类型:** `string[]`
- **默认值:** `['**/*.{test,spec}.?(c|m)[jt]s?(x)']`
+- **命令行终端:** `vitest [...include], vitest **/*.test.js`
匹配包含测试文件的 glob 规则。
@@ -123,11 +124,17 @@ export default defineConfig({
### exclude
- **类型:** `string[]`
-- **默认值:** `['**/node_modules/**', '**/.git/**']`
-- **命令行终端:** `vitest --exclude "**/excluded-file" --exclude "*/other-files/*.js"`
+- **默认值:** `['**/node_modules/**', '**/dist/**', '**/cypress/**', '**/.{idea,git,cache,output,temp}/**', '**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build,eslint,prettier}.config.*']`
+- **命令行终端:** `vitest --exclude "**/excluded-file"`
匹配排除测试文件的 glob 规则。
+::: warning
+该选项不会影响代码覆盖率。如需从覆盖率报告中排除特定文件,请使用 [`coverage.exclude`](#coverage-exclude)。
+
+如果使用命令行参数,这是唯一一个不会被覆盖配置的选项的参数。通过 `--exclude` 标志添加的所有 glob 规则都将追加到 `exclude` 中。
+:::
+
### includeSource
- **类型:** `string[]`
@@ -192,7 +199,7 @@ Vite-Node 调试器选项。
这些选项支持在 `node_modules` 中编写的包名称或在 [`deps.moduleDirectories`](#deps-moduledirectories) 中指定的包名称。例如,位于 `packages/some-name` 内的包`@company/some-name` 应指定为 `some-name`,并且 `packages` 应包含在 `deps.moduleDirectories` 中。基本上,Vitest 总是检查文件路径,而不是实际的包名称。
-如果成功匹配,Vitest 会在 _file path_ 上调用它,而不是包名称。
+如果使用正则匹配,Vitest 会在 _file path_ 上调用它,而不是包名称。
#### server.deps.inline
@@ -225,10 +232,10 @@ Vite 将处理内联模块。这可能有助于处理以 ESM 格式传送 `.js`
处理依赖关系解析。
-#### deps.optimizer {#deps-optimizer}
+#### deps.optimizer
- **类型:** `{ ssr?, client? }`
-- **参考:** [Dep Optimization Options](https://vitejs.dev/config/dep-optimization-options.html)
+- **参考:** [依赖优化选项](https://vitejs.dev/config/dep-optimization-options.html)
启用依赖优化。如果你有很多测试,这可能会提高它们的性能。
@@ -239,13 +246,7 @@ Vite 将处理内联模块。这可能有助于处理以 ESM 格式传送 `.js`
- 你的 `alias` 配置现在在捆绑包中得到处理
- 测试中的代码更接近于它在浏览器中的运行方式
-仅当包名出现在 `deps.optimizer?.[mode].include` 中时,才会被预打包(如 Svelte 等插件会自动填充)。完整选项见 [Vite 文档](https://cn.vitejs.dev/config/dep-optimization-options.html)(Vitest 暂不支持 `disable` 与 `noDiscovery`)。
-
-默认策略:
-
-- `jsdom` / `happy-dom` → `optimizer.client`
-
-- `node` / `edge` → `optimizer.ssr`
+请注意,只有 `deps.experimentalOptimizer?.[mode].include` 选项中的包会被捆绑(一些插件会自动填充它,比如 Svelte)。 你可以在 [Vite](https://cn.vitejs.dev/config/dep-optimization-options.html) 文档中阅读有关可用选项的更多信息。默认情况,Vitest 的 `experimentalOptimizer.web` 用在 `jsdom` 和 `happy-dom`, 在 `node` 和 `edge` 环境下使用 `experimentalOptimizer.ssr`,但这可以在 [`transformMode`](#transformmode) 进行配置。
此选项还继承了你的 `optimizeDeps` 配置(对于 web 环境, Vitest 将会继承 `optimizeDeps`,对于 ssr 则是 `ssr.optimizeDeps`)。如果你在 `deps.experimentalOptimizer` 中重新定义 `include`/`exclude`/`entries` 选项,它将在运行测试时覆盖你的 `optimizeDeps`。如果它们在 `exclude` 中配置,Vitest 会自动从 `include` 中删除相同的选项。
@@ -260,27 +261,14 @@ Vite 将处理内联模块。这可能有助于处理以 ESM 格式传送 `.js`
启用依赖优化。
-#### deps.client {#deps-client}
-
-#### deps.web 0.34.2+
-
-仅当环境设为 `client` 时,下列选项才会作用于外部文件。
-
-默认映射:
-
-- `jsdom`、`happy-dom` → `client`
-
-- `node`、`edge` → `ssr`
-
-故这些选项对后者中的文件无效。
-
+#### deps.web
- **类型:** `{ transformAssets?, ... }`
当转换模式设置为 `web` 时应用于外部文件的选项。默认情况下,`jsdom` 和 `happy-dom` 使用 `web` 模式,而 `node` 和 `edge` 环境使用 `ssr` 转换模式,因此这些选项不会影响这些环境中的文件。
通常,`node_modules` 内的文件是外部化的,但这些选项也会影响 [`server.deps.external`](#server-deps-external) 中的文件。
-#### deps.client.transformAssets
+#### deps.web.transformAssets
- **类型:** `boolean`
- **默认值:** `true`
@@ -293,7 +281,7 @@ Vitest 是否应该像 Vite 在浏览器中一样处理静态资源(.png、.sv
目前,此选项适用于 [`vmThreads`](#vmthreads) 和 [`vmForks`](#vmForks) 池。
:::
-#### deps.client.transformCss
+#### deps.web.transformCss
- **类型:** `boolean`
- **默认值:** `true`
@@ -306,7 +294,7 @@ Vitest 是否应该像 Vite 在浏览器中一样处理静态资源(.css, .scs
目前,此选项仅适用于 [`vmThreads`](#vmthreads) 和 [`vmForks`](#vmForks) 池。
:::
-#### deps.client.transformGlobPattern
+#### deps.web.transformGlobPattern
- **类型:** `RegExp | RegExp[]`
- **默认值:** `[]`
@@ -368,9 +356,9 @@ export default defineConfig({
### runner
- **类型**: `VitestRunnerConstructor`
-- **默认值**: `node`, when running tests, or `benchmark`, when running benchmarks
+- **默认值**: 运行测试时为`node`,运行基准测试时为 `benchmark`
-自定义测试运行程序的路径。这是一项高级功能,应与自定义库运行器一起使用。你可以在 [文档](/advanced/runner) 中阅读更多相关信息。
+自定义测试运行器的路径。这是一项高级功能,应与自定义库运行器一起使用。你可以在 [文档](/advanced/runner) 中阅读更多相关信息。
### benchmark
@@ -431,7 +419,7 @@ git checkout feature
vitest bench --compare main.json
```
-#### benchmark.compare {#benchmark-compare}
+#### benchmark.compare
- **类型:** `string | undefined`
- **默认值:** `undefined`
@@ -445,12 +433,12 @@ vitest bench --compare main.json
在测试内部运行时定义自定义别名。它们将与来自 `resolve.alias` 的别名合并。
::: warning
-Vitest 使用 Vite SSR 基元来运行测试,这有[一定的缺陷](https://vitejs.dev/guide/ssr.html#ssr-externals)。
+Vitest 使用 Vite SSR 基元来运行测试,这有 [一定的缺陷](https://vitejs.dev/guide/ssr.html#ssr-externals)。
-1. 别名只影响由[inlined](#server-deps-inline)模块直接用`import`关键字导入的模块(默认情况下所有源代码都是内联的)。
+1. 别名只影响由 [inlined](#server-deps-inline) 模块直接用 `import` 关键字导入的模块(默认情况下所有源代码都是内联的)。
2. Vitest 不支持对 `require` 调用进行别名。
3. 如果我们要别名外部依赖(例如,`react` -> `preact`),我们可能需要别名实际的 `node_modules` 包,以使其适用于外部依赖。[Yarn](https://classic.yarnpkg.com/en/docs/cli/add/#toc-yarn-add-alias) 和 [pnpm](https://pnpm.io/aliases/) 都支持通过 `npm:` 前缀进行别名。
- :::
+:::
### globals
@@ -583,7 +571,7 @@ export default {
Vitest 还通过 `vitest/environments` 入口导出 `builtinEnvironments`,以防你只想扩展它。 你可以在 [测试环境指南](/guide/environment) 中阅读有关扩展测试环境的更多信息。
::: tip
-jsdom 环境变量导出了等同于当前[JSDOM](https://github.com/jsdom/jsdom) 的 `jsdom` 全局变量实例。如果你想让 TypeScript 识别它,可以在使用此环境时将 `vitest/jsdom`添加到 `tsconfig.json` 中:
+jsdom 环境变量导出了等同于当前 [JSDOM](https://github.com/jsdom/jsdom) 的 `jsdom` 全局变量实例。如果你想让 TypeScript 识别它,可以在使用此环境时将 `vitest/jsdom`添加到 `tsconfig.json` 中:
```json [tsconfig.json]
{
@@ -602,6 +590,101 @@ jsdom 环境变量导出了等同于当前[JSDOM](https://github.com/jsdom/jsdom
这些选项被传递给当前 [`environment`](#environment) 的 `setup` 方法。 默认情况下,如果你将其用作测试环境,则只能配置 JSDOM 选项。
+### environmentMatchGlobs
+
+- **类型:** `[string, EnvironmentName][]`
+- **默认值:** `[]`
+
+::: danger DEPRECATED
+此 API 在 Vitest 3 中已弃用。请使用 [projects](/guide/projects) 来定义不同的配置。
+
+```ts
+export default defineConfig({
+ test: {
+ environmentMatchGlobs: [ // [!code --]
+ ['./*.jsdom.test.ts', 'jsdom'], // [!code --]
+ ], // [!code --]
+ workspace: [ // [!code ++]
+ { // [!code ++]
+ extends: true, // [!code ++]
+ test: { // [!code ++]
+ environment: 'jsdom', // [!code ++]
+ }, // [!code ++]
+ }, // [!code ++]
+ ], // [!code ++]
+ },
+})
+```
+:::
+
+基于 globs 自动匹配执行环境。将使用第一个匹配项。
+
+例如:
+
+```ts
+import { defineConfig } from 'vitest/config'
+
+export default defineConfig({
+ test: {
+ environmentMatchGlobs: [
+ // `tests/dom` 目录中的所有测试将在 jsdom 中运行。
+ ['tests/dom/**', 'jsdom'],
+ // `tests/` 目录中所有以 `.edge.test.ts` 结尾的测试将在 edge-runtime 中运行。
+ ['**/*.edge.test.ts', 'edge-runtime'],
+ // ...
+ ],
+ },
+})
+```
+
+### poolMatchGlobs
+
+- **类型:** `[string, 'threads' | 'forks' | 'vmThreads' | 'vmForks' | 'typescript'][]`
+- **默认值:** `[]`
+
+::: danger DEPRECATED
+此 API 在 Vitest 3 中已被弃用。请使用 [projects](/guide/projects) 来定义不同的配置:
+
+```ts
+export default defineConfig({
+ test: {
+ poolMatchGlobs: [ // [!code --]
+ ['./*.threads.test.ts', 'threads'], // [!code --]
+ ], // [!code --]
+ workspace: [ // [!code ++]
+ { // [!code ++]
+ test: { // [!code ++]
+ extends: true, // [!code ++]
+ pool: 'threads', // [!code ++]
+ }, // [!code ++]
+ }, // [!code ++]
+ ], // [!code ++]
+ },
+})
+```
+:::
+
+基于 globs 模式来匹配运行池中的测试并运行,将使用第一个匹配项。
+
+例如:
+
+```ts
+import { defineConfig } from 'vitest/config'
+
+export default defineConfig({
+ test: {
+ poolMatchGlobs: [
+ // all tests in "worker-specific" directory will run inside a worker as if you enabled `--pool=threads` for them,
+ ['**/tests/worker-specific/**', 'threads'],
+ // run all tests in "browser" directory in an actual browser
+ ['**/tests/browser/**', 'browser'],
+ // all other tests will run based on "browser.enabled" and "threads" options, if you didn't specify other globs
+ // ...
+ ],
+ },
+})
+```
+
### update
- **类型:** `boolean`
@@ -673,17 +756,7 @@ export default defineConfig({
- **默认值:** `'default'`
- **命令行终端:** `--reporter=`, `--reporter= --reporter=`
-用于输出的自定义 reporters 。 Reporters 可以是 [一个 Reporter 实例](https://github.com/vitest-dev/vitest/blob/main/packages/vitest/src/node/types/reporter.ts) 或选择内置的 reporters 字符串:
-
-- `'default'` - 当他们经过测试套件
-- `'basic'` - 给定一个类似于 CI 中的默认报告实例
-- `'verbose'` - 保持完整的任务树可见
-- `'dot'` - 将每个任务显示为一个点
-- `'junit'` - JUnit XML 报告器(你可以使用 `VITEST_JUNIT_SUITE_NAME` 环境变量配置 `test suites` 标签名称)
-- `'json'` - 给出一个简单的 JSON 总结
-- `'html'` - 根据 [`@vitest/ui`](/guide/ui) 输出 HTML 报告
-- `'hanging-process'` - 如果 Vitest 无法安全退出进程,则显示挂起进程列表。 这可能是一个复杂的操作,只有在 Vitest 始终无法退出进程时才启用它
-- 自定义报告的路径 (例如 `'./path/to/reporter.ts'`, `'@scope/reporter'`)
+自定义 [报告器](/guide/reporters) 输出。报告器可以是 [Reporter 实例](https://github.com/vitest-dev/vitest/blob/main/packages/vitest/src/node/types/reporter.ts)、用于选择内置报告器的字符串,或自定义实现的路径(例如 `./path/to/reporter.ts`、`@scope/reporter`)。
### outputFile
@@ -692,7 +765,7 @@ export default defineConfig({
当指定 `--reporter=json`、`--reporter=html` 或 `--reporter=junit` 时,将测试结果写入一个文件。通过提供对象而不是字符串,你可以在使用多个报告器时定义单独的输出。
-### pool {#pool}
+### pool
- **类型:** `'threads' | 'forks' | 'vmThreads' | 'vmForks'`
- **默认值:** `'forks'`
@@ -710,9 +783,9 @@ export default defineConfig({
#### vmThreads
-在 `threads` 线程池中使用[ VM 上下文](https://nodejs.org/api/vm.html)(在受限环境中)运行测试。
+在 `threads` 线程池中使用 [VM 上下文](https://nodejs.org/api/vm.html)(在沙箱环境中)运行测试。
-这样可以加快测试速度,但是当运行[ ESM 代码](https://github.com/nodejs/node/issues/37648)时,VM 模块可能不稳定。你的测试可能会[泄漏内存](https://github.com/nodejs/node/issues/33439),为了解决这个问题,考虑手动编辑 [`poolOptions.vmThreads.memoryLimit`](#pooloptions-vmthreads-memorylimit) 的值。
+这样可以加快测试速度,但是当运行 [ESM 代码](https://github.com/nodejs/node/issues/37648) 时,VM 模块可能不稳定。你的测试可能会 [泄漏内存](https://github.com/nodejs/node/issues/33439),为了解决这个问题,考虑手动编辑 [`poolOptions.vmThreads.memoryLimit`](#pooloptions-vmthreads-memorylimit) 的值。
::: warning
在沙箱中运行代码有一些优点(测试速度更快),但也有许多缺点。
@@ -738,14 +811,14 @@ catch (err) {
与 `vmThreads` 池类似,但通过 [tinypool](https://github.com/tinylibs/tinypool) 使用 `child_process` 而不使用 `worker_threads`。测试与主进程之间的通信速度虽然不如 `vmThreads` 快。但进程相关的 API(如 `process.chdir()` )在 `vmForks` 中却可以使用。请注意,这个与 `vmThreads` 中列出的池具有相同的缺陷。
-### poolOptions {#pooloptions}
+### poolOptions
- **类型:** `Record<'threads' | 'forks' | 'vmThreads' | 'vmForks', {}>`
- **默认值:** `{}`
#### poolOptions.threads
-`threads` 池的选项。
+`threads` 池相关选项。
```ts
import { defineConfig } from 'vitest/config'
@@ -764,10 +837,17 @@ export default defineConfig({
##### poolOptions.threads.maxThreads
- **类型:** `number | string`
-- **默认值:** _available CPUs_
+- **默认值:** _可用 CPU 核心数_
最大线程数或百分比。还可以使用`VITEST_MAX_THREADS`环境变量进行设置。
+##### poolOptions.threads.minThreads
+
+- **类型:** `number | string`
+- **默认值:** _可用 CPU 核心数_
+
+最小线程数或百分比。还可以使用`VITEST_MIN_THREADS`环境变量进行设置。
+
##### poolOptions.threads.singleThread
- **类型:** `boolean`
@@ -810,7 +890,7 @@ export default defineConfig({
#### poolOptions.forks
-`forks` 池的选项。
+`forks` 池相关选项。
```ts
import { defineConfig } from 'vitest/config'
@@ -829,10 +909,17 @@ export default defineConfig({
##### poolOptions.forks.maxForks
- **类型:** `number | string`
-- **默认值:** _available CPUs_
+- **默认值:** _可用 CPU 核心数_
最大分支数量或百分比。你也可以使用 `VITEST_MAX_FORKS` 环境变量。
+##### poolOptions.forks.minForks
+
+- **类型:** `number | string`
+- **默认值:** _可用 CPU 核心数_
+
+最小分支数量或百分比。你也可以使用 `VITEST_MIN_FORKS` 环境变量。
+
##### poolOptions.forks.isolate
- **类型:** `boolean`
@@ -866,7 +953,7 @@ export default defineConfig({
#### poolOptions.vmThreads
-`vmThreads` 池的选项。
+`vmThreads` 池相关选项。
```ts
import { defineConfig } from 'vitest/config'
@@ -885,10 +972,17 @@ export default defineConfig({
##### poolOptions.vmThreads.maxThreads
- **类型:** `number | string`
-- **默认:** _available CPUs_
+- **默认值:** _可用 CPU 核心数_
最大线程数或百分比。还可以使用`VITEST_MAX_THREADS`环境变量进行设置。
+##### poolOptions.vmThreads.minThreads
+
+- **类型:** `number | string`
+- **默认值:** _可用 CPU 核心数_
+
+最小线程数或百分比。还可以使用`VITEST_MAX_THREADS`环境变量进行设置。
+
##### poolOptions.vmThreads.memoryLimit
- **类型:** `string | number`
@@ -906,15 +1000,17 @@ export default defineConfig({
- 有单位时
- `50%` - 如上,占系统总内存的百分比
- `100KB`, `65MB`, 等 - 用单位表示固定的内存限制
- - `K` / `KB` - Kilobytes (x1000)
- - `KiB` - Kibibytes (x1024)
- - `M` / `MB` - Megabytes - `MiB` - Mebibytes
- - `G` / `GB` - Gigabytes - `GiB` - Gibibytes
+ - `K` / `KB` - 千字节 (x1000)
+ - `KiB` - 千字节 (x1024)
+ - `M` / `MB`- 千字节
+ - `MiB` - 兆字节
+ - `G` / `GB` - 千兆字节
+ - `GiB` - 千兆字节
:::
::: warning
-由于系统内存报告不正确,基于百分比的内存限制[在 Linux CircleCI 上不起作用](https://github.com/jestjs/jest/issues/11956#issuecomment-1212925677)。
+由于系统内存报告不正确,基于百分比的内存限制 [在 Linux CircleCI 上不起作用](https://github.com/jestjs/jest/issues/11956#issuecomment-1212925677)。
:::
##### poolOptions.vmThreads.useAtomics
@@ -939,7 +1035,7 @@ export default defineConfig({
#### poolOptions.vmForks
-`vmForks` 池的选项
+`vmForks` 池相关选项
```ts
import { defineConfig } from 'vitest/config'
@@ -958,10 +1054,17 @@ export default defineConfig({
##### poolOptions.vmForks.maxForks
- **类型:** `number | string`
-- **默认值:** _available CPUs_
+- **默认值:** _可用 CPU 核心数_
最大线程数或百分比。你也可以使用 `VITEST_MAX_FORKS` 环境变量。
+##### poolOptions.vmForks.minForks
+
+- **类型:** `number | string`
+- **默认值:** _可用 CPU 核心数_
+
+最小线程数或百分比。你也可以使用 `VITEST_MIN_FORKS` 环境变量。
+
##### poolOptions.vmForks.memoryLimit
- **类型:** `string | number`
@@ -980,7 +1083,7 @@ export default defineConfig({
使用时要小心,因为某些选项(如 `--prof` 、`--title`)可能会导致 worker 崩溃。查看 https://github.com/nodejs/node/issues/41103 了解更多详情。
:::
-### fileParallelism {#fileparallelism}
+### fileParallelism
- **类型:** `boolean`
- **默认值:** `true`
@@ -989,19 +1092,25 @@ export default defineConfig({
所有测试文件应该并行运行。将其设置为 `false` 将覆盖 `maxWorkers` 和 `minWorkers` 选项为 `1`。
::: tip
-此选项不会影响在同一文件中运行的测试。如果你想并行运行这些程序,请在[description](/api/#describe-concurrent)或通过[a config](#sequence-concurrent) 上使用 `concurrent` 选项。
+此选项不会影响在同一文件中运行的测试。如果你想并行运行这些程序,请在 [description](/api/#describe-concurrent) 或通过 [配置](#sequence-concurrent) 上使用 `concurrent` 选项。
:::
-### maxWorkers {#maxworkers}
+### maxWorkers
- **类型:** `number | string`
运行测试时设置的最大工作线程数或百分比。`poolOptions。{threads,vmThreads}.maxThreads `/`poolOptions.forks.maxForks` 具有更高的优先级。
+### minWorkers
+
+- **类型:** `number | string`
+
+运行测试时设置的最小工作线程数或百分比。`poolOptions.{threads,vmThreads}.minThreads`/`poolOptions.forks.minForks` 具有更高的优先级。
+
### testTimeout
- **类型:** `number`
-- **默认值:** `5_000` in Node.js, `15_000` if `browser.enabled` is `true`
+- **默认值:** 在 Node.js 环境下为 `5_000`,当 browser.enabled 为 `true` 时为 `15_000`
- **命令行终端:** `--test-timeout=5000`, `--testTimeout=5000`
测试的默认超时时间(以毫秒为单位)。使用 `0` 完全禁用超时。
@@ -1009,7 +1118,7 @@ export default defineConfig({
### hookTimeout
- **类型:** `number`
-- **默认值:** `10_000` in Node.js, `30_000` if `browser.enabled` is `true`
+- **默认值:** 在 Node.js 环境下为 `10_000`,当 browser.enabled 为 `true` 时为 `30_000`
- **命令行终端:** `--hook-timeout=10000`, `--hookTimeout=10000`
钩子(hook)的默认超时时间(以毫秒为单位)。使用 `0` 完全禁用超时。
@@ -1036,7 +1145,7 @@ Vitest 关闭时等待关闭的默认超时时间,以毫秒为单位
- **类型:** `string | string[]`
-setup 文件的路径。它们将运行在每个测试文件之前。
+setup 文件的路径。它们将在每个测试文件之前运行。
::: info 提示
编辑设置文件将自动触发所有测试的重新运行。
@@ -1094,8 +1203,10 @@ test('api key is defined', () => {
```
:::
+可以参考 如何在覆盖率报告中包含或排除文件 里的示例。
+
::: warning
-属性必须是字符串,值必须是[可序列化](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#supported_types),因为该对象将在不同进程之间传输。
+属性必须是字符串,值必须是 [可序列化](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#supported_types),因为该对象将在不同进程之间传输。
:::
::: tip
@@ -1225,7 +1336,6 @@ npx vitest --coverage.enabled --coverage.provider=istanbul
- **命令行终端:** `--coverage.enabled`, `--coverage.enabled=false`
是否启用收集测试覆盖率。可以使用 `--coverage` 覆盖 CLI 选项。
-
#### coverage.include
- **类型:** `string[]`
@@ -1233,20 +1343,74 @@ npx vitest --coverage.enabled --coverage.provider=istanbul
- **可用的测试提供者:** `'v8' | 'istanbul'`
- **命令行终端:** `--coverage.include=`, `--coverage.include= --coverage.include=`
-以 glob 模式指定需要统计覆盖率的文件列表。默认情况下,只有被测试实际执行到的文件会被纳入覆盖率统计。
+以 glob 模式指定需要统计覆盖率的文件列表。
-建议在 glob 模式中明确包含文件扩展名。
+#### coverage.extension
-可以参考 [如何在覆盖率报告中包含或排除文件](/guide/coverage.html#including-and-excluding-files-from-coverage-report) 里的示例。
+- **类型:** `string | string[]`
+- **默认值:** `['.js', '.cjs', '.mjs', '.ts', '.mts', '.tsx', '.jsx', '.vue', '.svelte', '.marko', '.astro']`
+- **可用的测试提供者:** `'v8' | 'istanbul'`
+- **命令行终端:** `--coverage.extension=`, `--coverage.extension= --coverage.extension=`
#### coverage.exclude
- **类型:** `string[]`
-- **默认值:** : `[]`
+- **默认值:**
+
+```js
+[
+ 'coverage/**',
+ 'dist/**',
+ '**/node_modules/**',
+ '**/[.]**',
+ 'packages/*/test?(s)/**',
+ '**/*.d.ts',
+ '**/virtual:*',
+ '**/__x00__*',
+ '**/\x00*',
+ 'cypress/**',
+ 'test?(s)/**',
+ 'test?(-*).?(c|m)[jt]s?(x)',
+ '**/*{.,-}{test,spec,bench,benchmark}?(-d).?(c|m)[jt]s?(x)',
+ '**/__tests__/**',
+ '**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build,eslint,prettier}.config.*',
+ '**/vitest.{workspace,projects}.[jt]s?(on)',
+ '**/.{eslint,mocha,prettier}rc.{?(c|m)js,yml}',
+]
+```
+
- **可用的测试提供者:** `'v8' | 'istanbul'`
- **命令行终端:** `--coverage.exclude=`, `--coverage.exclude= --coverage.exclude=`
-想要查看示例,请参考 [如何在覆盖率报告中包含或排除文件](/guide/coverage.html#including-and-excluding-files-from-coverage-report)。
+使用全局模式排除在覆盖范围之外的文件列表。
+
+该选项覆盖所有默认选项。添加新的忽略模式时,扩展默认选项:
+
+```ts
+import { coverageConfigDefaults, defineConfig } from 'vitest/config'
+
+export default defineConfig({
+ test: {
+ coverage: {
+ exclude: ['**/custom-pattern/**', ...coverageConfigDefaults.exclude],
+ },
+ },
+})
+```
+
+::: tip NOTE
+Vitest 会自动将测试文件的 `include` 模式添加到 `coverage.exclude` 中。
+无法显示测试文件的覆盖率。
+:::
+
+#### coverage.all
+
+- **类型:** `boolean`
+- **默认值:** `true`
+- **可用的测试提供者:** `'v8' | 'istanbul'`
+- **命令行终端:** `--coverage.all`, `--coverage.all=false`
+
+是否将所有文件(包括未测试的文件)包括在报告中。
#### coverage.clean
@@ -1279,7 +1443,7 @@ npx vitest --coverage.enabled --coverage.provider=istanbul
配置测试覆盖率报告写入的目录。
-要预览覆盖范围报告,请使用 [HTML reporter](/guide/reporters.html#html-reporter), 该选项必须设置为 html 报告目录的子目录 (比如 `./html/coverage`).
+要预览覆盖范围报告,请使用 [HTML 报告器](/guide/reporters.html#html-reporter), 该选项必须设置为 html 报告目录的子目录 (比如 `./html/coverage`).
#### coverage.reporter
@@ -1306,7 +1470,7 @@ npx vitest --coverage.enabled --coverage.provider=istanbul
}
```
-我们还可以传递自定义覆盖报告器。查看[自定义覆盖报告器](/guide/coverage#%E8%87%AA%E5%AE%9A%E4%B9%89%E8%A6%86%E7%9B%96%E7%8E%87%E6%8F%90%E4%BE%9B%E8%80%85)了解更多详情。
+我们还可以传递自定义覆盖报告器。查看 [自定义覆盖率的报告器](/guide/coverage#custom-coverage-reporter) 了解更多详情。
@@ -1324,9 +1488,9 @@ npx vitest --coverage.enabled --coverage.provider=istanbul
}
```
-我们可以在 Vitest UI 中查看覆盖率报告:查看 [Vitest UI Coverage](/guide/coverage#vitest-ui) 了解更多详情。
+我们可以在 Vitest UI 中查看覆盖率报告:查看 [UI 模式](/guide/coverage#vitest-ui) 了解更多详情。
-#### coverage.reportOnFailure {#coverage-reportonfailure}
+#### coverage.reportOnFailure
- **类型:** `boolean`
- **默认值:** `false`
@@ -1439,23 +1603,6 @@ statements 的全局阈值。
如果当前覆盖率优于配置的阈值时,将所有阈值 `lines`、`functions`、`branches` 和 `statements` 更新到配置文件中。
此选项有助于在覆盖率提高时保持阈值不变。
-你还可以传递一个函数来格式化更新的阈值:
-
-
-```ts
-{
- coverage: {
- thresholds: {
- // 更新不带小数的阈值
- autoUpdate: (newThreshold) => Math.floor(newThreshold),
-
- // 95.85 -> 95
- functions: 95,
- }
- }
-}
-```
-
##### coverage.thresholds.100
- **类型:** `boolean`
@@ -1532,6 +1679,47 @@ Vitest 会将所有文件,包括那些被 glob 模式覆盖的文件,计入
}
```
+#### coverage.ignoreEmptyLines
+
+- **类型:** `boolean`
+- **默认值:** `true` (`false` in v1)
+- **可用的测试提供者:** `'v8'`
+- **命令行终端:** `--coverage.ignoreEmptyLines=`
+
+忽略空行、注释和其他非运行时代码,如 Typescript 类型。
+
+该选项只有在使用的编译器删除了转译代码中的注释和其他非运行时代码时才有效。
+默认情况下,Vite 使用 ESBuild,它会删除 `.ts`、`.tsx` 和 `.jsx` 文件中的注释和 Typescript 类型。
+
+如果还想将 ESBuild 应用于其他文件,请在 [`esbuild` 选项](https://cn.vitejs.dev/config/shared-options.html#esbuild) 中定义它们:
+
+```ts
+import { defineConfig } from 'vitest/config'
+
+export default defineConfig({
+ esbuild: {
+ // 使用 ESBuild 转换所有文件以删除代码覆盖率中的注释。
+ // `test.coverage.ignoreEmptyLines` 需要工作:
+ include: ['**/*.js', '**/*.jsx', '**/*.mjs', '**/*.ts', '**/*.tsx'],
+ },
+ test: {
+ coverage: {
+ provider: 'v8',
+ ignoreEmptyLines: true,
+ },
+ },
+})
+```
+
+#### coverage.experimentalAstAwareRemapping
+
+- **Type:** `boolean`
+- **Default:** `false`
+- **Available for providers:** `'v8'`
+- **CLI:** `--coverage.experimentalAstAwareRemapping=`
+
+基于实验性 AST 分析的覆盖率重映射。相比默认模式能提供更精确的结果。
+
#### coverage.ignoreClassMethods
- **类型:** `string[]`
@@ -1587,7 +1775,7 @@ Vitest 会将所有文件,包括那些被 glob 模式覆盖的文件,计入
- **可用的测试提供者:** `'custom'`
- **命令行终端:** `--coverage.customProviderModule=`
-指定自定义覆盖率提供者的模块名称或路径。有关详细信息,请参阅[指南 - 自定义覆盖率提供者](/guide/coverage#custom-coverage-provider)。
+指定自定义覆盖率提供者的模块名称或路径。有关详细信息,请参阅 [指南 - 自定义覆盖率提供者](/guide/coverage#custom-coverage-provider)。
### testNamePattern
@@ -1627,12 +1815,12 @@ test('doNotRun', () => {
提供 API 服务的端口。当设置为 true 时,默认端口为 51204
-### browser experimental {#browser}
+### browser 实验性 {#browser}
- **默认值:** `{ enabled: false }`
- **命令行终端:** `--browser=`, `--browser.name=chrome --browser.headless`
-运行浏览器测试的配置。请参阅[“浏览器配置参考”](/guide/browser/config)。
+运行浏览器测试的配置。请参阅 [“浏览器配置参考”](/guide/browser/config)。
::: warning
这是一项实验性功能。重大更改可能不会遵循 semver,请在使用时锁定 Vitest 的版本。
@@ -1643,41 +1831,64 @@ test('doNotRun', () => {
- **类型:** `boolean`
- **默认值:** `false`
-每个测试开始前自动调用 [`vi.clearAllMocks()`](/api/vi#vi-clearallmocks),仅清除 mock 调用记录,不影响其实现。
+每次测试前,会对所有监听对象调用 [`.mockClear()`](/api/mock#mockclear)。这将清除模拟历史记录,但不会影响模拟实现。
### mockReset
- **类型:** `boolean`
- **默认值:** `false`
-每个测试开始前自动调用 [`vi.resetAllMocks()`](/api/vi#vi-resetallmocks),既清空 mock 调用记录,又将所有实现重置。
+每次测试前,都会对所有监听对象调用 [`.mockReset()`](/api/mock#mockreset)。这将清除模拟历史记录,并将每个实现重置为其原始状态。
### restoreMocks
- **类型:** `boolean`
- **默认值:** `false`
-每个测试开始前自动调用 [`vi.restoreAllMocks()`](/api/vi#vi-restoreallmocks),恢复所有由 [`vi.spyOn`](#vi-spyon) 创建的 spy 的原始实现。
+每次测试前,都会对所有监听对象调用 [`.mockRestore()`](/api/mock#mockrestore)。
+这将清除模拟历史记录,将每个实现恢复为原始实现,并恢复被监视对象的原始描述符。
-### unstubEnvs {#unstubenvs}
+### unstubEnvs
- **类型:** `boolean`
- **默认值:** `false`
将在每次测试前调用 [`vi.unstubAllEnvs`](/api/#vi-unstuballenvs)。
-### unstubGlobals {#unstubglobals}
+### unstubGlobals
- **类型:** `boolean`
- **默认值:** `false`
将在每次测试前调用 [`vi.unstubAllGlobals`](/api/#vi-unstuballglobals)。
+### testTransformMode
+
+- **类型:** `{ web?, ssr? }`
+
+确定与测试中的 glob 模式匹配的所有导入模块的转换方法。默认情况下,依赖于环境。例如,使用 JSDOM 环境的测试将处理所有带有 `ssr: false` 标志的文件,而使用 Node 环境的测试将处理所有带有 `ssr: true` 的模块。
+
+#### testTransformMode.ssr
+
+- **类型:** `string[]`
+- **默认值:** `[]`
+
+对指定的文件使用 SSR 转换管道。
+Vite 插件在处理这些文件时会收到 `ssr: true` 标志。
+
+#### testTransformMode.web
+
+- **类型:** `string[]`
+- **默认值:** `[]`
+
+首先会进行正常的转换流程(针对浏览器环境),然后进行 SSR 重写以在 Node 中运行代码。
+Vite 插件在处理这些文件时会收到 `ssr: false` 标志。
+
### snapshotFormat
- **类型:** `PrettyFormatOptions`
-快照测试的格式选项。这些选项被传递给我们 fork 的 [`pretty-format`](https://www.npmjs.com/package/pretty-format)。除了 `pretty-format` 选项外,我们还支持 `printShadowRoot: boolean`。
+快照测试的格式选项。这些选项被传递给 [`pretty-format`](https://www.npmjs.com/package/pretty-format)。
::: tip
请注意,此对象上的 `plugins` 字段将被忽略。
@@ -1685,17 +1896,17 @@ test('doNotRun', () => {
如果你需要通过 pretty-format 插件扩展快照序列器,请使用 [`expect.addSnapshotSerializer`](/api/expect#expect-addsnapshotserializer) 或 [snapshotSerializers](#snapshotserializers) 选项。
:::
-### snapshotSerializers {#snapshotserializers}
+### snapshotSerializers
- **类型:** `string[]`
- **默认值:** `[]`
-快照测试的快照序列化程序模块的路径列表,如果要添加自定义快照序列化器,则非常有用。有关详细信息,请参阅[自定义序列化器](/guide/snapshot#custom-serializer)。
+快照测试的快照序列化程序模块的路径列表,如果要添加自定义快照序列化器,则非常有用。有关详细信息,请参阅 [自定义序列化器](/guide/snapshot#custom-serializer)。
### resolveSnapshotPath
- **类型**: `(testPath: string, snapExtension: string, context: { config: SerializedConfig }) => string`
-- **默认值**: stores snapshot files in `__snapshots__` directory
+- **默认值**: 将快照文件存储在 `__snapshots__` 目录中
覆盖快照的默认路径。例如,要在测试文件旁边存储一下快照:
@@ -1848,9 +2059,9 @@ npx vitest --sequence.shuffle --sequence.seed=1000
#### groupOrder 3.2.0 {#grouporder}
- **类型:** `number`
-- **Default:** `0`
+- **默认值:** `0`
-控制使用多个[项目](/guide/projects) 时该项目运行测试的顺序。
+控制使用多个 [项目](/guide/projects) 时该项目运行测试的顺序。
- 具有相同组序号的项目将一起运行,并且组从低到高运行。
- 如果不设置此选项,所有项目将并行运行。
@@ -1859,7 +2070,7 @@ npx vitest --sequence.shuffle --sequence.seed=1000
此设置仅影响项目运行的顺序,而不影响项目中测试的顺序。
要控制项目内的测试隔离或测试顺序,请使用 [`isolate`](#isolate) 和 [`sequence.sequencer`](#sequence-sequencer) 选项。
-::: 详细信息示例
+::: details 示例
考虑这个例子:
```ts
@@ -1900,11 +2111,11 @@ export default defineConfig({
这些项目中的测试将按以下顺序运行:
```
- 0. slow |
+ 1. slow |
|> 一起运行
- 0. fast |
+ 2. fast |
- 1. flaky |> 在 slow 和 fast 之后单独运行
+ 3. flaky |> 在 slow 和 fast 之后单独运行
```
:::
@@ -1916,29 +2127,25 @@ export default defineConfig({
如果你希望测试随机运行,可以使用此选项或 CLI 参数 [`--sequence.shuffle`](/guide/cli) 启用它。
-Vitest 通常使用缓存对测试进行排序,因此长时间运行的测试会更早开始 - 这会使测试运行得更快。 如果你的测试将以随机顺序运行,你将失去这种性能改进,但跟踪意外依赖于先前运行的测试可能很有用。
-
-- **类型**: `boolean | { files?, tests? }`
-- **默认值**: `false`
-- **命令行终端**: `--sequence.shuffle`, `--sequence.shuffle=false`
+Vitest 通常使用缓存对测试进行排序,因此长时间运行的测试会更早开始,这会使测试运行得更快。如果你的测试将以随机顺序运行,你将失去这种性能改进,但跟踪意外依赖于先前运行的测试可能很有用。
-#### sequence.shuffle.files {#sequence-shuffle-files}
+#### sequence.shuffle.files
- **类型**: `boolean`
- **默认值**: `false`
- **命令行终端**: `--sequence.shuffle.files`, `--sequence.shuffle.files=false`
-是否随机化文件,注意如果启用此选项,长时间运行的测试将不会提前启动。
+是否随机执行测试文件顺序。请注意,若启用此选项,耗时较长的测试将不会提前开始执行。
-#### sequence.shuffle.tests {#sequence-shuffle-tests}
+#### sequence.shuffle.tests
- **类型**: `boolean`
- **默认值**: `false`
- **命令行终端**: `--sequence.shuffle.tests`, `--sequence.shuffle.tests=false`
-是否随机测试。
+是否随机执行测试顺序。
-#### sequence.concurrent {#sequence-concurrent}
+#### sequence.concurrent
- **类型**: `boolean`
- **默认值**: `false`
@@ -1970,7 +2177,7 @@ Vitest 通常使用缓存对测试进行排序,因此长时间运行的测试
该选项不会影响 [`onTestFinished`](/api/#ontestfinished)。它总是以相反的顺序调用。
:::
-#### sequence.setupFiles {#sequence-setupfiles}
+#### sequence.setupFiles
- **类型**: `'list' | 'parallel'`
- **默认值**: `'parallel'`
@@ -1983,17 +2190,17 @@ Vitest 通常使用缓存对测试进行排序,因此长时间运行的测试
### typecheck
-用于配置 [typechecking](/guide/testing-types) 测试环境的选项。
+[类型测试](/guide/testing-types) 测试环境的配置选项。
-#### typecheck.enabled {#typecheck-enabled}
+#### typecheck.enabled
- **类型**: `boolean`
- **默认值**: `false`
- **命令行终端**: `--typecheck`, `--typecheck.enabled`
-常规测试时是否进行类型检查。
+在常规测试的同时启用类型检查。
-#### typecheck.only {#typecheck-only}
+#### typecheck.only
- **类型**: `boolean`
- **默认值**: `false`
@@ -2065,9 +2272,9 @@ Vitest 通常使用缓存对测试进行排序,因此长时间运行的测试
- **默认值**: `300`
- **命令行终端:**:`--slow-test-threshold=`, `--slowTestThreshold=`
-如果测试被认为是缓慢的,那么会在报告结果中显示毫秒值。
+测试或测试套件执行超过该毫秒数即被视为缓慢,并在结果中相应标注。
-### chaiConfig {#chaiconfig}
+### chaiConfig
- **类型:** `{ includeStack?, showDiff?, truncateThreshold? }`
- **默认值:** `{ includeStack: false, showDiff: true, truncateThreshold: 40 }`
@@ -2097,7 +2304,7 @@ Vitest 通常使用缓存对测试进行排序,因此长时间运行的测试
此配置选项影响在 `test.each` 标题和断言错误消息中截断值的方式。
-### bail {#bail}
+### bail
- **类型:** `number`
- **默认值:** `0`
@@ -2107,7 +2314,7 @@ Vitest 通常使用缓存对测试进行排序,因此长时间运行的测试
默认情况下,即使其中一些测试失败,Vitest 也会运行你的所有测试用例。这可能不适用于 CI 构建,你只对 100% 成功的构建感兴趣,并且希望在测试失败时尽早停止测试执行。`bail` 选项可用于通过在发生故障时防止运行更多测试来加速 CI 运行。
-### retry {#retry}
+### retry
- **类型:** `number`
- **默认值:** `0`
@@ -2141,7 +2348,7 @@ export default defineConfig({
})
```
-### onStackTrace {#onstacktrace}
+### onStackTrace
- **类型**: `(error: Error, frame: ParsedStack) => boolean | void`
@@ -2170,30 +2377,6 @@ export default defineConfig({
})
```
-### onUnhandledError {#onunhandlederror}
-
-- **类型:** `(error: (TestError | Error) & { type: string }) => boolean | void`
-
-自定义处理程序,用于过滤掉不应报告的未处理错误。 如果过滤掉错误,则不会再影响测试结果。
-
-如果你希望报告未处理的错误而不影响测试结果,可以考虑使用 [`dangerouslyIgnoreUnhandledErrors`](#dangerouslyIgnoreUnhandledErrors) 选项
-
-```ts
-import type { ParsedStack } from 'vitest'
-import { defineConfig } from 'vitest/config'
-
-export default defineConfig({
- test: {
- onUnhandledError(error): boolean | void {
- // 忽略名为 “MySpecialError” 的所有错误。
- if (error.name === 'MySpecialError') {
- return false
- }
- },
- },
-})
-```
-
### diff
- **类型:** `string`
@@ -2341,7 +2524,17 @@ Expand all common lines.
通过委托各自的处理程序,告诉假冒计时器清除 "native"(即非假冒)计时器。禁用时,如果计时器在启动假计时器会话之前已经存在,则可能导致意外行为。
-### projects {#projects}
+### workspace
+
+- **类型:** `string | TestProjectConfiguration`
+- **命令行终端:** `--workspace=./file.js`
+- **默认值:** 配置文件或根目录附近的 `vitest.{workspace,projects}.{js,ts,json}`
+
+相对于[root](#root) 的 [workspace](/guide/projects) 配置文件的路径。
+
+自 Vitest 3 起,您也可以在根配置中直接定义 `workspace` 数组。若手动在配置中声明了 workspace 参数,Vitest 将忽略项目根目录下的 `vitest.workspace` 文件。
+
+### projects
- **类型:** `TestProjectConfiguration[]`
- **默认值:** `[]`
@@ -2356,7 +2549,7 @@ Expand all common lines.
在隔离的环境中运行测试。此选项对 `vmThreads` 和 `vmForks` 池没有影响。
-如果你的代码不依赖于副作用(对于具有 `node` 环境的项目通常如此),禁用此选项可能会[改进性能](/guide/improving-performance)。
+如果你的代码不依赖于副作用(这在 `node` 环境的项目通常如此),禁用此选项可能会 [性能提升](/guide/improving-performance)。
::: tip
你可以使用 [`poolOptions`](#poolOptions) 属性禁用特定池的隔离。
@@ -2367,14 +2560,14 @@ Expand all common lines.
- **类型:** `boolean`
- **默认值:** `false`
-Vitest API 在 [reporters](#reporters) 中接收任务时是否应包含`location`属性。如果我们有大量测试,这可能会导致性能小幅下降。
+Vitest API 在 [reporters](#reporters) 中接收任务时是否应包含 `location` 属性。如果我们有大量测试,这可能会导致性能小幅下降。
`location` 属性的 `列` 和 `行` 值与原始文件中的 `test` 或 `describe` 位置相对应。
如果我们没有明确禁用该选项,并且在运行 Vitest 时使用了该选项,则该选项将自动启用:
- [Vitest UI](/guide/ui)
-- 或使用不带 [headless](/guide/browser/#headless) 模式的 [浏览器模式](/guide/browser/)
-- 或使用[HTML 报告器](/guide/reporters#html-reporter)
+- 或使用不带 [无头模式](/guide/browser/#headless) 的 [浏览器](/guide/browser/)
+- 或使用 [HTML 报告器](/guide/reporters#html-reporter)
::: tip
如果不使用依赖于该选项的自定义代码,该选项将不起作用。
@@ -2386,7 +2579,7 @@ Vitest API 在 [reporters](#reporters) 中接收任务时是否应包含`locatio
自定义快照环境实现的路径。如果在不支持 Node.js API 的环境中运行测试,该选项将非常有用。此选项对浏览器运行程序没有任何影响。
-该对象应具有 `SnapshotEnvironment` 的形状,用于解析和读/写快照文件:
+该对象应具有 `SnapshotEnvironment` 的接口规范,用于解析和读/写快照文件:
```ts
export interface SnapshotEnvironment {
@@ -2405,10 +2598,10 @@ export interface SnapshotEnvironment {
::: warning
这是一个低级选项,仅适用于无法访问默认 Node.js API 的高级情况。
-如果只需要配置快照功能,请使用 [`snapshotFormat`](#snapshotformat)或 [`resolveSnapshotPath`](#resolvesnapshotpath)选项。
+如果只需要配置快照功能,请使用 [`snapshotFormat`](#snapshotformat) 或 [`resolveSnapshotPath`](#resolvesnapshotpath) 选项。
:::
-### env {#env}
+### env
- **类型:** `Partial`
@@ -2456,7 +2649,7 @@ export interface SnapshotEnvironment {
每次调用 `console` 方法时都输出堆栈追踪信息,这对于排查问题非常有帮助。
-### attachmentsDir 3.2.0 {#attachmentsdir}
+### attachmentsDir 3.2.0
- **类型:** `string`
- **默认值:** `'.vitest-attachments'`
diff --git a/guide/browser/assertion-api.md b/guide/browser/assertion-api.md
index c2eb7ad0..598e367f 100644
--- a/guide/browser/assertion-api.md
+++ b/guide/browser/assertion-api.md
@@ -284,13 +284,13 @@ function toBeVisible(): Promise
若要检查列表中至少有一个元素是可见的,请使用 `locator.first()`。
```ts
-// A specific element is visible.
+// 检测特定元素可见
await expect.element(page.getByText('Welcome')).toBeVisible()
-// At least one item in the list is visible.
+// 检测列表中至少有一项可见
await expect.element(page.getByTestId('todo-item').first()).toBeVisible()
-// At least one of the two elements is visible, possibly both.
+// 检测两个元素中至少有一个可见(可能同时可见)
await expect.element(
page.getByRole('button', { name: 'Sign in' })
.or(page.getByRole('button', { name: 'Sign up' }))
@@ -298,27 +298,6 @@ await expect.element(
).toBeVisible()
```
-## toBeInViewport
-
-```ts
-function toBeInViewport(options: { ratio?: number }): Promise
-```
-
-This allows you to check if an element is currently in viewport with [IntersectionObserver API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API).
-
-You can pass `ratio` argument as option, which means the minimal ratio of the element should be in viewport. `ratio` should be in 0~1.
-
-```ts
-// A specific element is in viewport.
-await expect.element(page.getByText('Welcome')).toBeInViewport()
-
-// 50% of a specific element should be in viewport
-await expect.element(page.getByText('To')).toBeInViewport({ ratio: 0.5 })
-
-// Full of a specific element should be in viewport
-await expect.element(page.getByText('Vitest')).toBeInViewport({ ratio: 1 })
-```
-
## toContainElement
```ts
@@ -379,9 +358,9 @@ await expect.element(getByTestId('parent')).toContainHTML('')
function toHaveAccessibleDescription(description?: string | RegExp): Promise
```
-这允许你断言一个元素具有预期的[可访问描述](https://w3c.github.io/accname/)。
+这允许你断言一个元素具有预期的 [可访问描述](https://w3c.github.io/accname/)。
-你可以传递预期的可访问描述的确切字符串,或者通过传递正则表达式来进行部分匹配,或者使用[`expect.stringContaining`](/api/expect#expect-stringcontaining)或[`expect.stringMatching`](/api/expect#expect-stringmatching)。
+你可以传递预期的可访问描述的确切字符串,或者通过传递正则表达式来进行部分匹配,或者使用 [`expect.stringContaining`](/api/expect#expect-stringcontaining) 或 [`expect.stringMatching`](/api/expect#expect-stringmatching)。
```html
```
-这允许你断言一个元素具有预期的[可访问错误消息](https://w3c.github.io/aria/#aria-errormessage)。
+这允许你断言一个元素具有预期的 [可访问错误消息](https://w3c.github.io/aria/#aria-errormessage)。
-你可以传递预期的可访问错误消息的确切字符串。或者,你可以通过传递正则表达式或使用[`expect.stringContaining`](/api/expect#expect-stringcontaining)或[`expect.stringMatching`](/api/expect#expect-stringmatching)来进行部分匹配。
+你可以传递预期的可访问错误消息的确切字符串。或者,你可以通过传递正则表达式或使用 [`expect.stringContaining`](/api/expect#expect-stringcontaining) 或 [`expect.stringMatching`](/api/expect#expect-stringmatching)来进行部分匹配。
```html
```
```ts
-// Inputs with Valid Error Messages
+// 有效错误信息的输入项
await expect.element(getByRole('textbox', { name: 'Has Error' })).toHaveAccessibleErrorMessage()
await expect.element(getByRole('textbox', { name: 'Has Error' })).toHaveAccessibleErrorMessage(
'This field is invalid',
@@ -462,7 +441,7 @@ await expect.element(
getByRole('textbox', { name: 'Has Error' }),
).not.toHaveAccessibleErrorMessage('This field is absolutely correct!')
-// Inputs without Valid Error Messages
+// 没有效错误信息的输入项
await expect.element(
getByRole('textbox', { name: 'No Error Attributes' }),
).not.toHaveAccessibleErrorMessage()
@@ -478,9 +457,9 @@ await expect.element(
function toHaveAccessibleName(name?: string | RegExp): Promise
```
-这允许你断言一个元素具有预期的[可访问名称](https://w3c.github.io/accname/)。例如,它有助于断言表单元素和按钮是否被正确标记。
+这允许你断言一个元素具有预期的 [可访问名称](https://w3c.github.io/accname/)。例如,它有助于断言表单元素和按钮是否被正确标记。
-你可以传递预期的可访问名称的确切字符串,或者通过传递正则表达式进行部分匹配,也可以使用[`expect.stringContaining`](/api/expect#expect-stringcontaining)或[`expect.stringMatching`](/api/expect#expect-stringmatching)。
+你可以传递预期的可访问名称的确切字符串,或者通过传递正则表达式进行部分匹配,也可以使用 [`expect.stringContaining`](/api/expect#expect-stringcontaining) 或 [`expect.stringMatching`](/api/expect#expect-stringmatching)。
```html
@@ -510,7 +489,7 @@ await expect.element(getByTestId('input-title')).toHaveAccessibleName()
function toHaveAttribute(attribute: string, value?: unknown): Promise
```
-这允许你检查给定的元素是否具有某个属性。你还可以选择性地验证该属性是否具有特定的预期值或使用[`expect.stringContaining`](/api/expect#expect-stringcontaining)或[`expect.stringMatching`](/api/expect#expect-stringmatching)进行部分匹配。
+这允许你检查给定的元素是否具有某个属性。你还可以选择性地验证该属性是否具有特定的预期值或使用 [`expect.stringContaining`](/api/expect#expect-stringcontaining) 或 [`expect.stringMatching`](/api/expect#expect-stringmatching) 进行部分匹配。
```html
@@ -542,7 +521,7 @@ function toHaveClass(...classNames: (string | RegExp)[]): Promise
这允许你检查给定元素在其 `class` 属性中是否包含某些类。除非你断言该元素没有任何类,否则必须提供至少一个类。
-类名列表可以包括字符串和正则表达式。正则表达式会与目标元素中的每个单独类进行匹配,**而不是与其完整的 `class` 属性值整体匹配**。
+类名列表可以包括字符串和正则表达式。正则表达式会与目标元素中的每个单独类进行匹配,而不是与其完整的 `class` 属性值整体匹配。
::: warning
请注意,当仅提供正则表达式时,不能使用 `exact: true` 选项。
@@ -566,14 +545,14 @@ await expect.element(deleteButton).toHaveClass('btn-danger', 'btn')
await expect.element(deleteButton).not.toHaveClass('btn-link')
await expect.element(deleteButton).not.toHaveClass(/link/)
-// ⚠️ regexp matches against individual classes, not the whole classList
+// ⚠️ 正则表达式仅匹配单个类名而非整个 classList
await expect.element(deleteButton).not.toHaveClass(/btn extra/)
-// the element has EXACTLY a set of classes (in any order)
+// 精确匹配类集合(顺序无关)
await expect.element(deleteButton).toHaveClass('btn-danger extra btn', {
exact: true
})
-// if it has more than expected it is going to fail
+// 若存在多余类则断言失败
await expect.element(deleteButton).not.toHaveClass('btn-danger extra', {
exact: true
})
@@ -705,7 +684,7 @@ function toHaveTextContent(
若要进行不区分大小写的匹配,可以使用带有 `/i` 修饰符的 `RegExp`。
-如果你想匹配整个内容,可以使用 `RegExp` 来实现。
+如果你想匹配整段内容,可以使用 `RegExp` 来实现。
```html
Text Content
@@ -715,9 +694,9 @@ function toHaveTextContent(
const element = getByTestId('text-content')
await expect.element(element).toHaveTextContent('Content')
-// to match the whole content
+// 匹配整段内容
await expect.element(element).toHaveTextContent(/^Text Content$/)
-// to use case-insensitive match
+// 不区分大小写匹配
await expect.element(element).toHaveTextContent(/content$/i)
await expect.element(element).not.toHaveTextContent('content')
```
@@ -903,11 +882,11 @@ await expect.element(inputCheckboxIndeterminate).toBePartiallyChecked()
function toHaveRole(role: ARIARole): Promise
```
-这允许你断言某个元素具有预期的[角色](https://www.w3.org/TR/html-aria/#docconformance)。
+这允许你断言某个元素具有预期的 [角色](https://www.w3.org/TR/html-aria/#docconformance)。
在你已经通过某种查询(而非角色本身)获取到某个元素,并希望对其可访问性进行更多断言时,这非常有用。
-角色可以匹配显式角色(通过 `role` 属性),也可以通过[隐式 ARIA 语义](https://www.w3.org/TR/html-aria/#docconformance)匹配隐式角色。
+角色可以匹配显式角色(通过 `role` 属性),也可以通过 [隐式 ARIA 语义](https://www.w3.org/TR/html-aria/#docconformance) 匹配隐式角色。
```html
@@ -979,12 +958,12 @@ selection.removeAllRanges()
selection.empty()
selection.addRange(range)
-// selection of child applies to the parent as well
+// 子元素的选择同样适用于父元素
range.selectNodeContents(getByTestId('child').element())
await expect.element(getByTestId('child')).toHaveSelection('selected')
await expect.element(getByTestId('parent')).toHaveSelection('selected')
-// selection that applies from prev all, parent text before child, and part child.
+// 选择范围包含:前序同级元素、父元素中子元素前的文本、以及子元素的部分内容
range.setStart(getByTestId('prev').element(), 0)
range.setEnd(getByTestId('child').element().childNodes[0], 3)
await expect.element(queryByTestId('prev')).toHaveSelection('prev')
@@ -992,7 +971,7 @@ await expect.element(queryByTestId('child')).toHaveSelection('sel')
await expect.element(queryByTestId('parent')).toHaveSelection('text sel')
await expect.element(queryByTestId('next')).not.toHaveSelection()
-// selection that applies from part child, parent text after child and part next.
+// 选择范围包含:子元素的部分内容、父元素中子元素后的文本、以及后续同级元素的部分内容
range.setStart(getByTestId('child').element().childNodes[0], 3)
range.setEnd(getByTestId('next').element().childNodes[0], 2)
await expect.element(queryByTestId('child')).toHaveSelection('ected')
@@ -1000,185 +979,3 @@ await expect.element(queryByTestId('parent')).toHaveSelection('ected text')
await expect.element(queryByTestId('prev')).not.toHaveSelection()
await expect.element(queryByTestId('next')).toHaveSelection('ne')
```
-
-## toMatchScreenshot 实验性 {#tomatchscreenshot}
-
-```ts
-function toMatchScreenshot(
- options?: ScreenshotMatcherOptions,
-): Promise
-function toMatchScreenshot(
- name?: string,
- options?: ScreenshotMatcherOptions,
-): Promise
-```
-
-::: tip
-`toMatchScreenshot` 断言可在 [Vitest 配置](/guide/browser/config#browser-expect-tomatchscreenshot) 中全局设定。
-:::
-
-该断言通过将元素或整页的截图与预先保存的基准图像进行比对,实现视觉回归测试。
-
-若差异超出设定阈值,测试即告失败。为便于定位变更,断言会自动生成:
-
-- 测试过程中的实际截图
-- 预期的基准截图
-- 差异高亮的对比图(如技术可行)
-
-::: warning 截图稳定性
-该断言会不断重试截图,直到连续两次结果完全一致,从而削弱动画、加载状态或其他动态内容带来的抖动。可通过 `timeout` 选项设定最长等待时间。
-
-但浏览器渲染易受多种变量影响:
-
-- 浏览器及其版本差异
-- 操作系统(Windows、macOS、Linux)
-- 屏幕分辨率与像素密度
-- GPU 驱动及硬件加速策略
-- 字体渲染与系统字体差异
-
-建议先阅读 [视觉回归测试指南](/guide/browser/visual-regression-testing),再落地实施。
-:::
-
-::: tip
-若截图对比因**有意变更**而失败,可在监听模式下按 `u` 键,或运行测试时加上 `-u`/`--update` 标志,以更新基准图。
-:::
-
-```html
-
-```
-
-```ts
-// basic usage, auto-generates screenshot name
-await expect.element(getByTestId('button')).toMatchScreenshot()
-
-// with custom name
-await expect.element(getByTestId('button')).toMatchScreenshot('fancy-button')
-
-// with options
-await expect.element(getByTestId('button')).toMatchScreenshot({
- comparatorName: 'pixelmatch',
- comparatorOptions: {
- allowedMismatchedPixelRatio: 0.01,
- },
-})
-
-// with both name and options
-await expect.element(getByTestId('button')).toMatchScreenshot('fancy-button', {
- comparatorName: 'pixelmatch',
- comparatorOptions: {
- allowedMismatchedPixelRatio: 0.01,
- },
-})
-```
-
-### Options
-
-- `comparatorName: "pixelmatch" = "pixelmatch"`
-
- 用于比较图像的算法/库名称。
-
- 目前,仅支持 [“pixelmatch”](https://github.com/mapbox/pixelmatch)。
-
-- `comparatorOptions: object`
-
- 用于调整比较器行为的选项,可设置的属性取决于所选的比较算法。
-
- Vitest 已内置默认值,但可以覆盖。
-
- - [`"pixelmatch"` options](#pixelmatch-comparator-options)
-
- ::: warning
- **始终显式设置 `comparatorName`,以确保 `comparatorOptions` 的类型推断正确**。
-
- 否则,TypeScript 无法识别哪些选项是有效的。
-
- ```ts
- // ❌ TypeScript can't infer the correct options
- await expect.element(button).toMatchScreenshot({
- comparatorOptions: {
- // might error when new comparators are added
- allowedMismatchedPixelRatio: 0.01,
- },
- })
-
- // ✅ TypeScript knows these are pixelmatch options
- await expect.element(button).toMatchScreenshot({
- comparatorName: 'pixelmatch',
- comparatorOptions: {
- allowedMismatchedPixelRatio: 0.01,
- },
- })
- ```
- :::
-
-- `screenshotOptions: object`
-
- 与 [`locator.screenshot()`](/guide/browser/locators.html#screenshot) 支持的选项一致,但以下情况除外:
-
- - `'base64'`
- - `'path'`
- - `'save'`
- - `'type'`
-
-- `timeout: number = 5_000`
-
- 等待获取稳定截图的时间。
-
- 设为 `0` 可禁用超时,但如果无法确定稳定截图,进程将不会结束。
-
-#### `"pixelmatch"` comparator options
-
-使用 `"pixelmatch"` 比较器时,以下选项可用:
-
-- `allowedMismatchedPixelRatio: number | undefined = undefined`
-
- 允许的捕获截图与参考图像之间不同的像素比例的最大值,范围为 `0` 到 `1`。
-
- 例如,`allowedMismatchedPixelRatio: 0.02` 表示最多允许 2% 的像素不同,否则测试失败。
-
-- `allowedMismatchedPixels: number | undefined = undefined`
-
- 允许的捕获截图与参考图像之间不同的像素的最大数量。
-
- 如果设置为 `undefined`,任何非零差异都将导致测试失败。
-
- 例如,`allowedMismatchedPixels: 10` 表示最多允许 10 个像素不同,否则测试失败。
-
-- `threshold: number = 0.1`
-
- 两张图像中相同像素的可接受颜色差异范围,值越小越敏感。
-
- 比较使用 [YIQ 色彩空间](https://en.wikipedia.org/wiki/YIQ)。
-
-- `includeAA: boolean = false`
-
- 如果为 `true`,则禁用抗锯齿像素的检测和忽略。
-
-- `alpha: number = 0.1`
-
- 差异图像中未改变像素的混合级别,范围为 `0`(白色)到 `1`(原始亮度)。
-
-- `aaColor: [r: number, g: number, b: number] = [255, 255, 0]`
-
- 差异图像中抗锯齿像素的颜色。
-
-- `diffColor: [r: number, g: number, b: number] = [255, 0, 0]`
-
- 差异图像中不同像素的颜色。
-
-- `diffColorAlt: [r: number, g: number, b: number] | undefined = undefined`
-
- 可选的替代颜色,用于区分深色和浅色背景下的差异,帮助区分添加和移除的内容。
- 如果未设置,则所有差异均使用 `diffColor`。
-
-- `diffMask: boolean = false`
-
- 如果为 `true`,则仅以透明背景上的遮罩形式显示差异,而不是将其叠加在原始图像上。
-
- 如果检测到抗锯齿像素,则不会显示。
-
-::: warning
-当 `allowedMismatchedPixels` 和 `allowedMismatchedPixelRatio` 同时设置时,将采用更严格的限制值。
-
-例如,如果你允许 100 个像素差异或 2% 的比例差异,且图像总像素为 10,000,那么实际限制将是 100 个像素,而不是 200 个。
-:::
diff --git a/guide/browser/commands.md b/guide/browser/commands.md
index e0a248e3..d7d2595c 100644
--- a/guide/browser/commands.md
+++ b/guide/browser/commands.md
@@ -59,7 +59,7 @@ expect(input).toHaveValue('a')
CDP session仅适用于 `playwright` provider,并且仅在使用 `chromium` 浏览器时有效。有关详细信息,请参阅 playwright 的 [`CDPSession`](https://playwright.dev/docs/api/class-cdpsession)文档。
:::
-## Custom Commands
+## 自定义命令 {#custom-commands}
我们也可以通过 [`browser.commands`](/guide/browser/config#browser-commands) 配置选项添加自己的命令。如果我们正在开发一个库,可以通过插件内的`config`钩子来提供它们:
@@ -108,7 +108,8 @@ test('custom command works correctly', async () => {
expect(result).toEqual({ someValue: true })
})
-// if you are using TypeScript, you can augment the module
+// 如果你正在使用 TypeScript,你可以扩展类型声明:
+
declare module 'vitest/browser' {
interface BrowserCommands {
myCustomCommand: (arg1: string, arg2: string) => Promise<{
@@ -122,7 +123,7 @@ declare module 'vitest/browser' {
如果自定义命令具有相同的名称,则它们将覆盖内置命令。
:::
-### 自定义命令 `playwright` {#custom-playwright-commands}
+### 自定义 `playwright` 命令 {#custom-playwright-commands}
Vitest 在命令上下文中公开了几个`playwright`特定属性。
@@ -148,7 +149,7 @@ export const myCommand: BrowserCommand<[string, number]> = async (
}
```
-### Custom `webdriverio` commands
+### 自定义 `webdriverio` 命令 {#custom-webdriverio-commands}
Vitest 在上下文对象上公开了一些 `webdriverio` 特有属性。
diff --git a/guide/browser/component-testing.md b/guide/browser/component-testing.md
deleted file mode 100644
index f1f8e9b8..00000000
--- a/guide/browser/component-testing.md
+++ /dev/null
@@ -1,575 +0,0 @@
----
-title: Component Testing | Guide
-outline: deep
----
-
-# 组件测试 {#component-testing}
-
-组件测试是一种专注于独立测试单个UI组件的测试策略。与测试整个用户流程的端到端测试不同,组件测试验证每个组件单独工作是否正确,使它们运行更快且更容易调试。
-
-Vitest为多个框架提供全面的组件测试支持,包括Vue、React、Svelte、Lit、Preact、Qwik、Solid、Marko等。本指南涵盖了使用Vitest有效测试组件的特定模式、工具和最佳实践。
-
-## 为什么进行组件测试? {#why-component-testing}
-
-组件测试位于单元测试和端到端测试之间,提供了几个优势:
-
-- **更快的反馈** - 测试单个组件而无需加载整个应用程序
-- **隔离测试** - 关注组件行为而无需外部依赖
-- **更好的调试** - 更容易定位特定组件中的问题
-- **全面的覆盖** - 更容易测试边缘情况和错误状态
-
-## 组件测试的浏览器模式 {#browser-mode-for-component-testing}
-
-Vitest中的组件测试使用**浏览器模式**在真实浏览器环境中运行测试,支持使用Playwright、WebdriverIO或预览模式。这提供了最准确的测试环境,因为你的组件在真实浏览器中运行,具有实际的DOM实现、CSS渲染和浏览器API。
-
-### 为什么使用浏览器模式? {#why-browser-mode}
-
-浏览器模式是组件测试的推荐方法,因为它提供了最准确的测试环境。与DOM模拟库不同,浏览器模式能够捕获影响用户的真实世界问题。
-
-::: tip
-浏览器模式能够捕获DOM模拟库可能遗漏的问题,包括:
-- CSS布局和样式问题
-- 真实浏览器API行为
-- 准确的事件处理和传播
-- 正确的焦点管理和无障碍功能特性
-
-:::
-
-### 本指南的目的 {#purpose-of-this-guide}
-
-本指南专门介绍使用Vitest功能的**组件测试模式和最佳实践**。虽然许多示例使用浏览器模式(因为这是推荐的方法),但这里的重点是组件特定的测试策略,而不是浏览器配置细节。
-
-有关详细的浏览器设置、配置选项和高级浏览器功能,请参阅[浏览器模式文档](/guide/browser/)。
-
-## 什么是好的组件测试 {#what-makes-a-good-component-test}
-
-好的组件测试关注**行为和用户体验**,而不是实现细节:
-
-- **测试契约** - 组件如何接收输入(props)并产生输出(事件、渲染)
-- **测试用户交互** - 点击、表单提交、键盘导航
-- **测试边缘情况** - 错误状态、加载状态、空状态
-- **避免测试内部实现** - 状态变量、私有方法、CSS类
-
-### 组件测试层次结构 {#component-testing-hierarchy}
-
-```
-1. Critical User Paths → Always test these
-2. Error Handling → Test failure scenarios
-3. Edge Cases → Empty data, extreme values
-4. Accessibility → Screen readers, keyboard nav
-5. Performance → Large datasets, animations
-```
-
-## 组件测试策略 {#component-testing-strategies}
-
-### 隔离策略 {#isolation-strategy}
-
-通过模拟依赖项来隔离测试组件:
-
-```tsx
-// For API requests, we recommend MSW (Mock Service Worker)
-// See: https://vitest.dev/guide/mocking/requests
-//
-// vi.mock(import('../api/userService'), () => ({
-// fetchUser: vi.fn().mockResolvedValue({ name: 'John' })
-// }))
-
-// Mock child components to focus on parent logic
-vi.mock(import('../components/UserCard'), () => ({
- default: vi.fn(({ user }) => `User: ${user.name}
`)
-}))
-
-test('UserProfile handles loading and data states', async () => {
- const { getByText } = render()
-
- // Test loading state
- await expect.element(getByText('Loading...')).toBeInTheDocument()
-
- // Test for data to load (expect.element auto-retries)
- await expect.element(getByText('User: John')).toBeInTheDocument()
-})
-```
-
-### 集成策略 {#integration-strategy}
-
-测试组件协作和数据流:
-
-```tsx
-test('ProductList filters and displays products correctly', async () => {
- const mockProducts = [
- { id: 1, name: 'Laptop', category: 'Electronics', price: 999 },
- { id: 2, name: 'Book', category: 'Education', price: 29 }
- ]
-
- const { getByLabelText, getByText } = render(
-
- )
-
- // Initially shows all products
- await expect.element(getByText('Laptop')).toBeInTheDocument()
- await expect.element(getByText('Book')).toBeInTheDocument()
-
- // Filter by category
- await userEvent.selectOptions(
- getByLabelText(/category/i),
- 'Electronics'
- )
-
- // Only electronics should remain
- await expect.element(getByText('Laptop')).toBeInTheDocument()
- await expect.element(queryByText('Book')).not.toBeInTheDocument()
-})
-```
-
-## Testing Library 集成 {#testing-library-integration}
-
-虽然Vitest为流行的框架提供了官方包([`vitest-browser-vue`](https://www.npmjs.com/package/vitest-browser-vue)、[`vitest-browser-react`](https://www.npmjs.com/package/vitest-browser-react)、[`vitest-browser-svelte`](https://www.npmjs.com/package/vitest-browser-svelte)),但你也可以为尚未得到官方支持的框架集成[Testing Library](https://testing-library.com/)。
-
-### 何时使用 Testing Library {#when-to-use-testing-library}
-
-- 你的框架还没有官方的Vitest浏览器包
-- 你正在迁移使用Testing Library的现有测试
-- 你更喜欢Testing Library的API来处理特定的测试场景
-
-### 集成模式 {#integration-pattern}
-
-关键是使用 `page.elementLocator()` 来桥接 Testing Library 的 DOM 输出与 Vitest 的浏览器模式 API:
-
-```jsx
-// For Solid.js components
-import { render } from '@testing-library/solid'
-import { page } from 'vitest/browser'
-
-test('Solid component handles user interaction', async () => {
- // Use Testing Library to render the component
- const { baseElement, getByRole } = render(() =>
-
- )
-
- // Bridge to Vitest's browser mode for interactions and assertions
- const screen = page.elementLocator(baseElement)
-
- // Use Vitest's page queries for finding elements
- const incrementButton = screen.getByRole('button', { name: /increment/i })
-
- // Use Vitest's assertions and interactions
- await expect.element(screen.getByText('Count: 0')).toBeInTheDocument()
-
- // Trigger user interaction using Vitest's page API
- await incrementButton.click()
-
- await expect.element(screen.getByText('Count: 1')).toBeInTheDocument()
-})
-```
-
-### 可用的 Testing Library 包 {#available-testing-library-packages}
-
-与Vitest配合使用效果良好的流行Testing Library包:
-
-- [`@testing-library/solid`](https://github.com/solidjs/solid-testing-library) - 用于Solid.js
-- [`@marko/testing-library`](https://testing-library.com/docs/marko-testing-library/intro) - 用于Marko
-- [`@testing-library/svelte`](https://testing-library.com/docs/svelte-testing-library/intro) - [`vitest-browser-svelte`](https://www.npmjs.com/package/vitest-browser-svelte)的替代方案
-- [`@testing-library/vue`](https://testing-library.com/docs/vue-testing-library/intro) - [`vitest-browser-vue`](https://www.npmjs.com/package/vitest-browser-vue)的替代方案
-
-::: tip Migration Path
-如果你的框架后来获得了官方的Vitest支持,你可以通过替换Testing Library的 `render` 函数来逐步迁移,同时保持大部分测试逻辑不变。
-:::
-
-## 最佳实践 {#best-practices}
-
-### 1. 在CI/CD中使用浏览器模式 {#_1-use-browser-mode-for-ci-cd}
-确保测试在真实浏览器环境中运行以获得最准确的测试结果。浏览器模式提供准确的CSS渲染、真实的浏览器API和正确的事件处理。
-
-### 2. 测试用户交互 {#_2-test-user-interactions}
-使用Vitest的[交互API](/guide/browser/interactivity-api)模拟真实用户行为。使用`page.getByRole()`和`userEvent`方法,如我们的[高级测试模式](#advanced-testing-patterns)所示:
-
-```tsx
-// Good: Test actual user interactions
-await page.getByRole('button', { name: /submit/i }).click()
-await page.getByLabelText(/email/i).fill('user@example.com')
-
-// Avoid: Testing implementation details
-// component.setState({ email: 'user@example.com' })
-```
-
-### 3. 测试可访问性 {#_3-test-accessibility}
-通过测试键盘导航、焦点管理和ARIA属性,确保组件对所有用户都能正常工作。请查看我们的[测试可访问性](#testing-accessibility)示例了解实用模式:
-
-```tsx
-// Test keyboard navigation
-await userEvent.keyboard('{Tab}')
-await expect.element(document.activeElement).toHaveFocus()
-
-// Test ARIA attributes
-await expect.element(modal).toHaveAttribute('aria-modal', 'true')
-```
-
-### 4. 模拟外部依赖 {#_4-mock-external-dependencies}
-通过模拟API和外部服务,将测试重点放在组件逻辑上。这使得测试更快、更可靠。请查看我们的[隔离策略](#isolation-strategy)获取示例:
-
-```tsx
-// For API requests, we recommend using MSW (Mock Service Worker)
-// See: https://vitest.dev/guide/mocking/requests
-// This provides more realistic request/response mocking
-
-// For module mocking, use the import() syntax
-vi.mock(import('../components/UserCard'), () => ({
- default: vi.fn(() => Mocked UserCard
)
-}))
-```
-
-### 5. 使用有意义的测试描述 {#_5-use-meaningful-test-descriptions}
-编写测试描述时,应解释预期行为,而不是实现细节:
-
-```tsx
-// Good: Describes user-facing behavior
-test('shows error message when email format is invalid')
-test('disables submit button while form is submitting')
-
-// Avoid: Implementation-focused descriptions
-test('calls validateEmail function')
-test('sets isSubmitting state to true')
-```
-
-## 高级测试模式 {#advanced-testing-patterns}
-
-### 测试组件状态管理 {#testing-component-state-management}
-
-```tsx
-// Testing stateful components and state transitions
-test('ShoppingCart manages items correctly', async () => {
- const { getByText, getByTestId } = render()
-
- // Initially empty
- await expect.element(getByText('Your cart is empty')).toBeInTheDocument()
-
- // Add item
- await page.getByRole('button', { name: /add laptop/i }).click()
-
- // Verify state change
- await expect.element(getByText('1 item')).toBeInTheDocument()
- await expect.element(getByText('Laptop - $999')).toBeInTheDocument()
-
- // Test quantity updates
- await page.getByRole('button', { name: /increase quantity/i }).click()
- await expect.element(getByText('2 items')).toBeInTheDocument()
-})
-```
-
-### 测试带有数据获取的异步组件 {#testing-async-components-with-data-fetching}
-
-```tsx
-// Option 1: Recommended - Use MSW (Mock Service Worker) for API mocking
-import { http, HttpResponse } from 'msw'
-import { setupServer } from 'msw/node'
-
-// Set up MSW server with API handlers
-const server = setupServer(
- http.get('/api/users/:id', ({ params }) => {
- const { id } = params
- if (id === '123') {
- return HttpResponse.json({ name: 'John Doe', email: 'john@example.com' })
- }
- return HttpResponse.json({ error: 'User not found' }, { status: 404 })
- })
-)
-
-// Start server before all tests
-beforeAll(() => server.listen())
-afterEach(() => server.resetHandlers())
-afterAll(() => server.close())
-
-test('UserProfile handles loading, success, and error states', async () => {
- // Test success state
- const { getByText } = render()
- // expect.element auto-retries until elements are found
- await expect.element(getByText('John Doe')).toBeInTheDocument()
- await expect.element(getByText('john@example.com')).toBeInTheDocument()
-
- // Test error state by overriding the handler for this test
- server.use(
- http.get('/api/users/:id', () => {
- return HttpResponse.json({ error: 'User not found' }, { status: 404 })
- })
- )
-
- const { getByText: getErrorText } = render()
- await expect.element(getErrorText('Error: User not found')).toBeInTheDocument()
-})
-```
-
-### 测试组件通信 {#testing-component-communication}
-
-```tsx
-// Test parent-child component interaction
-test('parent and child components communicate correctly', async () => {
- const mockOnSelectionChange = vi.fn()
-
- const { getByText } = render(
-
-
-
-
- )
-
- // Interact with child component
- await page.getByRole('checkbox', { name: /electronics/i }).click()
-
- // Verify parent receives the communication
- expect(mockOnSelectionChange).toHaveBeenCalledWith({
- category: 'electronics',
- filters: ['electronics']
- })
-
- // Verify other child component updates (expect.element auto-retries)
- await expect.element(getByText('Showing Electronics products')).toBeInTheDocument()
-})
-```
-
-### 测试带验证的复杂表单 {#testing-complex-forms-with-validation}
-
-```tsx
-test('ContactForm handles complex validation scenarios', async () => {
- const mockSubmit = vi.fn()
- const { getByLabelText, getByText } = render(
-
- )
-
- const nameInput = page.getByLabelText(/full name/i)
- const emailInput = page.getByLabelText(/email/i)
- const messageInput = page.getByLabelText(/message/i)
- const submitButton = page.getByRole('button', { name: /send message/i })
-
- // Test validation triggers
- await submitButton.click()
-
- await expect.element(getByText('Name is required')).toBeInTheDocument()
- await expect.element(getByText('Email is required')).toBeInTheDocument()
- await expect.element(getByText('Message is required')).toBeInTheDocument()
-
- // Test partial validation
- await nameInput.fill('John Doe')
- await submitButton.click()
-
- await expect.element(getByText('Name is required')).not.toBeInTheDocument()
- await expect.element(getByText('Email is required')).toBeInTheDocument()
-
- // Test email format validation
- await emailInput.fill('invalid-email')
- await submitButton.click()
-
- await expect.element(getByText('Please enter a valid email')).toBeInTheDocument()
-
- // Test successful submission
- await emailInput.fill('john@example.com')
- await messageInput.fill('Hello, this is a test message.')
- await submitButton.click()
-
- expect(mockSubmit).toHaveBeenCalledWith({
- name: 'John Doe',
- email: 'john@example.com',
- message: 'Hello, this is a test message.'
- })
-})
-```
-
-### 测试错误边界 {#testing-error-boundaries}
-
-```tsx
-// Test how components handle and recover from errors
-function ThrowError({ shouldThrow }: { shouldThrow: boolean }) {
- if (shouldThrow) {
- throw new Error('Component error!')
- }
- return Component working fine
-}
-
-test('ErrorBoundary catches and displays errors gracefully', async () => {
- const { getByText, rerender } = render(
- Something went wrong}>
-
-
- )
-
- // Initially working
- await expect.element(getByText('Component working fine')).toBeInTheDocument()
-
- // Trigger error
- rerender(
- Something went wrong}>
-
-
- )
-
- // Error boundary should catch it
- await expect.element(getByText('Something went wrong')).toBeInTheDocument()
-})
-```
-
-### 测试可访问性 {#testing-accessibility}
-
-```tsx
-test('Modal component is accessible', async () => {
- const { getByRole, getByLabelText } = render(
-
-
-
- )
-
- // Test focus management - modal should receive focus when opened
- // This is crucial for screen reader users to know a modal opened
- const modal = getByRole('dialog')
- await expect.element(modal).toHaveFocus()
-
- // Test ARIA attributes - these provide semantic information to screen readers
- await expect.element(modal).toHaveAttribute('aria-labelledby') // Links to title element
- await expect.element(modal).toHaveAttribute('aria-modal', 'true') // Indicates modal behavior
-
- // Test keyboard navigation - Escape key should close modal
- // This is required by ARIA authoring practices
- await userEvent.keyboard('{Escape}')
- // expect.element auto-retries until modal is removed
- await expect.element(modal).not.toBeInTheDocument()
-
- // Test focus trap - tab navigation should cycle within modal
- // This prevents users from tabbing to content behind the modal
- const firstInput = getByLabelText(/username/i)
- const lastButton = getByRole('button', { name: /save/i })
-
- // Use click to focus on the first input, then test tab navigation
- await firstInput.click()
- await userEvent.keyboard('{Shift>}{Tab}{/Shift}') // Shift+Tab goes backwards
- await expect.element(lastButton).toHaveFocus() // Should wrap to last element
-})
-```
-
-## 调试组件测试 {#debugging-component-tests}
-
-### 1. 使用浏览器开发者工具 {#_1-use-browser-dev-tools}
-
-浏览器模式在真实浏览器中运行测试,让你可以使用完整的开发者工具。当测试失败时,你可以:
-
-- **在测试执行期间打开浏览器开发者工具**(按F12或右键点击→检查)
-- **在测试代码或组件代码中设置断点**
-- **检查DOM**以查看实际渲染的输出
-- **检查控制台错误**以查找JavaScript错误或警告
-- **监控网络请求**以调试API调用
-
-对于有头模式调试,可以在浏览器配置中临时添加`headless: false`。
-
-### 2. 添加调试语句 {#_2-add-debug-statements}
-
-使用策略性日志记录来理解测试失败:
-
-```tsx
-test('debug form validation', async () => {
- render()
-
- const submitButton = page.getByRole('button', { name: /submit/i })
- await submitButton.click()
-
- // Debug: Check if element exists with different query
- const errorElement = page.getByText('Email is required')
- console.log('Error element found:', errorElement.length)
-
- await expect.element(errorElement).toBeInTheDocument()
-})
-```
-
-### 3. 检查渲染输出 {#_3-inspect-rendered-output}
-
-当组件未按预期渲染时,请系统性地进行调查:
-
-**使用Vitest的浏览器UI:**
-- 在启用浏览器模式的情况下运行测试
-- 打开终端中显示的浏览器URL以查看测试运行情况
-- 可视化检查有助于识别CSS问题、布局问题或缺失元素
-
-**测试元素查询:**
-```tsx
-// Debug why elements can't be found
-const button = page.getByRole('button', { name: /submit/i })
-console.log('Button count:', button.length) // Should be 1
-
-// Try alternative queries if the first one fails
-if (button.length === 0) {
- console.log('All buttons:', page.getByRole('button').length)
- console.log('By test ID:', page.getByTestId('submit-btn').length)
-}
-```
-
-### 4. 验证选择器 {#_4-verify-selectors}
-
-选择器问题是测试失败的常见原因。请系统性地调试它们:
-
-**检查可访问名称:**
-```tsx
-// If getByRole fails, check what roles/names are available
-const buttons = page.getByRole('button').all()
-for (const button of buttons) {
- // Use element() to get the DOM element and access native properties
- const element = button.element()
- const accessibleName = element.getAttribute('aria-label') || element.textContent
- console.log(`Button: "${accessibleName}"`)
-}
-```
-
-**测试不同的查询策略:**
-```tsx
-// Multiple ways to find the same element using .or for auto-retrying
-const submitButton = page.getByRole('button', { name: /submit/i }) // By accessible name
- .or(page.getByTestId('submit-button')) // By test ID
- .or(page.getByText('Submit')) // By exact text
-// Note: Vitest doesn't have page.locator(), use specific getBy* methods instead
-```
-
-**常见的选择器调试模式:**
-```tsx
-test('debug element queries', async () => {
- render()
-
- // Check if element is visible and enabled
- const emailInput = page.getByLabelText(/email/i)
- await expect.element(emailInput).toBeVisible() // Will show if element is visible and print DOM if not
-})
-```
-
-### 5. 调试异步问题 {#_5-debugging-async-issues}
-
-组件测试经常涉及时机问题:
-
-```tsx
-test('debug async component behavior', async () => {
- render()
-
- // expect.element will automatically retry and show helpful error messages
- await expect.element(page.getByText('John Doe')).toBeInTheDocument()
-})
-```
-
-## 从其他测试框架迁移 {#migration-from-other-testing-frameworks}
-
-### 从 Jest + Testing Library 迁移 {#from-jest-testing-library}
-
-大多数 Jest + Testing Library 测试只需少量更改即可工作:
-
-```ts
-// Before (Jest)
-import { render, screen } from '@testing-library/react' // [!code --]
-
-// After (Vitest)
-import { render } from 'vitest-browser-react' // [!code ++]
-```
-
-### 主要差异 {#key-differences}
-
-- 使用 `await expect.element()` 而不是 `expect()` 进行 DOM 断言
-- 使用 `vitest/browser` 进行用户交互而不是 `@testing-library/user-event`
-- 浏览器模式提供真实的浏览器环境以进行准确的测试
-
-## 了解更多 {#learn-more}
-
-- [浏览器模式文档](/guide/browser/)
-- [断言API](/guide/browser/assertion-api)
-- [交互性API](/guide/browser/interactivity-api)
-- [示例仓库](https://github.com/vitest-tests/browser-examples)
diff --git a/guide/browser/config.md b/guide/browser/config.md
index f5830437..b8ee8eb7 100644
--- a/guide/browser/config.md
+++ b/guide/browser/config.md
@@ -1,16 +1,15 @@
-# 浏览器配置参考 {#browser-config-reference}
+# 浏览器配置 {#browser-config-reference}
我们可以通过更新 [配置文件](/config/) 中的 `test.browser` 字段来更改浏览器配置。一个简单的配置文件示例如下:
```ts [vitest.config.ts]
import { defineConfig } from 'vitest/config'
-import { playwright } from '@vitest/browser-playwright'
export default defineConfig({
test: {
browser: {
enabled: true,
- provider: playwright(),
+ provider: 'playwright',
instances: [
{
browser: 'chromium',
@@ -22,7 +21,7 @@ export default defineConfig({
})
```
-请参阅 ["配置参考"](/config/) 文章以获取不同的配置示例。
+请参阅 ["配置文件"](/config/) 文章以获取不同的配置示例。
::: warning
此页面上列出的 _所有选项_ 都位于配置中的 `test` 属性内:
@@ -40,18 +39,30 @@ export default defineConfig({
- **类型:** `boolean`
- **默认值:** `false`
-- **CLI:** `--browser`, `--browser.enabled=false`
+- **命令行终端:** `--browser`, `--browser.enabled=false`
默认情况下在浏览器中运行所有测试。请注意,`--browser` 仅在我们至少有一个 [`browser.instances`](#browser-instances) 项时有效。
## browser.instances
- **类型:** `BrowserConfig`
-- **默认值:** `[]`
+- **默认值:** `[{ browser: name }]`
+
+定义多个浏览器设置。每个配置必须至少有一个 `browser` 字段。配置支持我们的提供者配置:
+
+- [配置 Playwright](/guide/browser/playwright)
+- [配置 WebdriverIO](/guide/browser/webdriverio)
+
+::: tip
+为了在使用内置提供者时获得更好的类型安全性,我们应该在 [配置文件](/config/) 中引用以下类型之一(针对我们使用的提供者):
-定义多个浏览器设置。每个配置必须至少有一个 `browser` 字段。
+```ts
+///
+///
+```
+:::
-你可以指定大部分[项目选项](/config/)(未标记图标的选项)和一些 `browser` 选项,如`browser.testerHtmlPath`。
+你可以指定大部分 [配置选项](/config/) (未标记图标的选项)和一些 `browser` 选项,如`browser.testerHtmlPath`。
::: warning
每个浏览器配置都从根配置继承选项:
@@ -76,7 +87,9 @@ export default defineConfig({
})
```
-有关更多示例,请参阅 ["多设置" 指南](/guide/browser/multiple-setups)。
+在开发过程中,Vitest 仅支持一个 [非无头](#browser-headless) 配置。我们可以通过在配置中指定 `headless: false`,或提供 `--browser.headless=false` 标志,或使用 `--project=chromium` 标志过滤项目来限制有头项目。
+
+有关更多示例,请参阅 ["多种设置" 指南](/guide/browser/multiple-setups)。
:::
可用的 `browser` 选项列表:
@@ -89,13 +102,28 @@ export default defineConfig({
- [`browser.screenshotFailures`](#browser-screenshotfailures)
- [`browser.provider`](#browser-provider)
-在底层,Vitest 将这些实例转换为共享单个 Vite 服务器的单独[测试项目](/advanced/api/test-project),以获得更好的缓存性能。
+在底层,Vitest 将这些实例转换为共享单个 Vite 服务器的单独 [测试项目](/advanced/api/test-project),以获得更好的缓存性能。
+
+## browser.name 已弃用 {#browser-name}
+
+- **类型:** `string`
+- **CLI:** `--browser=safari`
+
+::: danger 已弃用
+此 API 已弃用,并将在 Vitest 4 中移除。请改用 [`browser.instances`](#browser-instances) 选项。
+:::
+
+在特定浏览器中运行所有测试。不同提供者中的可能选项:
+
+- `webdriverio`: `firefox`, `chrome`, `edge`, `safari`
+- `playwright`: `firefox`, `webkit`, `chromium`
+- 自定义:任何将传递给提供者的字符串
## browser.headless
- **类型:** `boolean`
- **默认值:** `process.env.CI`
-- **CLI:** `--browser.headless`, `--browser.headless=false`
+- **命令行终端:** `--browser.headless`, `--browser.headless=false`
在 `headless` 模式下运行浏览器。如果我们在 CI 中运行 Vitest,则默认启用此模式。
@@ -103,7 +131,7 @@ export default defineConfig({
- **类型:** `boolean`
- **默认值:** `true`
-- **CLI:** `--browser.isolate`, `--browser.isolate=false`
+- **命令行终端:** `--browser.isolate`, `--browser.isolate=false`
在单独的 iframe 中运行每个测试。
@@ -117,96 +145,80 @@ HTML 入口点的路径。可以是相对于项目根目录的路径。此文件
- **类型:** `number | { port?, strictPort?, host? }`
- **默认值:** `63315`
-- **CLI:** `--browser.api=63315`, `--browser.api.port=1234, --browser.api.host=example.com`
+- **命令行终端:** `--browser.api=63315`, `--browser.api.port=1234, --browser.api.host=example.com`
配置为浏览器提供代码的 Vite 服务器的选项。不影响 [`test.api`](#api) 选项。默认情况下,Vitest 分配端口 `63315` 以避免与开发服务器冲突,允许我们同时运行两者。
## browser.provider {#browser-provider}
-- **类型:** `BrowserProviderOption`
+- **类型:** `'webdriverio' | 'playwright' | 'preview' | string`
- **默认值:** `'preview'`
- **CLI:** `--browser.provider=playwright`
-提供者工厂的返回值。你可以从 `@vitest/browser-` 导入工厂函数,或者创建自己的提供者:
-
-```ts{8-10}
-import { playwright } from '@vitest/browser-playwright'
-import { webdriverio } from '@vitest/browser-webdriverio'
-import { preview } from '@vitest/browser-preview'
+在运行浏览器测试时使用的提供者路径。Vitest 提供了三个提供者,分别是 `preview`(默认)、`webdriverio` 和 `playwright`。自定义提供者应使用 `default` 导出,并符合以下接口规范:
-export default defineConfig({
- test: {
- browser: {
- provider: playwright(),
- provider: webdriverio(),
- provider: preview(), // default
- },
- },
-})
+```ts
+export interface BrowserProvider {
+ name: string
+ supportsParallelism: boolean
+ getSupportedBrowsers: () => readonly string[]
+ beforeCommand?: (command: string, args: unknown[]) => Awaitable
+ afterCommand?: (command: string, args: unknown[]) => Awaitable
+ getCommandsContext: (sessionId: string) => Record
+ openPage: (sessionId: string, url: string, beforeNavigate?: () => Promise) => Promise
+ getCDPSession?: (sessionId: string) => Promise
+ close: () => Awaitable
+ initialize: (
+ ctx: TestProject,
+ options: BrowserProviderInitializationOptions
+ ) => Awaitable
+}
```
-要配置提供者如何初始化浏览器,你可以将选项传递给工厂函数:
+::: danger 高级 API
+自定义提供者 API 高度实验性,并且可能在补丁版本之间发生变化。如果你只需要在浏览器中运行测试,请改用 [`browser.instances`](#browser-instances) 选项。
+:::
+
+## browser.providerOptions 已弃用 {#browser-provideroptions}
+
+- **类型:** `BrowserProviderOptions`
+
+::: danger 已弃用
+此 API 已弃用,并将在 Vitest 4 中移除。请改用 [`browser.instances`](#browser-instances) 选项。
+:::
+
+调用 `provider.initialize` 时传递给提供者的选项。
-```ts{7-13,20-26}
-import { playwright } from '@vitest/browser-playwright'
+```ts
+import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
browser: {
- // shared provider options between all instances
- provider: playwright({
- launchOptions: {
- slowMo: 50,
- channel: 'chrome-beta',
+ providerOptions: {
+ launch: {
+ devtools: true,
},
- actionTimeout: 5_000,
- }),
- instances: [
- { browser: 'chromium' },
- {
- browser: 'firefox',
- // overriding options only for a single instance
- // this will NOT merge options with the parent one
- provider: playwright({
- launchOptions: {
- firefoxUserPrefs: {
- 'browser.startup.homepage': 'https://example.com',
- },
- },
- })
- }
- ],
+ },
},
},
})
```
-### Custom Provider advanced
-
-::: danger ADVANCED API
-自定义提供者 API 高度实验性,并且可能在补丁版本之间发生变化。如果你只需要在浏览器中运行测试,请改用 [`browser.instances`](#browser-instances) 选项。
-:::
+::: tip
+为了在使用内置提供者时获得更好的类型安全性,我们应该在 [配置文件](/config/) 中引用以下类型之一(针对我们使用的提供者):
```ts
-export interface BrowserProvider {
- name: string
- mocker?: BrowserModuleMocker
- /**
- * @experimental opt-in into file parallelisation
- */
- supportsParallelism: boolean
- getCommandsContext: (sessionId: string) => Record
- openPage: (sessionId: string, url: string) => Promise
- getCDPSession?: (sessionId: string) => Promise
- close: () => Awaitable
-}
+///
+///
```
+:::
## browser.ui
- **类型:** `boolean`
- **默认值:** `!isCI`
-- **CLI:** `--browser.ui=false`
+- **命令行终端:** `--browser.ui=false`
是否应将 Vitest UI 注入页面。默认情况下,在开发期间注入 UI iframe。
@@ -249,7 +261,7 @@ export interface BrowserProvider {
在测试 iframe 初始化之前应注入到编排器 HTML 中的自定义脚本。此 HTML 文档仅设置 iframe,并不实际导入我们的代码。
-脚本的 `src` 和 `content` 将由 Vite 插件处理。脚本应提供以下形状:
+脚本的 `src` 和 `content` 将由 Vite 插件处理。脚本应符合以下接口规范:
```ts
export interface BrowserScript {
@@ -282,12 +294,25 @@ export interface BrowserScript {
}
```
+## browser.testerScripts
+
+- **类型:** `BrowserScript[]`
+- **默认值:** `[]`
+
+::: danger 已弃用
+此 API 已弃用,并将在 Vitest 4 中移除。请改用 [`browser.testerHtmlPath`](#browser-testerhtmlpath) 字段。
+:::
+
+在测试环境初始化之前应注入到测试器 HTML 中的自定义脚本。这对于注入 Vitest 浏览器实现所需的 polyfill 非常有用。在几乎所有情况下,建议使用 [`setupFiles`](#setupfiles) 代替此选项。
+
+脚本的 `src` 和 `content` 将由 Vite 插件处理。
+
## browser.commands
- **类型:** `Record`
- **默认值:** `{ readFile, writeFile, ... }`
-可以在浏览器测试中从 `vitest/browser` 导入的自定义[命令](/guide/browser/commands)。
+可以从 `@vitest/browser/commands` 导入的自定义 [命令](/guide/browser/commands)。
## browser.connectTimeout
@@ -299,180 +324,3 @@ export interface BrowserScript {
::: info
这是浏览器与 Vitest 服务器建立 WebSocket 连接所需的时间。在正常情况下,此超时不应被触发。
:::
-
-## browser.trace
-
-- **类型:** `'on' | 'off' | 'on-first-retry' | 'on-all-retries' | 'retain-on-failure' | object`
-- **CLI:** `--browser.trace=on`, `--browser.trace=retain-on-failure`
-- **Default:** `'off'`
-
-Capture a trace of your browser test runs. You can preview traces with [Playwright Trace Viewer](https://trace.playwright.dev/).
-
-This options supports the following values:
-
-- `'on'` - capture trace for all tests. (not recommended as it's performance heavy)
-- `'off'` - do not capture traces.
-- `'on-first-retry'` - capture trace only when retrying the test for the first time.
-- `'on-all-retries'` - capture trace on every retry of the test.
-- `'retain-on-failure'` - capture trace only for tests that fail. This will automatically delete traces for tests that pass.
-- `object` - an object with the following shape:
-
-```ts
-interface TraceOptions {
- mode: 'on' | 'off' | 'on-first-retry' | 'on-all-retries' | 'retain-on-failure'
- /**
- * The directory where all traces will be stored. By default, Vitest
- * stores all traces in `__traces__` folder close to the test file.
- */
- tracesDir?: string
- /**
- * Whether to capture screenshots during tracing. Screenshots are used to build a timeline preview.
- * @default true
- */
- screenshots?: boolean
- /**
- * If this option is true tracing will
- * - capture DOM snapshot on every action
- * - record network activity
- * @default true
- */
- snapshots?: boolean
-}
-```
-
-::: danger WARNING
-This option is supported only by the [**playwright**](/guide/browser/playwright) provider.
-:::
-
-## browser.trackUnhandledErrors
-
-- **类型:** `boolean`
-- **Default:** `true`
-
-启用对未捕获错误和异常的跟踪,以便 Vitest 报告。
-
-如果需要隐藏某些错误,建议使用 [`onUnhandledError`](/config/#onunhandlederror) 选项。
-
-禁用此功能将完全移除所有 Vitest 的错误处理机制,有助于在启用“暂停于异常”功能时进行调试。
-
-## browser.expect
-
-- **类型:** `ExpectOptions`
-
-### browser.expect.toMatchScreenshot
-
-[`toMatchScreenshot`](/guide/browser/assertion-api.html#tomatchscreenshot) 断言的默认选项。
-这些选项将应用于所有截图断言。
-
-::: tip
-为截图断言设置全局默认值,有助于在整个测试套件中保持一致性,并减少单个测试中的重复。如果需要,你仍可以在特定测试用例的断言级别覆盖这些默认值。
-:::
-
-```ts
-import { defineConfig } from 'vitest/config'
-
-export default defineConfig({
- test: {
- browser: {
- enabled: true,
- expect: {
- toMatchScreenshot: {
- comparatorName: 'pixelmatch',
- comparatorOptions: {
- threshold: 0.2,
- allowedMismatchedPixels: 100,
- },
- resolveScreenshotPath: ({ arg, browserName, ext, testFileName }) =>
- `custom-screenshots/${testFileName}/${arg}-${browserName}${ext}`,
- },
- },
- },
- },
-})
-```
-
-`toMatchScreenshot` 断言中可用的 [所有选项](/guide/browser/assertion-api#options) 均可在此配置。此外,还提供了两个路径解析函数:`resolveScreenshotPath` 和 `resolveDiffPath`。
-
-#### browser.expect.toMatchScreenshot.resolveScreenshotPath
-
-- **类型:** `(data: PathResolveData) => string`
-- **Default output:** `` `${root}/${testFileDirectory}/${screenshotDirectory}/${testFileName}/${arg}-${browserName}-${platform}${ext}` ``
-
-一个用于自定义参考截图存储位置的函数。该函数接收一个包含以下属性的对象:
-
-- `arg: string`
-
- 路径**不含**扩展名,已清理且相对于测试文件。
- 这来自传递给 `toMatchScreenshot` 的参数;如果没有参数,将使用自动生成的名称。
-
- ```ts
- test('calls `onClick`', () => {
- expect(locator).toMatchScreenshot()
- // arg = "calls-onclick-1"
- })
-
- expect(locator).toMatchScreenshot('foo/bar/baz.png')
- // arg = "foo/bar/baz"
-
- expect(locator).toMatchScreenshot('../foo/bar/baz.png')
- // arg = "foo/bar/baz"
- ```
-
-- `ext: string`
-
- 截图扩展名,带前导点。
-
- 可以通过传递给 `toMatchScreenshot` 的参数设置,但如果使用了不支持的扩展名,值将回退为 `'.png'`。
-
-- `browserName: string`
-
- 实例的浏览器名称。
-
-- `platform: NodeJS.Platform`
-
- [`process.platform`](https://nodejs.org/docs/v22.16.0/api/process.html#processplatform) 属性的值。
-
-- `screenshotDirectory: string`
-
- 如果未提供值,则为 [`browser.screenshotDirectory`](/guide/browser/config#browser-screenshotdirectory)。
-
-- `root: string`
-
- 项目根目录([`root`](/config/#root))的绝对路径。
-
-- `testFileDirectory: string`
-
- 测试文件的路径,相对于项目的根目录([`root`](/config/#root))。
-
-- `testFileName: string`
-
- 测试文件的文件名。
-
-- `testName: string`
-
- [`test`](/api/#test) 的名称,包括父级 [`describe`](/api/#describe) ,已清理。
-
-- `attachmentsDir: string`
-
-如果未提供值,则为 [`attachmentsDir`](/config/#attachmentsdir) 提供的默认值。
-
-例如,按浏览器分组截图:
-
-```ts
-resolveScreenshotPath: ({ arg, browserName, ext, root, testFileName }) =>
- `${root}/screenshots/${browserName}/${testFileName}/${arg}${ext}`
-```
-
-#### browser.expect.toMatchScreenshot.resolveDiffPath
-
-- **类型:** `(data: PathResolveData) => string`
-- **Default output:** `` `${root}/${attachmentsDir}/${testFileDirectory}/${testFileName}/${arg}-${browserName}-${platform}${ext}` ``
-
-一个用于自定义截图比较失败时差异图像存储位置的函数。它接收与 [`resolveScreenshotPath`](#browser-expect-tomatchscreenshot-resolvescreenshotpath) 相同的数据对象。
-
-例如,将差异图像存储在附件的子目录中:
-
-```ts
-resolveDiffPath: ({ arg, attachmentsDir, browserName, ext, root, testFileName }) =>
- `${root}/${attachmentsDir}/screenshot-diffs/${testFileName}/${arg}-${browserName}${ext}`
-```
diff --git a/guide/browser/context.md b/guide/browser/context.md
index 2e5f6c07..fd4cc603 100644
--- a/guide/browser/context.md
+++ b/guide/browser/context.md
@@ -9,7 +9,7 @@ Vitest 通过 `vitest/browser` 入口点公开上下文模块。从 2.0 开始
## `userEvent`
::: tip
-`userEvent` API 的详细说明见[Interactivity API](/guide/browser/interactivity-api).
+`userEvent` API 的详细说明见 [Interactivity API](/guide/browser/interactivity-api)。
:::
```ts
@@ -43,7 +43,7 @@ export const userEvent: {
## `commands`
::: tip
-Commands API 的详细说明见[Commands API](/guide/browser/commands).
+Commands API 的详细说明见 [Commands API](/guide/browser/commands)。
:::
```ts
@@ -73,10 +73,11 @@ export const page: {
* 对测试 iframe 或特定元素进行截图。
* @returns 截图文件的路径或路径和 base64 编码。
*/
- screenshot: ((options: Omit & { base64: true }) => Promise<{
+ screenshot(options: Omit & { base64: true }): Promise<{
path: string
base64: string
- }>) & ((options?: ScreenshotOptions) => Promise)
+ }>
+ screenshot(options?: ScreenshotOptions): Promise
/**
* 使用自定义方法扩展默认的 `page` 对象。
*/
@@ -85,12 +86,6 @@ export const page: {
* 将一个 HTML 元素包装在 `Locator` 中。在查询元素时,搜索将始终返回此元素。
*/
elementLocator(element: Element): Locator
- /**
- * The iframe locator. This is a document locator that enters the iframe body
- * and works similarly to the `page` object.
- * **Warning:** At the moment, this is supported only by the `playwright` provider.
- */
- frameLocator(iframeElement: Locator): FrameLocator
/**
* Locator API。更多详细信息请参见其文档。
@@ -114,37 +109,8 @@ export const page: {
在这种情况下,`path` 也会被忽略。
:::
-### frameLocator
-
-```ts
-function frameLocator(iframeElement: Locator): FrameLocator
-```
-
-`frameLocator` 方法返回一个 `FrameLocator` 实例,可用于查找 iframe 内的元素。
-
-frame locator 类似于 `page`。它不指向 Iframe HTML 元素,而是指向 iframe 的文档。
-
-```ts
-const frame = page.frameLocator(
- page.getByTestId('iframe')
-)
-
-await frame.getByText('Hello World').click() // ✅
-await frame.click() // ❌ Not available
-```
-
-::: danger IMPORTANT
-目前,`frameLocator` 方法仅支持 `playwright` 提供者。
-
-交互方法(如 `click` 或 `fill`)在 iframe 内的元素上始终可用,但使用 `expect.element` 进行断言时要求 iframe 具有[同源策略](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy)。
-:::
-
## `cdp`
-```ts
-function cdp(): CDPSession
-```
-
`cdp` 导出返回当前的 Chrome DevTools 协议会话。它主要用于库作者在其基础上构建工具。
::: warning
diff --git a/guide/browser/index.md b/guide/browser/index.md
index 109639a7..1de5689e 100644
--- a/guide/browser/index.md
+++ b/guide/browser/index.md
@@ -8,7 +8,7 @@ outline: deep
此页面提供有关 Vitest API 中实验性浏览器模式功能的信息,该功能允许你在浏览器中本地运行测试,提供对窗口和文档等浏览器全局变量的访问。此功能目前正在开发中,API 未来可能会更改。
::: tip
-如果你需要 `expect` 、`vi` ,或者像测试项目、类型测试等通用 API 的文档,请查看 [「快速上手」指南](/guide/)。
+如果你需要 `expect` 、`vi` ,或者像测试项目、类型测试等通用 API 的文档,请查看 [“快速起步” 指南](/guide/)。
:::
@@ -35,7 +35,7 @@ bunx vitest init browser
### 手动安装 {#manual-installation}
-我们也可以手动安装软件包。默认情况下,浏览器模式不需要任何额外的 E2E provider 就能在本地运行测试,因为它会复用你现有的浏览器。
+我们也可以手动安装软件包。默认情况下,浏览器模式不需要任何额外的端到端 provider 就能在本地运行测试,因为它会复用你现有的浏览器。
::: code-group
```bash [npm]
@@ -104,9 +104,9 @@ import { playwright } from '@vitest/browser-playwright'
export default defineConfig({
test: {
browser: {
- provider: playwright(),
+ provider: playwright(), // 或者 'webdriverio'
enabled: true,
- // at least one instance is required
+ // 至少需要一个实例
instances: [
{ browser: 'chromium' },
],
@@ -210,26 +210,6 @@ export default defineConfig({
}
})
```
-```ts [qwik]
-import { qwikVite } from '@builder.io/qwik/optimizer'
-import { playwright } from '@vitest/browser-playwright'
-
-// optional, run the tests in SSR mode
-import { testSSR } from 'vitest-browser-qwik/ssr-plugin'
-
-import { defineConfig } from 'vitest/config'
-
-export default defineConfig({
- plugins: [testSSR(), qwikVite()],
- test: {
- browser: {
- enabled: true,
- provider: playwright(),
- instances: [{ browser: 'chromium' }]
- },
- },
-})
-```
:::
如果你想让部分测试通过基于 Node 的运行器执行,可以在配置中使用 [`projects`](/guide/projects) 选项,并为不同的测试策略提供独立的配置:
@@ -245,8 +225,8 @@ export default defineConfig({
projects: [
{
test: {
- // an example of file based convention,
- // you don't have to follow it
+ // 基于文件命名约定的示例
+ // 非强制要求
include: [
'tests/unit/**/*.{test,spec}.ts',
'tests/**/*.unit.{test,spec}.ts',
@@ -257,8 +237,8 @@ export default defineConfig({
},
{
test: {
- // an example of file based convention,
- // you don't have to follow it
+ // 基于文件命名约定的示例
+ // 非强制要求
include: [
'tests/browser/**/*.{test,spec}.ts',
'tests/**/*.browser.{test,spec}.ts',
@@ -278,9 +258,9 @@ export default defineConfig({
})
```
-## Browser Option Types
+## 浏览器选项类型 {#browser-option-types}
-Vitest 中的浏览器选项取决于provider。如果在配置文件中传递 `--browser` 且未指定其名称,则 Vitest 将失败。可用选项:
+Vitest 中的浏览器选项取决于 provider。如果在配置文件中传递 `--browser` 且未指定其名称,则 Vitest 将失败。可用选项:
- `webdriverio` 支持这些浏览器:
- `firefox`
- `chrome`
@@ -291,18 +271,62 @@ Vitest 中的浏览器选项取决于provider。如果在配置文件中传递 `
- `webkit`
- `chromium`
-## Browser Compatibility
+## TypeScript
+
+默认情况下,TypeScript 无法识别 providers 选项和额外的 `expect` 属性。如果我们不使用任何 providers ,请确保在测试、[设置文件](/config/#setupfiles) 或 [配置文件](/config/) 中引用 `@vitest/browser/matchers`,以获取额外的 `expect` 定义。如果我们使用自定义 providers ,请确保在同一文件中添加 `@vitest/browser/providers/playwright` 或 `@vitest/browser/providers/webdriverio`,以便 TypeScript 可以获取自定义选项的定义:
+
+::: code-group
+```ts [default]
+///
+```
+```ts [playwright]
+///
+```
+```ts [webdriverio]
+///
+```
+:::
+
+或者,我们也可以将它们添加到 `tsconfig.json` 文件中的 `compilerOptions.types` 字段。请注意,在此字段中指定任何内容将禁用 `@types/*` 包的 [自动加载](https://www.typescriptlang.org/tsconfig/#types) 功能。
+
+::: code-group
+```json [default]
+{
+ "compilerOptions": {
+ "types": ["@vitest/browser/matchers"]
+ }
+}
+```
+```json [playwright]
+{
+ "compilerOptions": {
+ "types": ["@vitest/browser/providers/playwright"]
+ }
+}
+```
+```json [webdriverio]
+{
+ "compilerOptions": {
+ "types": ["@vitest/browser/providers/webdriverio"]
+ }
+}
+```
+:::
+
+## 浏览器兼容性 {#browser-compatibility}
Vitest 使用 [Vite dev server](https://cn.vitejs.dev/guide/#browser-support) 来运行我们的测试,因此我们只支持 [`esbuild.target`](https://cn.vitejs.dev/config/shared-options#esbuild)选项(默认为 `esnext`)中指定的功能。
-默认情况下,Vite 的目标浏览器支持本地 [ES Modules](https://caniuse.com/es6-module)、本地 [ESM dynamic import](https://caniuse.com/es6-module-dynamic-import) 和 [`import.meta`](https://caniuse.com/mdn-javascript_operators_import_meta)。此外,我们还利用 [`BroadcastChannel`](https://caniuse.com/?search=BroadcastChannel)在 iframe 之间进行通信:
+默认情况下,Vite 的目标浏览器支持原生 [ES Modules](https://caniuse.com/es6-module)、原生 [ESM 动态导入](https://caniuse.com/es6-module-dynamic-import) 和 [`import.meta`](https://caniuse.com/mdn-javascript_operators_import_meta)。此外,我们还利用 [`BroadcastChannel`](https://caniuse.com/?search=BroadcastChannel)在 iframe 之间进行通信:
- Chrome >=87
- Firefox >=78
- Safari >=15.4
- Edge >=88
-## Running Tests
+## 运行测试 {#running-tests}
+
+当在 browser 选项中指定浏览器名称时,Vitest 默认会尝试使用 `preview` 启动指定浏览器,并运行测试。若不想使用 `preview`,可通过 `browser.provider` 选项配置自定义浏览器 provider。
要使用 CLI 指定浏览器,请使用 `--browser` 标志后跟浏览器名称,如下所示:
@@ -322,13 +346,13 @@ npx vitest --browser.headless
Vitest 默认会在开发模式下自动打开浏览器界面,测试会在页面中央的 iframe 中执行。你可以通过选择界面中的预设尺寸、在测试中调用 `page.viewport` 方法,或者在 [配置文件](/config/#browser-viewport) 中设置默认值来调整视口大小。
-## Headless
+## 无头模式 {#headless}
-headless 模式是浏览器模式下可用的另一个选项。在 headless 模式下,浏览器在没有用户界面的情况下在后台运行,这对于运行自动化测试非常有用。Vitest 中的 headless 选项可以设置为布尔值以启用或禁用 headless 模式。
+无头模式是浏览器模式下可用的另一个选项。在无头模式下,浏览器在没有用户界面的情况下在后台运行,这对于运行自动化测试非常有用。Vitest 中的 headless 选项可以设置为布尔值以启用或禁用无头模式。
-在使用 headless 模式时,Vitest 不会自动打开用户界面。如果我们希望继续使用用户界面,同时让测试以 headless 模式运行,我们可以安装`[@vitest/ui](/guide/ui)`包,并在运行Vitest时传递`--ui`标志。
+在使用无头模式时,Vitest 不会自动打开用户界面。如果我们希望继续使用用户界面,同时让测试以 无头模式运行,我们可以安装 [`@vitest/ui`](/guide/ui) 包,并在运行Vitest时传递 `--ui` 标志。
-这是启用 headless 模式的示例配置:
+这是启用无头模式的示例配置:
```ts [vitest.config.ts]
import { defineConfig } from 'vitest/config'
@@ -345,19 +369,19 @@ export default defineConfig({
})
```
-你还可以在 CLI 中使用 `--browser.headless` 标志设置 headless 模式,如下所示:
+你还可以在 CLI 中使用 `--browser.headless` 标志设置无头模式,如下所示:
```sh
npx vitest --browser.headless
```
-在这种情况下,Vitest 将使用 Chrome 浏览器以 headless 模式运行。
+在这种情况下,Vitest 将使用 Chrome 浏览器以无头模式运行。
::: warning
默认情况下Headless模式不可用。我们需要使用 [`playwright`](https://npmjs.com/package/playwright) 或 [`webdriverio`](https://www.npmjs.com/package/webdriverio) 提供程序来启用此功能。
:::
-## Examples
+## 示例 {#examples}
一般情况下,我们不需要任何依赖来使用浏览器模式:
@@ -367,7 +391,7 @@ import { page } from 'vitest/browser'
import { render } from './my-render-function.js'
test('properly handles form inputs', async () => {
- render() // mount DOM elements
+ render() // 挂载 DOM 元素
// 断言初始状态。
await expect.element(page.getByText('Hi, my name is Alice')).toBeInTheDocument()
@@ -391,9 +415,9 @@ test('properly handles form inputs', async () => {
其他框架也有社区提供的软件包:
-- [`vitest-browser-lit`](https://github.com/EskiMojo14/vitest-browser-lit) to render [lit](https://lit.dev) components
-- [`vitest-browser-preact`](https://github.com/JoviDeCroock/vitest-browser-preact) to render [preact](https://preactjs.com) components
-- [`vitest-browser-qwik`](https://github.com/kunai-consulting/vitest-browser-qwik) to render [qwik](https://qwik.dev) components
+- [`vitest-browser-lit`](https://github.com/EskiMojo14/vitest-browser-lit) 渲染 [lit](https://lit.dev) 组件
+- [`vitest-browser-preact`](https://github.com/JoviDeCroock/vitest-browser-preact) 渲染 [preact](https://preactjs.com) 组件
+- [`vitest-browser-qwik`](https://github.com/kunai-consulting/vitest-browser-qwik) 渲染 [qwik](https://qwik.dev) 组件
如果你的框架没有被包含在内,请随时创建你自己的软件包——它是一个简单的封装,围绕着框架渲染器和 `page.elementLocator` API。我们会在本页面添加指向它的链接。请确保其名称以 `vitest-browser-` 开头。
@@ -406,7 +430,7 @@ import { page } from 'vitest/browser'
await expect.element(page.getByText('Hello World')).toBeInTheDocument()
```
-Vitest 暴露了一个[上下文 API](/guide/browser/context),其中包含一组在测试中可能对你有用的实用程序。例如,如果你需要进行交互操作,比如点击元素或在输入框中输入文本,你可以使用来自 `vitest/browser` 的 `userEvent`。更多内容请参阅[交互性 API](/guide/browser/interactivity-api)。
+Vitest 暴露了一个 [上下文 API](/guide/browser/context),其中包含一组在测试中可能对你有用的实用程序。例如,如果你需要进行交互操作,比如点击元素或在输入框中输入文本,你可以使用来自 `vitest/browser` 的 `userEvent`。更多内容请参阅 [交互性 API](/guide/browser/interactivity-api)。
```ts
import { page, userEvent } from 'vitest/browser'
@@ -499,29 +523,14 @@ test('greeting appears on click', async () => {
await expect.element(greeting).toBeInTheDocument()
})
```
-```tsx [qwik]
-import { render } from 'vitest-browser-qwik'
-import Greeting from './greeting'
-
-test('greeting appears on click', async () => {
- // renderSSR and renderHook are also available
- const screen = render()
-
- const button = screen.getByRole('button')
- await button.click()
- const greeting = screen.getByText(/hello world/iu)
-
- await expect.element(greeting).toBeInTheDocument()
-})
-```
:::
Vitest 并不支持所有开箱即用的框架,但我们可以使用外部工具来运行这些框架的测试。我们还鼓励社区创建他们自己的 `vitest-browser` 封装程序,如果我们有这样的封装程序,请随时将其添加到上述示例中。
对于不支持的框架,我们建议使用 `testing-library` 软件包:
-- [`@solidjs/testing-library`](https://testing-library.com/docs/solid-testing-library/intro) to render [solid](https://www.solidjs.com) components
-- [`@marko/testing-library`](https://testing-library.com/docs/marko-testing-library/intro) to render [marko](https://markojs.com) components
+- [`@solidjs/testing-library`](https://testing-library.com/docs/solid-testing-library/intro) 渲染 [solid](https://www.solidjs.com) 组件
+- [`@marko/testing-library`](https://testing-library.com/docs/marko-testing-library/intro) 渲染 [marko](https://markojs.com) 组件
我们还可以在 [`browser-examples`](https://github.com/vitest-tests/browser-examples) 中查看更多的案例。
@@ -583,7 +592,7 @@ test('renders a message', async () => {
在这类情况下,Vitest 会为相关 API 提供带有默认返回值的内置 mock,从而避免用户不小心使用同步弹窗等 Web API 时导致程序卡死。不过,仍然强烈建议用户自行对这些 Web API 进行 mock,以获得更稳定、可控的测试体验。更多内容可参考 [模拟](/guide/mocking) 章节。
-### 对模块的导出内容进行监听(Spy)。 {#spying-on-module-exports}
+### 对模块的导出内容进行监听(Spy) {#spying-on-module-exports}
在浏览器模式下,Vitest 依赖浏览器自身对 ESM 模块的原生支持来加载模块。此时,模块的命名空间对象是不可修改的,这与 Node.js 测试中 Vitest 能够对模块执行打补丁不同。因此,你不能对通过 import 导入的对象使用 `vi.spyOn` :
diff --git a/guide/browser/interactivity-api.md b/guide/browser/interactivity-api.md
index ea88e14e..43e5c328 100644
--- a/guide/browser/interactivity-api.md
+++ b/guide/browser/interactivity-api.md
@@ -12,7 +12,16 @@ import { userEvent } from 'vitest/browser'
await userEvent.click(document.querySelector('.button'))
```
-几乎所有的 `userEvent` 方法都继承了其提供者的选项。
+几乎所有的 `userEvent` 方法都继承了其提供者的选项。要在我们的 IDE 中查看所有可用选项,请根据我们的提供者,将 `webdriver` 或 `playwright` 类型添加到我们的 [setup 文件](/config/#setupfile) 或 [配置文件](/config/)中(取决于我们的 `tsconfig.json` 中 `included` 部分包含的内容):
+
+::: code-group
+```ts [playwright]
+///
+```
+```ts [webdriverio]
+///
+```
+:::
## userEvent.setup
@@ -30,11 +39,11 @@ import { userEvent as vitestUserEvent } from 'vitest/browser'
import { userEvent as originalUserEvent } from '@testing-library/user-event'
import { userEvent as vitestUserEvent } from '@vitest/browser/context'
-await vitestUserEvent.keyboard('{Shift}') // press shift without releasing
-await vitestUserEvent.keyboard('{/Shift}') // releases shift
+await vitestUserEvent.keyboard('{Shift}') // 按住 shift 键不放
+await vitestUserEvent.keyboard('{/Shift}') // 放开 shift 键不放
-await originalUserEvent.keyboard('{Shift}') // press shift without releasing
-await originalUserEvent.keyboard('{/Shift}') // DID NOT release shift because the state is different
+await originalUserEvent.keyboard('{Shift}') // 按住 shift 键不放
+await originalUserEvent.keyboard('{/Shift}') // 没有放开 shift 键,因为状态不同
```
这种行为更有用,因为我们并没有模拟键盘,而是实际按下了 Shift 键,所以保留原来的行为会在字段中键入时造成意想不到的问题。
@@ -58,12 +67,12 @@ test('clicks on an element', async () => {
const logo = page.getByRole('img', { name: /logo/ })
await userEvent.click(logo)
- // or you can access it directly on the locator
+ // 或者你可以直接从定位器上访问
await logo.click()
})
```
-References:
+相关链接:
- [Playwright `locator.click` API](https://playwright.dev/docs/api/class-locator#locator-click)
- [WebdriverIO `element.click` API](https://webdriver.io/docs/api/element/click/)
@@ -89,12 +98,12 @@ test('triggers a double click on an element', async () => {
const logo = page.getByRole('img', { name: /logo/ })
await userEvent.dblClick(logo)
- // or you can access it directly on the locator
+ // 或者你可以直接从定位器上访问
await logo.dblClick()
})
```
-References:
+相关链接:
- [Playwright `locator.dblclick` API](https://playwright.dev/docs/api/class-locator#locator-dblclick)
- [WebdriverIO `element.doubleClick` API](https://webdriver.io/docs/api/element/doubleClick/)
@@ -126,7 +135,7 @@ test('triggers a triple click on an element', async () => {
})
await userEvent.tripleClick(logo)
- // or you can access it directly on the locator
+ // 或者你可以直接从定位器上访问
await logo.tripleClick()
expect(tripleClickFired).toBe(true)
@@ -160,7 +169,7 @@ test('update input', async () => {
await userEvent.fill(input, '{{a[[') // input.value == {{a[[
await userEvent.fill(input, '{Shift}') // input.value == {Shift}
- // or you can access it directly on the locator
+ // 或者你可以直接从定位器上访问
await input.fill('foo') // input.value == foo
})
```
@@ -255,7 +264,7 @@ function type(
`type` 方法在 [`keyboard`](https://testing-library.com/docs/user-event/keyboard) API 的基础上实现了 `@testing-library/user-event` 的 [`type`](https://testing-library.com/docs/user-event/utility/#type) 工具。
-你可以使用此函数向 `input` `、textarea` 或 `contenteditable` 元素中模拟键盘输入。[它兼容 user-event 提供的 keyboard 语法](https://testing-library.com/docs/user-event/keyboard)。
+你可以使用此函数向 `input` 、`textarea` 或 `contenteditable` 元素中模拟键盘输入。[它兼容 user-event 提供的 keyboard 语法](https://testing-library.com/docs/user-event/keyboard)。
如果只需按下字符而无需输入,请使用 [`userEvent.keyboard`](#userevent-keyboard) API。
@@ -299,7 +308,7 @@ test('clears input', async () => {
expect(input).toHaveValue('foo')
await userEvent.clear(input)
- // or you can access it directly on the locator
+ // 或者你可以直接从定位器上访问
await input.clear()
expect(input).toHaveValue('')
@@ -343,7 +352,7 @@ test('clears input', async () => {
const select = page.getByRole('select')
await userEvent.selectOptions(select, 'Option 1')
- // or you can access it directly on the locator
+ // 或者你可以直接从定位器上访问
await select.selectOptions('Option 1')
expect(select).toHaveValue('option-1')
@@ -393,7 +402,7 @@ test('hovers logo element', async () => {
const logo = page.getByRole('img', { name: /logo/ })
await userEvent.hover(logo)
- // or you can access it directly on the locator
+ // 或者你可以直接从定位器上访问
await logo.hover()
})
```
@@ -426,7 +435,7 @@ test('unhover logo element', async () => {
const logo = page.getByRole('img', { name: /logo/ })
await userEvent.unhover(logo)
- // or you can access it directly on the locator
+ // 或者你可以直接从定位器上访问
await logo.unhover()
})
```
@@ -458,7 +467,7 @@ test('can upload a file', async () => {
const file = new File(['file'], 'file.png', { type: 'image/png' })
await userEvent.upload(input, file)
- // or you can access it directly on the locator
+ // 或者你可以直接从定位器上访问
await input.upload(file)
// you can also use file paths relative to the root of the project
@@ -496,7 +505,7 @@ test('drag and drop works', async () => {
const target = page.getByTestId('logo-target')
await userEvent.dragAndDrop(source, target)
- // or you can access it directly on the locator
+ // 或者你可以直接从定位器上访问
await source.dropTo(target)
await expect.element(target).toHaveTextContent('Logo is processed')
diff --git a/guide/browser/locators.md b/guide/browser/locators.md
index 7f6699da..57403e14 100644
--- a/guide/browser/locators.md
+++ b/guide/browser/locators.md
@@ -3,7 +3,7 @@ title: Locators | Browser Mode
outline: [2, 3]
---
-# 定位 {#locators}
+# 定位器 {#locators}
定位器是表示一个或多个元素的方式。每个定位器都由一个称为选择器的字符串定义。Vitest 通过提供方便的方法在后台生成这些选择器,从而抽象了选择器。
@@ -189,7 +189,7 @@ await page.getByRole('button', { name: /submit/i }).click()
page.getByRole('button', { selected: false }) // ❌
```
-##### See also
+##### 更多内容请参阅 {#see-also}
- [MDN 上的 ARIA 角色列表](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles)
- [w3.org 上的 ARIA 角色列表](https://www.w3.org/TR/wai-aria-1.2/#role_definitions)
@@ -219,7 +219,7 @@ page.getByAltText('non existing alt text') // ❌
`text` 是否精确匹配:区分大小写且完全匹配字符串。默认情况下禁用此选项。如果 `text` 是正则表达式,则忽略此选项。请注意,精确匹配仍然会修剪空白字符。
-#### See also
+#### 更多内容请参阅 {#see-also-1}
- [testing-library's `ByAltText`](https://testing-library.com/docs/queries/byalttext/)
@@ -266,7 +266,7 @@ function getByLabelText(
`text` 是否精确匹配:区分大小写且完全匹配字符串。默认情况下禁用此选项。如果 `text` 是正则表达式,则忽略此选项。请注意,精确匹配仍然会修剪空白字符。
-#### See also
+#### 更多内容请参阅 {#see-also-2}
- [testing-library's `ByLabelText`](https://testing-library.com/docs/queries/bylabeltext/)
@@ -298,7 +298,7 @@ page.getByPlaceholder('not found') // ❌
`text` 是否精确匹配:区分大小写且完全匹配字符串。默认情况下禁用此选项。如果 `text` 是正则表达式,则忽略此选项。请注意,精确匹配仍然会修剪空白字符。
-#### See also
+#### 更多内容请参阅 {#see-also-3}
- [testing-library's `ByPlaceholderText`](https://testing-library.com/docs/queries/byplaceholdertext/)
@@ -330,7 +330,7 @@ page.getByText('about', { exact: true }) // ❌
`text` 是否精确匹配:区分大小写且完全匹配字符串。默认情况下禁用此选项。如果 `text` 是正则表达式,则忽略此选项。请注意,精确匹配仍然会修剪空白字符。
-#### See also
+#### 更多内容请参阅 {#see-also-4}
- [testing-library's `ByText`](https://testing-library.com/docs/queries/bytext/)
@@ -358,7 +358,7 @@ page.getByTitle('Create') // ❌
`text` 是否精确匹配:区分大小写且完全匹配字符串。默认情况下禁用此选项。如果 `text` 是正则表达式,则忽略此选项。请注意,精确匹配仍然会修剪空白字符。
-#### See also
+#### 更多内容请参阅 {#see-also-5}
- [testing-library's `ByTitle`](https://testing-library.com/docs/queries/bytitle/)
@@ -387,7 +387,7 @@ page.getByTestId('non-existing-element') // ❌
`text` 是否精确匹配:区分大小写和整个字符串。默认情况下禁用此选项。如果 `text` 是正则表达式,则忽略此选项。请注意,精确匹配仍然会修剪空格。
-#### See also
+#### 更多内容请参阅 {#see-also-6}
- [testing-library's `ByTestId`](https://testing-library.com/docs/queries/bytestid/)
@@ -460,7 +460,7 @@ page.getByRole('textbox').last() // ✅
function and(locator: Locator): Locator
```
-This method creates a new locator that matches both the parent and provided locator. The following example finds a button with a specific title:
+此方法创建一个新定位器,需同时匹配父级和传入的定位器。以下示例用于查找具有特定标题的按钮:
```ts
page.getByRole('button').and(page.getByTitle('Subscribe'))
@@ -472,10 +472,10 @@ page.getByRole('button').and(page.getByTitle('Subscribe'))
function or(locator: Locator): Locator
```
-This method creates a new locator that matches either one or both locators.
+此方法创建一个新定位器,只需匹配其中一个或同时匹配两个定位器。
::: warning
-Note that if locator matches more than a single element, calling another method might throw an error if it expects a single element:
+注意:若定位器匹配到多个元素,调用预期单个元素的方法可能会报错:
```tsx
<>
@@ -485,7 +485,7 @@ Note that if locator matches more than a single element, calling another method
page.getByRole('button')
.or(page.getByRole('link'))
- .click() // ❌ matches multiple elements
+ .click() // ❌ 匹配到多个元素
```
:::
@@ -495,13 +495,13 @@ page.getByRole('button')
function filter(options: LocatorOptions): Locator
```
-This methods narrows down the locator according to the options, such as filtering by text. It can be chained to apply multiple filters.
+此方法会根据选项(例如按文本过滤)缩小定位器范围。可通过链式调用应用多个过滤器。
### has
- **类型:** `Locator`
-This options narrows down the selector to match elements that contain other elements matching provided locator. For example, with this HTML:
+此选项会限定选择器范围,仅匹配包含符合指定定位器元素的节点。例如对于以下 HTML 结构:
```html{1,3}
@@ -512,26 +512,28 @@ This options narrows down the selector to match elements that contain other elem
```
-We can narrow down the locator to only find the `article` with `Vitest` text inside:
+我们可以限定定位器范围,仅查找内含 `Vitest` 文本的 `article` 元素:
```ts
page.getByRole('article').filter({ has: page.getByText('Vitest') }) // ✅
```
::: warning
-Provided locator (`page.getByText('Vitest')` in the example) must be relative to the parent locator (`page.getByRole('article')` in the example). It will be queried starting with the parent locator, not the document root.
-Meaning, you cannot pass down a locator that queries the element outside of the parent locator:
+传入的定位器(示例中的 `page.getByText('Vitest')`)必须相对于父级定位器(示例中的 `page.getByRole('article')`)。查询会从父级定位器开始,而非文档根节点。
+
+这意味着不能传入在父级定位器范围之外查询元素的定位器:
```ts
page.getByText('Vitest').filter({ has: page.getByRole('article') }) // ❌
```
-This example will fail because the `article` element is outside the element with `Vitest` text.
+此示例会失败,因为 `article` 元素位于包含 `Vitest` 文本的元素之外。
+
:::
::: tip
-This method can be chained to narrow down the element even further:
+此方法支持链式调用以进一步缩小元素定位范围:
```ts
page.getByRole('article')
@@ -544,7 +546,7 @@ page.getByRole('article')
- **类型:** `Locator`
-This option narrows down the selector to match elements that do not contain other elements matching provided locator. For example, with this HTML:
+此选项会限定选择器范围,仅匹配不包含指定定位器元素的节点。例如对于以下 HTML 结构:
```html{1,3}
@@ -555,7 +557,7 @@ This option narrows down the selector to match elements that do not contain othe
```
-We can narrow down the locator to only find the `article` that doesn't have `Rolldown` inside.
+我们可以限定定位器范围,仅查找内部不含 `Rolldown` 文本的 `article` 元素:
```ts
page.getByRole('article')
@@ -565,14 +567,14 @@ page.getByRole('article')
```
::: warning
-Note that provided locator is queried against the parent, not the document root, just like [`has`](#has) option.
+注意:与 [`has`](#has) 选项相同,传入的定位器是针对父级元素而非文档根节点进行查询。
:::
### hasText
- **类型:** `string | RegExp`
-This options narrows down the selector to only match elements that contain provided text somewhere inside. When the `string` is passed, matching is case-insensitive and searches for a substring.
+此选项会限定选择器范围,仅匹配内部某处包含指定文本的元素。当传入 `string` 时,匹配不区分大小写且执行子字符串搜索。
```html{1,3}
@@ -583,7 +585,7 @@ This options narrows down the selector to only match elements that contain provi
```
-Both locators will find the same element because the search is case-insensitive:
+由于搜索不区分大小写,以下两个定位器将匹配到同一个元素:
```ts
page.getByRole('article').filter({ hasText: 'Vitest' }) // ✅
@@ -594,7 +596,7 @@ page.getByRole('article').filter({ hasText: 'Vite' }) // ✅
- **类型:** `string | RegExp`
-This options narrows down the selector to only match elements that do not contain provided text somewhere inside. When the `string` is passed, matching is case-insensitive and searches for a substring.
+此选项会限定选择器范围,仅匹配内部不包含指定文本的元素。当传入 `string` 时,匹配不区分大小写且执行子字符串搜索。
## Methods
@@ -799,8 +801,7 @@ const { path, base64 } = await button.screenshot({
```
::: warning WARNING 3.2.0
-Note that `screenshot` will always return a base64 string if `save` is set to `false`.
-The `path` is also ignored in that case.
+注意,当 `save` 设置为 `false` 时,`screenshot` 将始终返回 base64 字符串。在此情况下,路径参数也会被忽略。
:::
### query
@@ -832,7 +833,7 @@ page.getByText('Hello', { exact: true }).query() // ✅ HTMLSpanElement
这些定位器将抛出错误:
```ts
-// returns multiple elements
+// 返回多个元素
page.getByText('Hello').query() // ❌
page.getByText(/^Hello/).query() // ❌
```
@@ -877,11 +878,11 @@ page.getByText('Hello', { exact: true }).element() // ✅
这些定位器将抛出错误:
```ts
-// returns multiple elements
+// 返回多个元素
page.getByText('Hello').element() // ❌
page.getByText(/^Hello/).element() // ❌
-// returns no elements
+// 不返回任意元素
page.getByText('Hello USA').element() // ❌
```
@@ -922,7 +923,7 @@ function all(): Locator[]
在内部,此方法调用 `.elements` 并使用 [`page.elementLocator`](/guide/browser/context#page) 包装每个元素。
-- [See `locator.elements()`](#elements)
+- [更多内容请参阅 `locator.elements()`](#elements)
## Properties
@@ -959,15 +960,16 @@ test('works correctly', async () => {
### length
This getter returns a number of elements that this locator is matching. It is equivalent to calling `locator.elements().length`.
+此属性返回当前定位器匹配的元素数量,等效于调用 g `locator.elements().length`。
-Consider the following DOM structure:
+参考以下 DOM 结构:
```html
```
-This property will always succeed:
+该属性始终会执行成功:
```ts
page.getByRole('button').length // ✅ 2
@@ -975,16 +977,17 @@ page.getByRole('button', { title: 'Click Me!' }).length // ✅ 1
page.getByRole('alert').length // ✅ 0
```
-## Custom Locators 3.2.0 advanced {#custom-locators}
+## 自定义定位器 3.2.0 advanced {#custom-locators}
-You can extend built-in locators API by defining an object of locator factories. These methods will exist as methods on the `page` object and any created locator.
+您可以通过定义定位器工厂对象来扩展内置定位器 API。这些方法将作为 `page` 对象和所有已创建定位器的方法存在。
-These locators can be useful if built-in locators are not enough. For example, when you use a custom framework for your UI.
+当内置定位器无法满足需求时(例如使用自定义 UI 框架时),这些定位器会非常有用。
-The locator factory needs to return a selector string or a locator itself.
+定位器工厂需要返回一个选择器字符串或定位器本身
::: tip
-The selector syntax is identical to Playwright locators. Please, read [their guide](https://playwright.dev/docs/other-locators) to better understand how to work with them.
+
+选择器语法与 Playwright 定位器完全一致。建议阅读 [Playwright 指南](https://playwright.dev/docs/other-locators) 以更好地理解其工作原理。
:::
```ts
@@ -998,8 +1001,8 @@ locators.extend({
return `.comments :text("${count} comments")`
},
async previewComments() {
- // you have access to the current locator via "this"
- // beware that if the method was called on `page`, `this` will be `page`,
+ // 可通过 "this" 访问当前定位器
+ // 注意:若方法在 `page` 上调用,`this` 将指向 `page` 而非定位器!
// not the locator!
if (this !== page) {
await this.click()
@@ -1008,16 +1011,16 @@ locators.extend({
}
})
-// if you are using typescript, you can extend LocatorSelectors interface
-// to have the autocompletion in locators.extend, page.* and locator.* methods
+// 使用 TypeScript 时可扩展 LocatorSelectors 接口
+// 以在 locators.extend、page.* 和 locator.* 方法中获得自动补全
declare module 'vitest/browser' {
interface LocatorSelectors {
- // if the custom method returns a string, it will be converted into a locator
- // if it returns anything else, then it will be returned as usual
+ // 若自定义方法返回字符串,将被转换为定位器
+ // 若返回其他类型,则按原样返回
getByArticleTitle(title: string): Locator
getByArticleCommentsCount(count: number): Locator
- // Vitest will return a promise and won't try to convert it into a locator
+ // Vitest 将返回 Promise 且不会尝试将其转换为定位器
previewComments(this: Locator): Promise
}
}
diff --git a/guide/browser/multiple-setups.md b/guide/browser/multiple-setups.md
index 95d070a2..925e83b5 100644
--- a/guide/browser/multiple-setups.md
+++ b/guide/browser/multiple-setups.md
@@ -1,4 +1,4 @@
-# 多种设置 {#multiple-setups}
+# 多环境配置 {#multiple-setups}
你可以使用 [`browser.instances`](/guide/browser/config#browser-instances) 选项来指定多个不同的浏览器设置。
@@ -28,7 +28,7 @@ export default defineConfig({
})
```
-## 不同的设置 {#different-setups}
+## 不同的配置方案 {#different-setups}
你还可以独立于浏览器指定不同的配置选项(尽管,实例也可以有 `browser` 字段):
@@ -119,3 +119,20 @@ export default defineConfig({
})
```
:::
+
+::: warning
+Vitest 无法运行多个将 `headless` 模式设置为 `false`(默认行为)的实例。在开发过程中,你可以在终端中选择要运行的项目:
+
+```shell
+? Found multiple projects that run browser tests in headed mode: "chromium", "firefox".
+Vitest cannot run multiple headed browsers at the same time. Select a single project
+to run or cancel and run tests with "headless: true" option. Note that you can also
+start tests with --browser=name or --project=name flag. › - Use arrow-keys. Return to submit.
+❯ chromium
+ firefox
+```
+
+如果我们在 CI 中有多个非 headless 项目(即在配置中手动设置了 `headless: false` 并且未在 CI 环境中覆盖),Vitest 将运行失败并且不会启动任何测试。
+
+这一限制不影响在无头模式下运行测试的能力。只要实例没有设置 `headless: false`,你仍然可以并行运行所有实例。
+:::
diff --git a/guide/browser/playwright.md b/guide/browser/playwright.md
index 170f91df..59f93cba 100644
--- a/guide/browser/playwright.md
+++ b/guide/browser/playwright.md
@@ -1,52 +1,36 @@
# 配置 Playwright {#configuring-playwright}
-要使用 playwright 运行测试,你需要安装 [`@vitest/browser-playwright`](https://www.npmjs.com/package/@vitest/browser-playwright) npm 包,并在配置中的 `test.browser.provider` 属性中指定其 `playwright` 导出:
+默认情况下,TypeScript 无法识别提供者选项和额外的 `expect` 属性。请确保引用 `@vitest/browser/providers/playwright`,以便 TypeScript 可以获取自定义选项的定义:
-```ts [vitest.config.js]
-import { playwright } from '@vitest/browser-playwright'
-import { defineConfig } from 'vitest/config'
+```ts [vitest.shims.d.ts]
+///
+```
-export default defineConfig({
- test: {
- browser: {
- provider: playwright(),
- instances: [{ browser: 'chromium' }]
- },
- },
-})
+或者,我们也可以将其添加到 `tsconfig.json` 文件中的 `compilerOptions.types` 字段。请注意,在此字段中指定任何内容将禁用 `@types/*` 包的 [自动加载](https://www.typescriptlang.org/tsconfig/#types)。
+
+```json [tsconfig.json]
+{
+ "compilerOptions": {
+ "types": ["@vitest/browser/providers/playwright"]
+ }
+}
```
-你可以在顶层或实例内部调用 `playwright` 时配置 [`launchOptions`](https://playwright.dev/docs/api/class-browsertype#browser-type-launch)、[`connectOptions`](https://playwright.dev/docs/api/class-browsertype#browser-type-connect) 和 [`contextOptions`](https://playwright.dev/docs/api/class-browser#browser-new-context):
+Vitest 打开一个页面以在同一文件中运行所有测试。我们可以在 `instances` 中配置 `launch` 、`connect` 和 `context` 属性:
-```ts{7-14,21-26} [vitest.config.js]
-import { playwright } from '@vitest/browser-playwright'
+```ts{9-11} [vitest.config.ts]
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
browser: {
- // shared provider options between all instances
- provider: playwright({
- launchOptions: {
- slowMo: 50,
- channel: 'chrome-beta',
- },
- actionTimeout: 5_000,
- }),
instances: [
- { browser: 'chromium' },
{
browser: 'firefox',
- // overriding options only for a single instance
- // this will NOT merge options with the parent one
- provider: playwright({
- launchOptions: {
- firefoxUserPrefs: {
- 'browser.startup.homepage': 'https://example.com',
- },
- },
- })
- }
+ launch: {},
+ connect: {},
+ context: {},
+ },
],
},
},
@@ -54,10 +38,25 @@ export default defineConfig({
```
::: warning
-Unlike Playwright test runner, Vitest opens a _single_ page to run all tests that are defined in the same file. This means that isolation is restricted to a single test file, not to every individual test.
+在 Vitest 3 之前,这些选项位于 `test.browser.providerOptions` 属性中:
+
+```ts [vitest.config.ts]
+export default defineConfig({
+ test: {
+ browser: {
+ providerOptions: {
+ launch: {},
+ context: {},
+ },
+ },
+ },
+})
+```
+
+`providerOptions` 已被弃用,推荐使用 `instances`。
:::
-## launchOptions
+## launch
这些选项直接传递给 `playwright[browser].launch` 命令。我们可以在 [Playwright 文档](https://playwright.dev/docs/api/class-browsertype#browser-type-launch) 中阅读有关该命令和可用参数的更多信息。
@@ -67,17 +66,17 @@ Vitest 将忽略 `launch.headless` 选项。请改用 [`test.browser.headless`](
请注意,如果启用了 [`--inspect`](/guide/cli#inspect),Vitest 会将调试标志推送到 `launch.args`。
:::
-## connectOptions
+## connect 3.2.0 {#connect}
-这些选项直接传递给 `playwright[browser].connect` 命令。你可以在 [Playwright 文档](https://playwright.dev/docs/api/class-browsertype#browser-type-connect) 中了解更多关于该命令和可用参数的信息。
+这些选项会直接传递给 `playwright[browser].connect` 命令。您可以在 [Playwright 文档](https://playwright.dev/docs/api/class-browsertype#browser-type-connect) 中,查阅该命令的详细说明及可用参数。
::: warning
-由于此命令连接到现有的 Playwright 服务器,任何 `launch` 选项都将被忽略。
+由于此命令会连接至现有的 Playwright 服务端,所有 `launch` 相关配置都将被忽略。
:::
-## contextOptions
+## context
-Vitest 通过调用 [`browser.newContext()`](https://playwright.dev/docs/api/class-browsercontext) 为每个测试文件创建一个新的上下文。你可以通过指定 [自定义参数](https://playwright.dev/docs/api/class-browser#browser-new-context) 来配置此行为。
+Vitest 通过调用 [`browser.newContext()`](https://playwright.dev/docs/api/class-browsercontext) 为每个测试文件创建一个新的上下文。我们可以通过指定 [自定义参数](https://playwright.dev/docs/api/class-apirequest#api-request-new-context) 来配置此行为。
::: tip
请注意,上下文是为每个 _测试文件_ 创建的,而不是像 Playwright 测试运行器那样为每个 _测试_ 创建。
@@ -89,16 +88,16 @@ Vitest 通过调用 [`browser.newContext()`](https://playwright.dev/docs/api/cla
建议使用 [`test.browser.viewport`](/guide/browser/config#browser-headless) 而不是在此处指定它,因为在无头模式下运行测试时会丢失该设置。
:::
-## `actionTimeout`
+## `actionTimeout` 3.0.0
-- **Default:** no timeout
+- **默认值:** 无超时,3.0.0 之前为 1 秒
此值配置 Playwright 等待所有可访问性检查通过并 [操作](/guide/browser/interactivity-api) 实际完成的默认超时时间。
我们还可以为每个操作配置操作超时:
```ts
-import { page, userEvent } from 'vitest/browser'
+import { page, userEvent } from '@vitest/browser/context'
await userEvent.click(page.getByRole('button'), {
timeout: 1_000,
diff --git a/guide/browser/preview.md b/guide/browser/preview.md
deleted file mode 100644
index 8b8bb3d4..00000000
--- a/guide/browser/preview.md
+++ /dev/null
@@ -1,32 +0,0 @@
-# Configuring Preview
-
-::: warning
-The `preview` provider's main functionality is to show tests in a real browser environment. However, it does not support advanced browser automation features like multiple browser instances or headless mode. For more complex scenarios, consider using [Playwright](/guide/browser/playwright) or [WebdriverIO](/guide/browser/webdriverio).
-:::
-
-To see your tests running in a real browser, you need to install the [`@vitest/browser-preview`](https://www.npmjs.com/package/@vitest/browser-preview) npm package and specify its `preview` export in the `test.browser.provider` property of your config:
-
-```ts [vitest.config.js]
-import { preview } from '@vitest/browser-preview'
-import { defineConfig } from 'vitest/config'
-
-export default defineConfig({
- test: {
- browser: {
- provider: preview(),
- instances: [{ browser: 'chromium' }]
- },
- },
-})
-```
-
-This will open a new browser window using your default browser to run the tests. You can configure which browser to use by setting the `browser` property in the `instances` array. Vitest will try to open that browser automatically, but it might not work in some environments. In that case, you can manually open the provided URL in your desired browser.
-
-## Differences with Other Providers
-
-The preview provider has some limitations compared to other providers like [Playwright](/guide/browser/playwright) or [WebdriverIO](/guide/browser/webdriverio):
-
-- It does not support headless mode; the browser window will always be visible.
-- It does not support multiple instances of the same browser; each instance must use a different browser.
-- It does not support advanced browser capabilities or options; you can only specify the browser name.
-- It does not support CDP (Chrome DevTools Protocol) commands or other low-level browser interactions. Unlike Playwright or WebdriverIO, the [`userEvent`](/guide/browser/interactivity-api) API is just re-exported from [`@testing-library/user-event`](https://www.npmjs.com/package/@testing-library/user-event) and does not have any special integration with the browser.
diff --git a/guide/browser/trace-view.md b/guide/browser/trace-view.md
deleted file mode 100644
index d78db55d..00000000
--- a/guide/browser/trace-view.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# Trace View
-
-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`](/guide/browser/config#browser-trace) option in the `test.browser` configuration.
-
-::: warning
-Generating trace files is only available when using the [Playwright provider](/guide/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` count and `retry` count](/api/#test-api-reference):
-
-```
-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.
-
-## 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.
-
-## Limitations
-
-At the moment, Vitest cannot populate the "Sources" tab in the Trace Viewer. This means that while you can see the actions and screenshots captured during the test, you won't be able to view the source code of your tests directly within the Trace Viewer. You will need to refer back to your code editor to see the test implementation.
diff --git a/guide/browser/visual-regression-testing.md b/guide/browser/visual-regression-testing.md
deleted file mode 100644
index 4037932c..00000000
--- a/guide/browser/visual-regression-testing.md
+++ /dev/null
@@ -1,692 +0,0 @@
----
-title: 可视化回归测试
-outline: [2, 3]
----
-
-# 可视化回归测试 {#visual-regression-testing}
-
-Vitest 原生支持可视化回归测试。它会自动截取 UI 组件或页面的截图,并与基准图像对比,以捕捉那些非预期的视觉变化。
-
-与只验证功能逻辑的功能测试不同,可视化测试能发现样式异常、布局偏移和渲染错误——这些问题如果没有细致的人工检查,往往会被忽略。
-
-## 为什么需要可视化回归测试? {#why-visual-regression-testing}
-
-视觉 bug 不会报错,但它们的外观已经改变。这正是可视化测试的意义所在:
-
-- 按钮依然能提交表单,但颜色却变成了亮粉色
-- 文本在桌面端显示正常,在移动端却被挤压变形
-- 功能没问题,可两个容器已跑出视口
-- 精心的 CSS 重构完成了,却破坏了某个无人测试的页面布局
-
-可视化回归测试是 UI 的安全网,确保这些变化在进入生产环境之前就被自动发现并处理。
-
-## 快速入门 {#getting-started}
-
-::: warning 浏览器渲染差异
-可视化回归测试对运行环境非常敏感,不同机器生成的截图可能存在差异,常见原因包括:
-
-- 字体渲染差异(最常见,Windows、macOS、Linux 各不相同)
-- GPU 驱动与硬件加速
-- 是否使用无头模式
-- 浏览器版本与设置
-- ……甚至偶发的系统差异
-
-因此,Vitest 会在截图文件名中添加浏览器和平台信息(如 `button-chromium-darwin.png`),避免不同环境的截图互相覆盖。
-
-要获得稳定结果,应使用相同的测试环境。**推荐**采用云端服务(如 [Azure App Testing](https://azure.microsoft.com/en-us/products/playwright-testing))或基于 [Docker containers](https://playwright.dev/docs/docker) 的环境。
-:::
-
-在 Vitest 中,可通过 [`toMatchScreenshot` assertion](/guide/browser/assertion-api.html#tomatchscreenshot) 断言运行可视化回归测试:
-
-```ts
-import { expect, test } from 'vitest'
-import { page } from 'vitest/browser'
-
-test('hero section looks correct', async () => {
- // ...the rest of the test
-
- // capture and compare screenshot
- await expect(page.getByTestId('hero')).toMatchScreenshot('hero-section')
-})
-```
-
-### 创建基准截图 {#creating-references}
-
-首次运行可视化测试时, Vitest 会生成一张基准( baseline )截图,并提示如下错误信息使测试失败:
-
-```
-expect(element).toMatchScreenshot()
-
-No existing reference screenshot found; a new one was created. Review it before running tests again.
-
-Reference screenshot:
- tests/__screenshots__/hero.test.ts/hero-section-chromium-darwin.png
-```
-
-确认截图正确后再次运行测试,Vitest 会将后续结果与该基准图比较。
-
-::: tip
-基准截图存放在测试文件所在目录下的 `__screenshots__` 文件夹中,
-**请务必提交到版本库**。
-:::
-
-### 截图组织方式 {#screenshot-organization}
-
-Vitest 默认将截图按以下结构保存:
-
-```
-.
-├── __screenshots__
-│ └── test-file.test.ts
-│ ├── test-name-chromium-darwin.png
-│ ├── test-name-firefox-linux.png
-│ └── test-name-webkit-win32.png
-└── test-file.test.ts
-```
-
-文件名由三部分组成:
-- **测试名**:来自 `toMatchScreenshot()` 的第一个参数,或自动根据测试用例名生成
-- **浏览器名**:`chrome`、`chromium`、`firefox`、`webkit`
-- **平台**:如 `aix`、`darwin`、`linux`、`win32` 等
-
-这种命名方式可避免不同环境生成的截图互相覆盖。
-
-### 更新基准截图 {#updating-references}
-
-当你有意修改 UI 时,需要更新基准截图:
-
-```bash
-$ vitest --update
-```
-
-提交前务必核对更新后的截图,确保改动符合预期。
-
-## 配置可视化测试 {#configuring-visual-tests}
-
-### 全局配置 {#global-configuration}
-
-可在 [Vitest 配置文件](/guide/browser/config#browser-expect-tomatchscreenshot) 中设定可视化回归测试的默认规则:
-
-```ts [vitest.config.ts]
-import { defineConfig } from 'vitest/config'
-
-export default defineConfig({
- test: {
- browser: {
- expect: {
- toMatchScreenshot: {
- comparatorName: 'pixelmatch',
- comparatorOptions: {
- // 0-1, how different can colors be?
- threshold: 0.2,
- // 1% of pixels can differ
- allowedMismatchedPixelRatio: 0.01,
- },
- },
- },
- },
- },
-})
-```
-
-### 单测试配置 {#per-test-configuration}
-
-若某个测试需要不同的比较标准,可在调用时覆盖全局设置:
-
-```ts
-await expect(element).toMatchScreenshot('button-hover', {
- comparatorName: 'pixelmatch',
- comparatorOptions: {
- // more lax comparison for text-heavy elements
- allowedMismatchedPixelRatio: 0.1,
- },
-})
-```
-
-## 最佳实践 {#best-practices}
-
-### 聚焦测试目标元素 {#test-specific-elements}
-
-除非确实需要测试整个页面,否则应优先只对目标组件截图,这能显著减少因页面其他部分变化而造成的误报。
-
-```ts
-// ❌ Captures entire page; prone to unrelated changes
-await expect(page).toMatchScreenshot()
-
-// ✅ Captures only the component under test
-await expect(page.getByTestId('product-card')).toMatchScreenshot()
-```
-
-### 处理动态内容 {#handle-dynamic-content}
-
-测试中,如果页面包含诸如时间戳、用户信息或随机值等动态内容,往往会导致结果不一致而造成测试失败。
-解决方法有两种:一是模拟这些动态数据的生成源;
-二是在使用 Playwright 进行截图时,在 `screenshotOptions` 中启用
-[`mask` 选项](https://playwright.dev/docs/api/class-page#page-screenshot-option-mask),
-将这些动态区域遮盖,从而确保测试结果的稳定性。
-
-```ts
-await expect(page.getByTestId('profile')).toMatchScreenshot({
- screenshotOptions: {
- mask: [page.getByTestId('last-seen')],
- },
-})
-```
-
-### 禁用所有动画 {#disable-animations}
-
-动画效果往往会导致测试结果出现波动。为避免这种情况,
-可以在测试执行过程中注入一段自定义的 CSS 样式代码,用于禁用所有动画,从而提升测试的稳定性。
-
-```css
-*, *::before, *::after {
- animation-duration: 0s !important;
- animation-delay: 0s !important;
- transition-duration: 0s !important;
- transition-delay: 0s !important;
-}
-```
-
-::: tip
-在使用 Playwright 作为测试工具时,若执行断言操作,动画会被自动禁用。
-具体而言,`screenshotOptions` 配置中的 `animations` 选项会默认设为 `"disabled"`,从而确保截图与测试结果的稳定一致。
-:::
-
-### 设置合理的阈值 {#set-appropriate-thresholds}
-
-在视觉回归测试中,阈值调整是一项需要权衡的工作——它取决于页面内容、测试环境、
-应用所能容忍的差异范围,且可能因具体测试而有所不同。
-
-Vitest 并未为像素差异设定默认阈值,这需要由用户根据实际需求来决定。
-官方建议使用 `allowedMismatchedPixelRatio`,让阈值按截图的整体尺寸比例计算,而非依赖固定像素数量。
-
-当 `allowedMismatchedPixelRatio` 与 `allowedMismatchedPixels` 同时设置时,
-Vitest 会优先采用二者中限制更严格的那一个,以确保测试结果的准确性与一致性。
-
-### 保持统一的视口大小 {#set-consistent-viewport-sizes}
-
-浏览器实例的默认窗口尺寸可能存在差异,这会影响视觉回归测试的稳定性。为避免由于尺寸不一致而产生的截图偏差,
-建议在测试脚本或浏览器实例配置中显式指定一个固定的视口大小,从而确保测试结果的可重复性与一致性。
-
-```ts
-await page.viewport(1280, 720)
-```
-
-```ts [vitest.config.ts]
-import { playwright } from '@vitest/browser-playwright'
-import { defineConfig } from 'vitest/config'
-
-export default defineConfig({
- test: {
- browser: {
- enabled: true,
- provider: playwright(),
- instances: [
- {
- browser: 'chromium',
- viewport: { width: 1280, height: 720 },
- },
- ],
- },
- },
-})
-```
-
-### 使用 Git LFS 管理基准截图 {#use-git-lfs}
-
-对于规模较大的视觉回归测试套件,建议将基准截图文件存储在
-[Git LFS](https://github.com/git-lfs/git-lfs?tab=readme-ov-file) 中。
-这样既能避免仓库体积膨胀,又能高效管理和传输这些大尺寸文件,提升团队协作效率。
-
-## 调试视觉测试失败 {#debugging-failed-tests}
-
-当视觉回归测试未能通过时, Vitest 会生成三张关键截图,帮助你分析问题所在:
-
-1. **参考截图( Reference screenshot )**:测试期望的基准图像
-2. **实际截图( Actual screenshot )**:测试运行过程中截取的画面
-3. **差异图( Diff image )**:用高亮标记出参考图与实际图的差异(有时可能不会生成)
-
-在调试时,你会在输出中看到类似如下的文件列表或路径信息:
-
-```
-expect(element).toMatchScreenshot()
-
-Screenshot does not match the stored reference.
-245 pixels (ratio 0.03) differ.
-
-Reference screenshot:
- tests/__screenshots__/button.test.ts/button-chromium-darwin.png
-
-Actual screenshot:
- tests/.vitest-attachments/button.test.ts/button-chromium-darwin-actual.png
-
-Diff image:
- tests/.vitest-attachments/button.test.ts/button-chromium-darwin-diff.png
-```
-
-### 如何解读差异图 {#understanding-the-diff-image}
-
-- **红色像素**:表示参考截图与实际截图之间存在显著差异的区域
-- **黄色像素**:由抗锯齿处理带来的细微差异(仅在未忽略抗锯齿时可见)
-- **透明或原始图像部分**:表示两张截图在该区域完全一致
-
-:::tip
-如果差异图几乎被红色覆盖,说明测试结果与预期严重不符,需要重点排查。
-若只是文字边缘零星出现少量红点,可能只是渲染细节差异,此时适当提高阈值即可解决。
-:::
-
-## 常见问题与解决方案 {#common-issues-and-solutions}
-
-### 字体渲染引发的误报 {#false-positives-from-font-rendering}
-
-由于不同操作系统在字体可用性与渲染方式上差异明显,视觉回归测试中可能会出现“误报”现象。为降低这种风险,可以考虑以下做法:
-
-- 使用 Web 字体,并在测试执行前等待字体完全加载;
-
- ```ts
- // wait for fonts to load
- await document.fonts.ready
-
- // continue with your tests
- ```
-
-- 对包含大量文字的区域适当提高像素差异的比较阈值,以减少因字体渲染细微差别导致的误报;
-
- ```ts
- await expect(page.getByTestId('article-summary')).toMatchScreenshot({
- comparatorName: 'pixelmatch',
- comparatorOptions: {
- // 10% of the pixels are allowed to change
- allowedMismatchedPixelRatio: 0.1,
- },
- })
- ```
-
-- 使用云端服务或容器化测试环境,确保字体渲染效果在各次测试中保持一致,从而减少系统差异带来的影响;
-
-### 测试不稳定或截图尺寸不一致 {#flaky-tests-or-different-screenshot-sizes}
-
-如果测试结果出现随机通过或失败,或者在不同运行中生成的截图尺寸不一致,可以采取以下措施:
-
-- 确保页面所有内容均已加载完成,包括加载指示器与动画;
-- 明确设置固定的视口大小,例如:`await page.viewport(1920, 1080)`;
-- 检查页面在视口临界尺寸下的响应式布局表现;
-- 排查是否存在非预期的动画或过渡效果干扰截图结果;
-- 对体积较大的截图适当延长测试的超时时间;
-- 使用云端服务或容器化环境,确保字体渲染、浏览器配置等保持一致。
-
-## 团队版视觉回归测试方案 {#visual-regression-testing-for-teams}
-
-视觉回归测试对环境的稳定性要求极高,而本地开发机并不适合担当这一角色。
-
-在团队协作中,常见的三种方案是:
-
-1. **自托管运行器**:部署过程复杂,日常维护工作量大;
-2. **GitHub Actions**:对开源项目免费,可与任何测试框架或服务集成;
-3. **云服务**:如 [Microsoft Playwright Testing](https://azure.microsoft.com/en-us/products/playwright-testing),专为解决视觉测试环境一致性问题而构建。
-
-我们将重点介绍第 2 和第 3 种方案,因为它们能最快投入使用。
-
-主要权衡点在于:
-
-- **GitHub Actions**:视觉测试只能在持续集成(CI)环境中运行,开发者无法直接在本地执行;
-- **Microsoft 云服务**:可在任意环境运行,但需额外付费,并且仅支持 Playwright。
-
-:::: tabs key:vrt-for-teams
-=== GitHub Actions
-
-要点在于,将视觉回归测试与常规测试分离运行。
-否则,你可能会因截图差异引发的失败日志而浪费数小时进行排查。
-
-#### 测试组织建议 {#organizing-your-tests}
-
-首先,应将视觉回归测试与其他测试隔离管理。
-建议单独建立一个 `visual` 文件夹(或根据项目结构选择更合适的目录名称)来存放这些测试用例,以便维护与执行。
-
-```json [package.json]
-{
- "scripts": {
- "test:unit": "vitest --exclude tests/visual/*.test.ts",
- "test:visual": "vitest tests/visual/*.test.ts"
- }
-}
-```
-
-这样,开发者就能在本地运行 `npm run test:unit` ,而无需受到视觉回归测试的影响;
-视觉测试则放在环境一致的持续集成( CI )平台中运行,以确保结果稳定可靠。
-
-::: tip 抉择
-不喜欢用 glob 匹配模式?那你也可以创建独立的 [测试项目](/guide/projects),并通过以下方式来运行它们:
-
-- `vitest --project unit`
-- `vitest --project visual`
-:::
-
-#### 持续集成( CI )环境配置 {#ci-setup}
-
-在 CI 环境中运行视觉回归测试时,需要确保浏览器已正确安装。至于如何安装,则取决于你所使用的 CI 服务提供商及其运行环境。
-
-::: tabs key:provider
-== Playwright
-
-[Playwright](https://npmjs.com/package/playwright) 能让浏览器安装与管理变得非常简单。
-你只需固定所用的 Playwright 版本,并在运行测试之前加入以下命令或脚本:
-
-```yaml [.github/workflows/ci.yml]
-# ...the rest of the workflow
-- name: Install Playwright Browsers
- run: npx --no playwright install --with-deps --only-shell
-```
-
-== WebdriverIO
-
-[WebdriverIO](https://www.npmjs.com/package/webdriverio) 要求用户自行准备浏览器环境。不过,
-[ @browser-actions ](https://github.com/browser-actions) 团队已经为此提供了方便的解决方案,
-帮你轻松完成浏览器的安装与配置。
-
-```yaml [.github/workflows/ci.yml]
-# ...the rest of the workflow
-- uses: browser-actions/setup-chrome@v1
- with:
- chrome-version: 120
-```
-
-:::
-
-最后,运行你的视觉回归测试:
-
-```yaml [.github/workflows/ci.yml]
-# ...the rest of the workflow
-# ...browser setup
-- name: Visual Regression Testing
- run: npm run test:visual
-```
-
-#### 更新工作流程 {#the-update-workflow}
-
-关键点来了——切勿在每一次 Pull Request 中都自动更新截图,
-*(那只会带来混乱)*。更稳妥的方式,是建立一个手动触发的工作流程,
-让开发者在有意更改 UI 时主动运行,从而更新基准截图。
-
-该工作流程具备以下特性:
-- 仅在功能分支上运行,确保主分支安全不受影响;
-- 自动将触发流程的开发者署名为共同作者;
-- 阻止同一分支上的并发执行,避免冲突与资源浪费;
-- 生成一份清晰美观的执行摘要,便于快速查看结果。
- - **当基准截图发生变动时**,系统会列出所有具体的变化项,方便开发者快速了解差异。
-
-
-
-
- - **当没有任何变化时**,系统同样会明确提示,让你一目了然。
-
-
-
-
-::: tip
-这只是实现的其中一种方式。
-有些团队倾向于在 Pull Request 中添加特定评论(如 `/update-screenshots`)来触发更新,
-也有团队通过添加标签来完成这一操作。
-你可以根据自身的开发流程进行调整。
-
-关键在于,必须建立一种可控的机制来更新基准截图,
-以避免不必要的混乱和错误。
-:::
-
-```yaml [.github/workflows/update-screenshots.yml]
-name: Update Visual Regression Screenshots
-
-on:
- workflow_dispatch: # manual trigger only
-
-env:
- AUTHOR_NAME: 'github-actions[bot]'
- AUTHOR_EMAIL: '41898282+github-actions[bot]@users.noreply.github.com'
- COMMIT_MESSAGE: |
- test: update visual regression screenshots
-
- Co-authored-by: ${{ github.actor }} <${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com>
-
-jobs:
- update-screenshots:
- runs-on: ubuntu-24.04
-
- # safety first: don't run on main
- if: github.ref_name != github.event.repository.default_branch
-
- # one at a time per branch
- concurrency:
- group: visual-regression-screenshots@${{ github.ref_name }}
- cancel-in-progress: true
-
- permissions:
- contents: write # needs to push changes
-
- steps:
- - name: Checkout selected branch
- uses: actions/checkout@v4
- with:
- ref: ${{ github.ref_name }}
- # use PAT if triggering other workflows
- # token: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Configure Git
- run: |
- git config --global user.name "${{ env.AUTHOR_NAME }}"
- git config --global user.email "${{ env.AUTHOR_EMAIL }}"
-
- # your setup steps here (node, pnpm, whatever)
- - name: Setup Node.js
- uses: actions/setup-node@v4
- with:
- node-version: 24
-
- - name: Install dependencies
- run: npm ci
-
- - name: Install Playwright Browsers
- run: npx --no playwright install --with-deps --only-shell
-
- # the magic happens below 🪄
- - name: Update Visual Regression Screenshots
- run: npm run test:visual --update
-
- # check what changed
- - name: Check for changes
- id: check_changes
- run: |
- CHANGED_FILES=$(git status --porcelain | awk '{print $2}')
- if [ "${CHANGED_FILES:+x}" ]; then
- echo "changes=true" >> $GITHUB_OUTPUT
- echo "Changes detected"
-
- # save the list for the summary
- echo "changed_files<> $GITHUB_OUTPUT
- echo "$CHANGED_FILES" >> $GITHUB_OUTPUT
- echo "EOF" >> $GITHUB_OUTPUT
- echo "changed_count=$(echo "$CHANGED_FILES" | wc -l)" >> $GITHUB_OUTPUT
- else
- echo "changes=false" >> $GITHUB_OUTPUT
- echo "No changes detected"
- fi
-
- # commit if there are changes
- - name: Commit changes
- if: steps.check_changes.outputs.changes == 'true'
- run: |
- git add -A
- git commit -m "${{ env.COMMIT_MESSAGE }}"
-
- - name: Push changes
- if: steps.check_changes.outputs.changes == 'true'
- run: git push origin ${{ github.ref_name }}
-
- # pretty summary for humans
- - name: Summary
- run: |
- if [[ "${{ steps.check_changes.outputs.changes }}" == "true" ]]; then
- echo "### 📸 Visual Regression Screenshots Updated" >> $GITHUB_STEP_SUMMARY
- echo "" >> $GITHUB_STEP_SUMMARY
- echo "Successfully updated **${{ steps.check_changes.outputs.changed_count }}** screenshot(s) on \`${{ github.ref_name }}\`" >> $GITHUB_STEP_SUMMARY
- echo "" >> $GITHUB_STEP_SUMMARY
- echo "#### Changed Files:" >> $GITHUB_STEP_SUMMARY
- echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
- echo "${{ steps.check_changes.outputs.changed_files }}" >> $GITHUB_STEP_SUMMARY
- echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
- echo "" >> $GITHUB_STEP_SUMMARY
- echo "✅ The updated screenshots have been committed and pushed. Your visual regression baseline is now up to date!" >> $GITHUB_STEP_SUMMARY
- else
- echo "### ℹ️ No Screenshot Updates Required" >> $GITHUB_STEP_SUMMARY
- echo "" >> $GITHUB_STEP_SUMMARY
- echo "The visual regression test command ran successfully but no screenshots needed updating." >> $GITHUB_STEP_SUMMARY
- echo "" >> $GITHUB_STEP_SUMMARY
- echo "All screenshots are already up to date! 🎉" >> $GITHUB_STEP_SUMMARY
- fi
-```
-
-=== Azure App Testing
-
-你的测试依旧在本地运行,只是将浏览器托管到云端执行。
-这基于 Playwright 的远程浏览器功能,但所有云端基础设施均由 Microsoft 负责维护与管理。
-
-#### 测试组织建议
-
-为控制成本,应将视觉回归测试与其他测试分离管理,
-并确保只有那些实际需要截取页面截图的用例才会调用该服务。
-
-最为简洁高效的做法,是使用 [Test Projects](/guide/projects) 功能来隔离这些测试。
-
-
-```ts [vitest.config.ts]
-import { env } from 'node:process'
-import { defineConfig } from 'vitest/config'
-import { playwright } from '@vitest/browser-playwright'
-
-export default defineConfig({
- // ...global Vite config
- tests: {
- // ...global Vitest config
- projects: [
- {
- extends: true,
- test: {
- name: 'unit',
- include: ['tests/**/*.test.ts'],
- // regular config, can use local browsers
- },
- },
- {
- extends: true,
- test: {
- name: 'visual',
- // or you could use a different suffix, e.g.,: `tests/**/*.visual.ts?(x)`
- include: ['visual-regression-tests/**/*.test.ts?(x)'],
- browser: {
- enabled: true,
- provider: playwright({
- connectOptions: {
- wsEndpoint: `${env.PLAYWRIGHT_SERVICE_URL}?${new URLSearchParams({
- 'api-version': '2025-09-01',
- os: 'linux', // always use Linux for consistency
- // helps identifying runs in the service's dashboard
- runName: `Vitest ${env.CI ? 'CI' : 'local'} run @${new Date().toISOString()}`,
- })}`,
- exposeNetwork: '',
- headers: {
- Authorization: `Bearer ${env.PLAYWRIGHT_SERVICE_ACCESS_TOKEN}`,
- },
- timeout: 30_000,
- }
- }),
- headless: true,
- instances: [
- {
- browser: 'chromium',
- viewport: { width: 2560, height: 1440 },
- },
- ],
- },
- },
- },
- ],
- },
-})
-```
-
-该服务会提供两个关键环境变量:
-
-- `PLAYWRIGHT_SERVICE_URL`:指示 Playwright 连接的服务器地址
-- `PLAYWRIGHT_SERVICE_ACCESS_TOKEN`:你的身份验证令牌
-
-
-
-Follow the [official guide to create a Playwright Workspace](https://learn.microsoft.com/en-us/azure/app-testing/playwright-workspaces/quickstart-run-end-to-end-tests?tabs=playwrightcli&pivots=playwright-test-runner#create-a-workspace).
-
-Once your workspace is created, configure Vitest to use it:
-
-1. **Set the endpoint URL**: following the [official guide](https://learn.microsoft.com/en-us/azure/app-testing/playwright-workspaces/quickstart-run-end-to-end-tests?tabs=playwrightcli&pivots=playwright-test-runner#configure-the-browser-endpoint), retrieve the URL and set it as the `PLAYWRIGHT_SERVICE_URL` environment variable.
-2. **Enable token authentication**: [enable access tokens](https://learn.microsoft.com/en-us/azure/app-testing/playwright-workspaces/how-to-manage-authentication?pivots=playwright-test-runner#enable-authentication-using-access-tokens) for your workspace, then [generate a token](https://learn.microsoft.com/en-us/azure/app-testing/playwright-workspaces/how-to-manage-access-tokens#generate-a-workspace-access-token) and set it as the `PLAYWRIGHT_SERVICE_ACCESS_TOKEN` environment variable.
-
-::: danger 令牌务必保密!
-切勿将 `PLAYWRIGHT_SERVICE_ACCESS_TOKEN` 提交到代码仓库。
-任何获取到该令牌的人都可能在你的账户上产生高额费用。
-在本地开发时,应通过环境变量引用令牌;在 CI 中,应将其存放于安全的密钥管理中。
-:::
-
-然后,将 `test` 脚本按如下方式拆分运行:
-
-```json [package.json]
-{
- "scripts": {
- "test:visual": "vitest --project visual",
- "test:unit": "vitest --project unit"
- }
-}
-```
-
-#### 运行测试
-
-```bash
-# Local development
-npm run test:unit # free, runs locally
-npm run test:visual # uses cloud browsers
-
-# Update screenshots
-npm run test:visual -- --update
-```
-
-这种方式的最大优势在于“开箱即用”:
-
-- **截图结果一致**:所有人共享相同的云端浏览器环境,避免环境差异;
-- **支持本地执行**:开发者可在本地直接运行并更新视觉回归测试;
-- **按量计费**:仅有视觉测试会消耗服务分钟数,成本可控;
-- **零运维负担**:无需配置 Docker 或复杂的工作流,几乎不需额外维护。
-
-#### 持续集成( CI )环境配置
-
-在 CI 平台中,将所需的密钥添加到环境变量或机密配置中:
-
-```yaml
-env:
- PLAYWRIGHT_SERVICE_URL: ${{ vars.PLAYWRIGHT_SERVICE_URL }}
- PLAYWRIGHT_SERVICE_ACCESS_TOKEN: ${{ secrets.PLAYWRIGHT_SERVICE_ACCESS_TOKEN }}
-```
-
-接下来,你只需像往常一样运行测试,其余的由服务全权负责处理。
-
-::::
-
-### 该选哪一个? {#so-which-one}
-
-两种方案都可行,关键在于团队最在意的痛点是什么。
-
-如果你的团队已经深度依赖 GitHub 生态,那么 **GitHub Actions** 几乎是无可替代的选择——对开源项目免费、
-支持任意浏览器服务商、并且可完全掌控执行流程。
-
-缺点在于:当有人在本地生成的截图与 CI 环境的基准不一致时,就会出现那句熟悉的“在我机器上没问题”。
-
-如果团队需要在本地执行视觉回归测试,那么云服务或许更适合。
-这种方式特别适合有设计师参与审核,或开发者希望在推送代码前发现并修复问题的团队,
-能够跳过“推送—等待—检查—修改—再推送”的繁琐循环。
-
-如果依然犹豫,不妨先从 GitHub Actions 开始;等到本地测试成为痛点时,再引入云服务也不迟。
diff --git a/guide/browser/webdriverio.md b/guide/browser/webdriverio.md
index 25784f6a..213f6553 100644
--- a/guide/browser/webdriverio.md
+++ b/guide/browser/webdriverio.md
@@ -1,64 +1,69 @@
-# 配置 WebdriverIO {#configuring-webdriverio}
+# 配置 WebdriverIO {#configuring-webdriverio}
-::: info Playwright 与 WebdriverIO
+::: info 对比 Playwright 与 WebdriverIO
如果我们的项目尚未使用 WebdriverIO,我们建议从 [Playwright](/guide/browser/playwright) 开始,因为它更易于配置且 API 更灵活。
:::
-要使用 WebdriverIO 运行测试,你需要安装 [`@vitest/browser-webdriverio`](https://www.npmjs.com/package/@vitest/browser-webdriverio) npm 包,并在配置中的 `test.browser.provider` 属性中指定其 `webdriverio` 导出:
+默认情况下,TypeScript 无法识别提供者选项和额外的 `expect` 属性。请确保引用 `@vitest/browser/providers/webdriverio`,以便 TypeScript 可以获取自定义选项的定义:
-```ts [vitest.config.js]
-import { webdriverio } from '@vitest/browser-webdriverio'
+```ts [vitest.shims.d.ts]
+///
+```
+
+或者,我们也可以将其添加到 `tsconfig.json` 文件中的 `compilerOptions.types` 字段。请注意,在此字段中指定任何内容将禁用 `@types/*` 包的 [自动加载](https://www.typescriptlang.org/tsconfig/#types)。
+
+```json [tsconfig.json]
+{
+ "compilerOptions": {
+ "types": ["@vitest/browser/providers/webdriverio"]
+ }
+}
+```
+
+Vitest 打开一个页面以在同一文件中运行所有测试。我们可以在 `instances` 中配置 `RemoteOptions` 中指定的任何属性:
+
+```ts{9-12} [vitest.config.ts]
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
browser: {
- provider: webdriverio(),
- instances: [{ browser: 'chrome' }]
+ instances: [
+ {
+ browser: 'chrome',
+ capabilities: {
+ browserVersion: 86,
+ platformName: 'Windows 10',
+ },
+ },
+ ],
},
},
})
```
-你可以配置 [`remote`](https://webdriver.io/docs/api/modules/#remoteoptions-modifier) 函数接受的所有参数:
-
-```ts{8-12,19-25} [vitest.config.js]
-import { webdriverio } from '@vitest/browser-webdriverio'
-import { defineConfig } from 'vitest/config'
+::: warning
+在 Vitest 3 之前,这些选项位于 `test.browser.providerOptions` 属性中:
+```ts [vitest.config.ts]
export default defineConfig({
test: {
browser: {
- // shared provider options between all instances
- provider: webdriverio({
- capabilities: {
- browserVersion: '82',
- },
- }),
- instances: [
- { browser: 'chrome' },
- {
- browser: 'firefox',
- // overriding options only for a single instance
- // this will NOT merge options with the parent one
- provider: webdriverio({
- capabilities: {
- 'moz:firefoxOptions': {
- args: ['--disable-gpu'],
- },
- },
- })
- },
- ],
+ providerOptions: {
+ capabilities: {},
+ },
},
},
})
```
-你可以在 [WebdriverIO 文档](https://webdriver.io/docs/configuration/) 中找到大多数可用选项。请注意,Vitest 将忽略所有测试运行器选项,因为我们仅使用 `webdriverio` 的浏览器功能。
+`providerOptions` 已被弃用,推荐使用 `instances`。
+:::
+
+我们可以在 [WebdriverIO 文档](https://webdriver.io/docs/configuration/) 中找到大多数可用选项。请注意,Vitest 将忽略所有测试运行器选项,因为我们仅使用 `webdriverio` 的浏览器功能。
::: tip
最有用的选项位于 `capabilities` 对象上。WebdriverIO 允许嵌套功能,但 Vitest 将忽略这些选项,因为我们依赖于不同的机制来生成多个浏览器。
-请注意,Vitest 将忽略 `capabilities.browserName` — 请改用 [`test.browser.instances.browser`](/guide/browser/config#browser-capabilities-name)。
+请注意,Vitest 将忽略 `capabilities.browserName`。请改用 [`test.browser.instances.name`](/guide/browser/config#browser-capabilities-name)。
:::
diff --git a/guide/cli-generated.md b/guide/cli-generated.md
index 9ca5fc3c..4cb93af6 100644
--- a/guide/cli-generated.md
+++ b/guide/cli-generated.md
@@ -1,904 +1,918 @@
### root
-- **CLI:** `-r, --root `
-- **Config:** [root](/config/#root)
+- **命令行终端:** `-r, --root `
+- **配置:** [root](/config/#root)
根路径
### config
-- **CLI:** `-c, --config `
+- **命令行终端:** `-c, --config `
配置文件的路径
### update
-- **CLI:** `-u, --update`
-- **Config:** [update](/config/#update)
+- **命令行终端:** `-u, --update`
+- **配置:** [update](/config/#update)
更新快照
### watch
-- **CLI:** `-w, --watch`
-- **Config:** [watch](/config/#watch)
+- **命令行终端:** `-w, --watch`
+- **配置:** [watch](/config/#watch)
启用观察模式
### testNamePattern
-- **CLI:** `-t, --testNamePattern `
-- **Config:** [testNamePattern](/config/#testnamepattern)
+- **命令行终端:** `-t, --testNamePattern `
+- **配置:** [testNamePattern](/config/#testnamepattern)
使用符合指定 regexp 模式的运行测试
### dir
-- **CLI:** `--dir `
-- **Config:** [dir](/config/#dir)
+- **命令行终端:** `--dir `
+- **配置:** [dir](/config/#dir)
扫描测试文件的基本目录
### ui
-- **CLI:** `--ui`
-- **Config:** [ui](/config/#ui)
+- **命令行终端:** `--ui`
+- **配置:** [ui](/config/#ui)
-启用UI
+启用 UI 模式
### open
-- **CLI:** `--open`
-- **Config:** [open](/config/#open)
+- **命令行终端:** `--open`
+- **配置:** [open](/config/#open)
自动打开用户界面(默认值:`!process.env.CI`)。
### api.port
-- **CLI:** `--api.port [port]`
+- **命令行终端:** `--api.port [port]`
指定服务器端口。注意,如果端口已被使用,Vite 会自动尝试下一个可用端口,因此这可能不是服务器最终监听的实际端口。如果为 `true`,将设置为`51204`
### api.host
-- **CLI:** `--api.host [host]`
+- **命令行终端:** `--api.host [host]`
指定服务器应该监听哪些 IP 地址。设为 `0.0.0.0` 或 `true` 则监听所有地址,包括局域网地址和公共地址
### api.strictPort
-- **CLI:** `--api.strictPort`
+- **命令行终端:** `--api.strictPort`
设置为 true 时,如果端口已被使用,则退出,而不是自动尝试下一个可用端口
### silent
-- **CLI:** `--silent [value]`
-- **Config:** [silent](/config/#silent)
+- **命令行终端:** `--silent [value]`
+- **配置:** [silent](/config/#silent)
测试的静默控制台输出。使用 `'passed-only'` 仅查看失败测试的日志。
### hideSkippedTests
-- **CLI:** `--hideSkippedTests`
+- **命令行终端:** `--hideSkippedTests`
隐藏跳过测试的日志
### reporters
-- **CLI:** `--reporter `
-- **Config:** [reporters](/config/#reporters)
+- **命令行终端:** `--reporter `
+- **配置:** [reporters](/config/#reporters)
指定报告器(default、blob、verbose、dot、json、tap、tap-flat、junit、tree、hanging-process、github-actions)
### outputFile
-- **CLI:** `--outputFile `
-- **Config:** [outputFile](/config/#outputfile)
+- **命令行终端:** `--outputFile `
+- **配置:** [outputFile](/config/#outputfile)
-如果还指定了支持报告程序,则将测试结果写入文件,使用 cac 的点符号表示多个报告程序的单个输出结果 (比如: --outputFile.tap=./tap.txt)
+如果还指定了支持报告程序,则将测试结果写入文件,使用 cac 的点符号表示多个报告程序的单个输出结果 (比如: `--outputFile.tap=./tap.txt`)
+
+### coverage.all
+
+- **命令行终端:** `--coverage.all`
+- **配置:** [coverage.all](/config/#coverage-all)
+
+是否将所有文件,包括未测试的文件,都纳入报告中。
### coverage.provider
-- **CLI:** `--coverage.provider `
-- **Config:** [coverage.provider](/config/#coverage-provider)
+- **命令行终端:** `--coverage.provider `
+- **配置:** [coverage.provider](/config/#coverage-provider)
选择覆盖范围采集工具, 可用值为: "v8", "istanbul" and "custom"
### coverage.enabled
-- **CLI:** `--coverage.enabled`
-- **Config:** [coverage.enabled](/config/#coverage-enabled)
+- **命令行终端:** `--coverage.enabled`
+- **配置:** [coverage.enabled](/config/#coverage-enabled)
启用覆盖范围收集。可使用 `--coverage` CLI 选项覆盖(默认值:`false`)。
### coverage.include
-- **CLI:** `--coverage.include `
-- **Config:** [coverage.include](/config/#coverage-include)
+- **命令行终端:** `--coverage.include `
+- **配置:** [coverage.include](/config/#coverage-include)
-作为通配符模式包含在覆盖率中的文件。在使用多个模式时可以指定多次。默认情况下,只包含被测试覆盖的文件。
+覆盖范围中要包含的文件。使用多个扩展名时,可指定多次(默认值:`**`)。
### coverage.exclude
-- **CLI:** `--coverage.exclude `
-- **Config:** [coverage.exclude](/config/#coverage-exclude)
+- **命令行终端:** `--coverage.exclude `
+- **配置:** [coverage.exclude](/config/#coverage-exclude)
+
+覆盖范围中要排除的文件。使用多个扩展名时,可指定多次(默认情况下: 访问 [`coverage.exclude`](https://vitest.dev/config/#coverage-exclude)
+
+### coverage.extension
-覆盖范围中要排除的文件。使用多个扩展名时,可指定多次。
+- **命令行终端:** `--coverage.extension `
+- **配置:** [coverage.extension](/config/#coverage-extension)
+
+包含在覆盖范围内的扩展名。使用多个扩展名时,可指定多次 (默认值: `[".js", ".cjs", ".mjs", ".ts", ".mts", ".tsx", ".jsx", ".vue", ".svelte"]`)
### coverage.clean
-- **CLI:** `--coverage.clean`
-- **Config:** [coverage.clean](/config/#coverage-clean)
+- **命令行终端:** `--coverage.clean`
+- **配置:** [coverage.clean](/config/#coverage-clean)
运行测试前清除覆盖结果(默认值:true)
### coverage.cleanOnRerun
-- **CLI:** `--coverage.cleanOnRerun`
-- **Config:** [coverage.cleanOnRerun](/config/#coverage-cleanonrerun)
+- **命令行终端:** `--coverage.cleanOnRerun`
+- **配置:** [coverage.cleanOnRerun](/config/#coverage-cleanonrerun)
重新运行监视时清理覆盖率报告(默认值:true)
### coverage.reportsDirectory
-- **CLI:** `--coverage.reportsDirectory `
-- **Config:** [coverage.reportsDirectory](/config/#coverage-reportsdirectory)
+- **命令行终端:** `--coverage.reportsDirectory `
+- **配置:** [coverage.reportsDirectory](/config/#coverage-reportsdirectory)
将覆盖率报告写入的目录(默认值: ./coverage)
### coverage.reporter
-- **CLI:** `--coverage.reporter `
-- **Config:** [coverage.reporter](/config/#coverage-reporter)
+- **命令行终端:** `--coverage.reporter `
+- **配置:** [coverage.reporter](/config/#coverage-reporter)
使用的报告。更多信息请访问 [`coverage.reporter`](https://vitest.dev/config/#coverage-reporter)。 (默认值: `["text", "html", "clover", "json"]`)
### coverage.reportOnFailure
-- **CLI:** `--coverage.reportOnFailure`
-- **Config:** [coverage.reportOnFailure](/config/#coverage-reportonfailure)
+- **命令行终端:** `--coverage.reportOnFailure`
+- **配置:** [coverage.reportOnFailure](/config/#coverage-reportonfailure)
即使测试失败也能生成覆盖率报告 (默认值: `false`)
### coverage.allowExternal
-- **CLI:** `--coverage.allowExternal`
-- **Config:** [coverage.allowExternal](/config/#coverage-allowexternal)
+- **命令行终端:** `--coverage.allowExternal`
+- **配置:** [coverage.allowExternal](/config/#coverage-allowexternal)
收集项目根目录外文件的覆盖范围(默认值:`false`)
### coverage.skipFull
-- **CLI:** `--coverage.skipFull`
-- **Config:** [coverage.skipFull](/config/#coverage-skipfull)
+- **命令行终端:** `--coverage.skipFull`
+- **配置:** [coverage.skipFull](/config/#coverage-skipfull)
不显示语句、分支和函数覆盖率为 100% 的文件(默认值:`false`)
### coverage.thresholds.100
-- **CLI:** `--coverage.thresholds.100`
-- **Config:** [coverage.thresholds.100](/config/#coverage-thresholds-100)
+- **命令行终端:** `--coverage.thresholds.100`
+- **配置:** [coverage.thresholds.100](/config/#coverage-thresholds-100)
将所有覆盖率阈值设置为 100 的快捷方式(默认值:`false`)
### coverage.thresholds.perFile
-- **CLI:** `--coverage.thresholds.perFile`
-- **Config:** [coverage.thresholds.perFile](/config/#coverage-thresholds-perfile)
+- **命令行终端:** `--coverage.thresholds.perFile`
+- **配置:** [coverage.thresholds.perFile](/config/#coverage-thresholds-perfile)
-查每个文件的阈值。 `--coverage.thresholds.lines`, `--coverage.thresholds.functions`, `--coverage.thresholds.branches`, `--coverage.thresholds.statements` 为实际阈值(默认值:`false`)
+检查每个文件的阈值。 `--coverage.thresholds.lines`, `--coverage.thresholds.functions`, `--coverage.thresholds.branches`, `--coverage.thresholds.statements` 为实际阈值(默认值:`false`)
### coverage.thresholds.autoUpdate
-- **CLI:** `--coverage.thresholds.autoUpdate `
-- **Config:** [coverage.thresholds.autoUpdate](/config/#coverage-thresholds-autoupdate)
+- **命令行终端:** `--coverage.thresholds.autoUpdate `
+- **配置:** [coverage.thresholds.autoUpdate](/config/#coverage-thresholds-autoupdate)
-更新阈值: 当当前覆盖率高于配置的阈值时,将 "lines"、"functions"、"branches"和 "statements"更新到配置文件(默认值:`false`)
+更新阈值: 当前覆盖率高于配置的阈值时,将 "lines"、"functions"、"branches"和 "statements"更新到配置文件(默认值:`false`)
### coverage.thresholds.lines
-- **CLI:** `--coverage.thresholds.lines `
+- **命令行终端:** `--coverage.thresholds.lines `
针对代码行的覆盖度阈值设定,请访问 [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) 了解更多信息。此选项不适用于自定义 providers
### coverage.thresholds.functions
-- **CLI:** `--coverage.thresholds.functions `
+- **命令行终端:** `--coverage.thresholds.functions `
-针对函数的覆盖度阈值设定,请访问 [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) 了解更多信息。 此选项不适用于自定义 providers
+针对函数的覆盖度阈值设定,请访问 [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) 了解更多信息。此选项不适用于自定义 providers
### coverage.thresholds.branches
-- **CLI:** `--coverage.thresholds.branches `
+- **命令行终端:** `--coverage.thresholds.branches `
-针对 branches 的覆盖度阈值设定,请访问 [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) 了解更多信息。 此选项不适用于自定义 providers
+针对 branches 的覆盖度阈值设定,请访问 [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) 了解更多信息。此选项不适用于自定义 providers
### coverage.thresholds.statements
-- **CLI:** `--coverage.thresholds.statements `
+- **命令行终端:** `--coverage.thresholds.statements `
-针对 statements 的覆盖度阈值设定,请访问 [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) 了解更多信息。 此选项不适用于自定义 providers
+针对 statements 的覆盖度阈值设定,请访问 [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) 了解更多信息。此选项不适用于自定义 providers
### coverage.ignoreClassMethods
-- **CLI:** `--coverage.ignoreClassMethods `
-- **Config:** [coverage.ignoreClassMethods](/config/#coverage-ignoreclassmethods)
+- **命令行终端:** `--coverage.ignoreClassMethods `
+- **配置:** [coverage.ignoreClassMethods](/config/#coverage-ignoreclassmethods)
覆盖时要忽略的类方法名称数组。更多信息请访问 [istanbuljs](https://github.com/istanbuljs/nyc#ignoring-methods) 。该选项仅适用于 istanbul providers(默认值:`[]`)。
### coverage.processingConcurrency
-- **CLI:** `--coverage.processingConcurrency `
-- **Config:** [coverage.processingConcurrency](/config/#coverage-processingconcurrency)
+- **命令行终端:** `--coverage.processingConcurrency `
+- **配置:** [coverage.processingConcurrency](/config/#coverage-processingconcurrency)
处理覆盖率结果时使用的并发限制。 (默认最小值介于 20 和 CPU 数量之间)
### coverage.customProviderModule
-- **CLI:** `--coverage.customProviderModule `
-- **Config:** [coverage.customProviderModule](/config/#coverage-customprovidermodule)
+- **命令行终端:** `--coverage.customProviderModule `
+- **配置:** [coverage.customProviderModule](/config/#coverage-customprovidermodule)
-指定自定义覆盖范围提供程序模块的模块名称或路径。 请访问[自定义 providers 覆盖范围](https://vitest.dev/guide/coverage#custom-coverage-provider) 了解更多信息。 此选项仅适用于自定义 providers
+指定自定义覆盖范围提供程序模块的模块名称或路径。 请访问 [自定义 providers 覆盖范围](/guide/coverage#custom-coverage-provider) 了解更多信息。此选项仅适用于自定义 providers
### coverage.watermarks.statements
-- **CLI:** `--coverage.watermarks.statements `
+- **命令行终端:** `--coverage.watermarks.statements `
High and low watermarks for statements in the format of `,`
### coverage.watermarks.lines
-- **CLI:** `--coverage.watermarks.lines `
+- **命令行终端:** `--coverage.watermarks.lines `
High and low watermarks for lines in the format of `,`
### coverage.watermarks.branches
-- **CLI:** `--coverage.watermarks.branches `
+- **命令行终端:** `--coverage.watermarks.branches `
High and low watermarks for branches in the format of `,`
### coverage.watermarks.functions
-- **CLI:** `--coverage.watermarks.functions `
+- **命令行终端:** `--coverage.watermarks.functions `
High and low watermarks for functions in the format of `,`
### mode
-- **CLI:** `--mode `
-- **Config:** [mode](/config/#mode)
+- **命令行终端:** `--mode `
+- **配置:** [mode](/config/#mode)
覆盖 Vite 模式 (默认值: `test` 或 `benchmark`)
+### workspace
+
+- **命令行终端:** `--workspace `
+- **配置:** [workspace](/config/#workspace)
+
+(已废弃)工作区配置文件的路径
+
### isolate
-- **CLI:** `--isolate`
-- **Config:** [isolate](/config/#isolate)
+- **命令行终端:** `--isolate`
+- **配置:** [isolate](/config/#isolate)
隔离运行每个测试文件。要禁用隔离, 使用 `--no-isolate` (默认值: `true`)
### globals
-- **CLI:** `--globals`
-- **Config:** [globals](/config/#globals)
+- **命令行终端:** `--globals`
+- **配置:** [globals](/config/#globals)
全局注入
### dom
-- **CLI:** `--dom`
+- **命令行终端:** `--dom`
使用 happy-dom 模拟浏览器 API
### browser.enabled
-- **CLI:** `--browser.enabled`
-- **Config:** [browser.enabled](/guide/browser/config#browser-enabled)
+- **命令行终端:** `--browser.enabled`
+- **配置:** [browser.enabled](/guide/browser/config#browser-enabled)
在浏览器中运行测试。 相当于 `--browser.enabled` (默认值: `false`)
### browser.name
-- **CLI:** `--browser.name `
-- **Config:** [browser.name](/guide/browser/config#browser-name)
+- **命令行终端:** `--browser.name `
+- **配置:** [browser.name](/guide/browser/config#browser-name)
在特定浏览器中运行所有测试。某些浏览器仅适用于特定提供商(请参阅 `--browser.provider` )。访问 [`browser.name`](https://vitest.dev/guide/browser/config/#browser-name) 了解更多信息
### browser.headless
-- **CLI:** `--browser.headless`
-- **Config:** [browser.headless](/guide/browser/config#browser-headless)
+- **命令行终端:** `--browser.headless`
+- **配置:** [browser.headless](/guide/browser/config#browser-headless)
在无头模式下运行浏览器(即不打开图形用户界面)。如果在 CI 中运行 Vitest,默认情况下将启用无头模式 (默认值: `process.env.CI`)
### browser.api.port
-- **CLI:** `--browser.api.port [port]`
-- **Config:** [browser.api.port](/guide/browser/config#browser-api-port)
+- **命令行终端:** `--browser.api.port [port]`
+- **配置:** [browser.api.port](/guide/browser/config#browser-api-port)
指定服务器端口。注意,如果端口已被使用,Vite 会自动尝试下一个可用端口,因此这可能不是服务器最终监听的实际端口。如果为 `true`,将设置为 `63315`
### browser.api.host
-- **CLI:** `--browser.api.host [host]`
-- **Config:** [browser.api.host](/guide/browser/config#browser-api-host)
+- **命令行终端:** `--browser.api.host [host]`
+- **配置:** [browser.api.host](/guide/browser/config#browser-api-host)
指定服务器应该监听哪些 IP 地址。设为 `0.0.0.0` 或 `true` 则监听所有地址,包括局域网地址和公共地址
### browser.api.strictPort
-- **CLI:** `--browser.api.strictPort`
-- **Config:** [browser.api.strictPort](/guide/browser/config#browser-api-strictport)
+- **命令行终端:** `--browser.api.strictPort`
+- **配置:** [browser.api.strictPort](/guide/browser/config#browser-api-strictport)
设置为 true 时,如果端口已被使用,则退出,而不是自动尝试下一个可用端口
### browser.provider
-- **CLI:** `--browser.provider `
-- **Config:** [browser.provider](/guide/browser/config#browser-provider)
+- **命令行终端:** `--browser.provider `
+- **配置:** [browser.provider](/guide/browser/config#browser-provider)
-指定执行浏览器测试时所使用的提供程序。部分浏览器仅在特定的提供程序下可用。可选值有 "webdriverio"、"playwright"、"preview",也可以填写自定义提供程序的路径。更多信息请查看 [`browser.provider`](https://vitest.dev/guide/browser/config.html#browser-provider)(默认值为 "preview")。
+指定执行浏览器测试时所使用的提供程序。部分浏览器仅在特定的提供程序下可用。可选值有 "webdriverio"、"playwright"、"preview",也可以填写自定义提供程序的路径。更多信息请查看 [`browser.provider`](https://vitest.dev/guide/browser/config.html#browser-provider)(默认值为 "preview")
+
+### browser.providerOptions
+
+- **命令行终端:** `--browser.providerOptions `
+- **配置:** [browser.providerOptions](/guide/browser/config#browser-provideroptions)
+
+传递给浏览器提供程序的选项。更多信息请访问 [`browser.providerOptions`](https://vitest.dev/config/#browser-provideroptions)
### browser.isolate
-- **CLI:** `--browser.isolate`
-- **Config:** [browser.isolate](/guide/browser/config#browser-isolate)
+- **命令行终端:** `--browser.isolate`
+- **配置:** [browser.isolate](/guide/browser/config#browser-isolate)
隔离运行每个浏览器测试文件。要禁用隔离请使用 `--browser.isolate=false` (默认值: `true`)
### browser.ui
-- **CLI:** `--browser.ui`
-- **Config:** [browser.ui](/guide/browser/config#browser-ui)
+- **命令行终端:** `--browser.ui`
+- **配置:** [browser.ui](/guide/browser/config#browser-ui)
-运行测试时显示 Vitest UI(默认值: `!process.env.CI`)
+运行测试时显示 Vitest UI (默认值: `!process.env.CI`)
### browser.fileParallelism
-- **CLI:** `--browser.fileParallelism`
-- **Config:** [browser.fileParallelism](/guide/browser/config#browser-fileparallelism)
+- **命令行终端:** `--browser.fileParallelism`
+- **配置:** [browser.fileParallelism](/guide/browser/config#browser-fileparallelism)
-浏览器测试文件是否应并行运行。使用 `--browser.fileParallelism=false` 可禁用 (默认值: `true`)
+浏览器测试文件是否应并行运行。使用 `--browser.fileParallelism=false` 进行禁用 (默认值: `true`)
### browser.connectTimeout
-- **CLI:** `--browser.connectTimeout `
-- **Config:** [browser.connectTimeout](/guide/browser/config#browser-connecttimeout)
-
-If connection to the browser takes longer, the test suite will fail (default: `60_000`)
-
-### browser.trackUnhandledErrors
-
-- **CLI:** `--browser.trackUnhandledErrors`
-- **Config:** [browser.trackUnhandledErrors](/guide/browser/config#browser-trackunhandlederrors)
-
-控制 Vitest 是否捕获未捕获的异常以便报告(默认:`true`)。
-
-### browser.trace
-
-- **CLI:** `--browser.trace `
-- **Config:** [browser.trace](/guide/browser/config#browser-trace)
+- **命令行终端:** `--browser.connectTimeout `
+- **配置:** [browser.connectTimeout](/guide/browser/config#browser-connecttimeout)
-Enable trace view mode. Supported: "on", "off", "on-first-retry", "on-all-retries", "retain-on-failure".
+如果连接浏览器时间超时,测试套件将失败 (默认值: `60_000`)
### pool
-- **CLI:** `--pool `
-- **Config:** [pool](/config/#pool)
+- **命令行终端:** `--pool `
+- **配置:** [pool](/config/#pool)
如果未在浏览器中运行,则指定 pool (默认值: `threads`)
### poolOptions.threads.isolate
-- **CLI:** `--poolOptions.threads.isolate`
-- **Config:** [poolOptions.threads.isolate](/config/#pooloptions-threads-isolate)
+- **命令行终端:** `--poolOptions.threads.isolate`
+- **配置:** [poolOptions.threads.isolate](/config/#pooloptions-threads-isolate)
在线程池中隔离测试 (默认值: `true`)
### poolOptions.threads.singleThread
-- **CLI:** `--poolOptions.threads.singleThread`
-- **Config:** [poolOptions.threads.singleThread](/config/#pooloptions-threads-singlethread)
+- **命令行终端:** `--poolOptions.threads.singleThread`
+- **配置:** [poolOptions.threads.singleThread](/config/#pooloptions-threads-singlethread)
在单线程内运行测试 (默认值: `false`)
### poolOptions.threads.maxThreads
-- **CLI:** `--poolOptions.threads.maxThreads `
-- **Config:** [poolOptions.threads.maxThreads](/config/#pooloptions-threads-maxthreads)
+- **命令行终端:** `--poolOptions.threads.maxThreads `
+- **配置:** [poolOptions.threads.maxThreads](/config/#pooloptions-threads-maxthreads)
运行测试的最大线程数或百分比
### poolOptions.threads.useAtomics
-- **CLI:** `--poolOptions.threads.useAtomics`
-- **Config:** [poolOptions.threads.useAtomics](/config/#pooloptions-threads-useatomics)
+- **命令行终端:** `--poolOptions.threads.useAtomics`
+- **配置:** [poolOptions.threads.useAtomics](/config/#pooloptions-threads-useatomics)
使用 Atomics 同步线程。这在某些情况下可以提高性能,但在较旧的 Node 版本中可能会导致 segfault。 (默认值: `false`)
### poolOptions.vmThreads.isolate
-- **CLI:** `--poolOptions.vmThreads.isolate`
-- **Config:** [poolOptions.vmThreads.isolate](/config/#pooloptions-vmthreads-isolate)
+- **命令行终端:** `--poolOptions.vmThreads.isolate`
+- **配置:** [poolOptions.vmThreads.isolate](/config/#pooloptions-vmthreads-isolate)
在线程池中隔离测试 (默认值: `true`)
### poolOptions.vmThreads.singleThread
-- **CLI:** `--poolOptions.vmThreads.singleThread`
-- **Config:** [poolOptions.vmThreads.singleThread](/config/#pooloptions-vmthreads-singlethread)
+- **命令行终端:** `--poolOptions.vmThreads.singleThread`
+- **配置:** [poolOptions.vmThreads.singleThread](/config/#pooloptions-vmthreads-singlethread)
在单线程内运行测试(默认值:`false`)
### poolOptions.vmThreads.maxThreads
-- **CLI:** `--poolOptions.vmThreads.maxThreads `
-- **Config:** [poolOptions.vmThreads.maxThreads](/config/#pooloptions-vmthreads-maxthreads)
+- **命令行终端:** `--poolOptions.vmThreads.maxThreads `
+- **配置:** [poolOptions.vmThreads.maxThreads](/config/#pooloptions-vmthreads-maxthreads)
运行测试的最大线程数或百分比
### poolOptions.vmThreads.useAtomics
-- **CLI:** `--poolOptions.vmThreads.useAtomics`
-- **Config:** [poolOptions.vmThreads.useAtomics](/config/#pooloptions-vmthreads-useatomics)
+- **命令行终端:** `--poolOptions.vmThreads.useAtomics`
+- **配置:** [poolOptions.vmThreads.useAtomics](/config/#pooloptions-vmthreads-useatomics)
使用 Atomics 同步线程。这在某些情况下可以提高性能,但在较旧的 Node 版本中可能会导致 segfault。 (默认值: `false`)
### poolOptions.vmThreads.memoryLimit
-- **CLI:** `--poolOptions.vmThreads.memoryLimit `
-- **Config:** [poolOptions.vmThreads.memoryLimit](/config/#pooloptions-vmthreads-memorylimit)
+- **命令行终端:** `--poolOptions.vmThreads.memoryLimit `
+- **配置:** [poolOptions.vmThreads.memoryLimit](/config/#pooloptions-vmthreads-memorylimit)
虚拟机线程池的内存限制。如果发现内存泄漏,请尝试调整该值。
### poolOptions.forks.isolate
-- **CLI:** `--poolOptions.forks.isolate`
-- **Config:** [poolOptions.forks.isolate](/config/#pooloptions-forks-isolate)
+- **命令行终端:** `--poolOptions.forks.isolate`
+- **配置:** [poolOptions.forks.isolate](/config/#pooloptions-forks-isolate)
在 forks pool 中隔离测试 (默认值: `true`)
### poolOptions.forks.singleFork
-- **CLI:** `--poolOptions.forks.singleFork`
-- **Config:** [poolOptions.forks.singleFork](/config/#pooloptions-forks-singlefork)
+- **命令行终端:** `--poolOptions.forks.singleFork`
+- **配置:** [poolOptions.forks.singleFork](/config/#pooloptions-forks-singlefork)
单个子进程内运行测试 (default: `false`)
### poolOptions.forks.maxForks
-- **CLI:** `--poolOptions.forks.maxForks `
-- **Config:** [poolOptions.forks.maxForks](/config/#pooloptions-forks-maxforks)
+- **命令行终端:** `--poolOptions.forks.maxForks `
+- **配置:** [poolOptions.forks.maxForks](/config/#pooloptions-forks-maxforks)
运行测试的最大进程数
### poolOptions.vmForks.isolate
-- **CLI:** `--poolOptions.vmForks.isolate`
-- **Config:** [poolOptions.vmForks.isolate](/config/#pooloptions-vmforks-isolate)
+- **命令行终端:** `--poolOptions.vmForks.isolate`
+- **配置:** [poolOptions.vmForks.isolate](/config/#pooloptions-vmforks-isolate)
在 forks pool 中隔离测试 (default: `true`)
### poolOptions.vmForks.singleFork
-- **CLI:** `--poolOptions.vmForks.singleFork`
-- **Config:** [poolOptions.vmForks.singleFork](/config/#pooloptions-vmforks-singlefork)
+- **命令行终端:** `--poolOptions.vmForks.singleFork`
+- **配置:** [poolOptions.vmForks.singleFork](/config/#pooloptions-vmforks-singlefork)
在单个子进程内运行测试 (default: `false`)
### poolOptions.vmForks.maxForks
-- **CLI:** `--poolOptions.vmForks.maxForks `
-- **Config:** [poolOptions.vmForks.maxForks](/config/#pooloptions-vmforks-maxforks)
+- **命令行终端:** `--poolOptions.vmForks.maxForks `
+- **配置:** [poolOptions.vmForks.maxForks](/config/#pooloptions-vmforks-maxforks)
运行测试的最大进程数
### poolOptions.vmForks.memoryLimit
-- **CLI:** `--poolOptions.vmForks.memoryLimit `
-- **Config:** [poolOptions.vmForks.memoryLimit](/config/#pooloptions-vmforks-memorylimit)
+- **命令行终端:** `--poolOptions.vmForks.memoryLimit `
+- **配置:** [poolOptions.vmForks.memoryLimit](/config/#pooloptions-vmforks-memorylimit)
VM forks pool 的内存限制。如果你观察到内存泄漏问题,可以尝试调整这个值。
### fileParallelism
-- **CLI:** `--fileParallelism`
-- **Config:** [fileParallelism](/config/#fileparallelism)
+- **命令行终端:** `--fileParallelism`
+- **配置:** [fileParallelism](/config/#fileparallelism)
是否所有测试文件都应并行运行. 使用 `--no-file-parallelism` 去禁用 (默认值: `true`)
### maxWorkers
-- **CLI:** `--maxWorkers `
-- **Config:** [maxWorkers](/config/#maxworkers)
+- **命令行终端:** `--maxWorkers `
+- **配置:** [maxWorkers](/config/#maxworkers)
同时并发执行测试任务的最大线程数或百分比
### environment
-- **CLI:** `--environment `
-- **Config:** [environment](/config/#environment)
+- **命令行终端:** `--environment `
+- **配置:** [environment](/config/#environment)
如果不在浏览器中运行,则指定运行环境 (默认值: `node`)
### passWithNoTests
-- **CLI:** `--passWithNoTests`
-- **Config:** [passWithNoTests](/config/#passwithnotests)
+- **命令行终端:** `--passWithNoTests`
+- **配置:** [passWithNoTests](/config/#passwithnotests)
未发现测试时通过
### logHeapUsage
-- **CLI:** `--logHeapUsage`
-- **Config:** [logHeapUsage](/config/#logheapusage)
+- **命令行终端:** `--logHeapUsage`
+- **配置:** [logHeapUsage](/config/#logheapusage)
在节点中运行时,显示每个测试的堆大小
### allowOnly
-- **CLI:** `--allowOnly`
-- **Config:** [allowOnly](/config/#allowonly)
+- **命令行终端:** `--allowOnly`
+- **配置:** [allowOnly](/config/#allowonly)
允许执行那些被标记为"only"的测试用例或测试套件 (默认值: `!process.env.CI`)
### dangerouslyIgnoreUnhandledErrors
-- **CLI:** `--dangerouslyIgnoreUnhandledErrors`
-- **Config:** [dangerouslyIgnoreUnhandledErrors](/config/#dangerouslyignoreunhandlederrors)
+- **命令行终端:** `--dangerouslyIgnoreUnhandledErrors`
+- **配置:** [dangerouslyIgnoreUnhandledErrors](/config/#dangerouslyignoreunhandlederrors)
忽略任何未处理的错误
### sequence.shuffle.files
-- **CLI:** `--sequence.shuffle.files`
-- **Config:** [sequence.shuffle.files](/config/#sequence-shuffle-files)
+- **命令行终端:** `--sequence.shuffle.files`
+- **配置:** [sequence.shuffle.files](/config/#sequence-shuffle-files)
以随机顺序运行文件。如果启用此选项,长时间运行的测试将不会提前开始。 (默认值: `false`)
### sequence.shuffle.tests
-- **CLI:** `--sequence.shuffle.tests`
-- **Config:** [sequence.shuffle.tests](/config/#sequence-shuffle-tests)
+- **命令行终端:** `--sequence.shuffle.tests`
+- **配置:** [sequence.shuffle.tests](/config/#sequence-shuffle-tests)
以随机方式运行测试(默认值:`false`)
### sequence.concurrent
-- **CLI:** `--sequence.concurrent`
-- **Config:** [sequence.concurrent](/config/#sequence-concurrent)
+- **命令行终端:** `--sequence.concurrent`
+- **配置:** [sequence.concurrent](/config/#sequence-concurrent)
使测试并行运行(默认值:`false`)
### sequence.seed
-- **CLI:** `--sequence.seed `
-- **Config:** [sequence.seed](/config/#sequence-seed)
+- **命令行终端:** `--sequence.seed `
+- **配置:** [sequence.seed](/config/#sequence-seed)
设置随机化种子。如果 --sequence.shuffle(随机序列)是`false`,则此选项无效。 t 通过 ["Random Seed" page](https://en.wikipedia.org/wiki/Random_seed) 查看更多信息
### sequence.hooks
-- **CLI:** `--sequence.hooks `
-- **Config:** [sequence.hooks](/config/#sequence-hooks)
+- **命令行终端:** `--sequence.hooks `
+- **配置:** [sequence.hooks](/config/#sequence-hooks)
更改钩子的执行顺序。 可接受的值有: "stack", "list" and "parallel". 通过 [`sequence.hooks`](https://vitest.dev/config/#sequence-hooks) 查看更多信息 (默认值: `"parallel"`)
### sequence.setupFiles
-- **CLI:** `--sequence.setupFiles `
-- **Config:** [sequence.setupFiles](/config/#sequence-setupfiles)
+- **命令行终端:** `--sequence.setupFiles `
+- **配置:** [sequence.setupFiles](/config/#sequence-setupfiles)
更改设置文件的执行顺序。可接受的值有 "list" 和 "parallel"。如果设置为"list",将按照定义的顺序运行设置文件。如果设置为 "parallel",将并行运行设置文件(默认值:`"parallel"`)。
### inspect
-- **CLI:** `--inspect [[host:]port]`
-- **Config:** [inspect](/config/#inspect)
+- **命令行终端:** `--inspect [[host:]port]`
+- **配置:** [inspect](/config/#inspect)
启用 Node.js 检查器(默认值:`127.0.0.1:9229`)
### inspectBrk
-- **CLI:** `--inspectBrk [[host:]port]`
-- **Config:** [inspectBrk](/config/#inspectbrk)
+- **命令行终端:** `--inspectBrk [[host:]port]`
+- **配置:** [inspectBrk](/config/#inspectbrk)
启用 Node.js 检查器并在测试开始前中断
### testTimeout
-- **CLI:** `--testTimeout `
-- **Config:** [testTimeout](/config/#testtimeout)
+- **命令行终端:** `--testTimeout `
+- **配置:** [testTimeout](/config/#testtimeout)
测试的默认超时(毫秒)(默认值:`5000`)。使用 `0` 完全禁用超时。
### hookTimeout
-- **CLI:** `--hookTimeout `
-- **Config:** [hookTimeout](/config/#hooktimeout)
+- **命令行终端:** `--hookTimeout `
+- **配置:** [hookTimeout](/config/#hooktimeout)
默认钩子超时(以毫秒为单位)(默认值:`10000`)。使用 `0` 完全禁用超时。
### bail
-- **CLI:** `--bail `
-- **Config:** [bail](/config/#bail)
+- **命令行终端:** `--bail `
+- **配置:** [bail](/config/#bail)
当指定数量的测试失败时停止测试执行(默认值:`0`)
### retry
-- **CLI:** `--retry `
-- **Config:** [retry](/config/#retry)
+- **命令行终端:** `--retry `
+- **配置:** [retry](/config/#retry)
如果测试失败,重试特定次数(默认值: `0`)。
### diff.aAnnotation
-- **CLI:** `--diff.aAnnotation `
-- **Config:** [diff.aAnnotation](/config/#diff-aannotation)
+- **命令行终端:** `--diff.aAnnotation `
+- **配置:** [diff.aAnnotation](/config/#diff-aannotation)
Annotation for expected lines (default: `Expected`)
### diff.aIndicator
-- **CLI:** `--diff.aIndicator `
-- **Config:** [diff.aIndicator](/config/#diff-aindicator)
+- **命令行终端:** `--diff.aIndicator `
+- **配置:** [diff.aIndicator](/config/#diff-aindicator)
Indicator for expected lines (default: `-`)
### diff.bAnnotation
-- **CLI:** `--diff.bAnnotation `
-- **Config:** [diff.bAnnotation](/config/#diff-bannotation)
+- **命令行终端:** `--diff.bAnnotation `
+- **配置:** [diff.bAnnotation](/config/#diff-bannotation)
Annotation for received lines (default: `Received`)
### diff.bIndicator
-- **CLI:** `--diff.bIndicator `
-- **Config:** [diff.bIndicator](/config/#diff-bindicator)
+- **命令行终端:** `--diff.bIndicator `
+- **配置:** [diff.bIndicator](/config/#diff-bindicator)
Indicator for received lines (default: `+`)
### diff.commonIndicator
-- **CLI:** `--diff.commonIndicator `
-- **Config:** [diff.commonIndicator](/config/#diff-commonindicator)
+- **命令行终端:** `--diff.commonIndicator `
+- **配置:** [diff.commonIndicator](/config/#diff-commonindicator)
Indicator for common lines (default: ` `)
### diff.contextLines
-- **CLI:** `--diff.contextLines