Jest: objectContaining should be recursive but isn't

Created on 28 Aug 2020  路  1Comment  路  Source: facebook/jest

馃悰 Bug Report

I couldn't find a duplicate of this, even though it seems like something that could have come up before. The closest I found was #10186, which is related, but only tangentially.

expect.objectContaining does not work recursively as docs state.

To Reproduce

Here's a small test that will fail:

it('testy test test', () => {
  const expected = {
    a: 1,
    subProps: {
      someArray: [1],
    },
  }

  const received = {
    a: 1,
    subProps: {
      someArray: [1],
      someOtherArray: [],
    },
  }

  expect(received).toEqual(expect.objectContaining(expected))
})

Expected behavior

The test above should have passed according to the docs.

Link to repl or repo (highly encouraged)

Passing and failing tests here

envinfo

doesn't appear to be environment specific - repl and local machines both reproduce. I can add mine and repl's if it seems to be necessary.

workaround

use toMatchObject instead (which incidentally seems to have a nicer api)

additional info

If we look at toMatchObject vs objectContaining, the customTesters passed to the equals function differ - it looks like toMatchObject is actually true subset equality where objectContaining is only subset equality for the first level in the object - in this loop, recursion isn't happening.

Looks like there are two options to fix this: either objectContaining can implement a recursive asymmetricMatch, or it can share a code path with toMatchObject, since the two appear to be trying to accomplish the same goal (unless I'm missing something). The latter seems easier, at least on the surface, but I've not looked into it deeply.

It also looks like #10430 could potentially replace this fix, and objectContaining could become deprecated in favor of toMatchObject.

Bug Report Needs Repro Needs Triage

Most helpful comment

PR facebook/jest#10508 should fix this.

In the meantime, if you want the objectContaining behavior that you describe, you should also wrap expected-result sub-objects in objectContaining. The following test should pass:

it('testy test test', () => {
  const expected = expect.objectContaining({
    a: 1,
    subProps: expect.objectContaining({
      someArray: [1],
    }),
  });

  const received = {
    a: 1,
    subProps: {
      someArray: [1],
      someOtherArray: [],
    },
  };

  expect(received).toEqual(expected);
});

Or, of course, just use toMatchObject...

>All comments

PR facebook/jest#10508 should fix this.

In the meantime, if you want the objectContaining behavior that you describe, you should also wrap expected-result sub-objects in objectContaining. The following test should pass:

it('testy test test', () => {
  const expected = expect.objectContaining({
    a: 1,
    subProps: expect.objectContaining({
      someArray: [1],
    }),
  });

  const received = {
    a: 1,
    subProps: {
      someArray: [1],
      someOtherArray: [],
    },
  };

  expect(received).toEqual(expected);
});

Or, of course, just use toMatchObject...

Was this page helpful?
0 / 5 - 0 ratings

Related issues

udbhav picture udbhav  路  236Comments

seibelj picture seibelj  路  116Comments

vitalibozhko picture vitalibozhko  路  138Comments

SimenB picture SimenB  路  69Comments

timoxley picture timoxley  路  76Comments