utils.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true
  4. });
  5. exports.isOneline = exports.isError = exports.partition = exports.typeEquality = exports.subsetEquality = exports.iterableEquality = exports.getObjectSubset = exports.getPath = exports.hasOwnProperty = undefined;
  6. exports.emptyObject = emptyObject;
  7. var _jasmine_utils = require('./jasmine_utils');
  8. const hasOwnProperty = (exports.hasOwnProperty = (object, value) =>
  9. Object.prototype.hasOwnProperty.call(object, value) ||
  10. Object.prototype.hasOwnProperty.call(object.constructor.prototype, value));
  11. /**
  12. * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
  13. *
  14. * This source code is licensed under the MIT license found in the
  15. * LICENSE file in the root directory of this source tree.
  16. *
  17. *
  18. */
  19. const getPath = (exports.getPath = (object, propertyPath) => {
  20. if (!Array.isArray(propertyPath)) {
  21. propertyPath = propertyPath.split('.');
  22. }
  23. if (propertyPath.length) {
  24. const lastProp = propertyPath.length === 1;
  25. const prop = propertyPath[0];
  26. const newObject = object[prop];
  27. if (!lastProp && (newObject === null || newObject === undefined)) {
  28. // This is not the last prop in the chain. If we keep recursing it will
  29. // hit a `can't access property X of undefined | null`. At this point we
  30. // know that the chain has broken and we can return right away.
  31. return {
  32. hasEndProp: false,
  33. lastTraversedObject: object,
  34. traversedPath: []
  35. };
  36. }
  37. const result = getPath(newObject, propertyPath.slice(1));
  38. if (result.lastTraversedObject === null) {
  39. result.lastTraversedObject = object;
  40. }
  41. result.traversedPath.unshift(prop);
  42. if (lastProp) {
  43. result.hasEndProp = hasOwnProperty(object, prop);
  44. if (!result.hasEndProp) {
  45. result.traversedPath.shift();
  46. }
  47. }
  48. return result;
  49. }
  50. return {
  51. lastTraversedObject: null,
  52. traversedPath: [],
  53. value: object
  54. };
  55. });
  56. // Strip properties from object that are not present in the subset. Useful for
  57. // printing the diff for toMatchObject() without adding unrelated noise.
  58. const getObjectSubset = (exports.getObjectSubset = (object, subset) => {
  59. if (Array.isArray(object)) {
  60. if (Array.isArray(subset) && subset.length === object.length) {
  61. return subset.map((sub, i) => getObjectSubset(object[i], sub));
  62. }
  63. } else if (object instanceof Date) {
  64. return object;
  65. } else if (
  66. typeof object === 'object' &&
  67. object !== null &&
  68. typeof subset === 'object' &&
  69. subset !== null
  70. ) {
  71. const trimmed = {};
  72. Object.keys(subset)
  73. .filter(key => hasOwnProperty(object, key))
  74. .forEach(
  75. key => (trimmed[key] = getObjectSubset(object[key], subset[key]))
  76. );
  77. if (Object.keys(trimmed).length > 0) {
  78. return trimmed;
  79. }
  80. }
  81. return object;
  82. });
  83. const IteratorSymbol = Symbol.iterator;
  84. const hasIterator = object => !!(object != null && object[IteratorSymbol]);
  85. const iterableEquality = (exports.iterableEquality = (a, b) => {
  86. if (
  87. typeof a !== 'object' ||
  88. typeof b !== 'object' ||
  89. Array.isArray(a) ||
  90. Array.isArray(b) ||
  91. !hasIterator(a) ||
  92. !hasIterator(b)
  93. ) {
  94. return undefined;
  95. }
  96. if (a.constructor !== b.constructor) {
  97. return false;
  98. }
  99. if (a.size !== undefined) {
  100. if (a.size !== b.size) {
  101. return false;
  102. } else if (
  103. (0, _jasmine_utils.isA)('Set', a) ||
  104. (0, _jasmine_utils.isImmutableUnorderedSet)(a)
  105. ) {
  106. let allFound = true;
  107. for (const aValue of a) {
  108. if (!b.has(aValue)) {
  109. let has = false;
  110. for (const bValue of b) {
  111. const isEqual = (0, _jasmine_utils.equals)(aValue, bValue, [
  112. iterableEquality
  113. ]);
  114. if (isEqual === true) {
  115. has = true;
  116. }
  117. }
  118. if (has === false) {
  119. allFound = false;
  120. break;
  121. }
  122. }
  123. }
  124. if (allFound) {
  125. return true;
  126. }
  127. } else if (
  128. (0, _jasmine_utils.isA)('Map', a) ||
  129. (0, _jasmine_utils.isImmutableUnorderedKeyed)(a)
  130. ) {
  131. let allFound = true;
  132. for (const aEntry of a) {
  133. if (
  134. !b.has(aEntry[0]) ||
  135. !(0, _jasmine_utils.equals)(aEntry[1], b.get(aEntry[0]), [
  136. iterableEquality
  137. ])
  138. ) {
  139. let has = false;
  140. for (const bEntry of b) {
  141. const matchedKey = (0, _jasmine_utils.equals)(
  142. aEntry[0],
  143. bEntry[0],
  144. [iterableEquality]
  145. );
  146. let matchedValue = false;
  147. if (matchedKey === true) {
  148. matchedValue = (0, _jasmine_utils.equals)(aEntry[1], bEntry[1], [
  149. iterableEquality
  150. ]);
  151. }
  152. if (matchedValue === true) {
  153. has = true;
  154. }
  155. }
  156. if (has === false) {
  157. allFound = false;
  158. break;
  159. }
  160. }
  161. }
  162. if (allFound) {
  163. return true;
  164. }
  165. }
  166. }
  167. const bIterator = b[IteratorSymbol]();
  168. for (const aValue of a) {
  169. const nextB = bIterator.next();
  170. if (
  171. nextB.done ||
  172. !(0, _jasmine_utils.equals)(aValue, nextB.value, [iterableEquality])
  173. ) {
  174. return false;
  175. }
  176. }
  177. if (!bIterator.next().done) {
  178. return false;
  179. }
  180. return true;
  181. });
  182. const isObjectWithKeys = a =>
  183. a !== null &&
  184. typeof a === 'object' &&
  185. !(a instanceof Error) &&
  186. !(a instanceof Array) &&
  187. !(a instanceof Date);
  188. const subsetEquality = (exports.subsetEquality = (object, subset) => {
  189. if (!isObjectWithKeys(subset)) {
  190. return undefined;
  191. }
  192. return Object.keys(subset).every(
  193. key =>
  194. object != null &&
  195. hasOwnProperty(object, key) &&
  196. (0, _jasmine_utils.equals)(object[key], subset[key], [
  197. iterableEquality,
  198. subsetEquality
  199. ])
  200. );
  201. });
  202. const typeEquality = (exports.typeEquality = (a, b) => {
  203. if (a == null || b == null || a.constructor.name === b.constructor.name) {
  204. return undefined;
  205. }
  206. return false;
  207. });
  208. const partition = (exports.partition = (items, predicate) => {
  209. const result = [[], []];
  210. items.forEach(item => result[predicate(item) ? 0 : 1].push(item));
  211. return result;
  212. });
  213. // Copied from https://github.com/graingert/angular.js/blob/a43574052e9775cbc1d7dd8a086752c979b0f020/src/Angular.js#L685-L693
  214. const isError = (exports.isError = value => {
  215. switch (Object.prototype.toString.call(value)) {
  216. case '[object Error]':
  217. return true;
  218. case '[object Exception]':
  219. return true;
  220. case '[object DOMException]':
  221. return true;
  222. default:
  223. return value instanceof Error;
  224. }
  225. });
  226. function emptyObject(obj) {
  227. return obj && typeof obj === 'object' ? !Object.keys(obj).length : false;
  228. }
  229. const MULTILINE_REGEXP = /[\r\n]/;
  230. const isOneline = (exports.isOneline = (expected, received) =>
  231. typeof expected === 'string' &&
  232. typeof received === 'string' &&
  233. (!MULTILINE_REGEXP.test(expected) || !MULTILINE_REGEXP.test(received)));