Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jest: expect object not to have property

I want to write a test that asserts a given object does not have certain properties.

Say I have a function

function removeFooAndBar(input) {
  delete input.foo;
  delete input.bar;
  return input;
}

Now I want to write a test:

describe('removeFooAndBar', () => {
  it('removes properties `foo` and `bar`', () => {
    const data = {
      foo: 'Foo',
      bar: 'Bar',
      baz: 'Baz',
    };
    expect(removeFooAndBar(data))
      .toEqual(expect.objectContaining({
        baz: 'Baz', // what's left
        foo: expect.not.exists() // pseudo
        bar: undefined // this doesn't work, and not what I want
      }));
  });
});

What's the proper way to assert this?

like image 896
joegomain Avatar asked Sep 12 '25 17:09

joegomain


1 Answers

Update after the discussion in the comments

You can use expect.not.objectContaining(). This approach works fine but has one unfortunate edge case: It matches when the property exists, but is undefined or null. To fix this you can explicitly add those values to be included in the check. You need the jest-extended package for the toBeOneOf() matcher.

expect({foo: undefined}).toEqual(expect.not.objectContaining(
    {foo: expect.toBeOneOf([expect.anything(), undefined, null])}
));

An example with nested props that fails:

const reallyAnything = expect.toBeOneOf([expect.anything(), undefined, null]);

expect({foo: undefined, bar: {baz: undefined}}).toEqual(
    expect.not.objectContaining(
        {
            foo: reallyAnything,
            bar: {baz: reallyAnything},
        }
    )
);

Original answer

What I'd do is to explicitly check whether the object has a property named bar or foo.

delete data.foo;
delete data.bar;
delete data.nested.property; 

expect(data).not.toHaveProperty('bar');
expect(data).not.toHaveProperty('foo');
expect(data.nested).not.toHaveProperty('property');
// or
expect(data).not.toHaveProperty('nested.property');

Or make this less repeating by looping over the properties that will be removed.

const toBeRemoved = ['foo', 'bar'];

toBeRemoved.forEach((prop) => {
    delete data[prop];
    expect(data).not.toHaveProperty(prop);
});

However, the loop approach isn't too great for possible nested objects. I believe what you are looking for is expect.not.objectContaining()

expect(data).toEqual(expect.not.objectContaining({foo: 'Foo', bar: 'Bar'}));

expect.not.objectContaining(object) matches any received object that does not recursively match the expected properties. That is, the expected object is not a subset of the received object. Therefore, it matches a received object which contains properties that are not in the expected object. - Jest Documentation

like image 81
Behemoth Avatar answered Sep 15 '25 06:09

Behemoth