Skip to content

Commit 4509988

Browse files
committed
refactor: move onTaskUpdate to its own TaskParser
1 parent 01e3dc4 commit 4509988

File tree

7 files changed

+371
-110
lines changed

7 files changed

+371
-110
lines changed

packages/vitest/src/node/reporters/summary.ts

Lines changed: 43 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
import type { Custom, File, Task, TaskResultPack, Test } from '@vitest/runner'
1+
import type { Custom, File, Test } from '@vitest/runner'
22
import type { Vitest } from '../core'
33
import type { Reporter } from '../types/reporter'
4+
import type { HookOptions } from './task-parser'
45
import { getTests } from '@vitest/runner/utils'
56
import c from 'tinyrainbow'
67
import { F_POINTER, F_TREE_NODE_END, F_TREE_NODE_MIDDLE } from './renderers/figures'
78
import { formatProjectName, formatTime, formatTimeString, padSummaryTitle } from './renderers/utils'
89
import { WindowRenderer } from './renderers/windowedRenderer'
10+
import { TaskParser } from './task-parser'
911

1012
const DURATION_UPDATE_INTERVAL_MS = 100
1113
const FINISHED_TEST_CLEANUP_TIME_MS = 1_000
@@ -23,14 +25,6 @@ interface Counter {
2325
todo: number
2426
}
2527

26-
interface HookOptions {
27-
name: string
28-
file: File
29-
id: File['id'] | Test['id']
30-
type: Task['type']
31-
32-
}
33-
3428
interface SlowTask {
3529
name: string
3630
visible: boolean
@@ -50,8 +44,7 @@ interface RunningTest extends Pick<Counter, 'total' | 'completed'> {
5044
* Reporter extension that renders summary and forwards all other logs above itself.
5145
* Intended to be used by other reporters, not as a standalone reporter.
5246
*/
53-
export class SummaryReporter implements Reporter {
54-
private ctx!: Vitest
47+
export class SummaryReporter extends TaskParser implements Reporter {
5548
private options!: Options
5649
private renderer!: WindowRenderer
5750

@@ -98,66 +91,6 @@ export class SummaryReporter implements Reporter {
9891
this.suites.total = (paths || []).length
9992
}
10093

101-
onTaskUpdate(packs: TaskResultPack[]) {
102-
const startingTestFiles: File[] = []
103-
const finishedTestFiles: File[] = []
104-
105-
const startingTests: (Test | Custom)[] = []
106-
const finishedTests: (Test | Custom)[] = []
107-
108-
const startingHooks: HookOptions[] = []
109-
const endingHooks: HookOptions[] = []
110-
111-
for (const pack of packs) {
112-
const task = this.ctx.state.idMap.get(pack[0])
113-
114-
if (task?.type === 'suite' && 'filepath' in task && task.result?.state) {
115-
if (task?.result?.state === 'run') {
116-
startingTestFiles.push(task)
117-
}
118-
else {
119-
// Skipped tests are not reported, do it manually
120-
for (const test of getTests(task)) {
121-
if (!test.result || test.result?.state === 'skip') {
122-
finishedTests.push(test)
123-
}
124-
}
125-
126-
finishedTestFiles.push(task.file)
127-
}
128-
}
129-
130-
if (task?.type === 'test' || task?.type === 'custom') {
131-
if (task.result?.state === 'run') {
132-
startingTests.push(task)
133-
}
134-
else if (task.result?.hooks?.afterEach !== 'run') {
135-
finishedTests.push(task)
136-
}
137-
}
138-
139-
if (task?.result?.hooks) {
140-
for (const [hook, state] of Object.entries(task.result.hooks)) {
141-
if (state === 'run') {
142-
startingHooks.push({ name: hook, file: task.file, id: task.id, type: task.type })
143-
}
144-
else {
145-
endingHooks.push({ name: hook, file: task.file, id: task.id, type: task.type })
146-
}
147-
}
148-
}
149-
}
150-
151-
endingHooks.forEach(hook => this.onHookEnd(hook))
152-
finishedTests.forEach(test => this.onTestFinished(test))
153-
finishedTestFiles.forEach(file => this.onTestFileFinished(file))
154-
155-
startingTestFiles.forEach(file => this.onTestFilePrepare(file))
156-
startingTests.forEach(test => this.onTestStart(test))
157-
startingHooks.forEach(hook => this.onHookStart(hook),
158-
)
159-
}
160-
16194
onWatcherRerun() {
16295
this.runningTests.clear()
16396
this.finishedTests.clear()
@@ -177,7 +110,7 @@ export class SummaryReporter implements Reporter {
177110
clearInterval(this.durationInterval)
178111
}
179112

180-
private onTestFilePrepare(file: File) {
113+
onTestFilePrepare(file: File) {
181114
if (this.allFinishedTests.has(file.id) || this.runningTests.has(file.id)) {
182115
return
183116
}
@@ -202,40 +135,7 @@ export class SummaryReporter implements Reporter {
202135
this.maxParallelTests = Math.max(this.maxParallelTests, this.runningTests.size)
203136
}
204137

205-
private getTestStats(test: Test | Custom) {
206-
const file = test.file
207-
let stats = this.runningTests.get(file.id)
208-
209-
if (!stats) {
210-
// It's possible that that test finished before it's preparation was even reported
211-
this.onTestFilePrepare(test.file)
212-
stats = this.runningTests.get(file.id)!
213-
214-
// It's also possible that this update came after whole test file was reported as finished
215-
if (!stats) {
216-
return
217-
}
218-
}
219-
220-
return stats
221-
}
222-
223-
private getHookStats({ file, id, type }: HookOptions) {
224-
// Track slow running hooks only on verbose mode
225-
if (!this.options.verbose) {
226-
return
227-
}
228-
229-
const stats = this.runningTests.get(file.id)
230-
231-
if (!stats) {
232-
return
233-
}
234-
235-
return type === 'suite' ? stats : stats?.tests.get(id)
236-
}
237-
238-
private onHookStart(options: HookOptions) {
138+
onHookStart(options: HookOptions) {
239139
const stats = this.getHookStats(options)
240140

241141
if (!stats) {
@@ -258,7 +158,7 @@ export class SummaryReporter implements Reporter {
258158
hook.onFinish = () => clearTimeout(timeout)
259159
}
260160

261-
private onHookEnd(options: HookOptions) {
161+
onHookEnd(options: HookOptions) {
262162
const stats = this.getHookStats(options)
263163

264164
if (stats?.hook?.name !== options.name) {
@@ -269,7 +169,7 @@ export class SummaryReporter implements Reporter {
269169
stats.hook.visible = false
270170
}
271171

272-
private onTestStart(test: Test | Custom) {
172+
onTestStart(test: Test | Custom) {
273173
// Track slow running tests only on verbose mode
274174
if (!this.options.verbose) {
275175
return
@@ -300,7 +200,7 @@ export class SummaryReporter implements Reporter {
300200
stats.tests.set(test.id, slowTest)
301201
}
302202

303-
private onTestFinished(test: Test | Custom) {
203+
onTestFinished(test: Test | Custom) {
304204
const stats = this.getTestStats(test)
305205

306206
if (!stats) {
@@ -324,7 +224,7 @@ export class SummaryReporter implements Reporter {
324224
}
325225
}
326226

327-
private onTestFileFinished(file: File) {
227+
onTestFileFinished(file: File) {
328228
if (this.allFinishedTests.has(file.id)) {
329229
return
330230
}
@@ -362,6 +262,39 @@ export class SummaryReporter implements Reporter {
362262
}
363263
}
364264

265+
private getTestStats(test: Test | Custom) {
266+
const file = test.file
267+
let stats = this.runningTests.get(file.id)
268+
269+
if (!stats) {
270+
// It's possible that that test finished before it's preparation was even reported
271+
this.onTestFilePrepare(test.file)
272+
stats = this.runningTests.get(file.id)!
273+
274+
// It's also possible that this update came after whole test file was reported as finished
275+
if (!stats) {
276+
return
277+
}
278+
}
279+
280+
return stats
281+
}
282+
283+
private getHookStats({ file, id, type }: HookOptions) {
284+
// Track slow running hooks only on verbose mode
285+
if (!this.options.verbose) {
286+
return
287+
}
288+
289+
const stats = this.runningTests.get(file.id)
290+
291+
if (!stats) {
292+
return
293+
}
294+
295+
return type === 'suite' ? stats : stats?.tests.get(id)
296+
}
297+
365298
private createSummary() {
366299
const summary = ['']
367300

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import type { Custom, File, Task, TaskResultPack, Test } from '@vitest/runner'
2+
import type { Vitest } from '../core'
3+
import { getTests } from '@vitest/runner/utils'
4+
5+
export interface HookOptions {
6+
name: string
7+
file: File
8+
id: File['id'] | Test['id']
9+
type: Task['type']
10+
}
11+
12+
export class TaskParser {
13+
ctx!: Vitest
14+
15+
onInit(ctx: Vitest) {
16+
this.ctx = ctx
17+
}
18+
19+
onHookStart(_options: HookOptions) {}
20+
onHookEnd(_options: HookOptions) {}
21+
22+
onTestStart(_test: Test | Custom) {}
23+
onTestFinished(_test: Test | Custom) {}
24+
25+
onTestFilePrepare(_file: File) {}
26+
onTestFileFinished(_file: File) {}
27+
28+
onTaskUpdate(packs: TaskResultPack[]) {
29+
const startingTestFiles: File[] = []
30+
const finishedTestFiles: File[] = []
31+
32+
const startingTests: (Test | Custom)[] = []
33+
const finishedTests: (Test | Custom)[] = []
34+
35+
const startingHooks: HookOptions[] = []
36+
const endingHooks: HookOptions[] = []
37+
38+
for (const pack of packs) {
39+
const task = this.ctx.state.idMap.get(pack[0])
40+
41+
if (task?.type === 'suite' && 'filepath' in task && task.result?.state) {
42+
if (task?.result?.state === 'run') {
43+
startingTestFiles.push(task)
44+
}
45+
else {
46+
// Skipped tests are not reported, do it manually
47+
for (const test of getTests(task)) {
48+
if (!test.result || test.result?.state === 'skip') {
49+
finishedTests.push(test)
50+
}
51+
}
52+
53+
finishedTestFiles.push(task.file)
54+
}
55+
}
56+
57+
if (task?.type === 'test' || task?.type === 'custom') {
58+
if (task.result?.state === 'run') {
59+
startingTests.push(task)
60+
}
61+
else if (task.result?.hooks?.afterEach !== 'run') {
62+
finishedTests.push(task)
63+
}
64+
}
65+
66+
if (task?.result?.hooks) {
67+
for (const [hook, state] of Object.entries(task.result.hooks)) {
68+
if (state === 'run') {
69+
startingHooks.push({ name: hook, file: task.file, id: task.id, type: task.type })
70+
}
71+
else {
72+
endingHooks.push({ name: hook, file: task.file, id: task.id, type: task.type })
73+
}
74+
}
75+
}
76+
}
77+
78+
endingHooks.forEach(hook => this.onHookEnd(hook))
79+
finishedTests.forEach(test => this.onTestFinished(test))
80+
finishedTestFiles.forEach(file => this.onTestFileFinished(file))
81+
82+
startingTestFiles.forEach(file => this.onTestFilePrepare(file))
83+
startingTests.forEach(test => this.onTestStart(test))
84+
startingHooks.forEach(hook => this.onHookStart(hook),
85+
)
86+
}
87+
}

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { beforeAll, beforeEach, afterEach, afterAll, test, describe } from "vitest";
2+
import { setTimeout } from "node:timers/promises";
3+
4+
beforeAll(async () => {
5+
await setTimeout(100);
6+
});
7+
8+
afterAll(async () => {
9+
await setTimeout(100);
10+
});
11+
12+
describe("some suite", async () => {
13+
beforeEach(async () => {
14+
await setTimeout(100);
15+
});
16+
17+
test("some test", async () => {
18+
await setTimeout(100);
19+
});
20+
21+
afterEach(async () => {
22+
await setTimeout(100);
23+
});
24+
});
25+
26+
test("Fast test 1", () => {
27+
//
28+
});
29+
30+
test.skip("Skipped test 1", () => {
31+
//
32+
});
33+
34+
test.concurrent("parallel slow tests 1.1", async () => {
35+
await setTimeout(100);
36+
});
37+
38+
test.concurrent("parallel slow tests 1.2", async () => {
39+
await setTimeout(100);
40+
});

0 commit comments

Comments
 (0)