Is there an Array equality match function that ignores element position in jest.js?

85,499

Solution 1

There is no built-in method to compare arrays without comparing the order, but you can simply sort the arrays using .sort() before making a comparison:

expect(["ping wool", "diorite"].sort()).toEqual(["diorite", "pink wool"].sort());

You can check the example in this fiddle.

Solution 2

Put the elements into a set. Jest knows how to match these.

expect(new Set(["pink wool", "diorite"])).toEqual(new Set(["diorite", "pink wool"]));

Solution 3

As already mentioned expect.arrayContaining checks if the actual array contains the expected array as a subset. To check for equivalence one may

  • either assert that the length of both arrays is the same (but that wouldn't result in a helpful failure message)
  • or assert the reverse: That the expected array contains the actual array:
// This is TypeScript, but remove the types and you get JavaScript
const expectArrayEquivalence = <T>(actual: T[], expected: T[]) => {
  expect(actual).toEqual(expect.arrayContaining(expected));
  expect(expected).toEqual(expect.arrayContaining(actual));
};

This still has the problem that when the test fails in the first assertion one is only made aware of the elements missing from actual and not of the extra ones that are not in expected.

Solution 4

this does not answer the question exactly, but still may help people that end up here by google search:

if you only care that a subset of the array has certain elements, use expect.arrayContaining() https://jestjs.io/docs/en/expect#expectarraycontainingarray

e.g.,

expect(["ping wool", "diorite"])
  .toEqual(expect.arrayContaining(["diorite", "pink wool"]));

Solution 5

Another way is to use the custom matcher .toIncludeSameMembers() from jest-community/jest-extended.

Example given from the README

test('passes when arrays match in a different order', () => {
    expect([1, 2, 3]).toIncludeSameMembers([3, 1, 2]);
    expect([{ foo: 'bar' }, { baz: 'qux' }]).toIncludeSameMembers([{ baz: 'qux' }, { foo: 'bar' }]);
});

It might not make sense to import a library just for one matcher but they have a lot of other useful matchers I've find useful.

Share:
85,499
Benjamin H Boruff
Author by

Benjamin H Boruff

I build stuff.

Updated on January 20, 2022

Comments

  • Benjamin H Boruff
    Benjamin H Boruff over 2 years

    I get that .toEqual() checks equality of all fields for plain objects:

    expect(
        {"key1":"pink  wool","key2":"diorite"}
    ).toEqual(
        {"key2":"diorite","key1":"pink wool"}
    );
    

    So this passes.

    But the same is not true for arrays:

    expect(["pink wool", "diorite"]).toEqual(["diorite", "pink wool"]);
    

    There does not seem to be a matcher function that does this in the jest docs, i.e. that tests for the equality of two arrays irrespective of their elements positions. Do I have to test each element in one array against all the elements in the other and vice versa? Or is there another way?

  • Andreas Herd
    Andreas Herd over 5 years
    This will not fail if arrays have additional values. Point was to check of equality.
  • jkondratowicz
    jkondratowicz over 5 years
    This was introduced in Jest 23.0.0, so won't work with previous versions.
  • Jezzamon
    Jezzamon over 5 years
    This will ignore duplicate values, which is probably not what you want. ["a", "a", "b"] will match ["a", "b"].
  • Avinav
    Avinav about 5 years
    this will not work if you are working with array of objects. Because the object would be converted to [Object object] and won't be sorted. And your comparison may still fail. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/….
  • Jimmy Kane
    Jimmy Kane over 4 years
    Do not use this as duplicate elements are not counted. Avoid before you break your head
  • Zakalwe
    Zakalwe almost 4 years
    You can always test the length of the array to ensure that this test matches what is expected rather than a subset of what is expected.
  • Xanlantos
    Xanlantos over 3 years
    I would highly encourage you to delete this answer as it is in almost every way inferior to the accepted. The only time I could imagine your answer to be better is a case where we have a lot of duplicates and therefore the comparison afterwards could be faster. If that is what you want to say please make it more clear. If not your answer is very misleading and can cause a lot of damage in an application as it looks fine and will work until it doesn't anymore then the damage can be dramatic.
  • Avin Kavish
    Avin Kavish over 3 years
    yeah, I mean you have to provide a suitable comparator to the sort function according to the data type.
  • Davide Rossetto
    Davide Rossetto about 3 years
    more compact way: const sortByKey = (a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0)
  • Gergő Horváth
    Gergő Horváth almost 3 years
    Be careful as this - as the name suggests - checks if the array contains the items in the other array. The test will pass if you check if expect(['a','b']).toEqual(expect.arrayContaining(['a'])); as mentioned in other answers.
  • 2oppin
    2oppin over 2 years
    be aware that this solution will work only for arrays with unique values. Try to compare ['pink wool', 'diorite', 'diorite'] with ['pink wool', 'pink wool', 'diorite']
  • ankush981
    ankush981 about 2 years
    Wow, so looks like Jest is smart enough to do an item-by-item comparison?