Skip to content

Commit 766624a

Browse files
feat: introduce the new reporter API (#7069)
Co-authored-by: Ari Perkkiö <ari.perkkio@gmail.com>
1 parent faca4de commit 766624a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2467
-944
lines changed

docs/.vitepress/config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,10 @@ export default ({ mode }: { mode: string }) => {
339339
text: 'Runner API',
340340
link: '/advanced/runner',
341341
},
342+
{
343+
text: 'Reporters API',
344+
link: '/advanced/api/reporters',
345+
},
342346
{
343347
text: 'Task Metadata',
344348
link: '/advanced/metadata',

docs/advanced/api/reporters.md

Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
# Reporters
2+
3+
::: warning
4+
This is an advanced API. If you just want to configure built-in reporters, read the ["Reporters"](/guide/reporters) guide.
5+
:::
6+
7+
Vitest has its own test run lifecycle. These are represented by reporter's methods:
8+
9+
- [`onInit`](#oninit)
10+
- [`onTestRunStart`](#ontestrunstart)
11+
- [`onTestModuleQueued`](#ontestmodulequeued)
12+
- [`onTestModuleCollected`](#ontestmodulecollected)
13+
- [`onTestModuleStart`](#ontestmodulestart)
14+
- [`onTestSuiteReady`](#ontestsuiteready)
15+
- [`onHookStart(beforeAll)`](#onhookstart)
16+
- [`onHookEnd(beforeAll)`](#onhookend)
17+
- [`onTestCaseReady`](#ontestcaseready)
18+
- [`onHookStart(beforeEach)`](#onhookstart)
19+
- [`onHookEnd(beforeEach)`](#onhookend)
20+
- [`onHookStart(afterEach)`](#onhookstart)
21+
- [`onHookEnd(afterEach)`](#onhookend)
22+
- [`onTestCaseResult`](#ontestcaseresult)
23+
- [`onHookStart(afterAll)`](#onhookstart)
24+
- [`onHookEnd(afterAll)`](#onhookend)
25+
- [`onTestSuiteResult`](#ontestsuiteresult)
26+
- [`onTestModuleEnd`](#ontestmoduleend)
27+
- [`onTestRunEnd`](#ontestrunend)
28+
29+
Tests and suites within a single module will be reported in order unless they were skipped. All skipped tests are reported at the end of suite/module.
30+
31+
Note that since test modules can run in parallel, Vitest will report them in parallel.
32+
33+
This guide lists all supported reporter methods. However, don't forget that instead of creating your own reporter, you can [extend existing one](/advanced/reporters) instead:
34+
35+
```ts [custom-reporter.js]
36+
import { BaseReporter } from 'vitest/reporters'
37+
38+
export default class CustomReporter extends BaseReporter {
39+
onTestRunEnd(testModules, errors) {
40+
console.log(testModule.length, 'tests finished running')
41+
super.onTestRunEnd(testModules, errors)
42+
}
43+
}
44+
```
45+
46+
## onInit
47+
48+
```ts
49+
function onInit(vitest: Vitest): Awaitable<void>
50+
```
51+
52+
This method is called when [Vitest](/advanced/api/vitest) was initiated or started, but before the tests were filtered.
53+
54+
::: info
55+
Internally this method is called inside [`vitest.start`](/advanced/api/vitest#start), [`vitest.init`](/advanced/api/vitest#init) or [`vitest.mergeReports`](/advanced/api/vitest#mergereports). If you are using programmatic API, make sure to call either one dependning on your needs before calling [`vitest.runTestSpecifications`](/advanced/api/vitest#runtestspecifications), for example. Built-in CLI will always run methods in correct order.
56+
:::
57+
58+
Note that you can also get access to `vitest` instance from test cases, suites and test modules via a [`project`](/advanced/api/test-project) property, but it might also be useful to store a reference to `vitest` in this method.
59+
60+
::: details Example
61+
```ts
62+
import type { Reporter, TestSpecification, Vitest } from 'vitest/node'
63+
64+
class MyReporter implements Reporter {
65+
private vitest!: Vitest
66+
67+
onInit(vitest: Vitest) {
68+
this.vitest = vitest
69+
}
70+
71+
onTestRunStart(specifications: TestSpecification[]) {
72+
console.log(
73+
specifications.length,
74+
'test files will run in',
75+
this.vitest.config.root,
76+
)
77+
}
78+
}
79+
80+
export default new MyReporter()
81+
```
82+
:::
83+
84+
## onTestRunStart
85+
86+
```ts
87+
function onTestRunStart(
88+
specifications: TestSpecification[]
89+
): Awaitable<void>
90+
```
91+
92+
This method is called when a new test run has started. It receives an array of [test specifications](/advanced/api/test-specification) scheduled to run. This array is readonly and available only for information purposes.
93+
94+
If Vitest didn't find any test files to run, this event will be invoked with an empty array, and then [`onTestRunEnd`](#ontestrunend) will be called immediately after.
95+
96+
::: details Example
97+
```ts
98+
import type { Reporter, TestSpecification } from 'vitest/node'
99+
100+
class MyReporter implements Reporter {
101+
onTestRunStart(specifications: TestSpecification[]) {
102+
console.log(specifications.length, 'test files will run')
103+
}
104+
}
105+
106+
export default new MyReporter()
107+
```
108+
:::
109+
110+
::: tip DEPRECATION NOTICE
111+
This method was added in Vitest 3, replacing `onPathsCollected` and `onSpecsCollected`, both of which are now deprecated.
112+
:::
113+
114+
## onTestRunEnd
115+
116+
```ts
117+
function onTestRunEnd(
118+
testModules: ReadonlyArray<TestModule>,
119+
unhandledErrors: ReadonlyArray<SerializedError>,
120+
reason: TestRunEndReason
121+
): Awaitable<void>
122+
```
123+
124+
This method is called after all tests have finished running and the coverage merged all reports, if it's enabled. Note that you can get the coverage information in [`onCoverage`](#oncoverage) hook.
125+
126+
It receives a readonly list of test modules. You can iterate over it via a [`testModule.children`](/advanced/api/test-collection) property to report the state and errors, if any.
127+
128+
The second argument is a readonly list of unhandled errors that Vitest wasn't able to attribute to any test. These can happen outside of the test run because of an error in a plugin, or inside the test run as a side-effect of a non-awaited function (for example, a timeout that threw an error after the test has finished running).
129+
130+
The third argument indicated why the test run was finished:
131+
132+
- `passed`: test run was finished normally and there are no errors
133+
- `failed`: test run has at least one error (due to a syntax error during collection or an actual error during test execution)
134+
- `interrupted`: test was interruped by [`vitest.cancelCurrentRun`](/advanced/api/vitest#cancelcurrentrun) call or `Ctrl+C` was pressed in the terminal (note that it's still possible to have failed tests in this case)
135+
136+
If Vitest didn't find any test files to run, this event will be invoked with empty arrays of modules and errors, and the state will depend on the value of [`config.passWithNoTests`](/config/#passwithnotests).
137+
138+
::: details Example
139+
```ts
140+
import type {
141+
Reporter,
142+
SerializedError,
143+
TestModule,
144+
TestRunEndReason,
145+
TestSpecification
146+
} from 'vitest/node'
147+
148+
class MyReporter implements Reporter {
149+
onTestRunEnd(
150+
testModules: ReadonlyArray<TestModule>,
151+
unhandledErrors: ReadonlyArray<SerializedError>,
152+
reason: TestRunEndReason,
153+
) {
154+
if (reason === 'passed') {
155+
testModules.forEach(module => console.log(module.moduleId, 'succeeded'))
156+
}
157+
else if (reason === 'failed') {
158+
// note that this will skip possible errors in suites
159+
// you can get them from testSuite.errors()
160+
for (const testCase of testModules.children.allTests()) {
161+
if (testCase.result().state === 'failed') {
162+
console.log(testCase.fullName, 'in', testCase.module.moduleId, 'failed')
163+
console.log(testCase.result().errors)
164+
}
165+
}
166+
}
167+
else {
168+
console.log('test run was interrupted, skipping report')
169+
}
170+
}
171+
}
172+
173+
export default new MyReporter()
174+
```
175+
:::
176+
177+
::: tip DEPRECATION NOTICE
178+
This method was added in Vitest 3, replacing `onFinished`, which is now deprecated.
179+
:::
180+
181+
## onCoverage
182+
183+
```ts
184+
function onCoverage(coverage: unknown): Awaitable<void>
185+
```
186+
187+
This hook is called after coverage results have been processed. Coverage provider's reporters are called after this hook. The typings of `coverage` depends on the `coverage.provider`. For Vitest's default built-in providers you can import the types from `istanbul-lib-coverage` package:
188+
189+
```ts
190+
import type { CoverageMap } from 'istanbul-lib-coverage'
191+
192+
declare function onCoverage(coverage: CoverageMap): Awaitable<void>
193+
```
194+
195+
If Vitest didn't perform any coverage, this hook is not called.
196+
197+
## onTestModuleQueued
198+
199+
```ts
200+
function onTestModuleQueued(testModule: TestModule): Awaitable<void>
201+
```
202+
203+
This method is called right before Vitest imports the setup file and the test module itself. This means that `testModule` will have no [`children`](/advanced/api/test-suite#children) yet, but you can start reporting it as the next test to run.
204+
205+
## onTestModuleCollected
206+
207+
```ts
208+
function onTestModuleCollected(testModule: TestModule): Awaitable<void>
209+
```
210+
211+
This method is called when all tests inside the file were collected, meaning [`testModule.children`](/advanced/api/test-suite#children) collection is populated, but tests don't have any results yet.
212+
213+
## onTestModuleStart
214+
215+
```ts
216+
function onTestModuleStart(testModule: TestModule): Awaitable<void>
217+
```
218+
219+
This method is called right after [`onTestModuleCollected`](#ontestmodulecollected) unless Vitest runs in collection mode ([`vitest.collect()`](/advanced/api/vitest#collect) or `vitest collect` in the CLI), in this case it will not be called at all because there are no tests to run.
220+
221+
## onTestModuleEnd
222+
223+
```ts
224+
function onTestModuleEnd(testModule: TestModule): Awaitable<void>
225+
```
226+
227+
This method is called when every test in the module finished running. This means, every test inside [`testModule.children`](/advanced/api/test-suite#children) will have a `test.result()` that is not equal to `pending`.
228+
229+
## onHookStart
230+
231+
```ts
232+
function onHookStart(context: ReportedHookContext): Awaitable<void>
233+
```
234+
235+
This method is called when any of these hooks have started running:
236+
237+
- `beforeAll`
238+
- `afterAll`
239+
- `beforeEach`
240+
- `afterEach`
241+
242+
If `beforeAll` or `afterAll` are started, the `entity` will be either [`TestSuite`](/advanced/api/test-suite) or [`TestModule`](/advanced/api/test-module).
243+
244+
If `beforeEach` or `afterEach` are started, the `entity` will always be [`TestCase`](/advanced/api/test-case).
245+
246+
::: warning
247+
`onHookStart` method will not be called if the hook did not run during the test run.
248+
:::
249+
250+
## onHookEnd
251+
252+
```ts
253+
function onHookEnd(context: ReportedHookContext): Awaitable<void>
254+
```
255+
256+
This method is called when any of these hooks have finished running:
257+
258+
- `beforeAll`
259+
- `afterAll`
260+
- `beforeEach`
261+
- `afterEach`
262+
263+
If `beforeAll` or `afterAll` have finished, the `entity` will be either [`TestSuite`](/advanced/api/test-suite) or [`TestModule`](/advanced/api/test-module).
264+
265+
If `beforeEach` or `afterEach` have finished, the `entity` will always be [`TestCase`](/advanced/api/test-case).
266+
267+
::: warning
268+
`onHookEnd` method will not be called if the hook did not run during the test run.
269+
:::
270+
271+
## onTestSuiteReady
272+
273+
```ts
274+
function onTestSuiteReady(testSuite: TestSuite): Awaitable<void>
275+
```
276+
277+
This method is called before the suite starts to run its tests. This method is also called if the suite was skipped.
278+
279+
If the file doesn't have any suites, this method will not be called. Consider using `onTestModuleStart` to cover this use case.
280+
281+
## onTestSuiteResult
282+
283+
```ts
284+
function onTestSuiteResult(testSuite: TestSuite): Awaitable<void>
285+
```
286+
287+
This method is called after the suite has finished running tests. This method is also called if the suite was skipped.
288+
289+
If the file doesn't have any suites, this method will not be called. Consider using `onTestModuleEnd` to cover this use case.
290+
291+
## onTestCaseReady
292+
293+
```ts
294+
function onTestCaseReady(testCase: TestCase): Awaitable<void>
295+
```
296+
297+
This method is called before the test starts to run or it was skipped. Note that `beforeEach` and `afterEach` hooks are considered part of the test because they can influence the result.
298+
299+
::: warning
300+
Notice that it's possible to have [`testCase.result()`](/advanced/api/test-case#result) with `passed` or `failed` state already when `onTestCaseReady` is called. This can happen if test was running too fast and both `onTestCaseReady` and `onTestCaseResult` were scheduled to run in the same microtask.
301+
:::
302+
303+
## onTestCaseResult
304+
305+
```ts
306+
function onTestCaseResult(testCase: TestCase): Awaitable<void>
307+
```
308+
309+
This method is called when the test has finished running or was just skipped. Note that this will be called after the `afterEach` hook is finished, if there are any.
310+
311+
At this point, [`testCase.result()`](/advanced/api/test-case#result) will have non-pending state.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy