Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the difference between '.toMatchObject' and 'objectContaining'

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?

like image 285
Julito Sanchis Avatar asked Aug 15 '17 12:08

Julito Sanchis


People also ask

What is toMatchObject?

toMatchObject() This assertion checks javascript object satisfies a value. values are compared using structural equality.

What is the difference between toBe and toEqual?

toEqual and the . toBe are equivalent, because the first thing they both check is if the values are strictly equal. So performance wise there is no difference. . toEqual just handles more cases if the strict equality fails on non-primatives.

What is deep equality in jest?

this.equals(a, b) ​ This is a deep-equality function that will return true if two objects have the same values (recursively).

How do you expect a function in jest?

The expect function is used every time you want to test a value. You will rarely call expect by itself. Instead, you will use expect along with a "matcher" function to assert something about a value. In this case, toBe is the matcher function.


2 Answers

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)     }   }); 
like image 144
Jonathan Avatar answered Oct 05 '22 12:10

Jonathan


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.

like image 24
David Avatar answered Oct 05 '22 11:10

David