Status.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. function _chalk() {
  7. const data = _interopRequireDefault(require('chalk'));
  8. _chalk = function () {
  9. return data;
  10. };
  11. return data;
  12. }
  13. function _stringLength() {
  14. const data = _interopRequireDefault(require('string-length'));
  15. _stringLength = function () {
  16. return data;
  17. };
  18. return data;
  19. }
  20. var _utils = require('./utils');
  21. function _interopRequireDefault(obj) {
  22. return obj && obj.__esModule ? obj : {default: obj};
  23. }
  24. function _defineProperty(obj, key, value) {
  25. if (key in obj) {
  26. Object.defineProperty(obj, key, {
  27. value: value,
  28. enumerable: true,
  29. configurable: true,
  30. writable: true
  31. });
  32. } else {
  33. obj[key] = value;
  34. }
  35. return obj;
  36. }
  37. const RUNNING_TEXT = ' RUNS ';
  38. const RUNNING = _chalk().default.reset.inverse.yellow.bold(RUNNING_TEXT) + ' ';
  39. /**
  40. * This class is a perf optimization for sorting the list of currently
  41. * running tests. It tries to keep tests in the same positions without
  42. * shifting the whole list.
  43. */
  44. class CurrentTestList {
  45. constructor() {
  46. _defineProperty(this, '_array', void 0);
  47. this._array = [];
  48. }
  49. add(testPath, config) {
  50. const index = this._array.indexOf(null);
  51. const record = {
  52. config,
  53. testPath
  54. };
  55. if (index !== -1) {
  56. this._array[index] = record;
  57. } else {
  58. this._array.push(record);
  59. }
  60. }
  61. delete(testPath) {
  62. const record = this._array.find(
  63. record => record !== null && record.testPath === testPath
  64. );
  65. this._array[this._array.indexOf(record || null)] = null;
  66. }
  67. get() {
  68. return this._array;
  69. }
  70. }
  71. /**
  72. * A class that generates the CLI status of currently running tests
  73. * and also provides an ANSI escape sequence to remove status lines
  74. * from the terminal.
  75. */
  76. class Status {
  77. constructor() {
  78. _defineProperty(this, '_cache', void 0);
  79. _defineProperty(this, '_callback', void 0);
  80. _defineProperty(this, '_currentTests', void 0);
  81. _defineProperty(this, '_currentTestCases', void 0);
  82. _defineProperty(this, '_done', void 0);
  83. _defineProperty(this, '_emitScheduled', void 0);
  84. _defineProperty(this, '_estimatedTime', void 0);
  85. _defineProperty(this, '_interval', void 0);
  86. _defineProperty(this, '_aggregatedResults', void 0);
  87. _defineProperty(this, '_showStatus', void 0);
  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, _utils.printDisplayName)(config) + ' '
  159. : '';
  160. const prefix = RUNNING + projectDisplayName;
  161. content +=
  162. (0, _utils.wrapAnsiString)(
  163. prefix +
  164. (0, _utils.trimAndFormatPath)(
  165. (0, _stringLength().default)(prefix),
  166. config,
  167. testPath,
  168. width
  169. ),
  170. width
  171. ) + '\n';
  172. }
  173. });
  174. if (this._showStatus && this._aggregatedResults) {
  175. content +=
  176. '\n' +
  177. (0, _utils.getSummary)(this._aggregatedResults, {
  178. currentTestCases: this._currentTestCases,
  179. estimatedTime: this._estimatedTime,
  180. roundTime: true,
  181. width
  182. });
  183. }
  184. let height = 0;
  185. for (let i = 0; i < content.length; i++) {
  186. if (content[i] === '\n') {
  187. height++;
  188. }
  189. }
  190. const clear = '\r\x1B[K\r\x1B[1A'.repeat(height);
  191. return (this._cache = {
  192. clear,
  193. content
  194. });
  195. }
  196. _emit() {
  197. this._cache = null;
  198. if (this._callback) this._callback();
  199. }
  200. _debouncedEmit() {
  201. if (!this._emitScheduled) {
  202. // Perf optimization to avoid two separate renders When
  203. // one test finishes and another test starts executing.
  204. this._emitScheduled = true;
  205. setTimeout(() => {
  206. this._emit();
  207. this._emitScheduled = false;
  208. }, 100);
  209. }
  210. }
  211. _tick() {
  212. this._debouncedEmit();
  213. }
  214. }
  215. exports.default = Status;