155

I have written the following test:

it('Can decrement the current step', function () {
 expect(reducer(TestState, { type: 'GOTO_PREVIOUS_STEP' })).toMatchObject({ currentStep: 4 });
});
it('Can decrement the current step v2', function () {
 expect(reducer(TestState, { type: 'GOTO_PREVIOUS_STEP' })).toEqual(expect.objectContaining({ currentStep: 4 }));
});

both of them seem to pass the test, is there any difference between them? is there a performance impact between them?

Canta
1,4802 gold badges13 silver badges26 bronze badges
asked Aug 15, 2017 at 12:02

3 Answers 3

231

From looking at the docs, and my own experimentation to confirm it, the difference is in the handling of objects nested within the props passed as an expectation.

If the expectation object has a property, containing an object, which contains some but not all of the properties in the equivalent property of the actual object, then:

  • .toMatchObject() will still pass, as seen in the docs.

  • expect.objectContaining() will fail (unless you declare that property in the expectation object itself with expect.objectContaining())

Examples (tested in Jest):

 // objectContaining, with nested object, containing full props/values
 // PASSES
 expect({ position: { x: 0, y: 0 } }).toEqual(expect.objectContaining({
 position: {
 x: expect.any(Number),
 y: expect.any(Number)
 }
 }));
 // objectContaining, with nested object, containing partial props/values
 // FAILS
 expect({ position: { x: 0, y: 0 } }).toEqual(expect.objectContaining({
 position: {
 x: expect.any(Number)
 }
 }));
 // objectContaining, with nested object, also declared with objectContaining, containing partial props/values
 // PASSES
 expect({ position: { x: 0, y: 0 } }).toEqual(expect.objectContaining({
 position: expect.objectContaining({
 x: expect.any(Number)
 })
 }));
 // toMatchObject, with nested object, containing full props/values
 // PASSES
 expect({ position: { x: 0, y: 0 } }).toMatchObject({
 position: {
 x: expect.any(Number),
 y: expect.any(Number)
 }
 });
 // toMatchObject, with nested object, containing partial props/values
 // PASSES
 expect({ position: { x: 0, y: 0 } }).toMatchObject({
 position: {
 x: expect.any(Number)
 }
 });
Audwin Oyong
2,5273 gold badges21 silver badges37 bronze badges
answered Oct 22, 2017 at 16:26
Sign up to request clarification or add additional context in comments.

3 Comments

"There are only two hard things in Computer Science: cache invalidation and naming things"
Great answer. The names of these matchers is the opposite of what I initially thought they would be.
18

My thinking is that expect.objectContaining (and other matchers like it) can be used instead of literal values inside the "object" you pass to other matchers.

This example is from the docs:

test('onPress gets called with the right thing', () => {
 const onPress = jest.fn();
 simulatePresses(onPress);
 expect(onPress).toBeCalledWith(expect.objectContaining({
 x: expect.any(Number),
 y: expect.any(Number),
 }));
});

So, while they seem to do the same thing in your example, the expect.* ones are also useful in this other way.

Paul T. Rawkeen
4,1133 gold badges38 silver badges53 bronze badges
answered Aug 21, 2017 at 23:03

Comments

11

Even without functional differences between the two constructs, here's an example as to why expect.objectContaining - though long and cumbersome compared to toMatchObject, can be useful:

describe('list of X', () => {
 it('should contain an element with a specific ID', () => {
 const listOfItems = uut.getItems();
 expect(listOfItems).toContainEqual(expect.objectContaining({id: 'some-id'}));
 });
});

Even if listOfItems contains items as such (i.e. with fields other than just the 'id') --

[
 {id: 'some-id', other: 'fields'},
 {id: 'some-other-id', even: 'more-fields'}
]

still expect.objectContaining allows for a simple way of implementing the comparison as you'd expect (i.e. based strictly on the id); toMatchObject cannot be used here at all. So while toMatchObject is short and readable, the longer construct of the two is more generic and allows for greater flexibility as it can be utilized in ways that toMatchObject() can't.

answered May 22, 2018 at 12:32

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.