index.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. 'use strict';
  2. var _prettyFormat = require('pretty-format');
  3. var _prettyFormat2 = _interopRequireDefault(_prettyFormat);
  4. var _chalk = require('chalk');
  5. var _chalk2 = _interopRequireDefault(_chalk);
  6. var _jestGetType = require('jest-get-type');
  7. var _jestGetType2 = _interopRequireDefault(_jestGetType);
  8. var _diff_strings = require('./diff_strings');
  9. var _diff_strings2 = _interopRequireDefault(_diff_strings);
  10. var _constants = require('./constants');
  11. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  12. /**
  13. * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
  14. *
  15. * This source code is licensed under the MIT license found in the
  16. * LICENSE file in the root directory of this source tree.
  17. *
  18. *
  19. */
  20. var _prettyFormat$plugins = _prettyFormat2.default.plugins;
  21. const AsymmetricMatcher = _prettyFormat$plugins.AsymmetricMatcher,
  22. DOMCollection = _prettyFormat$plugins.DOMCollection,
  23. DOMElement = _prettyFormat$plugins.DOMElement,
  24. Immutable = _prettyFormat$plugins.Immutable,
  25. ReactElement = _prettyFormat$plugins.ReactElement,
  26. ReactTestComponent = _prettyFormat$plugins.ReactTestComponent;
  27. const PLUGINS = [ReactTestComponent, ReactElement, DOMElement, DOMCollection, Immutable, AsymmetricMatcher];
  28. const FORMAT_OPTIONS = {
  29. plugins: PLUGINS
  30. };
  31. const FORMAT_OPTIONS_0 = Object.assign({}, FORMAT_OPTIONS, {
  32. indent: 0
  33. });
  34. const FALLBACK_FORMAT_OPTIONS = {
  35. callToJSON: false,
  36. maxDepth: 10,
  37. plugins: PLUGINS
  38. };
  39. const FALLBACK_FORMAT_OPTIONS_0 = Object.assign({}, FALLBACK_FORMAT_OPTIONS, {
  40. indent: 0
  41. });
  42. const MULTILINE_REGEXP = /[\r\n]/;
  43. // Generate a string that will highlight the difference between two values
  44. // with green and red. (similar to how github does code diffing)
  45. function diff(a, b, options) {
  46. if (a === b) {
  47. return _constants.NO_DIFF_MESSAGE;
  48. }
  49. const aType = (0, _jestGetType2.default)(a);
  50. let expectedType = aType;
  51. let omitDifference = false;
  52. if (aType === 'object' && typeof a.asymmetricMatch === 'function') {
  53. if (a.$$typeof !== Symbol.for('jest.asymmetricMatcher')) {
  54. // Do not know expected type of user-defined asymmetric matcher.
  55. return null;
  56. }
  57. if (typeof a.getExpectedType !== 'function') {
  58. // For example, expect.anything() matches either null or undefined
  59. return null;
  60. }
  61. expectedType = a.getExpectedType();
  62. // Primitive types boolean and number omit difference below.
  63. // For example, omit difference for expect.stringMatching(regexp)
  64. omitDifference = expectedType === 'string';
  65. }
  66. if (expectedType !== (0, _jestGetType2.default)(b)) {
  67. return ' Comparing two different types of values.' + ` Expected ${_chalk2.default.green(expectedType)} but ` + `received ${_chalk2.default.red((0, _jestGetType2.default)(b))}.`;
  68. }
  69. if (omitDifference) {
  70. return null;
  71. }
  72. switch (aType) {
  73. case 'string':
  74. const multiline = MULTILINE_REGEXP.test(a) && b.indexOf('\n') !== -1;
  75. if (multiline) {
  76. return (0, _diff_strings2.default)(a, b, options);
  77. }
  78. return null;
  79. case 'number':
  80. case 'boolean':
  81. return null;
  82. case 'map':
  83. return compareObjects(sortMap(a), sortMap(b), options);
  84. case 'set':
  85. return compareObjects(sortSet(a), sortSet(b), options);
  86. default:
  87. return compareObjects(a, b, options);
  88. }
  89. }
  90. function sortMap(map) {
  91. return new Map(Array.from(map.entries()).sort());
  92. }
  93. function sortSet(set) {
  94. return new Set(Array.from(set.values()).sort());
  95. }
  96. function compareObjects(a, b, options) {
  97. let diffMessage;
  98. let hasThrown = false;
  99. try {
  100. diffMessage = (0, _diff_strings2.default)((0, _prettyFormat2.default)(a, FORMAT_OPTIONS_0), (0, _prettyFormat2.default)(b, FORMAT_OPTIONS_0), options, {
  101. a: (0, _prettyFormat2.default)(a, FORMAT_OPTIONS),
  102. b: (0, _prettyFormat2.default)(b, FORMAT_OPTIONS)
  103. });
  104. } catch (e) {
  105. hasThrown = true;
  106. }
  107. // If the comparison yields no results, compare again but this time
  108. // without calling `toJSON`. It's also possible that toJSON might throw.
  109. if (!diffMessage || diffMessage === _constants.NO_DIFF_MESSAGE) {
  110. diffMessage = (0, _diff_strings2.default)((0, _prettyFormat2.default)(a, FALLBACK_FORMAT_OPTIONS_0), (0, _prettyFormat2.default)(b, FALLBACK_FORMAT_OPTIONS_0), options, {
  111. a: (0, _prettyFormat2.default)(a, FALLBACK_FORMAT_OPTIONS),
  112. b: (0, _prettyFormat2.default)(b, FALLBACK_FORMAT_OPTIONS)
  113. });
  114. if (diffMessage !== _constants.NO_DIFF_MESSAGE && !hasThrown) {
  115. diffMessage = _constants.SIMILAR_MESSAGE + '\n\n' + diffMessage;
  116. }
  117. }
  118. return diffMessage;
  119. }
  120. module.exports = diff;