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..6dac9959 100644 --- a/.vitepress/config.ts +++ b/.vitepress/config.ts @@ -567,54 +567,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 +587,7 @@ function guide(): DefaultTheme.SidebarItem[] { link: '/guide/testing-types', }, { - text: 'UI模式', + text: 'UI 模式', link: '/guide/ui', }, { @@ -633,6 +598,10 @@ function guide(): DefaultTheme.SidebarItem[] { text: '测试上下文', link: '/guide/test-context', }, + { + text: '测试注释', + link: '/guide/test-annotations', + }, { text: '测试环境', link: '/guide/environment', @@ -659,8 +628,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 +661,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..fd28be9c 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 将导入原始模块并自动模拟其所有输出。有关应用的规则,请参阅 [模块](/mocking.html#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) 相同的规则。有关应用的规则,请参阅 [模块](/mocking.html#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.html#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.html#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..dec7c6db 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,31 @@ Expand all common lines. 通过委托各自的处理程序,告诉假冒计时器清除 "native"(即非假冒)计时器。禁用时,如果计时器在启动假计时器会话之前已经存在,则可能导致意外行为。 -### projects {#projects} +### workspace + +- **类型:** `string | TestProjectConfiguration` +- **命令行终端:** `--workspace=./file.js` +- **默认值:** `vitest.{workspace,projects}.{js,ts,json}` close to the config file or root + +相对于[root](#root) 的 [workspace](/guide/workspace) 配置文件的路径。 + +Since Vitest 3, you can also define the workspace array in the root config. If the `workspace` is defined in the config manually, Vitest will ignore the `vitest.workspace` file in the root. + +### workspace + +::: danger 弃用 +此选项已弃用,将在下一个主要版本中移除。请改用 [`projects`](#projects)。 +::: + +- **类型:** `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 +2563,7 @@ Expand all common lines. 在隔离的环境中运行测试。此选项对 `vmThreads` 和 `vmForks` 池没有影响。 -如果你的代码不依赖于副作用(对于具有 `node` 环境的项目通常如此),禁用此选项可能会[改进性能](/guide/improving-performance)。 +如果你的代码不依赖于副作用(这在 `node` 环境的项目通常如此),禁用此选项可能会 [性能提升](/guide/improving-performance)。 ::: tip 你可以使用 [`poolOptions`](#poolOptions) 属性禁用特定池的隔离。 @@ -2367,14 +2574,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 如果不使用依赖于该选项的自定义代码,该选项将不起作用。 @@ -2405,10 +2612,10 @@ export interface SnapshotEnvironment { ::: warning 这是一个低级选项,仅适用于无法访问默认 Node.js API 的高级情况。 -如果只需要配置快照功能,请使用 [`snapshotFormat`](#snapshotformat)或 [`resolveSnapshotPath`](#resolvesnapshotpath)选项。 +如果只需要配置快照功能,请使用 [`snapshotFormat`](#snapshotformat) 或 [`resolveSnapshotPath`](#resolvesnapshotpath) 选项。 ::: -### env {#env} +### env - **类型:** `Partial` @@ -2456,7 +2663,7 @@ export interface SnapshotEnvironment { 每次调用 `console` 方法时都输出堆栈追踪信息,这对于排查问题非常有帮助。 -### attachmentsDir 3.2.0 {#attachmentsdir} +### attachmentsDir 3.2.0 - **类型:** `string` - **默认值:** `'.vitest-attachments'` diff --git a/guide/browser/config.md b/guide/browser/config.md index f5830437..381e8275 100644 --- a/guide/browser/config.md +++ b/guide/browser/config.md @@ -40,7 +40,7 @@ export default defineConfig({ - **类型:** `boolean` - **默认值:** `false` -- **CLI:** `--browser`, `--browser.enabled=false` +- **命令行终端:** `--browser`, `--browser.enabled=false` 默认情况下在浏览器中运行所有测试。请注意,`--browser` 仅在我们至少有一个 [`browser.instances`](#browser-instances) 项时有效。 @@ -95,7 +95,7 @@ export default defineConfig({ - **类型:** `boolean` - **默认值:** `process.env.CI` -- **CLI:** `--browser.headless`, `--browser.headless=false` +- **命令行终端:** `--browser.headless`, `--browser.headless=false` 在 `headless` 模式下运行浏览器。如果我们在 CI 中运行 Vitest,则默认启用此模式。 @@ -103,7 +103,7 @@ export default defineConfig({ - **类型:** `boolean` - **默认值:** `true` -- **CLI:** `--browser.isolate`, `--browser.isolate=false` +- **命令行终端:** `--browser.isolate`, `--browser.isolate=false` 在单独的 iframe 中运行每个测试。 @@ -117,7 +117,7 @@ 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` 以避免与开发服务器冲突,允许我们同时运行两者。 @@ -125,7 +125,7 @@ HTML 入口点的路径。可以是相对于项目根目录的路径。此文件 - **类型:** `BrowserProviderOption` - **默认值:** `'preview'` -- **CLI:** `--browser.provider=playwright` +- **命令行终端:** `--browser.provider=playwright` 提供者工厂的返回值。你可以从 `@vitest/browser-` 导入工厂函数,或者创建自己的提供者: @@ -206,7 +206,7 @@ export interface BrowserProvider { - **类型:** `boolean` - **默认值:** `!isCI` -- **CLI:** `--browser.ui=false` +- **命令行终端:** `--browser.ui=false` 是否应将 Vitest UI 注入页面。默认情况下,在开发期间注入 UI iframe。 @@ -303,7 +303,7 @@ export interface BrowserScript { ## browser.trace - **类型:** `'on' | 'off' | 'on-first-retry' | 'on-all-retries' | 'retain-on-failure' | object` -- **CLI:** `--browser.trace=on`, `--browser.trace=retain-on-failure` +- **命令行终端:** `--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/). 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/)。 ::: Vitest UI @@ -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/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 ` -- **Config:** [diff.contextLines](/config/#diff-contextlines) +- **命令行终端:** `--diff.contextLines ` +- **配置:** [diff.contextLines](/config/#diff-contextlines) Number of lines of context to show around each change (default: `5`) ### diff.emptyFirstOrLastLinePlaceholder -- **CLI:** `--diff.emptyFirstOrLastLinePlaceholder ` -- **Config:** [diff.emptyFirstOrLastLinePlaceholder](/config/#diff-emptyfirstorlastlineplaceholder) +- **命令行终端:** `--diff.emptyFirstOrLastLinePlaceholder ` +- **配置:** [diff.emptyFirstOrLastLinePlaceholder](/config/#diff-emptyfirstorlastlineplaceholder) Placeholder for an empty first or last line (default: `""`) ### diff.expand -- **CLI:** `--diff.expand` -- **Config:** [diff.expand](/config/#diff-expand) +- **命令行终端:** `--diff.expand` +- **配置:** [diff.expand](/config/#diff-expand) Expand all common lines (default: `true`) ### diff.includeChangeCounts -- **CLI:** `--diff.includeChangeCounts` -- **Config:** [diff.includeChangeCounts](/config/#diff-includechangecounts) +- **命令行终端:** `--diff.includeChangeCounts` +- **配置:** [diff.includeChangeCounts](/config/#diff-includechangecounts) Include comparison counts in diff output (default: `false`) ### diff.omitAnnotationLines -- **CLI:** `--diff.omitAnnotationLines` -- **Config:** [diff.omitAnnotationLines](/config/#diff-omitannotationlines) +- **命令行终端:** `--diff.omitAnnotationLines` +- **配置:** [diff.omitAnnotationLines](/config/#diff-omitannotationlines) Omit annotation lines from the output (default: `false`) ### diff.printBasicPrototype -- **CLI:** `--diff.printBasicPrototype` -- **Config:** [diff.printBasicPrototype](/config/#diff-printbasicprototype) +- **命令行终端:** `--diff.printBasicPrototype` +- **配置:** [diff.printBasicPrototype](/config/#diff-printbasicprototype) Print basic prototype Object and Array (default: `true`) ### diff.maxDepth -- **CLI:** `--diff.maxDepth ` -- **Config:** [diff.maxDepth](/config/#diff-maxdepth) +- **命令行终端:** `--diff.maxDepth ` +- **配置:** [diff.maxDepth](/config/#diff-maxdepth) Limit the depth to recurse when printing nested objects (default: `20`) ### diff.truncateThreshold -- **CLI:** `--diff.truncateThreshold ` -- **Config:** [diff.truncateThreshold](/config/#diff-truncatethreshold) +- **命令行终端:** `--diff.truncateThreshold ` +- **配置:** [diff.truncateThreshold](/config/#diff-truncatethreshold) Number of lines to show before and after each change (default: `0`) ### diff.truncateAnnotation -- **CLI:** `--diff.truncateAnnotation ` -- **Config:** [diff.truncateAnnotation](/config/#diff-truncateannotation) +- **命令行终端:** `--diff.truncateAnnotation ` +- **配置:** [diff.truncateAnnotation](/config/#diff-truncateannotation) Annotation for truncated lines (default: `... Diff result is truncated`) ### exclude -- **CLI:** `--exclude ` -- **Config:** [exclude](/config/#exclude) +- **命令行终端:** `--exclude ` +- **配置:** [exclude](/config/#exclude) 测试中排除的其他文件路径匹配模式 ### expandSnapshotDiff -- **CLI:** `--expandSnapshotDiff` -- **Config:** [expandSnapshotDiff](/config/#expandsnapshotdiff) +- **命令行终端:** `--expandSnapshotDiff` +- **配置:** [expandSnapshotDiff](/config/#expandsnapshotdiff) 快照失败时显示完整差异 ### disableConsoleIntercept -- **CLI:** `--disableConsoleIntercept` -- **Config:** [disableConsoleIntercept](/config/#disableconsoleintercept) +- **命令行终端:** `--disableConsoleIntercept` +- **配置:** [disableConsoleIntercept](/config/#disableconsoleintercept) 禁用自动拦截控制台日志(默认值:`false`) ### typecheck.enabled -- **CLI:** `--typecheck.enabled` -- **Config:** [typecheck.enabled](/config/#typecheck-enabled) +- **命令行终端:** `--typecheck.enabled` +- **配置:** [typecheck.enabled](/config/#typecheck-enabled) 在测试的同时启用类型检查(默认值:`false`) ### typecheck.only -- **CLI:** `--typecheck.only` -- **Config:** [typecheck.only](/config/#typecheck-only) +- **命令行终端:** `--typecheck.only` +- **配置:** [typecheck.only](/config/#typecheck-only) 仅运行类型检查测试。这将自动启用类型检查(默认值:`false`) ### typecheck.checker -- **CLI:** `--typecheck.checker ` -- **Config:** [typecheck.checker](/config/#typecheck-checker) +- **命令行终端:** `--typecheck.checker ` +- **配置:** [typecheck.checker](/config/#typecheck-checker) 指定要使用的类型检查器。可用值为 "tsc"和 "vue-tsc "以及一个可执行文件的路径(默认值:`tsc`) ### typecheck.allowJs -- **CLI:** `--typecheck.allowJs` -- **Config:** [typecheck.allowJs](/config/#typecheck-allowjs) +- **命令行终端:** `--typecheck.allowJs` +- **配置:** [typecheck.allowJs](/config/#typecheck-allowjs) 允许对 JavaScript 文件进行类型检查。默认值取自 tsconfig.json ### typecheck.ignoreSourceErrors -- **CLI:** `--typecheck.ignoreSourceErrors` -- **Config:** [typecheck.ignoreSourceErrors](/config/#typecheck-ignoresourceerrors) +- **命令行终端:** `--typecheck.ignoreSourceErrors` +- **配置:** [typecheck.ignoreSourceErrors](/config/#typecheck-ignoresourceerrors) 忽略源文件中的类型错误 ### typecheck.tsconfig -- **CLI:** `--typecheck.tsconfig ` -- **Config:** [typecheck.tsconfig](/config/#typecheck-tsconfig) +- **命令行终端:** `--typecheck.tsconfig ` +- **配置:** [typecheck.tsconfig](/config/#typecheck-tsconfig) 自定义 tsconfig 文件的路径 ### typecheck.spawnTimeout -- **CLI:** `--typecheck.spawnTimeout