Use a combination with the arrayContaining
within the toEqual
:
const array = [{ name: 'Bob' }, { name: 'Alice' }]
expect(array).toEqual(
expect.arrayContaining([{ name: 'Alice' }, { name: 'Bob' }])
)
It would ignore the array order in this case.
Or maybe try to sort both arrays before comparing to the toEqual
.
Some details
As described in the documentation on arrayContaining
:
expect.arrayContaining(array)
corresponds to a received array that contains all elements in the expected array. That is, the expected array is a subset of the received array. Therefore, it combines with a received array that contains elements that are not in the expected array.
"That is, the expected array is a subset of the received array" - This implies that it is sufficient that the expected array has certain values of the tested array for the pass test. This behavior is similar to expect.objectContaining
where you do not need all the keys to be present in the object, only a few checked in the test are enough to pass. But what about the case where the array is the same, ie, same size, but disordered? A test like the below would pass without problems:
it.only('array test', () => {
const array = [{ name: 'Bob' }, { name: 'Alice' }, { name: 'Foo' }]
expect(array).toEqual(
expect.arrayContaining([{ name: 'Alice' }, { name: 'Bob' }])
)
})
Notice that
[{ name: 'Alice' }, { name: 'Bob' }]
is a subset of
[{ name: 'Bob' }, { name: 'Alice' }, { name: 'Foo' }]
This test should fail because it would be missing { name: 'Foo' }
in the expect.arrayContaining
.
How to solve
In the most imperative and simple way, compare the size of the arrays using toHaveLength()
before checking with the expect.arrayContaining
:
// funcao utilitária para reuso em todos os testes
function checkArraysInAnyOrder (array: any[], expected: any[]) {
expect(array).toHaveLength(expected.length)
expect(array).toEqual(expect.arrayContaining(expected))
}
Success:
it('array test', () => {
const array = [{ name: 'Bob' }, { name: 'Alice' }]
const expected = [{ name: 'Alice' }, { name: 'Bob' }]
checkArraysInAnyOrder(array, expected) // sucesso
})
Glitch:
it('array test', () => {
const array = [{ name: 'Bob' }, { name: 'Alice' }, { name: 'Foo' }]
const expected = [{ name: 'Alice' }, { name: 'Bob' }]
checkArraysInAnyOrder(array, expected) // falha
})
As discussed in the comments, checkArraysInAnyOrder
could be a custom matcher, but I think the effort and complexity wouldn’t be worth it. Using community libraries that extend Jest’s resources like jest-Extended, could help to reach the goal. This, inclusive, has the method toIncludeSameMembers
that could be used to fulfill the goal:
Use .toIncludeSameMembers
checking if two arrays contain Equal values, in any order.
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' }]);
});
Of course it is up to the discussion and analysis if it is worth adding an entire library just for the use of a specific functionality. Still talking about this library, you could base, or copy, the source code that implements the toIncludeSameMembers
and create your own match.
There is a simple solution using Jest’s expansion pack jest-Extended. The use of this package would be within the scope of your question?
– Augusto Vasques
Yeah, @Augustovasques, super valid.
– Rafael Tavares