utils.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true
  4. });
  5. exports.wrapAnsiString = exports.getSummary = exports.relativePath = exports.formatTestPath = exports.trimAndFormatPath = exports.printDisplayName = void 0;
  6. function path() {
  7. const data = _interopRequireWildcard(require('path'));
  8. path = function () {
  9. return data;
  10. };
  11. return data;
  12. }
  13. function _chalk() {
  14. const data = _interopRequireDefault(require('chalk'));
  15. _chalk = function () {
  16. return data;
  17. };
  18. return data;
  19. }
  20. function _slash() {
  21. const data = _interopRequireDefault(require('slash'));
  22. _slash = function () {
  23. return data;
  24. };
  25. return data;
  26. }
  27. function _jestUtil() {
  28. const data = require('jest-util');
  29. _jestUtil = function () {
  30. return data;
  31. };
  32. return data;
  33. }
  34. function _interopRequireDefault(obj) {
  35. return obj && obj.__esModule ? obj : {default: obj};
  36. }
  37. function _getRequireWildcardCache() {
  38. if (typeof WeakMap !== 'function') return null;
  39. var cache = new WeakMap();
  40. _getRequireWildcardCache = function () {
  41. return cache;
  42. };
  43. return cache;
  44. }
  45. function _interopRequireWildcard(obj) {
  46. if (obj && obj.__esModule) {
  47. return obj;
  48. }
  49. if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
  50. return {default: obj};
  51. }
  52. var cache = _getRequireWildcardCache();
  53. if (cache && cache.has(obj)) {
  54. return cache.get(obj);
  55. }
  56. var newObj = {};
  57. var hasPropertyDescriptor =
  58. Object.defineProperty && Object.getOwnPropertyDescriptor;
  59. for (var key in obj) {
  60. if (Object.prototype.hasOwnProperty.call(obj, key)) {
  61. var desc = hasPropertyDescriptor
  62. ? Object.getOwnPropertyDescriptor(obj, key)
  63. : null;
  64. if (desc && (desc.get || desc.set)) {
  65. Object.defineProperty(newObj, key, desc);
  66. } else {
  67. newObj[key] = obj[key];
  68. }
  69. }
  70. }
  71. newObj.default = obj;
  72. if (cache) {
  73. cache.set(obj, newObj);
  74. }
  75. return newObj;
  76. }
  77. /**
  78. * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
  79. *
  80. * This source code is licensed under the MIT license found in the
  81. * LICENSE file in the root directory of this source tree.
  82. */
  83. const PROGRESS_BAR_WIDTH = 40;
  84. const printDisplayName = config => {
  85. const {displayName} = config;
  86. const white = _chalk().default.reset.inverse.white;
  87. if (!displayName) {
  88. return '';
  89. }
  90. const {name, color} = displayName;
  91. const chosenColor = _chalk().default.reset.inverse[color]
  92. ? _chalk().default.reset.inverse[color]
  93. : white;
  94. return _chalk().default.supportsColor ? chosenColor(` ${name} `) : name;
  95. };
  96. exports.printDisplayName = printDisplayName;
  97. const trimAndFormatPath = (pad, config, testPath, columns) => {
  98. const maxLength = columns - pad;
  99. const relative = relativePath(config, testPath);
  100. const {basename} = relative;
  101. let {dirname} = relative; // length is ok
  102. if ((dirname + path().sep + basename).length <= maxLength) {
  103. return (0, _slash().default)(
  104. _chalk().default.dim(dirname + path().sep) +
  105. _chalk().default.bold(basename)
  106. );
  107. } // we can fit trimmed dirname and full basename
  108. const basenameLength = basename.length;
  109. if (basenameLength + 4 < maxLength) {
  110. const dirnameLength = maxLength - 4 - basenameLength;
  111. dirname =
  112. '...' + dirname.slice(dirname.length - dirnameLength, dirname.length);
  113. return (0, _slash().default)(
  114. _chalk().default.dim(dirname + path().sep) +
  115. _chalk().default.bold(basename)
  116. );
  117. }
  118. if (basenameLength + 4 === maxLength) {
  119. return (0, _slash().default)(
  120. _chalk().default.dim('...' + path().sep) + _chalk().default.bold(basename)
  121. );
  122. } // can't fit dirname, but can fit trimmed basename
  123. return (0, _slash().default)(
  124. _chalk().default.bold(
  125. '...' + basename.slice(basename.length - maxLength - 4, basename.length)
  126. )
  127. );
  128. };
  129. exports.trimAndFormatPath = trimAndFormatPath;
  130. const formatTestPath = (config, testPath) => {
  131. const {dirname, basename} = relativePath(config, testPath);
  132. return (0, _slash().default)(
  133. _chalk().default.dim(dirname + path().sep) + _chalk().default.bold(basename)
  134. );
  135. };
  136. exports.formatTestPath = formatTestPath;
  137. const relativePath = (config, testPath) => {
  138. // this function can be called with ProjectConfigs or GlobalConfigs. GlobalConfigs
  139. // do not have config.cwd, only config.rootDir. Try using config.cwd, fallback
  140. // to config.rootDir. (Also, some unit just use config.rootDir, which is ok)
  141. testPath = path().relative(config.cwd || config.rootDir, testPath);
  142. const dirname = path().dirname(testPath);
  143. const basename = path().basename(testPath);
  144. return {
  145. basename,
  146. dirname
  147. };
  148. };
  149. exports.relativePath = relativePath;
  150. const getValuesCurrentTestCases = (currentTestCases = []) => {
  151. let numFailingTests = 0;
  152. let numPassingTests = 0;
  153. let numPendingTests = 0;
  154. let numTodoTests = 0;
  155. let numTotalTests = 0;
  156. currentTestCases.forEach(testCase => {
  157. switch (testCase.testCaseResult.status) {
  158. case 'failed': {
  159. numFailingTests++;
  160. break;
  161. }
  162. case 'passed': {
  163. numPassingTests++;
  164. break;
  165. }
  166. case 'skipped': {
  167. numPendingTests++;
  168. break;
  169. }
  170. case 'todo': {
  171. numTodoTests++;
  172. break;
  173. }
  174. }
  175. numTotalTests++;
  176. });
  177. return {
  178. numFailingTests,
  179. numPassingTests,
  180. numPendingTests,
  181. numTodoTests,
  182. numTotalTests
  183. };
  184. };
  185. const getSummary = (aggregatedResults, options) => {
  186. let runTime = (Date.now() - aggregatedResults.startTime) / 1000;
  187. if (options && options.roundTime) {
  188. runTime = Math.floor(runTime);
  189. }
  190. const valuesForCurrentTestCases = getValuesCurrentTestCases(
  191. options === null || options === void 0 ? void 0 : options.currentTestCases
  192. );
  193. const estimatedTime = (options && options.estimatedTime) || 0;
  194. const snapshotResults = aggregatedResults.snapshot;
  195. const snapshotsAdded = snapshotResults.added;
  196. const snapshotsFailed = snapshotResults.unmatched;
  197. const snapshotsOutdated = snapshotResults.unchecked;
  198. const snapshotsFilesRemoved = snapshotResults.filesRemoved;
  199. const snapshotsDidUpdate = snapshotResults.didUpdate;
  200. const snapshotsPassed = snapshotResults.matched;
  201. const snapshotsTotal = snapshotResults.total;
  202. const snapshotsUpdated = snapshotResults.updated;
  203. const suitesFailed = aggregatedResults.numFailedTestSuites;
  204. const suitesPassed = aggregatedResults.numPassedTestSuites;
  205. const suitesPending = aggregatedResults.numPendingTestSuites;
  206. const suitesRun = suitesFailed + suitesPassed;
  207. const suitesTotal = aggregatedResults.numTotalTestSuites;
  208. const testsFailed = aggregatedResults.numFailedTests;
  209. const testsPassed = aggregatedResults.numPassedTests;
  210. const testsPending = aggregatedResults.numPendingTests;
  211. const testsTodo = aggregatedResults.numTodoTests;
  212. const testsTotal = aggregatedResults.numTotalTests;
  213. const width = (options && options.width) || 0;
  214. const suites =
  215. _chalk().default.bold('Test Suites: ') +
  216. (suitesFailed
  217. ? _chalk().default.bold.red(`${suitesFailed} failed`) + ', '
  218. : '') +
  219. (suitesPending
  220. ? _chalk().default.bold.yellow(`${suitesPending} skipped`) + ', '
  221. : '') +
  222. (suitesPassed
  223. ? _chalk().default.bold.green(`${suitesPassed} passed`) + ', '
  224. : '') +
  225. (suitesRun !== suitesTotal
  226. ? suitesRun + ' of ' + suitesTotal
  227. : suitesTotal) +
  228. ` total`;
  229. const updatedTestsFailed =
  230. testsFailed + valuesForCurrentTestCases.numFailingTests;
  231. const updatedTestsPending =
  232. testsPending + valuesForCurrentTestCases.numPendingTests;
  233. const updatedTestsTodo = testsTodo + valuesForCurrentTestCases.numTodoTests;
  234. const updatedTestsPassed =
  235. testsPassed + valuesForCurrentTestCases.numPassingTests;
  236. const updatedTestsTotal =
  237. testsTotal + valuesForCurrentTestCases.numTotalTests;
  238. const tests =
  239. _chalk().default.bold('Tests: ') +
  240. (updatedTestsFailed > 0
  241. ? _chalk().default.bold.red(`${updatedTestsFailed} failed`) + ', '
  242. : '') +
  243. (updatedTestsPending > 0
  244. ? _chalk().default.bold.yellow(`${updatedTestsPending} skipped`) + ', '
  245. : '') +
  246. (updatedTestsTodo > 0
  247. ? _chalk().default.bold.magenta(`${updatedTestsTodo} todo`) + ', '
  248. : '') +
  249. (updatedTestsPassed > 0
  250. ? _chalk().default.bold.green(`${updatedTestsPassed} passed`) + ', '
  251. : '') +
  252. `${updatedTestsTotal} total`;
  253. const snapshots =
  254. _chalk().default.bold('Snapshots: ') +
  255. (snapshotsFailed
  256. ? _chalk().default.bold.red(`${snapshotsFailed} failed`) + ', '
  257. : '') +
  258. (snapshotsOutdated && !snapshotsDidUpdate
  259. ? _chalk().default.bold.yellow(`${snapshotsOutdated} obsolete`) + ', '
  260. : '') +
  261. (snapshotsOutdated && snapshotsDidUpdate
  262. ? _chalk().default.bold.green(`${snapshotsOutdated} removed`) + ', '
  263. : '') +
  264. (snapshotsFilesRemoved && !snapshotsDidUpdate
  265. ? _chalk().default.bold.yellow(
  266. (0, _jestUtil().pluralize)('file', snapshotsFilesRemoved) +
  267. ' obsolete'
  268. ) + ', '
  269. : '') +
  270. (snapshotsFilesRemoved && snapshotsDidUpdate
  271. ? _chalk().default.bold.green(
  272. (0, _jestUtil().pluralize)('file', snapshotsFilesRemoved) + ' removed'
  273. ) + ', '
  274. : '') +
  275. (snapshotsUpdated
  276. ? _chalk().default.bold.green(`${snapshotsUpdated} updated`) + ', '
  277. : '') +
  278. (snapshotsAdded
  279. ? _chalk().default.bold.green(`${snapshotsAdded} written`) + ', '
  280. : '') +
  281. (snapshotsPassed
  282. ? _chalk().default.bold.green(`${snapshotsPassed} passed`) + ', '
  283. : '') +
  284. `${snapshotsTotal} total`;
  285. const time = renderTime(runTime, estimatedTime, width);
  286. return [suites, tests, snapshots, time].join('\n');
  287. };
  288. exports.getSummary = getSummary;
  289. const renderTime = (runTime, estimatedTime, width) => {
  290. // If we are more than one second over the estimated time, highlight it.
  291. const renderedTime =
  292. estimatedTime && runTime >= estimatedTime + 1
  293. ? _chalk().default.bold.yellow((0, _jestUtil().formatTime)(runTime, 0))
  294. : (0, _jestUtil().formatTime)(runTime, 0);
  295. let time = _chalk().default.bold(`Time:`) + ` ${renderedTime}`;
  296. if (runTime < estimatedTime) {
  297. time += `, estimated ${(0, _jestUtil().formatTime)(estimatedTime, 0)}`;
  298. } // Only show a progress bar if the test run is actually going to take
  299. // some time.
  300. if (estimatedTime > 2 && runTime < estimatedTime && width) {
  301. const availableWidth = Math.min(PROGRESS_BAR_WIDTH, width);
  302. const length = Math.min(
  303. Math.floor((runTime / estimatedTime) * availableWidth),
  304. availableWidth
  305. );
  306. if (availableWidth >= 2) {
  307. time +=
  308. '\n' +
  309. _chalk().default.green('█').repeat(length) +
  310. _chalk()
  311. .default.white('█')
  312. .repeat(availableWidth - length);
  313. }
  314. }
  315. return time;
  316. }; // word-wrap a string that contains ANSI escape sequences.
  317. // ANSI escape sequences do not add to the string length.
  318. const wrapAnsiString = (string, terminalWidth) => {
  319. if (terminalWidth === 0) {
  320. // if the terminal width is zero, don't bother word-wrapping
  321. return string;
  322. }
  323. const ANSI_REGEXP = /[\u001b\u009b]\[\d{1,2}m/g;
  324. const tokens = [];
  325. let lastIndex = 0;
  326. let match;
  327. while ((match = ANSI_REGEXP.exec(string))) {
  328. const ansi = match[0];
  329. const index = match['index'];
  330. if (index != lastIndex) {
  331. tokens.push(['string', string.slice(lastIndex, index)]);
  332. }
  333. tokens.push(['ansi', ansi]);
  334. lastIndex = index + ansi.length;
  335. }
  336. if (lastIndex != string.length - 1) {
  337. tokens.push(['string', string.slice(lastIndex, string.length)]);
  338. }
  339. let lastLineLength = 0;
  340. return tokens
  341. .reduce(
  342. (lines, [kind, token]) => {
  343. if (kind === 'string') {
  344. if (lastLineLength + token.length > terminalWidth) {
  345. while (token.length) {
  346. const chunk = token.slice(0, terminalWidth - lastLineLength);
  347. const remaining = token.slice(
  348. terminalWidth - lastLineLength,
  349. token.length
  350. );
  351. lines[lines.length - 1] += chunk;
  352. lastLineLength += chunk.length;
  353. token = remaining;
  354. if (token.length) {
  355. lines.push('');
  356. lastLineLength = 0;
  357. }
  358. }
  359. } else {
  360. lines[lines.length - 1] += token;
  361. lastLineLength += token.length;
  362. }
  363. } else {
  364. lines[lines.length - 1] += token;
  365. }
  366. return lines;
  367. },
  368. ['']
  369. )
  370. .join('\n');
  371. };
  372. exports.wrapAnsiString = wrapAnsiString;