7

I am writing a test case using jest in to test the data returned from a method.The method returns array of non repeating elements.Now i am trying to use expect() in jest to test whether the array returned from the method has only unique elements.

Returned array from method

arr = [ 'Pizza' ,'Burger' , 'HotDogs'] // All elements are unique

Are there any jest matchers like below to check non repeating elements in array ?

expect(arr).toBeUnique()

Or any logic using existing matchers should be done ?

Sathya Narayanan GVK
  • 849
  • 2
  • 16
  • 32
  • 1
    You can use the [`expect(arr).toIncludeSameMembers([...new Set(arr)])`](https://github.com/jest-community/jest-extended#toincludesamemembersmembers) – chridam Jul 12 '19 at 07:47

2 Answers2

17

There is no built on the method to check that array has a unique value, but I would suggest doing something like that:

const goods = [ 'Pizza' ,'Burger' , 'HotDogs'];
const isArrayUnique = arr => Array.isArray(arr) && new Set(arr).size === arr.length; // add function to check that array is unique.

expect(isArrayUnique(goods)).toBeTruthy();

You can use expect.extend to add your own matchers to Jest.

For example:

     expect.extend({
       toBeDistinct(received) {
         const pass = Array.isArray(received) && new Set(received).size === received.length;
         if (pass) {
           return {
             message: () => `expected [${received}] array is unique`,
             pass: true,
           };
         } else {
           return {
             message: () => `expected [${received}] array is not to unique`,
             pass: false,
           };
         }
       },
     });

and use it:

const goods = [ 'Pizza' ,'Burger' , 'HotDogs'];
const randomArr = [ 'Pizza' ,'Burger' , 'Pizza'];

expect(goods).toBeDistinct(); // Passed
expect(randomArr).toBeDistinct(); // Failed
Yevhen Laichenkov
  • 7,746
  • 2
  • 27
  • 33
  • By the way can you explain this line and what Set(recieved) mean.. `const pass = Array.isArray(received) && new Set(received).size === received.length;` – Sathya Narayanan GVK Jul 12 '19 at 08:41
  • 2
    yep, Array.isArray(receivedArray) - method determines whether the passed value is an Array. The `Set` is a new data structure introduced in ES6, a value in the `Set` may only occur once; it is unique in the Set's collection. So If we put the array with nonunique values to the `new Set(arr)` we will get an array with unique values, because as I said value in the `Set` only occur once. Then we just check the size of the new (with only unique values) array and received array and If the length of the array is not changed after `new Set(arr)` it means there are no unique values in the given array. – Yevhen Laichenkov Jul 12 '19 at 08:56
  • Note that this solution works, but only with literal array elements - with objects, the set will contain duplicate elements since it only performs a shallow equality check. [This answer](https://stackoverflow.com/a/49050668/168735) provides a working (if slightly nasty) workaround. – n00dle May 09 '20 at 14:07
0

This is very similar to Yevhen's answer but I've changed the error message to describe the first duplicate item encountered, like

item 3 is repeated in [1,2,3,3]

at the expense of sorting the array

expect.extend({
  toContainUniqueItems(received) {
    const items = [...(received || [])];
    items.sort();
    for (let i = 0; i < items.length - 1; i++) {
      if (items[i] === items[i + 1]) {
        return {
          pass: false,
          message: () => `item ${items[i]} is repeated in [${items}]`,
        };
      }
    }

    return {
      pass: true,
      message: () => `all items are unique in [${items}]`,
    };
  },
});
ESV
  • 7,620
  • 4
  • 39
  • 29