Skip to content

Commit 64abbda

Browse files
committed
feat(reporters): add first 5/7 test run life cycles
1 parent 6f0da08 commit 64abbda

File tree

5 files changed

+119
-10
lines changed

5 files changed

+119
-10
lines changed

packages/vitest/src/node/reporters/reported-tasks.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,9 @@ abstract class SuiteImplementation extends ReportedTaskImplementation {
359359
if (mode === 'skip' || mode === 'todo' || state === 'skip' || state === 'todo') {
360360
return 'skipped'
361361
}
362+
if (state === 'queued') {
363+
return 'queued'
364+
}
362365
if (state == null || state === 'run' || state === 'only') {
363366
return 'pending'
364367
}
@@ -518,7 +521,7 @@ function buildOptions(
518521
}
519522
}
520523

521-
export type TestSuiteState = 'skipped' | 'pending' | 'failed' | 'passed'
524+
export type TestSuiteState = 'skipped' | 'pending' | 'queued' | 'failed' | 'passed'
522525

523526
export type TestResult =
524527
| TestResultPassed

packages/vitest/src/node/reporters/task-parser.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// TODO: Remove once Reporter API implements these life cycles
2+
13
import type { File, Task, TaskResultPack, Test } from '@vitest/runner'
24
import type { Vitest } from '../core'
35
import { getTests } from '@vitest/runner/utils'

packages/vitest/src/node/state.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,11 @@ export class StateManager {
184184
}
185185
}
186186

187-
getReportedEntity(task: Task) {
187+
getReportedEntity(task?: Task) {
188+
if (!task) {
189+
return undefined
190+
}
191+
188192
return this.reportedTasksMap.get(task)
189193
}
190194

packages/vitest/src/node/test-run.ts

Lines changed: 100 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,126 @@
11
import type { TaskResultPack } from '@vitest/runner'
22
import type { Vitest } from './core'
3-
import type { TestModule } from './reporters/reported-tasks'
3+
import type { TestCase, TestModule } from './reporters/reported-tasks'
44
import type { TestSpecification } from './spec'
55

66
export class TestRun {
77
private tests = emptyCounters()
88
private suites = emptyCounters()
99

10+
// Internal state to prevent reporting duplicates and guaranteeing correct order
11+
private queuedTestModules = new Set<TestModule['id']>()
12+
private runningTestModules = new Set<TestModule['id']>()
13+
private finishedTestModules = new Set<TestModule['id']>()
14+
15+
private runningTestCases = new Set<TestCase['id']>()
16+
private finishedTestCases = new Set<TestCase['id']>()
17+
1018
constructor(private vitest: Vitest) {}
1119

1220
async start(specifications: TestSpecification[]) {
1321
this.tests = emptyCounters()
1422
this.suites = emptyCounters()
1523
this.suites.total = specifications.length
24+
25+
this.queuedTestModules.clear()
26+
this.runningTestModules.clear()
27+
this.finishedTestModules.clear()
28+
this.runningTestCases.clear()
29+
this.finishedTestCases.clear()
30+
1631
await this.vitest.report('onTestRunStart', specifications)
1732
}
1833

19-
enqueued(module: TestModule) {
34+
enqueued(_module: TestModule) {
2035
// TODO
2136
}
2237

23-
collected(modules: TestModule[]) {
38+
collected(_modules: TestModule[]) {
2439
// TODO
2540
}
2641

27-
updated(update: TaskResultPack[]) {
28-
// TODO
42+
async updated(update: TaskResultPack[]) {
43+
const queuedTestModules: TestModule[] = []
44+
const runningTestModules: TestModule[] = []
45+
const finishedTestModules: TestModule[] = []
46+
47+
const runningTestCases: TestCase[] = []
48+
const finishedTestCases: TestCase[] = []
49+
50+
for (const [id] of update) {
51+
const entity = this.vitest.state.getReportedEntity(this.vitest.state.idMap.get(id))
52+
53+
if (!entity) {
54+
continue
55+
}
56+
57+
if (entity.type === 'module') {
58+
const state = entity.state()
59+
60+
if (state === 'queued' && !this.queuedTestModules.has(entity.id)) {
61+
this.queuedTestModules.add(entity.id)
62+
queuedTestModules.push(entity)
63+
}
64+
65+
if (state === 'pending' && !this.runningTestModules.has(entity.id)) {
66+
this.runningTestModules.add(entity.id)
67+
runningTestModules.push(entity)
68+
69+
// If queue phase was fast, it's possible that it was never reported
70+
if (!this.queuedTestModules.has(entity.id)) {
71+
this.queuedTestModules.add(entity.id)
72+
queuedTestModules.push(entity)
73+
}
74+
75+
// TODO: Check if skipped TestCases of finished module were reported.
76+
// If not, get TestCases here and push them to TestCase arrays+sets.
77+
}
78+
79+
if (state !== 'pending' && state !== 'queued' && !this.finishedTestModules.has(entity.id)) {
80+
this.finishedTestModules.add(entity.id)
81+
finishedTestModules.push(entity)
82+
83+
if (!this.queuedTestModules.has(entity.id)) {
84+
this.queuedTestModules.add(entity.id)
85+
queuedTestModules.push(entity)
86+
}
87+
88+
// If module run was fast, it's possible that it was never reported to be running
89+
if (!this.runningTestModules.has(entity.id)) {
90+
this.runningTestModules.add(entity.id)
91+
runningTestModules.push(entity)
92+
}
93+
}
94+
}
95+
96+
if (entity.type === 'test') {
97+
const state = entity.result().state
98+
99+
if (state === 'pending' && !this.runningTestCases.has(entity.id)) {
100+
this.runningTestCases.add(entity.id)
101+
runningTestCases.push(entity)
102+
}
103+
104+
if (state !== 'pending' && !this.finishedTestCases.has(entity.id)) {
105+
this.finishedTestCases.add(entity.id)
106+
finishedTestCases.push(entity)
107+
108+
// If test finished quickly, it's possible that it was never reported as running
109+
if (!this.runningTestCases.has(entity.id)) {
110+
this.runningTestCases.add(entity.id)
111+
runningTestCases.push(entity)
112+
}
113+
}
114+
}
115+
}
116+
117+
// Order of reporting is important here
118+
await Promise.all(finishedTestCases.map(testCase => this.vitest.report('onTestCaseFinished', testCase)))
119+
await Promise.all(finishedTestModules.map(module => this.vitest.report('onTestModuleFinished', module)))
120+
121+
await Promise.all(queuedTestModules.map(module => this.vitest.report('onTestModuleQueued', module)))
122+
await Promise.all(runningTestModules.map(module => this.vitest.report('onTestModulePrepare', module)))
123+
await Promise.all(runningTestCases.map(testCase => this.vitest.report('onTestCasePrepare', testCase)))
29124
}
30125

31126
async end() {

packages/vitest/src/node/types/reporter.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@ import type { SerializedError } from '@vitest/utils'
33
import type { SerializedTestSpecification } from '../../runtime/types/utils'
44
import type { Awaitable, UserConsoleLog } from '../../types/general'
55
import type { Vitest } from '../core'
6-
import type { TestModule } from '../reporters/reported-tasks'
6+
import type { TestCase, TestModule } from '../reporters/reported-tasks'
77
import type { TestSpecification } from '../spec'
8-
import type { TestModule } from '../reporters/reported-tasks'
98

109
export interface Reporter {
1110
onInit?: (ctx: Vitest) => void
1211
onPathsCollected?: (paths?: string[]) => Awaitable<void>
1312
onSpecsCollected?: (specs?: SerializedTestSpecification[]) => Awaitable<void>
14-
onTestModuleQueued?: (file: TestModule) => Awaitable<void>
1513
onCollected?: (files?: File[]) => Awaitable<void>
1614
onFinished?: (
1715
files: File[],
@@ -33,4 +31,11 @@ export interface Reporter {
3331
errors: SerializedError[],
3432
reason: 'passed' | 'interrupted' | 'failed'
3533
) => Awaitable<void>
34+
onTestModuleQueued?: (testModule: TestModule) => Awaitable<void>
35+
onTestModulePrepare?: (testModule: TestModule) => Awaitable<void>
36+
onTestModuleFinished?: (testModule: TestModule) => Awaitable<void>
37+
38+
// TODO: This was planned as onTestFinished, but maybe we could use TestCase in name directly?
39+
onTestCasePrepare?: (testCase: TestCase) => Awaitable<void>
40+
onTestCaseFinished?: (testCase: TestCase) => Awaitable<void>
3641
}

0 commit comments

Comments
 (0)