1 | 'use strict';
|
2 | const Emittery = require('emittery');
|
3 | const cloneDeep = require('lodash/cloneDeep');
|
4 |
|
5 | class RunStatus extends Emittery {
|
6 | constructor(files, parallelRuns) {
|
7 | super();
|
8 |
|
9 | this.pendingTests = new Map();
|
10 |
|
11 | this.stats = {
|
12 | byFile: new Map(),
|
13 | declaredTests: 0,
|
14 | failedHooks: 0,
|
15 | failedTests: 0,
|
16 | failedWorkers: 0,
|
17 | files,
|
18 | parallelRuns,
|
19 | finishedWorkers: 0,
|
20 | internalErrors: 0,
|
21 | remainingTests: 0,
|
22 | passedKnownFailingTests: 0,
|
23 | passedTests: 0,
|
24 | selectedTests: 0,
|
25 | skippedTests: 0,
|
26 | timeouts: 0,
|
27 | todoTests: 0,
|
28 | uncaughtExceptions: 0,
|
29 | unhandledRejections: 0
|
30 | };
|
31 | }
|
32 |
|
33 | observeWorker(worker, testFile) {
|
34 | this.stats.byFile.set(testFile, {
|
35 | declaredTests: 0,
|
36 | failedHooks: 0,
|
37 | failedTests: 0,
|
38 | internalErrors: 0,
|
39 | remainingTests: 0,
|
40 | passedKnownFailingTests: 0,
|
41 | passedTests: 0,
|
42 | selectedTests: 0,
|
43 | skippedTests: 0,
|
44 | todoTests: 0,
|
45 | uncaughtExceptions: 0,
|
46 | unhandledRejections: 0
|
47 | });
|
48 |
|
49 | this.pendingTests.set(testFile, new Set());
|
50 | worker.onStateChange(data => this.emitStateChange(data));
|
51 | }
|
52 |
|
53 | emitStateChange(event) {
|
54 | const {stats} = this;
|
55 | const fileStats = stats.byFile.get(event.testFile);
|
56 |
|
57 | let changedStats = true;
|
58 | switch (event.type) {
|
59 | case 'declared-test':
|
60 | stats.declaredTests++;
|
61 | fileStats.declaredTests++;
|
62 | break;
|
63 | case 'hook-failed':
|
64 | stats.failedHooks++;
|
65 | fileStats.failedHooks++;
|
66 | break;
|
67 | case 'internal-error':
|
68 | stats.internalErrors++;
|
69 | if (event.testFile) {
|
70 | fileStats.internalErrors++;
|
71 | }
|
72 |
|
73 | break;
|
74 | case 'selected-test':
|
75 | stats.selectedTests++;
|
76 | fileStats.selectedTests++;
|
77 | if (event.skip) {
|
78 | stats.skippedTests++;
|
79 | fileStats.skippedTests++;
|
80 | } else if (event.todo) {
|
81 | stats.todoTests++;
|
82 | fileStats.todoTests++;
|
83 | } else {
|
84 | stats.remainingTests++;
|
85 | fileStats.remainingTests++;
|
86 | this.addPendingTest(event);
|
87 | }
|
88 |
|
89 | break;
|
90 | case 'test-failed':
|
91 | stats.failedTests++;
|
92 | fileStats.failedTests++;
|
93 | stats.remainingTests--;
|
94 | fileStats.remainingTests--;
|
95 | this.removePendingTest(event);
|
96 | break;
|
97 | case 'test-passed':
|
98 | if (event.knownFailing) {
|
99 | stats.passedKnownFailingTests++;
|
100 | fileStats.passedKnownFailingTests++;
|
101 | } else {
|
102 | stats.passedTests++;
|
103 | fileStats.passedTests++;
|
104 | }
|
105 |
|
106 | stats.remainingTests--;
|
107 | fileStats.remainingTests--;
|
108 | this.removePendingTest(event);
|
109 | break;
|
110 | case 'timeout':
|
111 | event.pendingTests = this.pendingTests;
|
112 | this.pendingTests = new Map();
|
113 | stats.timeouts++;
|
114 | break;
|
115 | case 'interrupt':
|
116 | event.pendingTests = this.pendingTests;
|
117 | this.pendingTests = new Map();
|
118 | break;
|
119 | case 'uncaught-exception':
|
120 | stats.uncaughtExceptions++;
|
121 | fileStats.uncaughtExceptions++;
|
122 | break;
|
123 | case 'unhandled-rejection':
|
124 | stats.unhandledRejections++;
|
125 | fileStats.unhandledRejections++;
|
126 | break;
|
127 | case 'worker-failed':
|
128 | stats.failedWorkers++;
|
129 | break;
|
130 | case 'worker-finished':
|
131 | stats.finishedWorkers++;
|
132 | break;
|
133 | default:
|
134 | changedStats = false;
|
135 | break;
|
136 | }
|
137 |
|
138 | if (changedStats) {
|
139 | this.emit('stateChange', {type: 'stats', stats: cloneDeep(stats)});
|
140 | }
|
141 |
|
142 | this.emit('stateChange', event);
|
143 | }
|
144 |
|
145 | suggestExitCode(circumstances) {
|
146 | if (circumstances.matching && this.stats.selectedTests === 0) {
|
147 | return 1;
|
148 | }
|
149 |
|
150 | if (
|
151 | this.stats.declaredTests === 0 ||
|
152 | this.stats.internalErrors > 0 ||
|
153 | this.stats.failedHooks > 0 ||
|
154 | this.stats.failedTests > 0 ||
|
155 | this.stats.failedWorkers > 0 ||
|
156 | this.stats.timeouts > 0 ||
|
157 | this.stats.uncaughtExceptions > 0 ||
|
158 | this.stats.unhandledRejections > 0
|
159 | ) {
|
160 | return 1;
|
161 | }
|
162 |
|
163 | return 0;
|
164 | }
|
165 |
|
166 | addPendingTest(event) {
|
167 | if (this.pendingTests.has(event.testFile)) {
|
168 | this.pendingTests.get(event.testFile).add(event.title);
|
169 | }
|
170 | }
|
171 |
|
172 | removePendingTest(event) {
|
173 | if (this.pendingTests.has(event.testFile)) {
|
174 | this.pendingTests.get(event.testFile).delete(event.title);
|
175 | }
|
176 | }
|
177 | }
|
178 |
|
179 | module.exports = RunStatus;
|