Implementing a Custom toBeCloseTo Matcher in Jest
Jest's built-in matchers are powerful, but sometimes you need more specialized comparisons, particularly when dealing with floating-point numbers. This challenge asks you to implement a custom Jest matcher called toBeCloseTo that allows you to assert that two numbers are approximately equal within a specified tolerance. This is crucial for avoiding flaky tests caused by minor floating-point inaccuracies.
Problem Description
You need to create a Jest matcher named toBeCloseTo. This matcher should compare two numbers and determine if they are "close enough" to each other, based on a provided tolerance value. The matcher should return true if the difference between the two numbers is less than or equal to the tolerance, and false otherwise. The matcher should be robust and handle various scenarios, including negative numbers and zero tolerance.
Key Requirements:
- Accepts a Tolerance: The matcher must accept a single argument representing the tolerance value. This value determines how close the numbers need to be to be considered equal.
- Number Comparison: The matcher should compare two numbers.
- Tolerance Check: The matcher should calculate the absolute difference between the two numbers and compare it to the tolerance.
- Clear Error Message: If the numbers are not close enough, the matcher should provide a clear and informative error message indicating the expected value, the received value, and the tolerance used.
- Handles Negative Numbers: The matcher should correctly handle negative numbers.
- Handles Zero Tolerance: The matcher should correctly handle a tolerance of zero.
Expected Behavior:
toBeCloseTo(tolerance)should be called as a matcher function.- The matcher should return
trueif the absolute difference between the two numbers being compared is less than or equal to the tolerance. - The matcher should return
falseif the absolute difference is greater than the tolerance. - If the matcher fails, it should produce a descriptive error message.
Edge Cases to Consider:
- NaN: Handle cases where either input is
NaN.NaNshould always fail the comparison. - Infinity: Handle cases where either input is
Infinityor-Infinity. - Zero Tolerance: What should happen when the tolerance is zero?
- Negative Tolerance: While not strictly required, consider how to handle negative tolerance values (should they be treated as invalid?). For simplicity, you can assume tolerance will always be non-negative.
Examples
Example 1:
Input: 1.001, 1.002, 0.005
Output: true
Explanation: The absolute difference between 1.001 and 1.002 is 0.001, which is less than or equal to the tolerance of 0.005.
Example 2:
Input: -2.5, -2.6, 0.1
Output: true
Explanation: The absolute difference between -2.5 and -2.6 is 0.1, which is less than or equal to the tolerance of 0.1.
Example 3:
Input: 5, 5.1, 0.05
Output: false
Explanation: The absolute difference between 5 and 5.1 is 0.1, which is greater than the tolerance of 0.05. The error message should clearly indicate this.
Example 4:
Input: 3.14, 3.14159, 0.0001
Output: true
Explanation: The absolute difference is 0.00159, which is less than 0.0001.
Constraints
- The tolerance value must be a non-negative number.
- The matcher must be implemented using TypeScript.
- The matcher should be compatible with Jest's existing matcher infrastructure.
- The matcher should not introduce any significant performance overhead.
Notes
- You'll need to understand how to create custom matchers in Jest. Refer to the Jest documentation for guidance: https://jestjs.io/docs/creating-custom-matchers
- Consider using
expect.extendto register your custom matcher. - Pay close attention to the error messages generated when the matcher fails. They should be clear and helpful for debugging.
- Think about how to handle edge cases like
NaNandInfinitygracefully. Returningfalseand a descriptive error message is generally appropriate.