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?
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},
}
)
);
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