Hone logo
Hone
Problems

Implementing expect.extend in Jest for Custom Matchers

Jest's expect.extend allows you to add custom matchers to the expect assertion library, making your tests more readable and expressive. This challenge asks you to implement a basic expect.extend functionality that allows users to register custom matchers with descriptive names and logic. This is crucial for writing tests that are tailored to your specific application's domain and data structures.

Problem Description

You need to implement a function extendExpect that takes a Jest expect object and a matcher factory function as input. The matcher factory function should accept a single argument (the value being asserted) and return an object with pass and message properties. The pass property should be a boolean indicating whether the assertion passed, and the message property should be a string providing a descriptive message for both passing and failing assertions. The extendExpect function should then add this custom matcher to the expect object.

Key Requirements:

  • The extendExpect function must accept a Jest expect object and a matcher factory function.
  • The matcher factory function must return an object with pass and message properties.
  • The extendExpect function must add the custom matcher to the expect object, allowing it to be used in assertions.
  • The added matcher should be accessible via a string name provided to the matcher factory.
  • The message property of the returned object should be a function that accepts the expected and received values and returns a string.

Expected Behavior:

When extendExpect is called with a valid expect object and matcher factory, the custom matcher should be available on the expect object. Assertions using the custom matcher should behave as expected, with appropriate passing and failing messages.

Edge Cases to Consider:

  • What happens if the matcher factory function doesn't return an object with pass and message properties? (Consider throwing an error or logging a warning).
  • What happens if the expect object is invalid (e.g., not a Jest expect object)? (Consider throwing an error).
  • How to handle multiple matchers with the same name? (The last registered matcher should overwrite previous ones).

Examples

Example 1:

Input:
expect: Jest's expect object
matcherFactory: (value) => ({ pass: value > 5, message: (received, expected) => `Expected ${received} to be greater than ${expected}` })
matcherName: "toBeGreaterThan5"

Output:
expect(7).toBeGreaterThan5() // Passes
expect(3).toBeGreaterThan5() // Fails with message "Expected 3 to be greater than 5"

Example 2:

Input:
expect: Jest's expect object
matcherFactory: (value) => ({ pass: value === "hello", message: (received, expected) => `Expected "${received}" to be "${expected}"` })
matcherName: "toBeHello"

Output:
expect("hello").toBeHello() // Passes
expect("world").toBeHello() // Fails with message "Expected "world" to be "hello""

Example 3: (Edge Case - Invalid Matcher Factory)

Input:
expect: Jest's expect object
matcherFactory: (value) => "not an object"
matcherName: "invalidMatcher"

Output:
Error: Matcher factory must return an object with 'pass' and 'message' properties.

Constraints

  • The extendExpect function should be compatible with standard Jest versions.
  • The matcher factory function should be synchronous.
  • The message function should accept two arguments: the received value and the expected value.
  • The extendExpect function should not modify the original expect object directly; it should add the matcher as a new property.
  • The matcher name should be a string.

Notes

  • You'll need to understand how Jest's expect object works internally to implement this effectively. Consider how Jest handles custom matchers.
  • Focus on creating a robust and well-documented solution.
  • Error handling is important – consider what should happen if the input is invalid.
  • Think about how to make the extendExpect function reusable and easy to use.
  • The message function is crucial for providing informative error messages. Make sure it's well-formatted and includes the relevant values.
Loading editor...
typescript