I'm testing that an object matches a set of fields, but one of them is floating point and I need to use .toBeCloseTo. How can that be done within one expect?
expect(foo).toMatchObject({
bar: 'baz',
value: ???.toBeCloseTo(5), // TODO
});
I could use expect(foo.value).toBeCloseTo(5)
, but I don't want to break the logic into multiple expect
s, one for each floating point number.
Issue
The docs for toMatchObject
states "You can match properties against values or against matchers".
Unfortunately, toBeCloseTo
is not currently available as an asymmetric matcher, it looks like these are the only asymmetric matchers currently provided by Jest.
Solution
If you are using Jest v23 or higher you can create your own, essentially duplicating toBeCloseTo
using expect.extend
:
expect.extend({
toBeAround(actual, expected, precision = 2) {
const pass = Math.abs(expected - actual) < Math.pow(10, -precision) / 2;
if (pass) {
return {
message: () => `expected ${actual} not to be around ${expected}`,
pass: true
};
} else {
return {
message: () => `expected ${actual} to be around ${expected}`,
pass: false
}
}
}
});
const foo = {
bar: 'baz',
value: 4.9999
};
test('foo', () => {
expect(foo.value).toBeAround(5, 3); // SUCCESS in Jest > v20
expect(foo).toMatchObject({
bar: 'baz',
value: expect.toBeAround(5, 3) // SUCCESS only in Jest > v23
});
});
Note that expect.extend
creates a matcher that can be used within functions like toMatchObject
only in Jest v23 and higher.
Alternate Solution
From this post by a Jest collaborator: "Although it is implied but not currently documented, Jest assertions evaluate asymmetric matcher objects as defined in Jasmine".
An asymmetric matcher using the logic from toBeCloseTo
can be created like this:
const closeTo = (expected, precision = 2) => ({
asymmetricMatch: (actual) => Math.abs(expected - actual) < Math.pow(10, -precision) / 2
});
const foo = {
bar: 'baz',
value: 4.9999
};
test('foo', () => {
expect(foo).toMatchObject({
bar: 'baz',
value: closeTo(5, 3) // SUCCESS
});
});