Create a toMatchObject Matcher for Jest
Writing custom Jest matchers extends Jest's capabilities, allowing you to create assertions tailored to your specific needs. This challenge asks you to implement a toMatchObject matcher that deeply compares a received value against an expected object, providing helpful error messages when discrepancies are found. This is useful for verifying complex data structures and ensuring that objects have the expected properties and values.
Problem Description
You need to create a Jest matcher called toMatchObject. This matcher will take an expected object as an argument and compare it against the received value. The comparison should be a deep equality check, meaning it should recursively compare nested objects and arrays.
Key Requirements:
- Deep Equality: The matcher must perform a deep comparison, not just a shallow one.
- Informative Error Messages: When the received value does not match the expected object, the matcher should provide clear and helpful error messages indicating the differences. The error message should highlight which properties are missing, have incorrect values, or have unexpected types.
- Handles Arrays: The matcher must correctly handle arrays within the objects being compared.
- Handles Primitive Types: The matcher must correctly handle primitive types (string, number, boolean, null, undefined) within the objects.
Expected Behavior:
- If the received value is deeply equal to the expected object, the matcher should pass.
- If the received value is not deeply equal to the expected object, the matcher should fail, providing a detailed error message.
Edge Cases to Consider:
- Null and Undefined: Handle cases where either the received value or the expected object contains
nullorundefined. - Circular References: While not strictly required, consider how your matcher would behave (or not behave) with circular references. A simple error message indicating circular references is acceptable.
- Different Types: Handle cases where properties have different types than expected.
- Extra Properties: Handle cases where the received value has properties that are not present in the expected object.
Examples
Example 1:
Input:
received: { a: 1, b: { c: 2 } }
expected: { a: 1, b: { c: 2 } }
Output: expect(received).toMatchObject(expected) passes.
Explanation: The received object is deeply equal to the expected object.
Example 2:
Input:
received: { a: 1, b: { c: 3 } }
expected: { a: 1, b: { c: 2 } }
Output: expect(received).toMatchObject(expected) fails with an error message similar to: "Expected object to deeply equal:\n {\n a: 1,\n b: {\n c: 2\n }\n },\n but received:\n {\n a: 1,\n b: {\n c: 3\n }\n }"
Explanation: The value of property b.c is different.
Example 3:
Input:
received: { a: 1, b: { c: 2 }, d: 4 }
expected: { a: 1, b: { c: 2 } }
Output: expect(received).toMatchObject(expected) fails with an error message similar to: "Expected object to deeply equal:\n {\n a: 1,\n b: {\n c: 2\n }\n },\n but received:\n {\n a: 1,\n b: {\n c: 2\n },\n d: 4\n }"
Explanation: The received object has an extra property d.
Example 4:
Input:
received: { a: 1, b: null }
expected: { a: 1, b: undefined }
Output: expect(received).toMatchObject(expected) fails with an error message indicating the difference in b.
Constraints
- The matcher must be implemented in TypeScript.
- The matcher should be reasonably performant for objects with a moderate number of properties (up to 100). Optimization for extremely large objects is not required.
- The matcher should not throw errors during the comparison process. Instead, it should gracefully handle differences and provide informative error messages.
- The matcher should be compatible with Jest's existing assertion framework.
Notes
- You'll need to define the matcher as a Jest
expect.extendfunction. - Consider using a recursive helper function to perform the deep comparison.
- Pay close attention to the formatting of the error messages to ensure they are clear and easy to understand. Consistent indentation is key.
- Think about how to handle different data types gracefully. A simple type check can be helpful.
- This is a good opportunity to practice your TypeScript skills and your understanding of Jest's testing framework.