第18章 Vitest 内置 Reporter 配置与使用指南
Reporters
Vitest 内置了多种 Reporter,支持以不同格式展示测试结果,同时也允许使用自定义 Reporter。你可以通过 `--reporter` 命令行参数或在配置文件中设置 `reporters` 属性来选择不同的 Reporter。如果未指定,Vitest 会根据运行环境自动选择合适的 Reporter。
使用命令行指定 Reporter: `bash npx vitest --reporter=verbose ` 在 `vitest.config.ts` 中指定: `ts import { defineConfig } from 'vitest/config'
export default defineConfig({ test: { reporters: ['verbose'] }, }) ` 部分 Reporter 支持通过传递额外选项进行自定义,具体选项参见下文各节说明。 `ts export default defineConfig({ test: { reporters: [ 'default', ['junit', { suiteName: 'UI tests' }] ], }, }) `
默认配置
当未配置 `reporters` 时,Vitest 默认使用以下 Reporter: - 在普通终端运行时使用 `default` - 检测到 AI 编码代理时使用 `minimal` - 当 `process.env.GITHUB_ACTIONS === 'true'` 时,额外添加 `github-actions`
如果你配置了自己的 `reporters` 列表,该列表将替换默认列表。若需在保留默认配置的基础上增加 Reporter,请扩展 `configDefaults.reporters`: `ts import { configDefaults, defineConfig } from 'vitest/config'
export default defineConfig({ test: { reporters: ['json', ...configDefaults.reporters], }, }) `
Reporter 输出
默认情况下,Vitest 的 Reporter 将输出打印到终端。但 `json`、`junit` 和 `html` Reporter 会将结果写入 `.vitest/` 目录下的指定位置: - `json` 写入 `.vitest/json/output.json` - `junit` 写入 `.vitest/junit/output.xml` - `html` 写入 `.vitest/index.html`
`json` 和 `junit` 的输出路径可通过配置文件中 `outputFile` 选项或 CLI 参数覆盖。`html` Reporter 则使用自身的 `outputDir` 选项。
CLI 方式: `vitest.config.ts bash npx vitest --reporter=json --outputFile=./test-output.json ` 配置文件方式: `ts export default defineConfig({ test: { reporters: ['json'], outputFile: './test-output.json' }, }) ` `json` 和 `junit` Reporter 也支持将 `outputFile` 作为 Reporter 自身选项传入,此时优先级高于顶层的 `outputFile`: `vitest.config.ts ts export default defineConfig({ test: { reporters: [['json', { outputFile: './test-output.json' }]], }, }) ` 若希望将报告直接打印到终端而非写入文件,可设置 `json` 或 `junit` Reporter 的 `stdout` 选项。注意:当设置了 `outputFile` 时,此选项将被忽略: `vitest.config.ts ts export default defineConfig({ test: { reporters: [['json', { stdout: true }]], }, }) ` 警告 启用 `stdout` 后,报告内容可能会与其他直接写入终端的输出(如测试文件中的 `process.stdout.write` 或全局 setup 文件中的日志)交错混杂,导致 JSON 或 XML 无法解析。如果需要程序化消费报告,建议默认使用文件输出。
组合使用 Reporter
你可以同时使用多个 Reporter,以不同格式输出测试结果。示例如下: `bash npx vitest --reporter=json --reporter=default ` `ts import { configDefaults, defineConfig } from 'vitest/config'
export default defineConfig({ test: { reporters: ['json', ...configDefaults.reporters], outputFile: './test-output.json' }, }) ` 上述示例既会在终端以默认样式打印测试结果,同时将结果写入指定的 JSON 文件。
使用多个 Reporter 时,还可以指定多个输出文件,示例如下: `ts export default defineConfig({ test: { reporters: ['junit', 'json', 'verbose'], outputFile: { junit: './junit-report.xml', json: './json-report.json', }, }, }) ` 此示例将分别生成 JSON 和 XML 报告,同时在终端打印 verbose 格式的报告。
内置 Reporter
Default Reporter
默认 Reporter 在底部显示测试运行摘要及状态。当某个测试套件通过后,其状态会显示在摘要上方。
你可以通过配置 Reporter 来禁用摘要显示: `vitest.config.ts ts export default defineConfig({ test: { reporters: [ ['default', { summary: false }] ] }, }) ` 测试运行中示例输出: `bash ✓ test/example-1.test.ts (5 tests | 1 skipped) 306ms ✓ test/example-2.test.ts (5 tests | 1 skipped) 307ms
❯ test/example-3.test.ts 3/5 ❯ test/example-4.test.ts 1/5
Test Files 2 passed (4) Tests 10 passed | 3 skipped (65) Start at 11:01:36 Duration 2.00s ` 测试结束后的最终输出示例: `bash ✓ test/example-1.test.ts (5 tests | 1 skipped) 306ms ✓ test/example-2.test.ts (5 tests | 1 skipped) 307ms ✓ test/example-3.test.ts (5 tests | 1 skipped) 307ms ✓ test/example-4.test.ts (5 tests | 1 skipped) 307ms
Test Files 4 passed (4) Tests 16 passed | 4 skipped (20) Start at 12:34:32 Duration 1.26s (transform 35ms, setup 1ms, collect 90ms, tests 1.47s, environment 0ms, prepare 267ms) ` 如果只有一个测试文件在运行,Vitest 会输出该文件的完整测试树,类似于 tree reporter。若文件中存在至少一个失败的测试,默认 Reporter 也会打印测试树。 `bash ✓ __tests__/file1.test.ts (2) 725ms ✓ first test file (2) 725ms ✓ 2 + 2 should equal 4 ✓ 4 - 2 should equal 2
Test Files 1 passed (1) Tests 2 passed (2) Start at 12:34:32 Duration 1.26s (transform 35ms, setup 1ms, collect 90ms, tests 1.47s, environment 0ms, prepare 267ms) `
Verbose Reporter
verbose Reporter 在每个测试用例完成后立即打印,不单独报告套件或文件。如果启用了 `--includeTaskLocation`,输出中还会包含每个测试的位置信息。与默认 Reporter 类似,你可以通过配置禁用摘要。
此外,verbose Reporter 会在测试出错时立即打印错误信息,而在测试运行结束后报告完整的测试错误详情。
这是唯一一个在测试未失败时也会报告注解(annotations)的终端 Reporter。
CLI: `vitest.config.ts bash npx vitest --reporter=verbose ` 配置示例: `ts export default defineConfig({ test: { reporters: [ ['verbose', { summary: false }] ] }, }) ` 示例输出: `bash ✓ __tests__/file1.test.ts > first test file > 2 + 2 should equal 4 1ms ✓ __tests__/file1.test.ts > first test file > 4 - 2 should equal 2 1ms ✓ __tests__/file2.test.ts > second test file > 1 + 1 should equal 2 1ms ✓ __tests__/file2.test.ts > second test file > 2 - 1 should equal 1 1ms
Test Files 2 passed (2) Tests 4 passed (4) Start at 12:34:32 Duration 1.26s (transform 35ms, setup 1ms, collect 90ms, tests 1.47s, environment 0ms, prepare 267ms) ` 启用 `--includeTaskLocation` 的示例输出: `bash ✓ __tests__/file1.test.ts:2 > first test file > 2 + 2 should equal 4 1ms ✓ __tests__/file1.test.ts:3 > first test file > 4 - 2 should equal 2 1ms ✓ __tests__/file2.test.ts:2 > second test file > 1 + 1 should equal 2 1ms ✓ __tests__/file2.test.ts:3 > second test file > 2 - 1 should equal 1 1ms
Test Files 2 passed (2) Tests 4 passed (4) Start at 12:34:32 Duration 1.26s (transform 35ms, setup 1ms, collect 90ms, tests 1.47s, environment 0ms, prepare 267ms) `
Tree Reporter
tree Reporter 与默认 Reporter 类似,但会在套件结束后显示每个单独的测试。与默认 Reporter 一样,可通过配置禁用摘要。
CLI: `vitest.config.ts bash npx vitest --reporter=tree ` 配置示例: `ts export default defineConfig({ test: { reporters: [ ['tree', { summary: false }] ] }, }) ` 测试运行中示例输出(默认 `slowTestThreshold: 300`): `bash ✓ __tests__/example-1.test.ts (2) 725ms ✓ first test file (2) 725ms ✓ 2 + 2 should equal 4 ✓ 4 - 2 should equal 2
❯ test/example-2.test.ts 3/5 ↳ should run longer than three seconds 1.57s ❯ test/example-3.test.ts 1/5
Test Files 2 passed (4) Tests 10 passed | 3 skipped (65) Start at 11:01:36 Duration 2.00s ` 通过的测试套件最终终端输出示例: `bash ✓ __tests__/file1.test.ts (2) 725ms ✓ first test file (2) 725ms ✓ 2 + 2 should equal 4 ✓ 4 - 2 should equal 2 ✓ __tests__/file2.test.ts (2) 746ms ✓ second test file (2) 746ms ✓ 1 + 1 should equal 2 ✓ 2 - 1 should equal 1
Test Files 2 passed (2) Tests 4 passed (4) Start at 12:34:32 Duration 1.26s (transform 35ms, setup 1ms, collect 90ms, tests 1.47s, environment 0ms, prepare 267ms) `
Dot Reporter
dot Reporter 为每个完成的测试打印一个点,提供最小化的输出,同时展示已运行的所有测试。仅在测试失败时提供详细信息,并附带套件摘要。
CLI: `vitest.config.ts bash npx vitest --reporter=dot ` 配置示例: `ts export default defineConfig({ test: { reporters: ['dot'] }, }) ` 通过的测试套件终端输出示例: `bash ....
Test Files 2 passed (2) Tests 4 passed (4) Start at 12:34:32 Duration 1.26s (transform 35ms, setup 1ms, collect 90ms, tests 1.47s, environment 0ms, prepare 267ms) `
JUnit Reporter
以 JUnit XML 格式输出测试报告。默认写入 `.vitest/junit/output.xml`。若要写入其他位置,请使用 `outputFile` 配置项或该 Reporter 自身的 `outputFile` 选项。若希望打印到终端,请设置该 Reporter 的 `stdout` 选项。
CLI:
`vitest.config.ts
bash
npx vitest --reporter=junit
`
配置示例:
`ts
export default defineConfig({
test: {
reporters: ['junit']
},
})
`
JUnit XML 报告示例:
`xml
- `suiteName`:`
`suiteNameTemplate` 支持的占位符: - `{title}` – 第一个顶级 describe 块的名称;若不存在顶级 describe,则回退到文件名 - `{filename}` – 相对于根目录的文件路径(例如 `src/foo.test.ts`) - `{filepath}` – 文件绝对路径 - `{basename}` – 不含目录的文件名(例如 `foo.test.ts`) - `{displayName}` – Vitest 项目名称
`classnameTemplate` 和 `titleTemplate` 支持的占位符: - `{classname}` – 由 `ancestorSeparator` 连接的祖先 describe 块名称(例如 `outer > inner`) - `{title}` – 叶子测试标题(传递给 `it`/`test` 的字符串) - `{suitename}` – 顶级 describe 块名称,若测试没有外层 describe 则为空字符串 - `{filename}` – 相对于根目录的文件路径 - `{filepath}` – 文件绝对路径 - `{basename}` – 不含目录的文件名 - `{displayName}` – Vitest 项目名称
提示 `{filename}` 遵循 Vitest 约定,解析为相对于项目根目录的路径(例如 `src/foo.test.ts`)。这与 jest-junit 不同,后者中 `{filename}` 仅为文件名。若只需获取文件名,请使用 `{basename}`。
`ts export default defineConfig({ test: { reporters: [ ['junit', { suiteName: 'My Test Suite', // 使用第一个顶级 describe 块名称作为 testsuite 名称 suiteNameTemplate: '{title}', // classname = 祖先 describe 链 classnameTemplate: '{classname}', // name = 仅叶子测试标题(兼容 jest-junit) titleTemplate: '{title}', ancestorSeparator: ' > ', }] ] }, }) ` 基于函数的模板接收所有可用变量,并可返回任意字符串: `ts export default defineConfig({ test: { reporters: [ ['junit', { classnameTemplate: ({ classname, filename }) => classname ? `${filename}::${classname}` : filename, titleTemplate: ({ suitename, title }) => suitename ? `[${suitename}] ${title}` : title, }] ] }, }) `
JSON Reporter
生成与 Jest 的 `--json` 选项兼容的 JSON 格式测试报告。默认写入 `.vitest/json/output.json`。若要写入其他位置,请使用 `outputFile` 配置项或该 Reporter 自身的 `outputFile` 选项。若希望打印到终端,请设置该 Reporter 的 `stdout` 选项。
CLI: `vitest.config.ts bash npx vitest --reporter=json ` 配置示例: `ts export default defineConfig({ test: { reporters: ['json'] }, }) ` JSON 报告示例: `json { "numTotalTestSuites": 4, "numPassedTestSuites": 2, "numFailedTestSuites": 1, "numPendingTestSuites": 1, "numTotalTests": 4, "numPassedTests": 1, "numFailedTests": 1, "numPendingTests": 1, "numTodoTests": 1, "startTime": 1697737019307, "success": false, "testResults": [ { "assertionResults": [ { "ancestorTitles": [ "", "first test file" ], "fullName": " first test file 2 + 2 should equal 4", "status": "failed", "title": "2 + 2 should equal 4", "duration": 9, "failureMessages": [ "expected 5 to be 4 // Object.is equality" ], "location": { "line": 20, "column": 28 }, "meta": {} } ], "startTime": 1697737019787, "endTime": 1697737019797, "status": "failed", "message": "", "name": "/root-directory/__tests__/test-file-1.test.ts" } ], "coverageMap": {} } ` 信息 从 Vitest 3 开始,如果启用了覆盖率,JSON Reporter 会在 `coverageMap` 中包含覆盖率信息。
每个断言结果中的 `meta` 字段可以通过 `filterMeta` Reporter 选项进行过滤。该函数接收字段的 key 和 value,若返回 falsy 值,则该字段将从报告中排除: `ts export default defineConfig({ test: { reporters: [ ['json', { filterMeta: (key, value) => key !== 'internalField', }] ] }, }) `
HTML Reporter
生成 Vitest UI 的静态版本,用于回顾已完成的测试运行。关于本地预览、CI 工件及共享工作流,请参阅 HTML Reporter 指南。
可通过 Reporter 的 `outputDir` 选项指定报告工件根目录,报告入口将写入 `
使用 `singleFile` 选项可生成单个可移植的 HTML 文件。关于配置和限制,请参阅“Share as a Single File”章节。
CLI: `vitest.config.ts bash npx vitest --reporter=html ` 配置示例: `ts export default defineConfig({ test: { reporters: ['html'] }, }) `
TAP Reporter
按照 Test Anything Protocol (TAP) 标准输出报告。
CLI: `vitest.config.ts bash npx vitest --reporter=tap ` 配置示例: `ts export default defineConfig({ test: { reporters: ['tap'] }, }) ` TAP 报告示例: `bash TAP version 13 1..1 not ok 1 - __tests__/test-file-1.test.ts # time=14.00ms { 1..1 not ok 1 - first test file # time=13.00ms { 1..2 not ok 1 - 2 + 2 should equal 4 # time=11.00ms --- error: name: "AssertionError" message: "expected 5 to be 4 // Object.is equality" at: "/root-directory/__tests__/test-file-1.test.ts:20:28" actual: "5" expected: "4" ... ok 2 - 4 - 2 should equal 2 # time=1.00ms } } `
TAP Flat Reporter
输出扁平化的 TAP 报告。与 `tap` Reporter 类似,测试结果遵循 TAP 标准,但测试套件以扁平列表形式呈现,而非嵌套层级。
CLI: `vitest.config.ts bash npx vitest --reporter=tap-flat ` 配置示例: `ts export default defineConfig({ test: { reporters: ['tap-flat'] }, }) ` TAP 扁平报告示例: `bash TAP version 13 1..2 not ok 1 - __tests__/test-file-1.test.ts > first test file > 2 + 2 should equal 4 # time=11.00ms --- error: name: "AssertionError" message: "expected 5 to be 4 // Object.is equality" at: "/root-directory/__tests__/test-file-1.test.ts:20:28" actual: "5" expected: "4" ... ok 2 - __tests__/test-file-1.test.ts > first test file > 4 - 2 should equal 2 # time=0.00ms `
Hanging Process Reporter
显示挂起进程列表(如果有进程阻止 Vitest 安全退出)。hanging-process Reporter 本身不显示测试结果,但可与其它 Reporter 配合使用,在测试运行时监控进程。由于使用此 Reporter 可能占用较多资源,通常仅建议在 Vitest 始终无法退出进程的情况下用于调试目的。
CLI: `vitest.config.ts bash npx vitest --reporter=hanging-process ` 配置示例: `ts export default defineConfig({ test: { reporters: ['hanging-process'] }, }) `
GitHub Actions Reporter
输出工作流命令,为测试失败提供注解。当 `process.env.GITHUB_ACTIONS === 'true'`(即在 GitHub Actions 环境中)时,此 Reporter 会自动启用。
你可以通过 `onWritePath` 选项自定义在 GitHub 注解命令格式中打印的文件路径。这在容器化环境(如 Docker)中非常有用,此时文件路径可能与 GitHub Actions 环境中的路径不匹配。 `ts export default defineConfig({ test: { reporters: process.env.GITHUB_ACTIONS === 'true' ? [ 'default', ['github-actions', { onWritePath(path) { return path.replace(/^\/app\//, `${process.env.GITHUB_WORKSPACE}/`) } }], ] : ['default'], }, }) ` 如果使用 Annotations API,Reporter 会自动在 GitHub UI 中内联显示它们。可以通过将 `displayAnnotations` 选项设置为 `false` 来禁用此行为: `ts export default defineConfig({ test: { reporters: [ ['github-actions', { displayAnnotations: false }], ], }, }) ` GitHub Actions Reporter 会自动生成 Job Summary,概述测试结果。摘要包含测试文件和测试用例的统计信息,并突出显示需要重试的 flaky 测试。
Job Summary 默认启用,并写入 `$GITHUB_STEP_SUMMARY` 指定的路径。你可以使用 `jobSummary.outputPath` 选项覆盖此路径: `ts export default defineConfig({ test: { reporters: [ ['github-actions', { jobSummary: { outputPath: '/home/runner/jobs/summary/step', }, }], ], }, }) ` 若要禁用 Job Summary: `ts export default defineConfig({ test: { reporters: [ ['github-actions', { jobSummary: { enabled: false } }], ], }, }) ` Job Summary 标题默认为 “Vitest Test Report”;若设置了 `test.name`,则标题为 “(${test.name}) Vitest Test Report”。
可以通过设置 `jobSummary.title` 来自定义标题,以便区分添加到同一 Job Summary 的多个 Vitest 调用。请注意,使用自定义标题时不会显示 `test.name`。 `ts export default defineConfig({ test: { reporters: [ ['github-actions', { jobSummary: { title: 'My Test Report', }, }], ], }, }) ` 摘要中的 flaky 测试部分包含指向 GitHub 相关源代码行的永久链接。这些链接使用 GitHub Actions 提供的环境变量(`$GITHUB_REPOSITORY`、`$GITHUB_SHA` 和 `$GITHUB_WORKSPACE`)自动生成,大多数情况下无需配置。
如果需要覆盖这些值(例如在容器或自定义环境中运行),可以通过 `fileLinks` 选项进行自定义: - `repository`: GitHub 仓库,格式为 owner/repo。默认为 `process.env.GITHUB_REPOSITORY`。 - `commitHash`: 在永久链接中使用的提交 SHA。默认为 `process.env.GITHUB_SHA`。 - `workspacePath`: 磁盘上仓库根目录的绝对路径。用于计算永久链接的相对文件路径。默认为 `process.env.GITHUB_WORKSPACE`。 这三个值必须都可用,才能生成链接。 `ts export default defineConfig({ test: { reporters: [ ['github-actions', { jobSummary: { fileLinks: { repository: 'owner/repo', commitHash: 'abcdefg', workspacePath: '/home/runner/work/repo/', }, }, }], ], }, }) `
Minimal Reporter
别名:`agent` 输出最小化报告,仅包含失败的测试及其错误信息。通过的测试的控制台日志和摘要部分也会被抑制。
Agent Reporter
此 Reporter 专为 AI 编码助手和基于 LLM 的工作流进行了优化,旨在减少 token 消耗。当 Vitest 检测到其运行在 AI 编码代理内部时,会自动启用此 Reporter。
CLI: `vitest.config.ts bash npx vitest --reporter=minimal ` 配置示例: `ts export default defineConfig({ test: { reporters: ['minimal'] }, }) `
Blob Reporter
将测试结果存储在机器上,以便之后使用 `--merge-reports` 命令合并。默认情况下,所有结果存储在 `.vitest/blob/` 文件夹中,但可通过 `--outputFile` 或 `--outputFile.blob` 标志覆盖。 `bash npx vitest --reporter=blob --outputFile=reports/blob-1.json ` 如果使用的是 `--shard` 标志在不同机器上运行 Vitest,或在多个环境(例如 linux/macos/windows)中运行,我们推荐使用此 Reporter。所有 blob 报告都可以使用 `--merge-reports` 命令在 CI 管道末尾合并到任意报告中: `bash npx vitest --merge-reports=reports --reporter=json --reporter=default ` 在多个环境中运行相同测试时,请使用 `VITEST_BLOB_LABEL` 环境变量来区分每个环境的 blob。Vitest 在合并时读取标签并分别显示结果: `bash VITEST_BLOB_LABEL=linux vitest run --reporter=blob ` 也可以通过 blob Reporter 选项提供标签,其优先级高于 `VITEST_BLOB_LABEL`。 `vitest.config.ts ts import { defineConfig } from 'vitest/config'
export default defineConfig({ test: { reporters: [ ['blob', { label: 'linux' }], ], }, }) ` Blob Reporter 输出不包含基于文件的附件。使用此功能时,请确保在 CI 上单独合并 `attachmentsDir` 与 blob 报告。
提示 `--reporter=blob` 和 `--merge-reports` 在 watch 模式下均不起作用。
自定义 Reporters
你可以通过在 `reporters` 选项中指定 NPM 包名,使用第三方自定义 Reporter:
CLI: `vitest.config.ts bash npx vitest --reporter=some-published-vitest-reporter ` 配置示例: `ts export default defineConfig({ test: { reporters: ['some-published-vitest-reporter'] }, }) ` 此外,你可以定义自己的自定义 Reporter,并通过指定文件路径来使用它们: `bash npx vitest --reporter=./path/to/reporter.ts ` 自定义 Reporter 应当实现 `Reporter` 接口。