UNPKG

5.82 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', {
4 value: true
5});
6exports.default = void 0;
7
8function _chalk() {
9 const data = _interopRequireDefault(require('chalk'));
10
11 _chalk = function () {
12 return data;
13 };
14
15 return data;
16}
17
18function _stringLength() {
19 const data = _interopRequireDefault(require('string-length'));
20
21 _stringLength = function () {
22 return data;
23 };
24
25 return data;
26}
27
28var _utils = require('./utils');
29
30function _interopRequireDefault(obj) {
31 return obj && obj.__esModule ? obj : {default: obj};
32}
33
34function _defineProperty(obj, key, value) {
35 if (key in obj) {
36 Object.defineProperty(obj, key, {
37 value: value,
38 enumerable: true,
39 configurable: true,
40 writable: true
41 });
42 } else {
43 obj[key] = value;
44 }
45 return obj;
46}
47
48const RUNNING_TEXT = ' RUNS ';
49const RUNNING = _chalk().default.reset.inverse.yellow.bold(RUNNING_TEXT) + ' ';
50/**
51 * This class is a perf optimization for sorting the list of currently
52 * running tests. It tries to keep tests in the same positions without
53 * shifting the whole list.
54 */
55
56class CurrentTestList {
57 constructor() {
58 _defineProperty(this, '_array', void 0);
59
60 this._array = [];
61 }
62
63 add(testPath, config) {
64 const index = this._array.indexOf(null);
65
66 const record = {
67 config,
68 testPath
69 };
70
71 if (index !== -1) {
72 this._array[index] = record;
73 } else {
74 this._array.push(record);
75 }
76 }
77
78 delete(testPath) {
79 const record = this._array.find(
80 record => record !== null && record.testPath === testPath
81 );
82
83 this._array[this._array.indexOf(record || null)] = null;
84 }
85
86 get() {
87 return this._array;
88 }
89}
90
91/**
92 * A class that generates the CLI status of currently running tests
93 * and also provides an ANSI escape sequence to remove status lines
94 * from the terminal.
95 */
96class Status {
97 constructor() {
98 _defineProperty(this, '_cache', void 0);
99
100 _defineProperty(this, '_callback', void 0);
101
102 _defineProperty(this, '_currentTests', void 0);
103
104 _defineProperty(this, '_currentTestCases', void 0);
105
106 _defineProperty(this, '_done', void 0);
107
108 _defineProperty(this, '_emitScheduled', void 0);
109
110 _defineProperty(this, '_estimatedTime', void 0);
111
112 _defineProperty(this, '_interval', void 0);
113
114 _defineProperty(this, '_aggregatedResults', void 0);
115
116 _defineProperty(this, '_showStatus', void 0);
117
118 this._cache = null;
119 this._currentTests = new CurrentTestList();
120 this._currentTestCases = [];
121 this._done = false;
122 this._emitScheduled = false;
123 this._estimatedTime = 0;
124 this._showStatus = false;
125 }
126
127 onChange(callback) {
128 this._callback = callback;
129 }
130
131 runStarted(aggregatedResults, options) {
132 this._estimatedTime = (options && options.estimatedTime) || 0;
133 this._showStatus = options && options.showStatus;
134 this._interval = setInterval(() => this._tick(), 1000);
135 this._aggregatedResults = aggregatedResults;
136
137 this._debouncedEmit();
138 }
139
140 runFinished() {
141 this._done = true;
142 if (this._interval) clearInterval(this._interval);
143
144 this._emit();
145 }
146
147 addTestCaseResult(test, testCaseResult) {
148 this._currentTestCases.push({
149 test,
150 testCaseResult
151 });
152
153 if (!this._showStatus) {
154 this._emit();
155 } else {
156 this._debouncedEmit();
157 }
158 }
159
160 testStarted(testPath, config) {
161 this._currentTests.add(testPath, config);
162
163 if (!this._showStatus) {
164 this._emit();
165 } else {
166 this._debouncedEmit();
167 }
168 }
169
170 testFinished(_config, testResult, aggregatedResults) {
171 const {testFilePath} = testResult;
172 this._aggregatedResults = aggregatedResults;
173
174 this._currentTests.delete(testFilePath);
175
176 this._currentTestCases = this._currentTestCases.filter(({test}) => {
177 if (_config !== test.context.config) {
178 return true;
179 }
180
181 return test.path !== testFilePath;
182 });
183
184 this._debouncedEmit();
185 }
186
187 get() {
188 if (this._cache) {
189 return this._cache;
190 }
191
192 if (this._done) {
193 return {
194 clear: '',
195 content: ''
196 };
197 }
198
199 const width = process.stdout.columns;
200 let content = '\n';
201
202 this._currentTests.get().forEach(record => {
203 if (record) {
204 const {config, testPath} = record;
205 const projectDisplayName = config.displayName
206 ? (0, _utils.printDisplayName)(config) + ' '
207 : '';
208 const prefix = RUNNING + projectDisplayName;
209 content +=
210 (0, _utils.wrapAnsiString)(
211 prefix +
212 (0, _utils.trimAndFormatPath)(
213 (0, _stringLength().default)(prefix),
214 config,
215 testPath,
216 width
217 ),
218 width
219 ) + '\n';
220 }
221 });
222
223 if (this._showStatus && this._aggregatedResults) {
224 content +=
225 '\n' +
226 (0, _utils.getSummary)(this._aggregatedResults, {
227 currentTestCases: this._currentTestCases,
228 estimatedTime: this._estimatedTime,
229 roundTime: true,
230 width
231 });
232 }
233
234 let height = 0;
235
236 for (let i = 0; i < content.length; i++) {
237 if (content[i] === '\n') {
238 height++;
239 }
240 }
241
242 const clear = '\r\x1B[K\r\x1B[1A'.repeat(height);
243 return (this._cache = {
244 clear,
245 content
246 });
247 }
248
249 _emit() {
250 this._cache = null;
251 if (this._callback) this._callback();
252 }
253
254 _debouncedEmit() {
255 if (!this._emitScheduled) {
256 // Perf optimization to avoid two separate renders When
257 // one test finishes and another test starts executing.
258 this._emitScheduled = true;
259 setTimeout(() => {
260 this._emit();
261
262 this._emitScheduled = false;
263 }, 100);
264 }
265 }
266
267 _tick() {
268 this._debouncedEmit();
269 }
270}
271
272exports.default = Status;