Hone logo
Hone
Problems

Implementing a Custom arrayContaining Matcher for Jest

Jest's built-in matchers are powerful, but sometimes you need a custom one to handle specific scenarios. This challenge asks you to implement a custom Jest matcher that checks if an array contains all the elements of another array, regardless of order. This is useful for verifying that a function returns an array with the expected elements, even if they're not in the same order as the input.

Problem Description

You need to create a Jest custom matcher called arrayContaining. This matcher should take an array as an argument and determine if the array being tested contains all the elements of the provided argument array. The order of elements does not matter.

Key Requirements:

  • The matcher should be case-sensitive when comparing elements (if the arrays contain strings).
  • The matcher should handle arrays containing primitive types (numbers, strings, booleans) and objects. For objects, the matcher should perform a deep equality check using Object.is.
  • The matcher should return true if the array being tested contains all elements of the argument array, and false otherwise.
  • The matcher should provide a descriptive failure message if the test fails, indicating which elements were missing.

Expected Behavior:

When used in a Jest test, the matcher should behave similarly to Jest's built-in toContain matcher, but for multiple elements.

Edge Cases to Consider:

  • Empty arrays: An empty array should be considered to contain all elements of another empty array.
  • Arrays with duplicate elements: The matcher should correctly handle arrays with duplicate elements in either the tested array or the argument array.
  • Arrays containing null and undefined: These values should be compared correctly.
  • Arrays containing objects: Deep equality check is required for objects.
  • Arrays with different data types: The matcher should handle arrays containing mixed data types.

Examples

Example 1:

Input: arrayContaining([1, 2])
Array being tested: [2, 1, 3]
Output: true
Explanation: The array [2, 1, 3] contains both 1 and 2, regardless of order.

Example 2:

Input: arrayContaining([1, 4])
Array being tested: [1, 2, 3]
Output: false
Explanation: The array [1, 2, 3] does not contain 4.

Example 3:

Input: arrayContaining([ { a: 1 }, { b: 2 } ])
Array being tested: [ { b: 2 }, { a: 1 } ]
Output: true
Explanation: The array contains both objects, even though their order is different.  Object.is is used for deep comparison.

Example 4:

Input: arrayContaining([1, 1, 2])
Array being tested: [1, 2, 1]
Output: true
Explanation: Duplicate elements are handled correctly.

Constraints

  • The matcher must be implemented in TypeScript.
  • The matcher should be performant enough to not significantly slow down test execution. Avoid unnecessary iterations or complex operations.
  • The matcher should be compatible with Jest versions 25 and above.
  • The matcher should not modify the original arrays.

Notes

  • You'll need to use Jest's expect and matcherHint functions to create the custom matcher.
  • Consider using Object.is for deep equality checks of objects. This is important for accurate comparisons.
  • Think about how to provide a helpful failure message that clearly indicates which elements are missing from the array being tested.
  • Remember that the order of elements in the arrays does not matter.
  • The matcher should be reusable and testable independently of the Jest testing framework. While it's integrated with Jest, the core logic should be well-defined.
Loading editor...
typescript