JestJs π Delightful JavaScript Testing
It is really delightful as the team states! For the last couple of years that is accompanying me in my daily struggles, it has shown it's worth. One of the best parts is the partial match on object, array and function, which will be the focus of this blog post.
Partially matching objects
Let's say you need to test a unit that changes just parts of an object. It is indifferent of the remaining parts of the object. Your unit test should check just the changes the unit influences.
In the code block below, a simple fixture containing some nested objects and arrays, which will be used in the following examples:
const resultFixtureObject = {
active: true,
id: 'e0e0e0e0-2b79-4eba-ab39-b2dfdb2f0eba',
firstName: 'Jester',
lastName: 'Magic',
finances: {
incomes: [
{
type: 'salary',
amount: 150000,
currency: '$',
},
{
type: 'dividend',
amount: 6000,
currency: '$',
},
{
type: 'rent',
amount: 12000,
currency: '$',
},
],
},
};
Match object
In the test below, the expected result object must match a few properties:
expect(resultFixtureObject).toEqual(
expect.objectContaining({
active: true,
id: 'e0e0e0e0-2b79-4eba-ab39-b2dfdb2f0eba',
firstName: 'Jester',
lastName: 'Magic',
})
);
Match nested object
You can match nested objects by simply nesting objectContaining() expectations. In this case, expecting object finances that must have nested object incomes. We do not care about the content of the incomes, in this unit test:
expect(resultFixtureObject).toEqual(
expect.objectContaining({
finances: expect.objectContaining({
incomes: expect.anything()
})
})
);
Partially matching arrays
Just as the objects, there is a way to partially match arrays. You can expect single or multiple item matches on an array.
Expecting one item to match:
expect(resultFixtureObject).toEqual(
expect.objectContaining({
finances: expect.objectContaining({
incomes: expect.arrayContaining([
{
type: 'rent',
amount: 12000,
currency: '$',
},
]),
}),
})
);
or multiple, complete or partial matches:
expect(resultFixtureObject).toEqual(
expect.objectContaining({
finances: expect.objectContaining({
incomes: expect.arrayContaining([
{
type: 'rent',
amount: 12000,
currency: '$',
},
expect.objectContaining({
type: 'salary',
}),
]),
}),
})
);
Partially matching function parameter calls
Aforementioned operations can be applied to toHaveBeenCalledWith() matcher as well.
Below a variant with toHaveBeenNthCalledWith() matcher. Verifying just the third call to the function:
const functionMock = jest.fn();
functionMock('string arg');
functionMock(['array arg']);
functionMock(resultFixtureObject);
expect(functionMock).toHaveBeenNthCalledWith(
3,
expect.objectContaining({
finances: expect.objectContaining({
incomes: expect.arrayContaining([
expect.objectContaining({
type: 'rent',
}),
expect.objectContaining({
type: 'salary',
}),
]),
}),
})
);
Complete test file with comments inside
describe('Jest Expect Partial Match', () => { | |
const resultFixtureObject = { | |
active: true, | |
id: 'e0e0e0e0-2b79-4eba-ab39-b2dfdb2f0eba', | |
firstName: 'Jester', | |
lastName: 'Magic', | |
finances: { | |
incomes: [ | |
{ | |
type: 'salary', | |
amount: 150000, | |
currency: '$', | |
}, | |
{ | |
type: 'dividend', | |
amount: 6000, | |
currency: '$', | |
}, | |
{ | |
type: 'rent', | |
amount: 12000, | |
currency: '$', | |
}, | |
], | |
}, | |
}; | |
it('should expect partial match on object', async () => { | |
//partial match | |
expect(resultFixtureObject).toEqual( | |
expect.objectContaining({ | |
active: true, | |
id: 'e0e0e0e0-2b79-4eba-ab39-b2dfdb2f0eba', | |
firstName: 'Jester', | |
lastName: 'Magic', | |
}) | |
); | |
//nested object match | |
expect(resultFixtureObject).toEqual( | |
expect.objectContaining({ | |
finances: expect.objectContaining({ | |
incomes: expect.anything() | |
}), | |
}) | |
); | |
//partial match | |
//match finances object contains incomes object/array | |
//incomes array contains specific item | |
expect(resultFixtureObject).toEqual( | |
expect.objectContaining({ | |
finances: expect.objectContaining({ | |
incomes: expect.arrayContaining([ | |
{ | |
type: 'rent', | |
amount: 12000, | |
currency: '$', | |
}, | |
]), | |
}), | |
}) | |
); | |
//partial match | |
//match finances object contains incomes object/array | |
//incomes array contains item rent and partial item where type is salary | |
expect(resultFixtureObject).toEqual( | |
expect.objectContaining({ | |
finances: expect.objectContaining({ | |
incomes: expect.arrayContaining([ | |
{ | |
type: 'rent', | |
amount: 12000, | |
currency: '$', | |
}, | |
expect.objectContaining({ | |
type: 'salary', | |
}), | |
]), | |
}), | |
}) | |
); | |
}); | |
it('should expect function to be called with', async () => { | |
const functionMock = jest.fn(); | |
functionMock('string arg'); | |
functionMock(['array arg']); | |
functionMock(resultFixtureObject); | |
//third call to the function was made with object | |
//array contains objects with 'rent' and 'salary' types | |
expect(functionMock).toHaveBeenNthCalledWith( | |
3, | |
expect.objectContaining({ | |
finances: expect.objectContaining({ | |
incomes: expect.arrayContaining([ | |
expect.objectContaining({ | |
type: 'rent', | |
}), | |
expect.objectContaining({ | |
type: 'salary', | |
}), | |
]), | |
}), | |
}) | |
); | |
}); | |
}); |
Top comments (0)