index.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true
  4. });
  5. Object.defineProperty(exports, 'DiffOptions', {
  6. enumerable: true,
  7. get: function get() {
  8. return _jestDiff.DiffOptions;
  9. }
  10. });
  11. exports.matcherHint = exports.matcherErrorMessage = exports.getLabelPrinter = exports.pluralize = exports.diff = exports.printDiffOrStringify = exports.ensureExpectedIsNonNegativeInteger = exports.ensureNumbers = exports.ensureExpectedIsNumber = exports.ensureActualIsNumber = exports.ensureNoExpected = exports.printWithType = exports.printExpected = exports.printReceived = exports.highlightTrailingWhitespace = exports.stringify = exports.SUGGEST_TO_CONTAIN_EQUAL = exports.DIM_COLOR = exports.BOLD_WEIGHT = exports.INVERTED_COLOR = exports.RECEIVED_COLOR = exports.EXPECTED_COLOR = void 0;
  12. var _chalk = _interopRequireDefault(require('chalk'));
  13. var _jestDiff = _interopRequireWildcard(require('jest-diff'));
  14. var _jestGetType = _interopRequireWildcard(require('jest-get-type'));
  15. var _prettyFormat = _interopRequireDefault(require('pretty-format'));
  16. function _interopRequireWildcard(obj) {
  17. if (obj && obj.__esModule) {
  18. return obj;
  19. } else {
  20. var newObj = {};
  21. if (obj != null) {
  22. for (var key in obj) {
  23. if (Object.prototype.hasOwnProperty.call(obj, key)) {
  24. var desc =
  25. Object.defineProperty && Object.getOwnPropertyDescriptor
  26. ? Object.getOwnPropertyDescriptor(obj, key)
  27. : {};
  28. if (desc.get || desc.set) {
  29. Object.defineProperty(newObj, key, desc);
  30. } else {
  31. newObj[key] = obj[key];
  32. }
  33. }
  34. }
  35. }
  36. newObj.default = obj;
  37. return newObj;
  38. }
  39. }
  40. function _interopRequireDefault(obj) {
  41. return obj && obj.__esModule ? obj : {default: obj};
  42. }
  43. /**
  44. * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
  45. *
  46. * This source code is licensed under the MIT license found in the
  47. * LICENSE file in the root directory of this source tree.
  48. */
  49. const _prettyFormat$plugins = _prettyFormat.default.plugins,
  50. AsymmetricMatcher = _prettyFormat$plugins.AsymmetricMatcher,
  51. DOMCollection = _prettyFormat$plugins.DOMCollection,
  52. DOMElement = _prettyFormat$plugins.DOMElement,
  53. Immutable = _prettyFormat$plugins.Immutable,
  54. ReactElement = _prettyFormat$plugins.ReactElement,
  55. ReactTestComponent = _prettyFormat$plugins.ReactTestComponent;
  56. const PLUGINS = [
  57. ReactTestComponent,
  58. ReactElement,
  59. DOMElement,
  60. DOMCollection,
  61. Immutable,
  62. AsymmetricMatcher
  63. ];
  64. const EXPECTED_COLOR = _chalk.default.green;
  65. exports.EXPECTED_COLOR = EXPECTED_COLOR;
  66. const RECEIVED_COLOR = _chalk.default.red;
  67. exports.RECEIVED_COLOR = RECEIVED_COLOR;
  68. const INVERTED_COLOR = _chalk.default.inverse;
  69. exports.INVERTED_COLOR = INVERTED_COLOR;
  70. const BOLD_WEIGHT = _chalk.default.bold;
  71. exports.BOLD_WEIGHT = BOLD_WEIGHT;
  72. const DIM_COLOR = _chalk.default.dim;
  73. exports.DIM_COLOR = DIM_COLOR;
  74. const MULTILINE_REGEXP = /\n/;
  75. const SPACE_SYMBOL = '\u{00B7}'; // middle dot
  76. const NUMBERS = [
  77. 'zero',
  78. 'one',
  79. 'two',
  80. 'three',
  81. 'four',
  82. 'five',
  83. 'six',
  84. 'seven',
  85. 'eight',
  86. 'nine',
  87. 'ten',
  88. 'eleven',
  89. 'twelve',
  90. 'thirteen'
  91. ];
  92. const SUGGEST_TO_CONTAIN_EQUAL = _chalk.default.dim(
  93. 'Looks like you wanted to test for object/array equality with the stricter `toContain` matcher. You probably need to use `toContainEqual` instead.'
  94. );
  95. exports.SUGGEST_TO_CONTAIN_EQUAL = SUGGEST_TO_CONTAIN_EQUAL;
  96. const stringify = (object, maxDepth = 10) => {
  97. const MAX_LENGTH = 10000;
  98. let result;
  99. try {
  100. result = (0, _prettyFormat.default)(object, {
  101. maxDepth,
  102. min: true,
  103. plugins: PLUGINS
  104. });
  105. } catch (e) {
  106. result = (0, _prettyFormat.default)(object, {
  107. callToJSON: false,
  108. maxDepth,
  109. min: true,
  110. plugins: PLUGINS
  111. });
  112. }
  113. return result.length >= MAX_LENGTH && maxDepth > 1
  114. ? stringify(object, Math.floor(maxDepth / 2))
  115. : result;
  116. };
  117. exports.stringify = stringify;
  118. const highlightTrailingWhitespace = text =>
  119. text.replace(/\s+$/gm, _chalk.default.inverse('$&')); // Instead of inverse highlight which now implies a change,
  120. // replace common spaces with middle dot at the end of any line.
  121. exports.highlightTrailingWhitespace = highlightTrailingWhitespace;
  122. const replaceTrailingSpaces = text =>
  123. text.replace(/\s+$/gm, spaces => SPACE_SYMBOL.repeat(spaces.length));
  124. const printReceived = object =>
  125. RECEIVED_COLOR(replaceTrailingSpaces(stringify(object)));
  126. exports.printReceived = printReceived;
  127. const printExpected = value =>
  128. EXPECTED_COLOR(replaceTrailingSpaces(stringify(value)));
  129. exports.printExpected = printExpected;
  130. const printWithType = (
  131. name,
  132. value,
  133. print // printExpected or printReceived
  134. ) => {
  135. const type = (0, _jestGetType.default)(value);
  136. const hasType =
  137. type !== 'null' && type !== 'undefined'
  138. ? `${name} has type: ${type}\n`
  139. : '';
  140. const hasValue = `${name} has value: ${print(value)}`;
  141. return hasType + hasValue;
  142. };
  143. exports.printWithType = printWithType;
  144. const ensureNoExpected = (expected, matcherName, options) => {
  145. if (typeof expected !== 'undefined') {
  146. // Prepend maybe not only for backward compatibility.
  147. const matcherString = (options ? '' : '[.not]') + matcherName;
  148. throw new Error(
  149. matcherErrorMessage(
  150. matcherHint(matcherString, undefined, '', options), // Because expected is omitted in hint above,
  151. 'this matcher must not have an expected argument',
  152. printWithType('Expected', expected, printExpected)
  153. )
  154. );
  155. }
  156. };
  157. exports.ensureNoExpected = ensureNoExpected;
  158. const ensureActualIsNumber = (actual, matcherName, options) => {
  159. if (typeof actual !== 'number') {
  160. // Prepend maybe not only for backward compatibility.
  161. const matcherString = (options ? '' : '[.not]') + matcherName;
  162. throw new Error(
  163. matcherErrorMessage(
  164. matcherHint(matcherString, undefined, undefined, options),
  165. `${RECEIVED_COLOR('received')} value must be a number`,
  166. printWithType('Received', actual, printReceived)
  167. )
  168. );
  169. }
  170. };
  171. exports.ensureActualIsNumber = ensureActualIsNumber;
  172. const ensureExpectedIsNumber = (expected, matcherName, options) => {
  173. if (typeof expected !== 'number') {
  174. // Prepend maybe not only for backward compatibility.
  175. const matcherString = (options ? '' : '[.not]') + matcherName;
  176. throw new Error(
  177. matcherErrorMessage(
  178. matcherHint(matcherString, undefined, undefined, options),
  179. `${EXPECTED_COLOR('expected')} value must be a number`,
  180. printWithType('Expected', expected, printExpected)
  181. )
  182. );
  183. }
  184. };
  185. exports.ensureExpectedIsNumber = ensureExpectedIsNumber;
  186. const ensureNumbers = (actual, expected, matcherName, options) => {
  187. ensureActualIsNumber(actual, matcherName, options);
  188. ensureExpectedIsNumber(expected, matcherName, options);
  189. };
  190. exports.ensureNumbers = ensureNumbers;
  191. const ensureExpectedIsNonNegativeInteger = (expected, matcherName, options) => {
  192. if (
  193. typeof expected !== 'number' ||
  194. !Number.isSafeInteger(expected) ||
  195. expected < 0
  196. ) {
  197. // Prepend maybe not only for backward compatibility.
  198. const matcherString = (options ? '' : '[.not]') + matcherName;
  199. throw new Error(
  200. matcherErrorMessage(
  201. matcherHint(matcherString, undefined, undefined, options),
  202. `${EXPECTED_COLOR('expected')} value must be a non-negative integer`,
  203. printWithType('Expected', expected, printExpected)
  204. )
  205. );
  206. }
  207. };
  208. exports.ensureExpectedIsNonNegativeInteger = ensureExpectedIsNonNegativeInteger;
  209. const isLineDiffable = (expected, received) => {
  210. const expectedType = (0, _jestGetType.default)(expected);
  211. const receivedType = (0, _jestGetType.default)(received);
  212. if (expectedType !== receivedType) {
  213. return false;
  214. }
  215. if ((0, _jestGetType.isPrimitive)(expected)) {
  216. // Print generic line diff for strings only:
  217. // * if neither string is empty
  218. return (
  219. typeof expected === 'string' &&
  220. typeof received === 'string' &&
  221. expected.length !== 0 &&
  222. received.length !== 0 &&
  223. (MULTILINE_REGEXP.test(expected) || MULTILINE_REGEXP.test(received))
  224. );
  225. }
  226. if (
  227. expectedType === 'date' ||
  228. expectedType === 'function' ||
  229. expectedType === 'regexp'
  230. ) {
  231. return false;
  232. }
  233. if (expected instanceof Error && received instanceof Error) {
  234. return false;
  235. }
  236. if (
  237. expectedType === 'object' &&
  238. typeof expected.asymmetricMatch === 'function'
  239. ) {
  240. return false;
  241. }
  242. if (
  243. receivedType === 'object' &&
  244. typeof received.asymmetricMatch === 'function'
  245. ) {
  246. return false;
  247. }
  248. return true;
  249. };
  250. const printDiffOrStringify = (
  251. expected,
  252. received,
  253. expectedLabel,
  254. receivedLabel,
  255. expand
  256. ) => {
  257. if (typeof expected === 'string' && typeof received === 'string') {
  258. const result = (0, _jestDiff.getStringDiff)(expected, received, {
  259. aAnnotation: expectedLabel,
  260. bAnnotation: receivedLabel,
  261. expand
  262. });
  263. if (result !== null) {
  264. if (result.isMultiline) {
  265. return result.annotatedDiff;
  266. }
  267. const printLabel = getLabelPrinter(expectedLabel, receivedLabel);
  268. const expectedLine = printLabel(expectedLabel) + printExpected(result.a);
  269. const receivedLine = printLabel(receivedLabel) + printReceived(result.b);
  270. return expectedLine + '\n' + receivedLine;
  271. }
  272. }
  273. if (isLineDiffable(expected, received)) {
  274. const difference = (0, _jestDiff.default)(expected, received, {
  275. aAnnotation: expectedLabel,
  276. bAnnotation: receivedLabel,
  277. expand
  278. });
  279. if (
  280. typeof difference === 'string' &&
  281. difference.includes('- ' + expectedLabel) &&
  282. difference.includes('+ ' + receivedLabel)
  283. ) {
  284. return difference;
  285. }
  286. }
  287. const printLabel = getLabelPrinter(expectedLabel, receivedLabel);
  288. const expectedLine = printLabel(expectedLabel) + printExpected(expected);
  289. const receivedLine =
  290. printLabel(receivedLabel) +
  291. (stringify(expected) === stringify(received)
  292. ? 'serializes to the same string'
  293. : printReceived(received));
  294. return expectedLine + '\n' + receivedLine;
  295. }; // Sometimes, e.g. when comparing two numbers, the output from jest-diff
  296. // does not contain more information than the `Expected:` / `Received:` already gives.
  297. // In those cases, we do not print a diff to make the output shorter and not redundant.
  298. exports.printDiffOrStringify = printDiffOrStringify;
  299. const shouldPrintDiff = (actual, expected) => {
  300. if (typeof actual === 'number' && typeof expected === 'number') {
  301. return false;
  302. }
  303. if (typeof actual === 'boolean' && typeof expected === 'boolean') {
  304. return false;
  305. }
  306. return true;
  307. };
  308. const diff = (a, b, options) =>
  309. shouldPrintDiff(a, b) ? (0, _jestDiff.default)(a, b, options) : null;
  310. exports.diff = diff;
  311. const pluralize = (word, count) =>
  312. (NUMBERS[count] || count) + ' ' + word + (count === 1 ? '' : 's'); // To display lines of labeled values as two columns with monospace alignment:
  313. // given the strings which will describe the values,
  314. // return function which given each string, returns the label:
  315. // string, colon, space, and enough padding spaces to align the value.
  316. exports.pluralize = pluralize;
  317. const getLabelPrinter = (...strings) => {
  318. const maxLength = strings.reduce(
  319. (max, string) => (string.length > max ? string.length : max),
  320. 0
  321. );
  322. return string => `${string}: ${' '.repeat(maxLength - string.length)}`;
  323. };
  324. exports.getLabelPrinter = getLabelPrinter;
  325. const matcherErrorMessage = (
  326. hint,
  327. generic,
  328. specific // incorrect value returned from call to printWithType
  329. ) =>
  330. `${hint}\n\n${_chalk.default.bold(
  331. 'Matcher error'
  332. )}: ${generic}\n\n${specific}`; // Display assertion for the report when a test fails.
  333. // New format: rejects/resolves, not, and matcher name have black color
  334. // Old format: matcher name has dim color
  335. exports.matcherErrorMessage = matcherErrorMessage;
  336. const matcherHint = (
  337. matcherName,
  338. received = 'received',
  339. expected = 'expected',
  340. options = {}
  341. ) => {
  342. const _options$comment = options.comment,
  343. comment = _options$comment === void 0 ? '' : _options$comment,
  344. _options$expectedColo = options.expectedColor,
  345. expectedColor =
  346. _options$expectedColo === void 0 ? EXPECTED_COLOR : _options$expectedColo,
  347. _options$isDirectExpe = options.isDirectExpectCall,
  348. isDirectExpectCall =
  349. _options$isDirectExpe === void 0 ? false : _options$isDirectExpe,
  350. _options$isNot = options.isNot,
  351. isNot = _options$isNot === void 0 ? false : _options$isNot,
  352. _options$promise = options.promise,
  353. promise = _options$promise === void 0 ? '' : _options$promise,
  354. _options$receivedColo = options.receivedColor,
  355. receivedColor =
  356. _options$receivedColo === void 0 ? RECEIVED_COLOR : _options$receivedColo,
  357. _options$secondArgume = options.secondArgument,
  358. secondArgument =
  359. _options$secondArgume === void 0 ? '' : _options$secondArgume,
  360. _options$secondArgume2 = options.secondArgumentColor,
  361. secondArgumentColor =
  362. _options$secondArgume2 === void 0
  363. ? EXPECTED_COLOR
  364. : _options$secondArgume2;
  365. let hint = '';
  366. let dimString = 'expect'; // concatenate adjacent dim substrings
  367. if (!isDirectExpectCall && received !== '') {
  368. hint += DIM_COLOR(dimString + '(') + receivedColor(received);
  369. dimString = ')';
  370. }
  371. if (promise !== '') {
  372. hint += DIM_COLOR(dimString + '.') + promise;
  373. dimString = '';
  374. }
  375. if (isNot) {
  376. hint += DIM_COLOR(dimString + '.') + 'not';
  377. dimString = '';
  378. }
  379. if (matcherName.includes('.')) {
  380. // Old format: for backward compatibility,
  381. // especially without promise or isNot options
  382. dimString += matcherName;
  383. } else {
  384. // New format: omit period from matcherName arg
  385. hint += DIM_COLOR(dimString + '.') + matcherName;
  386. dimString = '';
  387. }
  388. if (expected === '') {
  389. dimString += '()';
  390. } else {
  391. hint += DIM_COLOR(dimString + '(') + expectedColor(expected);
  392. if (secondArgument) {
  393. hint += DIM_COLOR(', ') + secondArgumentColor(secondArgument);
  394. }
  395. dimString = ')';
  396. }
  397. if (comment !== '') {
  398. dimString += ' // ' + comment;
  399. }
  400. if (dimString !== '') {
  401. hint += DIM_COLOR(dimString);
  402. }
  403. return hint;
  404. };
  405. exports.matcherHint = matcherHint;