报告器 API
WARNING
这是一个高级 API。如果您只想配置内置报告器,请阅读 "报告器" 指南。
Vitest 拥有自己的测试运行生命周期,这些生命周期通过报告器的方法来表示:
onInit
onTestRunStart
onTestRunEnd
单个模块中的测试和套件将按顺序报告,除非它们被跳过。所有跳过的测试都在套件/模块的末尾报告。
请注意,由于测试模块可以并行运行,Vitest 将并行报告它们。
本指南列出了所有支持的报告器方法。除了创建自己的报告器之外,您还可以扩展现有报告器:
import { BaseReporter } from 'vitest/reporters';
export default class CustomReporter extends BaseReporter {
onTestRunEnd(testModules, errors) {
console.log(testModule.length, 'tests finished running');
super.onTestRunEnd(testModules, errors);
}
}
onInit
function onInit(vitest: Vitest): Awaitable<void>;
此方法在 Vitest 初始化或启动时调用,但在测试被过滤之前。
INFO
在内部,此方法在 vitest.start
、vitest.init
或 vitest.mergeReports
中调用。如果您使用编程 API,请确保根据您的需要调用其中一个,例如在调用 vitest.runTestSpecifications
之前。内置 CLI 将始终按正确顺序运行方法。
请注意,您还可以通过 project
属性从测试用例、套件和测试模块访问 vitest
实例。此外,在此方法中存储对 vitest
的引用也可能很有用。
示例
import type { Reporter, TestSpecification, Vitest } from 'vitest/node';
class MyReporter implements Reporter {
private vitest!: Vitest;
onInit(vitest: Vitest) {
this.vitest = vitest;
}
onTestRunStart(specifications: TestSpecification[]) {
console.log(
specifications.length,
'个测试文件将在',
this.vitest.config.root,
'中运行'
);
}
}
export default new MyReporter();
onBrowserInit 实验性
function onBrowserInit(project: TestProject): Awaitable<void>;
此方法在浏览器实例初始化时调用。它接收为其初始化浏览器的项目实例。当调用此方法时,project.browser
将始终被定义。
onTestRunStart
function onTestRunStart(specifications: TestSpecification[]): Awaitable<void>;
此方法在新的测试运行开始时调用。它接收一个测试规范数组,表示计划运行的测试。此数组是只读的,仅用于信息目的。
如果 Vitest 没有找到任何要运行的测试文件,此事件将使用空数组调用,然后 onTestRunEnd
将立即调用。
示例
import type { Reporter, TestSpecification } from 'vitest/node';
class MyReporter implements Reporter {
onTestRunStart(specifications: TestSpecification[]) {
console.log(specifications.length, 'test files will run');
}
}
export default new MyReporter();
废弃通知
此方法在 Vitest 3 中添加,取代了 onPathsCollected
和 onSpecsCollected
,这两个方法现在都已废弃。
onTestRunEnd
function onTestRunEnd(
testModules: ReadonlyArray<TestModule>,
unhandledErrors: ReadonlyArray<SerializedError>,
reason: TestRunEndReason
): Awaitable<void>;
此方法在所有测试运行完毕且覆盖率合并所有报告(如果启用)后调用。请注意,您可以在 onCoverage
钩子中获取覆盖率信息。
它接收一个只读的测试模块列表。您可以通过 testModule.children
属性遍历它以报告状态和错误(如果有)。
第二个参数是 Vitest 无法归因于任何测试的未处理错误的只读列表。这些错误可能发生在测试运行之外,因为插件中存在错误,或者发生在测试运行内部,作为未等待函数的副作用(例如,测试运行结束后抛出错误的超时)。
第三个参数指示测试运行结束的原因:
passed
:测试运行正常结束,没有错误failed
:测试运行至少有一个错误(由于收集期间的语法错误或测试执行期间的实际错误)interrupted
:测试被vitest.cancelCurrentRun
调用或在终端中按下Ctrl+C
中断(请注意,在这种情况下仍然可能存在失败的测试)
如果 Vitest 没有找到任何要运行的测试文件,此事件将使用空的模块和错误数组调用,并且状态将取决于 config.passWithNoTests
的值。
示例
import type {
Reporter,
SerializedError,
TestModule,
TestRunEndReason,
TestSpecification,
} from 'vitest/node';
class MyReporter implements Reporter {
onTestRunEnd(
testModules: ReadonlyArray<TestModule>,
unhandledErrors: ReadonlyArray<SerializedError>,
reason: TestRunEndReason
) {
if (reason === 'passed') {
testModules.forEach(module => console.log(module.moduleId, 'succeeded'));
} else if (reason === 'failed') {
// 注意:这将跳过套件中可能存在的错误
// 您可以从 testSuite.errors() 获取它们
for (const testCase of testModules.children.allTests()) {
if (testCase.result().state === 'failed') {
console.log(
testCase.fullName,
'in',
testCase.module.moduleId,
'failed'
);
console.log(testCase.result().errors);
}
}
} else {
console.log('测试运行被中断,报告将被跳过');
}
}
}
export default new MyReporter();
废弃通知
此方法在 Vitest 3 中添加,取代了 onFinished
,后者现在已废弃。
onCoverage
function onCoverage(coverage: unknown): Awaitable<void>;
此钩子在覆盖率结果处理后调用。覆盖率提供程序的报告器在此钩子之后调用。coverage
的类型取决于 coverage.provider
。对于 Vitest 的默认内置提供程序,您可以从 istanbul-lib-coverage
包导入类型:
import type { CoverageMap } from 'istanbul-lib-coverage';
declare function onCoverage(coverage: CoverageMap): Awaitable<void>;
如果 Vitest 没有执行任何覆盖率,则不调用此钩子。
onTestModuleQueued
function onTestModuleQueued(testModule: TestModule): Awaitable<void>;
此方法在 Vitest 导入设置文件和测试模块本身之前调用。这意味着 testModule
还没有 children
,但您可以开始将其报告为下一个要运行的测试。
onTestModuleCollected
function onTestModuleCollected(testModule: TestModule): Awaitable<void>;
此方法在文件中所有测试收集完成后调用,这意味着 testModule.children
集合已填充,但测试尚未执行。
onTestModuleStart
function onTestModuleStart(testModule: TestModule): Awaitable<void>;
此方法在 onTestModuleCollected
之后立即调用。但如果 Vitest 在收集模式下运行(例如通过 vitest.collect()
或 CLI 中的 vitest collect
命令),则不会调用此方法,因为没有要运行的测试。
onTestModuleEnd
function onTestModuleEnd(testModule: TestModule): Awaitable<void>;
此方法在模块中的每个测试运行完成后调用。这意味着,testModule.children
中的每个测试的 test.result()
都不再是 pending
状态。
onHookStart
function onHookStart(context: ReportedHookContext): Awaitable<void>;
此方法会在以下任何钩子开始运行时被调用:
beforeAll
afterAll
beforeEach
afterEach
如果 beforeAll
或 afterAll
开始运行,entity
将是 TestSuite
或 TestModule
。
如果 beforeEach
或 afterEach
开始运行,entity
将始终是 TestCase
。
WARNING
如果钩子在测试运行期间没有运行,则不会调用 onHookStart
方法。
onHookEnd
function onHookEnd(context: ReportedHookContext): Awaitable<void>;
此方法会在以下任何钩子运行完毕时被调用:
beforeAll
afterAll
beforeEach
afterEach
如果 beforeAll
或 afterAll
完成运行,entity
将是 TestSuite
或 TestModule
。
如果 beforeEach
或 afterEach
完成运行,entity
将始终是 TestCase
。
WARNING
如果钩子在测试运行期间没有运行,则不会调用 onHookEnd
方法。
onTestSuiteReady
function onTestSuiteReady(testSuite: TestSuite): Awaitable<void>;
此方法在套件开始运行测试之前调用。如果套件被跳过,也会调用此方法。
如果文件没有任何套件,则不会调用此方法。可以考虑使用 onTestModuleStart
来处理这种情况。
onTestSuiteResult
function onTestSuiteResult(testSuite: TestSuite): Awaitable<void>;
此方法在套件完成测试运行后调用。如果套件被跳过,也会调用此方法。
如果文件没有任何套件,则不会调用此方法。可以考虑使用 onTestModuleEnd
来处理这种情况。
onTestCaseReady
function onTestCaseReady(testCase: TestCase): Awaitable<void>;
此方法在测试开始运行或被跳过之前调用。请注意,beforeEach
和 afterEach
钩子被认为是测试的一部分,因为它们可以影响结果。
WARNING
请注意,当调用 onTestCaseReady
时,testCase.result()
可能已是 passed
或 failed
状态。如果测试运行过快,并且 onTestCaseReady
和 onTestCaseResult
都被安排在同一个微任务中运行,则可能会发生这种情况。
onTestCaseResult
function onTestCaseResult(testCase: TestCase): Awaitable<void>;
此方法在测试运行完成或被跳过时调用。请注意,如果存在 afterEach
钩子,此方法将在 afterEach
钩子完成运行后调用。
此时,testCase.result()
将具有非 pending
状态。
onTestAnnotate 3.2.0+
function onTestAnnotate(
testCase: TestCase,
annotation: TestAnnotation
): Awaitable<void>;
onTestAnnotate
钩子与 context.annotate
方法相关联。当调用 annotate
时,Vitest 会对其进行序列化并将相同的附件发送到主线程,报告器可以在主线程中对其进行处理。
如果指定了路径,Vitest 会将其存储在单独的目录中(由 attachmentsDir
配置),并修改 path
属性以指向该附件。