I often use and come across a pattern like this when reading and writing tests:
test('should contain specific value in object', () => {
const object = {
specific: 'specific value',
other: 'other',
};
expect(object).toEqual(expect.objectContaining({
specific: 'specific value'
}));
d});
why would you go for something like that over the following example:
test('should contain specific value in object', () => {
const object = {
specific: 'specific value',
other: 'other',
};
expect(object.specific).toEqual('specific value');
d});
The second example feels more readable and still achieves the same goal, so what’s the advantage to the first one?
>Solution :
Compare these three tests:
describe("object comparison", () => {
const wrongObject = { foo: "bar" };
it("compares property directly", () => {
expect(wrongObject.specific).toEqual("specific value");
});
it("uses asymmetric matcher", () => {
expect(wrongObject).toEqual(expect.objectContaining({
specific: "specific value",
}));
});
it("uses property matcher", () => {
expect(wrongObject).toHaveProperty("specific", "specific value");
});
});
If they passed, there wouldn’t be much to choose between them, they express the same thing in different ways. But when they fail, compare:
● object comparison › compares property directly
expect(received).toEqual(expected) // deep equality
Expected: "specific value"
Received: undefined
3 |
4 | it("compares property directly", () => {
> 5 | expect(wrongObject.specific).toEqual("specific value");
| ^
6 | });
7 |
8 | it("uses asymmetric matcher", () => {
at Object.toEqual (path/to/demo.test.js:5:32)
● object comparison › uses asymmetric matcher
expect(received).toEqual(expected) // deep equality
- Expected - 2
+ Received + 2
- ObjectContaining {
- "specific": "specific value",
+ Object {
+ "foo": "bar",
}
7 |
8 | it("uses asymmetric matcher", () => {
> 9 | expect(wrongObject).toEqual(expect.objectContaining({
| ^
10 | specific: "specific value",
11 | }));
12 | });
at Object.toEqual (path/to/demo.test.js:9:23)
● object comparison › uses property matcher
expect(received).toHaveProperty(path, value)
Expected path: "specific"
Received path: []
Expected value: "specific value"
Received value: {"foo": "bar"}
13 |
14 | it("uses property matcher", () => {
> 15 | expect(wrongObject).toHaveProperty("specific", "specific value");
| ^
16 | });
17 | });
18 |
at Object.toHaveProperty (path/to/demo.test.js:15:23)
The more information the test gives you about why exactly it failed ("diagnostics", to use the language from Growing Object-Oriented Software Guided by Tests by Steve Freeman and Nat Pryce), the easier it will be to figure out the problem if it does. This is one of the advantages of test-driven development; you always see the output of the failing test.