|
1 | 1 | import type { TaskResultPack } from '@vitest/runner' |
2 | 2 | import type { Vitest } from './core' |
3 | | -import type { TestModule } from './reporters/reported-tasks' |
| 3 | +import type { TestCase, TestModule } from './reporters/reported-tasks' |
4 | 4 | import type { TestSpecification } from './spec' |
5 | 5 |
|
6 | 6 | export class TestRun { |
7 | 7 | private tests = emptyCounters() |
8 | 8 | private suites = emptyCounters() |
9 | 9 |
|
| 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 | + |
10 | 18 | constructor(private vitest: Vitest) {} |
11 | 19 |
|
12 | 20 | async start(specifications: TestSpecification[]) { |
13 | 21 | this.tests = emptyCounters() |
14 | 22 | this.suites = emptyCounters() |
15 | 23 | 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 | + |
16 | 31 | await this.vitest.report('onTestRunStart', specifications) |
17 | 32 | } |
18 | 33 |
|
19 | | - enqueued(module: TestModule) { |
| 34 | + enqueued(_module: TestModule) { |
20 | 35 | // TODO |
21 | 36 | } |
22 | 37 |
|
23 | | - collected(modules: TestModule[]) { |
| 38 | + collected(_modules: TestModule[]) { |
24 | 39 | // TODO |
25 | 40 | } |
26 | 41 |
|
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))) |
29 | 124 | } |
30 | 125 |
|
31 | 126 | async end() { |
|
0 commit comments