Hone logo
Hone
Problems

Implementing a Custom toHaveProperty Matcher in Jest (TypeScript)

Jest's matchers are the core of writing effective tests. While Jest provides a wide range of built-in matchers, sometimes you need to verify the existence and/or value of a specific property on an object. This challenge asks you to implement a custom toHaveProperty matcher for Jest, allowing you to assert that an object has a property with a specific name and optionally, a specific value. This is a common testing need and demonstrates how to extend Jest's functionality.

Problem Description

You need to create a Jest matcher that checks if an object has a property with a given name and, optionally, a specific value. The matcher should be reusable and handle various scenarios, including cases where the property doesn't exist, the value doesn't match, or the property is undefined.

What needs to be achieved:

  • Create a Jest matcher named toHaveProperty.
  • The matcher should accept a property name as the first argument.
  • The matcher should optionally accept a property value as the second argument.
  • If a value is provided, the matcher should verify that the property exists and its value matches the provided value.
  • If no value is provided, the matcher should only verify that the property exists.

Key Requirements:

  • The matcher must be implemented using TypeScript.
  • The matcher must be compatible with Jest's testing framework.
  • The matcher should provide clear and informative error messages when the assertion fails.
  • The matcher should handle edge cases gracefully (e.g., null or undefined objects).

Expected Behavior:

  • expect({ name: 'John' }).toHaveProperty('name') should pass.
  • expect({ name: 'John' }).toHaveProperty('age') should fail with a descriptive error message.
  • expect({ name: 'John', age: 30 }).toHaveProperty('age', 30) should pass.
  • expect({ name: 'John', age: 30 }).toHaveProperty('age', 31) should fail with a descriptive error message.
  • expect(null).toHaveProperty('name') should fail with a descriptive error message.
  • expect({}).toHaveProperty('name') should fail with a descriptive error message.

Edge Cases to Consider:

  • Null or undefined objects.
  • Objects without the specified property.
  • Property values that are null, undefined, or of unexpected types.
  • Property values that are objects or arrays (consider strict equality vs. deep equality). For this challenge, use strict equality (===).

Examples

Example 1:

Input: expect({ name: 'John', age: 30 }).toHaveProperty('name');
Output: Pass
Explanation: The object has the property 'name'.

Example 2:

Input: expect({ name: 'John' }).toHaveProperty('age', 30);
Output: Fail - Expected object to have property 'age' with value 30, but it does not exist.
Explanation: The object does not have the property 'age'.

Example 3:

Input: expect({ name: 'John', age: undefined }).toHaveProperty('age', undefined);
Output: Pass
Explanation: The object has the property 'age' and its value is undefined.

Constraints

  • The matcher must be implemented in TypeScript.
  • The matcher should be performant enough for typical Jest test scenarios. Avoid unnecessary iterations or complex operations.
  • The matcher should not introduce any external dependencies.
  • The matcher should be compatible with Jest versions 25 and above.

Notes

  • You'll need to create a Jest custom matcher file (e.g., src/matchers.ts) and export the matcher function.
  • Remember to register the custom matcher in your Jest configuration file (jest.config.js or jest.config.ts).
  • Consider using Jest's expect.extend function to register your matcher.
  • Focus on creating a clear and concise matcher with informative error messages.
  • The matcher should handle the case where the object is null or undefined gracefully.
Loading editor...
typescript