Skip to content

Commit

Permalink
add isError check
Browse files Browse the repository at this point in the history
  • Loading branch information
barakyosi committed Feb 19, 2021
1 parent 5ed7693 commit 9bedd5a
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 38 deletions.
37 changes: 36 additions & 1 deletion src/calculateDeepEqualDiffs.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
isArray, isPlainObject, isDate,
isRegExp, isFunction, isSet,
isRegExp, isError, isFunction, isSet,
has,
} from 'lodash';

Expand Down Expand Up @@ -127,6 +127,41 @@ function accumulateDeepEqualDiffs(a, b, diffsAccumulator, pathString = '', { det
return trackDiff(a, b, diffsAccumulator, pathString, diffTypes.function);
}

if (isError(a) && isError(b)) {
const keys = Object.getOwnPropertyNames(a);
if (keys.length !== Object.getOwnPropertyNames(b).length) {
return trackDiff(a, b, diffsAccumulator, pathString, diffTypes.different);
}
// Do not compare the stack as it might differ even though the errors are identical.
const relevantKeys = keys.filter(k => k !== 'stack');

for (let i = relevantKeys.length; i--; i > 0) {
if (!has(b, relevantKeys[i])) {
return trackDiff(a, b, diffsAccumulator, pathString, diffTypes.different);
}
}

const objectValuesDiffs = [];
let numberOfDeepEqualsObjectValues = 0;
for (let i = relevantKeys.length; i--; i > 0) {
const key = relevantKeys[i];
const deepEquals = accumulateDeepEqualDiffs(a[key], b[key], objectValuesDiffs, `${pathString}.${key}`, { detailed });
if (deepEquals) {
numberOfDeepEqualsObjectValues++;
}
}

if (detailed || numberOfDeepEqualsObjectValues !== relevantKeys.length) {
diffsAccumulator.push(...objectValuesDiffs);
}

if (numberOfDeepEqualsObjectValues === relevantKeys.length) {
return trackDiff(a, b, diffsAccumulator, pathString, diffTypes.deepEquals);
}

return trackDiff(a, b, diffsAccumulator, pathString, diffTypes.different);
}

if (typeof a === 'object' && typeof b === 'object' && Object.getPrototypeOf(a) === Object.getPrototypeOf(b)) {
const keys = Object.getOwnPropertyNames(a);
const keysLength = keys.length;
Expand Down
120 changes: 83 additions & 37 deletions tests/calculateDeepEqualDiffs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -459,47 +459,93 @@ test('mix', () => {
},
]);
});
describe('calculateDeepEqualDiffs - Errors', () => {
test('Equal Native Errors', () => {
const prevValue = new Error('message');
const nextValue = new Error('message');
const diffs = calculateDeepEqualDiffs(prevValue, nextValue);
expect(diffs).toEqual([
{
pathString: '',
prevValue,
nextValue,
diffType: diffTypes.deepEquals,
},
]);
});

test('Different Native Errors', () => {
const prevValue = new Error('message');
const nextValue = new Error('Second message');
const diffs = calculateDeepEqualDiffs(prevValue, nextValue);
expect(diffs).toEqual([
{
pathString: '.message',
prevValue: 'message',
nextValue: 'Second message',
diffType: diffTypes.different,
},
{
pathString: '',
prevValue,
nextValue,
diffType: diffTypes.different,
},
]);
});

test('Equal Custom Errors', () => {
class CustomError extends Error {
constructor(message, code) {
super(message);
this.name = 'ValidationError';
this.code = code;
}
}

test('Equal Errors', () => {
const sharedStack = new Error().stack;
const prevValue = new Error('message');
const nextValue = new Error('message');
prevValue.stack = sharedStack;
nextValue.stack = sharedStack;
const diffs = calculateDeepEqualDiffs(prevValue, nextValue);
expect(diffs).toEqual([
{
pathString: '',
prevValue,
nextValue,
diffType: diffTypes.deepEquals,
},
]);
});
const prevValue = new CustomError('message', 1001);
const nextValue = new CustomError('message', 1001);
const diffs = calculateDeepEqualDiffs(prevValue, nextValue);
expect(diffs).toEqual([
{
pathString: '',
prevValue,
nextValue,
diffType: diffTypes.deepEquals,
},
]);
});

test('Different Custom Errors', () => {
class CustomError extends Error {
constructor(message, code) {
super(message);
this.name = 'ValidationError';
this.code = code;
}
}

test('Different Errors', () => {
const sharedStack = new Error().stack;
const prevValue = new Error('message');
const nextValue = new Error('Second message');
prevValue.stack = sharedStack;
nextValue.stack = sharedStack;
const diffs = calculateDeepEqualDiffs(prevValue, nextValue);
expect(diffs).toEqual([
{
pathString: '.message',
prevValue: 'message',
nextValue: 'Second message',
diffType: diffTypes.different,
},
{
pathString: '',
prevValue,
nextValue,
diffType: diffTypes.different,
},
]);
const prevValue = new CustomError('message', 1001);
const nextValue = new CustomError('message', 1002);
const diffs = calculateDeepEqualDiffs(prevValue, nextValue);
expect(diffs).toEqual([
{
pathString: '.code',
prevValue: 1001,
nextValue: 1002,
diffType: diffTypes.different,
},
{
pathString: '',
prevValue,
nextValue,
diffType: diffTypes.different,
},
]);
});
});


test('Equal class instances', () => {
class Person {
constructor(name) {
Expand Down
39 changes: 39 additions & 0 deletions tests/logOnDifferentValues.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,42 @@ test('hook value change', () => {
expect.objectContaining({ displayName: 'Foo' }),
]);
});

test('Non simple objects', () => {
const Foo = React.memo(function Foo({ error }) {
return (
<div>
<h1>{error.message}</h1>
<p>{error.stack}</p>
</div>
);
});

const App = React.memo(function App() {
const [text, setText] = React.useState('Click me');

return (
<div className="App">
<button
onClick={() => setText(state => state + '.')}
data-testid="button"
>
{text}
</button>
<hr/>
<Foo error={new Error('message')}/>
</div>
);
});

const { getByTestId } = rtl.render(
<App/>
);

const button = getByTestId('button');
rtl.fireEvent.click(button);

expect(updateInfos[1].reason.propsDifferences[0]).toEqual(
expect.objectContaining({ diffType: 'deepEquals', 'pathString': 'error' }),
);
});

0 comments on commit 9bedd5a

Please sign in to comment.