Expect Arrays to be equal ignoring order

84,412

Solution 1

If it's just integers or other primitive values, you can sort() them before comparing.

expect(array1.sort()).toEqual(array2.sort());

If its objects, combine it with the map() function to extract an identifier that will be compared

array1 = [{id:1}, {id:2}, {id:3}];
array2 = [{id:3}, {id:2}, {id:1}];

expect(array1.map(a => a.id).sort()).toEqual(array2.map(a => a.id).sort());

Solution 2

You could use expect.arrayContaining(array) from standard jest:

  const expected = ['Alice', 'Bob'];
  it('matches even if received contains additional elements', () => {
    expect(['Alice', 'Bob', 'Eve']).toEqual(expect.arrayContaining(expected));
  });

Solution 3

jasmine version 2.8 and later has

jasmine.arrayWithExactContents()

Which expects that an array contains exactly the elements listed, in any order.

array1 = [1,2,3];
array2 = [3,2,1];
expect(array1).toEqual(jasmine.arrayWithExactContents(array2))

See https://jasmine.github.io/api/3.4/jasmine.html

Solution 4

simple...

array1 = [1,2,3];
array2 = [3,2,1];

expect(array1).toEqual(jasmine.arrayContaining(array2));

Solution 5

The jest-extended package provides us few assertions to simplify our tests, it's less verbose and for failing tests the error is more explicit.

For this case we could use toIncludeSameMembers

expect([{foo: "bar"}, {baz: "qux"}]).toIncludeSameMembers([{baz: "qux"}, {foo: "bar"}]);
Share:
84,412
David says Reinstate Monica
Author by

David says Reinstate Monica

https://meta.stackexchange.com/questions/333965/firing-mods-and-forced-relicensing-is-stack-exchange-still-interested-in-cooper?noredirect=1&lq=1 https://meta.stackexchange.com/questions/336024/how-can-we-put-pressure-on-stack-exchange-inc-without-damaging-the-community#comment1110223_336024 https://meta.stackexchange.com/questions/336526/stack-overflow-is-doing-me-ongoing-harm-its-time-to-fix-it Please help in saving StackOverflow!

Updated on July 17, 2021

Comments

  • David says Reinstate Monica
    David says Reinstate Monica almost 3 years

    With Jasmine is there a way to test if 2 arrays contain the same elements, but are not necessarily in the same order? ie

    array1 = [1,2,3];
    array2 = [3,2,1];
    
    expect(array1).toEqualIgnoreOrder(array2);//should be true
    
    • raina77ow
      raina77ow almost 9 years
      expect(array1.sort()).toEqual(array2.sort()); ?
    • David says Reinstate Monica
      David says Reinstate Monica almost 9 years
      @raina77ow I guess that would work as well.
    • raina77ow
      raina77ow almost 9 years
      Should I make this an answer?
    • David says Reinstate Monica
      David says Reinstate Monica almost 9 years
      @raina77ow It gets a little bit more complicated when its an array of objects. It would be nice if Jasmine had something out of the box for this.
    • ktharsis
      ktharsis almost 9 years
      I didn't find anything great in jasmine itself so actually introduced lodash (or you could use underscore/other js collection library) into my test project for things just like this.
    • jimmyfever
      jimmyfever over 3 years
      I like @raina77ow's answer the best. The only caveat is that the sort will mutate the input arrays, though that's probably not a big deal. If it causes a problem, you can do [...array1].sort()
  • Darkhogg
    Darkhogg over 6 years
    Use .forEach instead of .map to save some time and a bunch of memory.
  • Shmiddty
    Shmiddty about 6 years
    the default array sort method uses string comparison for numbers. "10" < "2" === true
  • Shmiddty
    Shmiddty about 6 years
    [10, 2, 1].sort() ---> [1, 10, 2]
  • Coloured Panda
    Coloured Panda about 6 years
    @Shmiddty I dont see how it matters in this case. As long as the order is the same for both arrays, it should be fine.
  • Shmiddty
    Shmiddty about 6 years
    Fair point. It is worth noting that sort happens in-place, though. (it mutates the instance on which it is called)
  • philraj
    philraj almost 6 years
    What do you mean when you say it creates lots of copies? Array#sort sorts arrays in-place.
  • Torben Kohlmeier
    Torben Kohlmeier over 5 years
    Fails for these arrays: [1,1,2,3], [3,3,1,2].
  • Domi
    Domi over 5 years
    @TorbenKohlmeier Thanks, I updated my answer (admitting defeat in regard to non-unique arrays)
  • redbmk
    redbmk over 5 years
    @Shmiddty that's true, but .map returns a new array, so you're still not mutating the original.
  • redbmk
    redbmk over 5 years
    Unfortunately this will pass with the following arrays even though they are different: array1 = [1, 2], array2 = [1, 1]
  • Jannic Beck
    Jannic Beck over 5 years
    Nice catch @redbmk I added a check for this, thanks!
  • redbmk
    redbmk over 5 years
    I think there's still an issue - what if the arrays are [1,1,2] and [1,2,2]? Maybe using a Map for each one or something? e.g. array1.reduce((map, item) => { map.set(item, (map.get(item) || 0) + 1)), new Map()) for both arrays, then loop through them and check that the amounts are the same? Seems like a lot of iterations but would be more thorough.
  • lifecoder
    lifecoder over 5 years
    Exclusions from the control array may be used (remove element when found, then check length is 0 in the end), but it doesn't worth the effort in regular cases.
  • Kristian Hanekamp
    Kristian Hanekamp over 5 years
    Nice answer! You also need to check that the lengths are equal, otherwise you'll have a false positive on [1,2,3,4] and [3,2,1].
  • MarkMYoung
    MarkMYoung over 4 years
    This does not take into account the frequency of items: equal([1, 1, 2], [1, 2, 2]) returns true.
  • slifty
    slifty almost 4 years
    The object portion of this answer will not actually verify that the objects match, since it is only comparing the mapped arrays. You don't need map, sort takes an optional function that it can use to do the comparison.
  • bluenote10
    bluenote10 over 3 years
    But that is part of jest-extended, i.e., not available as a core Jest functionality, right?
  • mjarraya
    mjarraya over 3 years
    It is not an appropriate answer for this use case as the two arrays in the question are expected to be equal, with only order differing.
  • Emmanuel Mahuni
    Emmanuel Mahuni over 3 years
    there is toIncludeSameMembers in jest-extended. I don't know whether this is equivalent
  • enanone
    enanone about 3 years
    This is the correct answer. Please mark this as the correct answer. @mjarraya just test for the length of both arrays to be the same and you are fine.
  • mjarraya
    mjarraya about 3 years
    It should not be marked as the correct answer since it is not complete! @enanone
  • zeroliu
    zeroliu about 3 years
    There are two issues: 1. length needs to be checked. expect(actual.length).toEqual(expected.length); 2. It should be jasmine.arrayContaining. jasmine.github.io/2.6/…
  • paul23
    paul23 almost 3 years
    If for example the sorting key is "id" but there is extra data and those are not equal (but should be) this fails.
  • Jordan Burnett
    Jordan Burnett over 2 years
    expect([1, 2, 3]).toEqual(expect.arrayContaining([3, 3, 3])) will still pass, so this should not be used.
  • Hannes Schneidermayer
    Hannes Schneidermayer about 2 years
    this is the only way to go
  • Shachar Har-Shuv
    Shachar Har-Shuv about 2 years
    This should not be the first answer as it's outdated. Please see answer below regarding arrayWithExactContents