UNPKG

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