toEqual assertion does not work with objects where the values are anonymous functions, like this:
const foo = {a:_in=>_in}
const bar = {a:_in=>_in}
It really surprised me.
Write a test like this:
describe('toEqual', () => {
it('should handle an anonymous function', () => {
const foo = {a:_in=>_in}
const bar = {a:_in=>_in}
expect(foo).toEqual(bar)
})
})
I expected the following two objects to be equal:
const foo = {a:_in=>_in}
const bar = {a:_in=>_in}
https://repl.it/repls/DefinitiveMintyHypercard
Paste the results here:
Jest v22.1.2 node v7.4.0 linux/amd64
FAIL ./toEqual-test.js
toEqual
✓ handles a simple object (5ms)
✓ handles a function as object value
✕ shuld handle an anonymous function (9ms)
● toEqual › shuld handle an anonymous function
expect(received).toEqual(expected)
Expected value to equal:
{"a": [Function a]}
Received:
{"a": [Function a]}
Difference:
Compared values have no visual difference.
16 | const foo = {a:_in=>identity(_in)}
17 | const bar = {a:_in=>identity(_in)}
> 18 | expect(foo).toEqual(bar)
19 | })
20 | })
21 |
at Object.it (toEqual-test.js:18:15)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 2 passed, 3 total
Snapshots: 0 total
Time: 0.978s, estimated 1s
Ran all test suites.
exit status 1
@pedrottimark thoughts on this one?
Why would they be equal? I think functions are compared using reference equality
To exclude methods when you compare data properties, we recommend .toMatchObject
The consensus of libraries is referential identity, as Tim said in previous comment:
const concordance = require('concordance');
const lodash = require('lodash');
const underscore = require('underscore');
const util = require('util'); // node 9.0.0 or later
describe('function', () => {
const a = {a: _in => _in};
const b = {a: _in => _in};
test('concordance', () => {
expect(concordance.compare(a, b).pass).toBe(false);
});
test('lodash', () => {
expect(lodash.isEqual(a, b)).toBe(false);
});
test('jest', () => {
expect(a).not.toEqual(b);
});
test('node', () => {
expect(util.isDeepStrictEqual(a, b)).toBe(false);
});
test('underscore', () => {
expect(underscore.isEqual(a, b)).toBe(false);
});
});
These are compelling arguments! And they do make clear the way things are implemented.
Still as a developer testing my code, I'm inclined to see this a useful assertion to make in my tests: two objects with the same shaped anonymous function hanging off it are equal for the purpose of my application. I think it's a pretty common scenario.
I guess it's a chance to write my own assertion.
Yes, it was a surprise to me.
Another alternative is snapshot test because serialization of anonymous function is equivalent.
@rmoskal expect.any(constructor) is another alternative:
test('asymmetric matcher', () => {
const expected = {a: expect.any(Function)};
const received = {a: _in => _in};
expect(received).toEqual(expected);
});
That'll do.
Most helpful comment
@rmoskal expect.any(constructor) is another alternative: