jest-extended icon indicating copy to clipboard operation
jest-extended copied to clipboard

Feature Request: .toMatchArray()

Open kara-ryli opened this issue 4 years ago • 3 comments

I was looking for a shortcut to check if an Array exactly matches the contents including order (but was not necessarily strictly equal). The matcher would have test cases like this:

describe('matchArray', () => {

  it('matches arrays', () => {
    expect(matchArray(['a', 'b'], ['a', 'b'])).toBeTruthy();
    expect(matchArray(['a', 'b', 'c'], ['a', 'b'])).toBeFalsy();
    expect(matchArray(['a', 'b'], ['a', 'b', 'c'])).toBeFalsy();
    expect(matchArray(['a', 'b'], ['b', 'a'])).toBeFalsy();
  });

  it('short-circuits via equality', () => {
    const a = [NaN]; // NaN === NaN returns false
    expect(matchArray(a, a)).toBeTruthy();
  });

  it('uses strict equality', () => {
    expect(matchArray(['1'], [1])).toBeFalsy();
    expect(matchArray([{}], [{}])).toBeFalsy();
    const a = {};
    expect(matchArray([a], [a])).toBeTruthy();
  });

});

I ended up writing this myself but would be happy to contribute it if you'll accept it.

kara-ryli avatar Oct 05 '19 17:10 kara-ryli

not necessarily strictly equal

But the third it uses strict equality. Did you mean 'not necessarily deeply equal'?

vatosarmat avatar Oct 12 '19 08:10 vatosarmat

By not necessarily strictly equal, I mean the two arrays, rather than their contents. I basically want to be able to check if an array holds what I expected it to hold, including order.

kara-ryli avatar Oct 16 '19 12:10 kara-ryli

.toIncludeAllMembers() does what you want, I think, except it accepts the same items in different order.

So maybe .toIncludeAllMembersInOrder() would be a good name for this?

expect( [1, 2, 3] ).toIncludeAllMembersInOrder( [1, 2, 3] ) // => pass
expect( [3, 2, 1] ).toIncludeAllMembersInOrder( [1, 2, 3] ) // => fail

That would throw an error like "Expected list to have all of the following members in order", rather than your implementation which will throw "expect(received).toBeTruthy()", which is less clear.

overlookmotel avatar Feb 20 '20 22:02 overlookmotel

.toIncludeAllMembers() would not resolve the second item, but toIncludeAllMembersInOrder() might.

expect([1,2,3]).toMatchArray([1,2]) // => fail
expect([1,2,3]).toIncludeAllMembers([1,2]) // => pass (should have failed!)

Should toIncludeAllMembersInOrder() allow disjoint matching? The cases below are possibly ambiguous:

expect([1,2,3,4]).toIncludeAllMembersInOrder([1,2,3]) // pass or fail?
expect([1,2,3,4]).toIncludeAllMembersInOrder([2,3,4]) // pass or fail?

In the context of this issue, it is obvious, but from the matcher name only, it is not obvious (they do include all members and they are in order). Maybe the new matcher in #512 should be renamed to something along the lines of:

  • toIncludeExactMembers
  • toIncludeExactlyAllMembers
  • toEqualArray

Honestly, it seems like a simple .toEqual() (mostly) works:

expect(['a', 'b']).toEqual(['a', 'b']) // => pass
expect(['a', 'b', 'c']).not.toEqual(['a', 'b']) // => pass
expect(['a', 'b']).not.toEqual(['a', 'b', 'c']) // => pass
expect(['a', 'b']).not.toEqual(['b', 'a']) // => pass

const a = [NaN]
expect(a).toEqual(a) // => pass

expect(['1']).not.toEqual([1]) // => pass
expect([{}]).not.toEqual([{}]) // => fail
const b = {}
expect([b]).toEqual([b]) // => pass

The [{}] case differs from what OP expected (and [NaN] differs from my expectations), but I find the differences agreeable if strict equality or object identity are not desired.

beeryt avatar Oct 26 '22 05:10 beeryt

I don't have a way of telling, but I'd wager that when I opened this issue, toEqual didn't behave the same way. Regardless, I think the example above is close enough for the use case I was looking for that it would make sense to add similar-yet-different matcher.

kara-ryli avatar Oct 27 '22 00:10 kara-ryli