All files / src/testing-helpers/jasmine-matchers to-deep-equal.matcher.ts

100% Statements 52/52
100% Branches 43/43
100% Functions 11/11
100% Lines 52/52
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120    1x   47x   47x 47x   47x 15x 15x 28x   15x 15x 27x     47x               47x 4x     43x 1x     42x 8x     34x 73x 73x 73x 73x 14x       20x                     135x   475x 168x     307x 307x 50x     257x 3x     254x   254x 254x 3x     251x 251x 21x     108x       254x         332x 2x   330x 135x   195x         79x 115x 24x   24x     91x            
import {isEqual} from 'lodash';
 
export const toDeepEqualMatcher = {
  toDeepEqual: (util) => {
    return {
        compare: function(actuals, expecteds) {
          const test = compareArrays(actuals, expecteds);
          const result = { pass: (test === 'pass'), message: `compareArrays say: ${test}` + '\n\n' };
 
          if (!result.pass && Array.isArray(actuals) && Array.isArray(expecteds)) {
            result.message += 'Actual \n';
            actuals.forEach(function(x) {
              result.message += stringify(x) + '\n';
            });
            result.message += '\nExpected \n';
            expecteds.forEach(function(x) {
              result.message += stringify(x) + '\n';
            });
          }
          return result;
        }
    };
  }
};
 
function compareArrays(actuals, expecteds): any {
 
  if ((actuals !== null && expecteds === null) || (actuals === null && expecteds !== null)) {
    return 'Failed: Non-null does not compare to null';
  }
 
  if (actuals.length !== expecteds.length) {
    return 'Failed: Arrays not the same length';
  }
 
  if (!Array.isArray(actuals) || !Array.isArray(expecteds)) {
    return compareValues(expecteds, actuals, -1);
  }
 
  for (let idx = 0; idx < expecteds.length; idx++ ) {
    const expected = expecteds[idx];
    const actual = actuals[idx];
    const result = compareValues(actual, expected, idx);
    if (result !== 'pass') {
      return result;
    }
  };
 
  return 'pass';
}
 
/*
  Compares objects irrespective of the property ordering
  and only compares those properties supplied in 'expected'
  Saves a bit of refactoring in tests when 'actual' property order changes,
  or new properties are added that are irrelevent to the test
*/
function compareProperties(actual, expected, idx): any {
 
  for (const key in expected) {
 
    if (typeof expected[key] === 'function') {
      continue;  // ignore function properties
    }
 
    const value = expected[key];
    if (value === undefined) {
      continue;
    }
 
    if (!actual.hasOwnProperty(key)) {
      return `Index: ${idx}, Actual has no property '${key}'`;
    }
 
    const otherValue = actual[key];
 
    const types = compareTypes(value, otherValue, key, idx);
    if (types !== 'pass') {
      return types;
    }
 
    const values = compareValues(value, otherValue, idx);
    if (values !== 'pass') {
      return values;
    }
  }
  return 'pass';
}
 
function compareTypes(value, otherValue, key, idx): any {
  return typeof value === typeof otherValue ? 'pass'
    : `Index: ${idx}, Key: '${key}', Types differ ('${typeof value}' vs '${typeof otherValue}')`;
}
 
function compareValues(value, otherValue, idx): any {
  if ((value !== null && otherValue === null) || (value === null && otherValue !== null)) {
    return 'Failed: Non-null does not compare to null';
  }
  if (typeof value === 'object') {
    return compareProperties(value, otherValue, idx);
  }
  return value === otherValue ? 'pass'
    : `Index: ${idx}, Not objects, values differ (${value} vs ${otherValue})`;
}
 
function stringify(x) {
  return JSON.stringify(x, function(key, value) {
    if (Array.isArray(value)) {
      return '[' + value
        .map(function(i) {
          return '\n\t' + stringify(i);
        }) + '\n]';
    }
    return value;
  })
    .replace(/\\"/g, '"')
    .replace(/\\t/g, '\t')
    .replace(/\\n/g, '\n');
}