utils.js 13 KB

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