483 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			483 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | ||
| 
 | ||
| Object.defineProperty(exports, '__esModule', {
 | ||
|   value: true
 | ||
| });
 | ||
| exports.emptyObject = emptyObject;
 | ||
| exports.isOneline = exports.isError = exports.partition = exports.sparseArrayEquality = exports.typeEquality = exports.subsetEquality = exports.iterableEquality = exports.getObjectSubset = exports.getPath = exports.hasOwnProperty = void 0;
 | ||
| 
 | ||
| var _jestGetType = require('jest-get-type');
 | ||
| 
 | ||
| var _jasmineUtils = require('./jasmineUtils');
 | ||
| 
 | ||
| var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol;
 | ||
| 
 | ||
| // Return whether object instance inherits getter from its class.
 | ||
| const hasGetterFromConstructor = (object, key) => {
 | ||
|   const constructor = object.constructor;
 | ||
| 
 | ||
|   if (constructor === Object) {
 | ||
|     // A literal object has Object as constructor.
 | ||
|     // Therefore, it cannot inherit application-specific getters.
 | ||
|     // Furthermore, Object has __proto__ getter which is not relevant.
 | ||
|     // Array, Boolean, Number, String constructors don’t have any getters.
 | ||
|     return false;
 | ||
|   }
 | ||
| 
 | ||
|   if (typeof constructor !== 'function') {
 | ||
|     // Object.create(null) constructs object with no constructor nor prototype.
 | ||
|     // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Custom_and_Null_objects
 | ||
|     return false;
 | ||
|   }
 | ||
| 
 | ||
|   const descriptor = Object.getOwnPropertyDescriptor(
 | ||
|     constructor.prototype,
 | ||
|     key
 | ||
|   );
 | ||
|   return descriptor !== undefined && typeof descriptor.get === 'function';
 | ||
| };
 | ||
| 
 | ||
| const hasOwnProperty = (object, key) =>
 | ||
|   Object.prototype.hasOwnProperty.call(object, key) ||
 | ||
|   hasGetterFromConstructor(object, key);
 | ||
| 
 | ||
| exports.hasOwnProperty = hasOwnProperty;
 | ||
| 
 | ||
| const getPath = (object, propertyPath) => {
 | ||
|   if (!Array.isArray(propertyPath)) {
 | ||
|     propertyPath = propertyPath.split('.');
 | ||
|   }
 | ||
| 
 | ||
|   if (propertyPath.length) {
 | ||
|     const lastProp = propertyPath.length === 1;
 | ||
|     const prop = propertyPath[0];
 | ||
|     const newObject = object[prop];
 | ||
| 
 | ||
|     if (!lastProp && (newObject === null || newObject === undefined)) {
 | ||
|       // This is not the last prop in the chain. If we keep recursing it will
 | ||
|       // hit a `can't access property X of undefined | null`. At this point we
 | ||
|       // know that the chain has broken and we can return right away.
 | ||
|       return {
 | ||
|         hasEndProp: false,
 | ||
|         lastTraversedObject: object,
 | ||
|         traversedPath: []
 | ||
|       };
 | ||
|     }
 | ||
| 
 | ||
|     const result = getPath(newObject, propertyPath.slice(1));
 | ||
| 
 | ||
|     if (result.lastTraversedObject === null) {
 | ||
|       result.lastTraversedObject = object;
 | ||
|     }
 | ||
| 
 | ||
|     result.traversedPath.unshift(prop);
 | ||
| 
 | ||
|     if (lastProp) {
 | ||
|       // Does object have the property with an undefined value?
 | ||
|       // Although primitive values support bracket notation (above)
 | ||
|       // they would throw TypeError for in operator (below).
 | ||
|       result.hasEndProp =
 | ||
|         newObject !== undefined ||
 | ||
|         (!(0, _jestGetType.isPrimitive)(object) && prop in object);
 | ||
| 
 | ||
|       if (!result.hasEndProp) {
 | ||
|         result.traversedPath.shift();
 | ||
|       }
 | ||
|     }
 | ||
| 
 | ||
|     return result;
 | ||
|   }
 | ||
| 
 | ||
|   return {
 | ||
|     lastTraversedObject: null,
 | ||
|     traversedPath: [],
 | ||
|     value: object
 | ||
|   };
 | ||
| }; // Strip properties from object that are not present in the subset. Useful for
 | ||
| // printing the diff for toMatchObject() without adding unrelated noise.
 | ||
| 
 | ||
| exports.getPath = getPath;
 | ||
| 
 | ||
| const getObjectSubset = (object, subset) => {
 | ||
|   if (Array.isArray(object)) {
 | ||
|     if (Array.isArray(subset) && subset.length === object.length) {
 | ||
|       return subset.map((sub, i) => getObjectSubset(object[i], sub));
 | ||
|     }
 | ||
|   } else if (object instanceof Date) {
 | ||
|     return object;
 | ||
|   } else if (
 | ||
|     typeof object === 'object' &&
 | ||
|     object !== null &&
 | ||
|     typeof subset === 'object' &&
 | ||
|     subset !== null
 | ||
|   ) {
 | ||
|     const trimmed = {};
 | ||
|     Object.keys(subset)
 | ||
|       .filter(key => hasOwnProperty(object, key))
 | ||
|       .forEach(
 | ||
|         key => (trimmed[key] = getObjectSubset(object[key], subset[key]))
 | ||
|       );
 | ||
| 
 | ||
|     if (Object.keys(trimmed).length > 0) {
 | ||
|       return trimmed;
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   return object;
 | ||
| };
 | ||
| 
 | ||
| exports.getObjectSubset = getObjectSubset;
 | ||
| const IteratorSymbol = Symbol.iterator;
 | ||
| 
 | ||
| const hasIterator = object => !!(object != null && object[IteratorSymbol]);
 | ||
| 
 | ||
| const iterableEquality = (a, b, aStack = [], bStack = []) => {
 | ||
|   if (
 | ||
|     typeof a !== 'object' ||
 | ||
|     typeof b !== 'object' ||
 | ||
|     Array.isArray(a) ||
 | ||
|     Array.isArray(b) ||
 | ||
|     !hasIterator(a) ||
 | ||
|     !hasIterator(b)
 | ||
|   ) {
 | ||
|     return undefined;
 | ||
|   }
 | ||
| 
 | ||
|   if (a.constructor !== b.constructor) {
 | ||
|     return false;
 | ||
|   }
 | ||
| 
 | ||
|   let length = aStack.length;
 | ||
| 
 | ||
|   while (length--) {
 | ||
|     // Linear search. Performance is inversely proportional to the number of
 | ||
|     // unique nested structures.
 | ||
|     // circular references at same depth are equal
 | ||
|     // circular reference is not equal to non-circular one
 | ||
|     if (aStack[length] === a) {
 | ||
|       return bStack[length] === b;
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   aStack.push(a);
 | ||
|   bStack.push(b);
 | ||
| 
 | ||
|   const iterableEqualityWithStack = (a, b) =>
 | ||
|     iterableEquality(a, b, [...aStack], [...bStack]);
 | ||
| 
 | ||
|   if (a.size !== undefined) {
 | ||
|     if (a.size !== b.size) {
 | ||
|       return false;
 | ||
|     } else if (
 | ||
|       (0, _jasmineUtils.isA)('Set', a) ||
 | ||
|       (0, _jasmineUtils.isImmutableUnorderedSet)(a)
 | ||
|     ) {
 | ||
|       let allFound = true;
 | ||
|       var _iteratorNormalCompletion = true;
 | ||
|       var _didIteratorError = false;
 | ||
|       var _iteratorError = undefined;
 | ||
| 
 | ||
|       try {
 | ||
|         for (
 | ||
|           var _iterator = a[Symbol.iterator](), _step;
 | ||
|           !(_iteratorNormalCompletion = (_step = _iterator.next()).done);
 | ||
|           _iteratorNormalCompletion = true
 | ||
|         ) {
 | ||
|           const aValue = _step.value;
 | ||
| 
 | ||
|           if (!b.has(aValue)) {
 | ||
|             let has = false;
 | ||
|             var _iteratorNormalCompletion2 = true;
 | ||
|             var _didIteratorError2 = false;
 | ||
|             var _iteratorError2 = undefined;
 | ||
| 
 | ||
|             try {
 | ||
|               for (
 | ||
|                 var _iterator2 = b[Symbol.iterator](), _step2;
 | ||
|                 !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next())
 | ||
|                   .done);
 | ||
|                 _iteratorNormalCompletion2 = true
 | ||
|               ) {
 | ||
|                 const bValue = _step2.value;
 | ||
|                 const isEqual = (0, _jasmineUtils.equals)(aValue, bValue, [
 | ||
|                   iterableEqualityWithStack
 | ||
|                 ]);
 | ||
| 
 | ||
|                 if (isEqual === true) {
 | ||
|                   has = true;
 | ||
|                 }
 | ||
|               }
 | ||
|             } catch (err) {
 | ||
|               _didIteratorError2 = true;
 | ||
|               _iteratorError2 = err;
 | ||
|             } finally {
 | ||
|               try {
 | ||
|                 if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
 | ||
|                   _iterator2.return();
 | ||
|                 }
 | ||
|               } finally {
 | ||
|                 if (_didIteratorError2) {
 | ||
|                   throw _iteratorError2;
 | ||
|                 }
 | ||
|               }
 | ||
|             }
 | ||
| 
 | ||
|             if (has === false) {
 | ||
|               allFound = false;
 | ||
|               break;
 | ||
|             }
 | ||
|           }
 | ||
|         } // Remove the first value from the stack of traversed values.
 | ||
|       } catch (err) {
 | ||
|         _didIteratorError = true;
 | ||
|         _iteratorError = err;
 | ||
|       } finally {
 | ||
|         try {
 | ||
|           if (!_iteratorNormalCompletion && _iterator.return != null) {
 | ||
|             _iterator.return();
 | ||
|           }
 | ||
|         } finally {
 | ||
|           if (_didIteratorError) {
 | ||
|             throw _iteratorError;
 | ||
|           }
 | ||
|         }
 | ||
|       }
 | ||
| 
 | ||
|       aStack.pop();
 | ||
|       bStack.pop();
 | ||
|       return allFound;
 | ||
|     } else if (
 | ||
|       (0, _jasmineUtils.isA)('Map', a) ||
 | ||
|       (0, _jasmineUtils.isImmutableUnorderedKeyed)(a)
 | ||
|     ) {
 | ||
|       let allFound = true;
 | ||
|       var _iteratorNormalCompletion3 = true;
 | ||
|       var _didIteratorError3 = false;
 | ||
|       var _iteratorError3 = undefined;
 | ||
| 
 | ||
|       try {
 | ||
|         for (
 | ||
|           var _iterator3 = a[Symbol.iterator](), _step3;
 | ||
|           !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done);
 | ||
|           _iteratorNormalCompletion3 = true
 | ||
|         ) {
 | ||
|           const aEntry = _step3.value;
 | ||
| 
 | ||
|           if (
 | ||
|             !b.has(aEntry[0]) ||
 | ||
|             !(0, _jasmineUtils.equals)(aEntry[1], b.get(aEntry[0]), [
 | ||
|               iterableEqualityWithStack
 | ||
|             ])
 | ||
|           ) {
 | ||
|             let has = false;
 | ||
|             var _iteratorNormalCompletion4 = true;
 | ||
|             var _didIteratorError4 = false;
 | ||
|             var _iteratorError4 = undefined;
 | ||
| 
 | ||
|             try {
 | ||
|               for (
 | ||
|                 var _iterator4 = b[Symbol.iterator](), _step4;
 | ||
|                 !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next())
 | ||
|                   .done);
 | ||
|                 _iteratorNormalCompletion4 = true
 | ||
|               ) {
 | ||
|                 const bEntry = _step4.value;
 | ||
|                 const matchedKey = (0, _jasmineUtils.equals)(
 | ||
|                   aEntry[0],
 | ||
|                   bEntry[0],
 | ||
|                   [iterableEqualityWithStack]
 | ||
|                 );
 | ||
|                 let matchedValue = false;
 | ||
| 
 | ||
|                 if (matchedKey === true) {
 | ||
|                   matchedValue = (0, _jasmineUtils.equals)(
 | ||
|                     aEntry[1],
 | ||
|                     bEntry[1],
 | ||
|                     [iterableEqualityWithStack]
 | ||
|                   );
 | ||
|                 }
 | ||
| 
 | ||
|                 if (matchedValue === true) {
 | ||
|                   has = true;
 | ||
|                 }
 | ||
|               }
 | ||
|             } catch (err) {
 | ||
|               _didIteratorError4 = true;
 | ||
|               _iteratorError4 = err;
 | ||
|             } finally {
 | ||
|               try {
 | ||
|                 if (!_iteratorNormalCompletion4 && _iterator4.return != null) {
 | ||
|                   _iterator4.return();
 | ||
|                 }
 | ||
|               } finally {
 | ||
|                 if (_didIteratorError4) {
 | ||
|                   throw _iteratorError4;
 | ||
|                 }
 | ||
|               }
 | ||
|             }
 | ||
| 
 | ||
|             if (has === false) {
 | ||
|               allFound = false;
 | ||
|               break;
 | ||
|             }
 | ||
|           }
 | ||
|         } // Remove the first value from the stack of traversed values.
 | ||
|       } catch (err) {
 | ||
|         _didIteratorError3 = true;
 | ||
|         _iteratorError3 = err;
 | ||
|       } finally {
 | ||
|         try {
 | ||
|           if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
 | ||
|             _iterator3.return();
 | ||
|           }
 | ||
|         } finally {
 | ||
|           if (_didIteratorError3) {
 | ||
|             throw _iteratorError3;
 | ||
|           }
 | ||
|         }
 | ||
|       }
 | ||
| 
 | ||
|       aStack.pop();
 | ||
|       bStack.pop();
 | ||
|       return allFound;
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   const bIterator = b[IteratorSymbol]();
 | ||
|   var _iteratorNormalCompletion5 = true;
 | ||
|   var _didIteratorError5 = false;
 | ||
|   var _iteratorError5 = undefined;
 | ||
| 
 | ||
|   try {
 | ||
|     for (
 | ||
|       var _iterator5 = a[Symbol.iterator](), _step5;
 | ||
|       !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done);
 | ||
|       _iteratorNormalCompletion5 = true
 | ||
|     ) {
 | ||
|       const aValue = _step5.value;
 | ||
|       const nextB = bIterator.next();
 | ||
| 
 | ||
|       if (
 | ||
|         nextB.done ||
 | ||
|         !(0, _jasmineUtils.equals)(aValue, nextB.value, [
 | ||
|           iterableEqualityWithStack
 | ||
|         ])
 | ||
|       ) {
 | ||
|         return false;
 | ||
|       }
 | ||
|     }
 | ||
|   } catch (err) {
 | ||
|     _didIteratorError5 = true;
 | ||
|     _iteratorError5 = err;
 | ||
|   } finally {
 | ||
|     try {
 | ||
|       if (!_iteratorNormalCompletion5 && _iterator5.return != null) {
 | ||
|         _iterator5.return();
 | ||
|       }
 | ||
|     } finally {
 | ||
|       if (_didIteratorError5) {
 | ||
|         throw _iteratorError5;
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   if (!bIterator.next().done) {
 | ||
|     return false;
 | ||
|   } // Remove the first value from the stack of traversed values.
 | ||
| 
 | ||
|   aStack.pop();
 | ||
|   bStack.pop();
 | ||
|   return true;
 | ||
| };
 | ||
| 
 | ||
| exports.iterableEquality = iterableEquality;
 | ||
| 
 | ||
| const isObjectWithKeys = a =>
 | ||
|   a !== null &&
 | ||
|   typeof a === 'object' &&
 | ||
|   !(a instanceof Error) &&
 | ||
|   !(a instanceof Array) &&
 | ||
|   !(a instanceof Date);
 | ||
| 
 | ||
| const subsetEquality = (object, subset) => {
 | ||
|   if (!isObjectWithKeys(subset)) {
 | ||
|     return undefined;
 | ||
|   }
 | ||
| 
 | ||
|   return Object.keys(subset).every(
 | ||
|     key =>
 | ||
|       object != null &&
 | ||
|       hasOwnProperty(object, key) &&
 | ||
|       (0, _jasmineUtils.equals)(object[key], subset[key], [
 | ||
|         iterableEquality,
 | ||
|         subsetEquality
 | ||
|       ])
 | ||
|   );
 | ||
| };
 | ||
| 
 | ||
| exports.subsetEquality = subsetEquality;
 | ||
| 
 | ||
| const typeEquality = (a, b) => {
 | ||
|   if (a == null || b == null || a.constructor === b.constructor) {
 | ||
|     return undefined;
 | ||
|   }
 | ||
| 
 | ||
|   return false;
 | ||
| };
 | ||
| 
 | ||
| exports.typeEquality = typeEquality;
 | ||
| 
 | ||
| const sparseArrayEquality = (a, b) => {
 | ||
|   if (!Array.isArray(a) || !Array.isArray(b)) {
 | ||
|     return undefined;
 | ||
|   } // A sparse array [, , 1] will have keys ["2"] whereas [undefined, undefined, 1] will have keys ["0", "1", "2"]
 | ||
| 
 | ||
|   const aKeys = Object.keys(a);
 | ||
|   const bKeys = Object.keys(b);
 | ||
|   return (
 | ||
|     (0, _jasmineUtils.equals)(a, b, [iterableEquality, typeEquality], true) &&
 | ||
|     (0, _jasmineUtils.equals)(aKeys, bKeys)
 | ||
|   );
 | ||
| };
 | ||
| 
 | ||
| exports.sparseArrayEquality = sparseArrayEquality;
 | ||
| 
 | ||
| const partition = (items, predicate) => {
 | ||
|   const result = [[], []];
 | ||
|   items.forEach(item => result[predicate(item) ? 0 : 1].push(item));
 | ||
|   return result;
 | ||
| }; // Copied from https://github.com/graingert/angular.js/blob/a43574052e9775cbc1d7dd8a086752c979b0f020/src/Angular.js#L685-L693
 | ||
| 
 | ||
| exports.partition = partition;
 | ||
| 
 | ||
| const isError = value => {
 | ||
|   switch (Object.prototype.toString.call(value)) {
 | ||
|     case '[object Error]':
 | ||
|       return true;
 | ||
| 
 | ||
|     case '[object Exception]':
 | ||
|       return true;
 | ||
| 
 | ||
|     case '[object DOMException]':
 | ||
|       return true;
 | ||
| 
 | ||
|     default:
 | ||
|       return value instanceof Error;
 | ||
|   }
 | ||
| };
 | ||
| 
 | ||
| exports.isError = isError;
 | ||
| 
 | ||
| function emptyObject(obj) {
 | ||
|   return obj && typeof obj === 'object' ? !Object.keys(obj).length : false;
 | ||
| }
 | ||
| 
 | ||
| const MULTILINE_REGEXP = /[\r\n]/;
 | ||
| 
 | ||
| const isOneline = (expected, received) =>
 | ||
|   typeof expected === 'string' &&
 | ||
|   typeof received === 'string' &&
 | ||
|   (!MULTILINE_REGEXP.test(expected) || !MULTILINE_REGEXP.test(received));
 | ||
| 
 | ||
| exports.isOneline = isOneline;
 |