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'); } |