在 jest.js 中是否存在忽略元素位置的 Array 相等匹配函数?

我得到 .toEqual()检查纯对象的所有字段的相等性:

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

所以这一切都过去了。

但对于数组来说,情况并非如此:

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

似乎没有一个 matcher 函数在 jest 文档中执行此操作,即测试两个数组的相等性,而不管它们的元素位置如何。我是否必须测试一个数组中的每个元素与另一个数组中的所有元素的对比,反之亦然?还有别的办法吗?

120865 次浏览

没有内置的方法可以在不比较顺序的情况下对数组进行比较,但是在进行比较之前,您可以简单地使用 .sort()对数组进行排序:

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

您可以检查 这把小提琴中的示例。

这并不能准确地回答这个问题,但仍然可以帮助那些通过谷歌搜索找到这里的人:

如果只关心数组的子集是否具有某些元素,请使用 expect.arrayContaining() https://jestjs.io/docs/en/expect#expectarraycontainingarray

例如:

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

把元素放在一个集合里,杰斯知道如何匹配这些元素。

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

如前所述,expect.arrayContaining检查 actual数组是否包含 expected数组作为子集。 为了检查等效性,可以

  • 要么断言两个数组的长度相同(但这不会导致有用的失败消息)
  • 或断言相反: expected数组包含 actual数组:
// 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));
};

这仍然存在一个问题,即当第一个断言中的测试失败时,只能意识到 actual中缺少的元素,而不能意识到 expected中没有的额外元素。

另一种方法是使用来自 开玩笑社区/开玩笑扩展的自定义匹配器 .toIncludeSameMembers()

来自 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' }]);
});

为一个匹配器导入一个库可能没有意义,但是他们有很多其他有用的匹配器,我发现很有用。

如果没有对象数组,那么可以在比较之前简单地使用 Sort ()函数进行排序。(在接受的回答中提及) :

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

但是,如果你有一个对象数组,在这种情况下 sort函数不工作,问题就出现了。在这种情况下,需要提供自定义排序函数。 例如:

const x = [
{key: 'forecast', visible: true},
{key: 'pForecast', visible: false},
{key: 'effForecast', visible: true},
{key: 'effRegForecast', visible: true}
]


// In my use case, i wanted to sort by key
const sortByKey = (a, b) => {
if(a.key < b.key) return -1;
else if(a.key > b.key) return 1;
else return 0;
}


x.sort(sortByKey)
console.log(x)

希望有一天能帮到别人。

您可以将使用 这个答案中所述的集合与检查实际结果的长度和期望值相结合。这将忽略元素的位置并同时保护您不受重复元素的影响。

const materials = ['pink wool', 'diorite'];
const expectedMaterials = ['diorite', 'pink wool'];


expect(new Set(materials)).toEqual(new Set(expectedMaterials));
expect(materials.length).toBe(expectedMaterials.length);

编辑: 正如下面的注释中所建议的那样,这只适用于具有唯一值的数组。

如果您想比较 JEST 中的两个数组,请使用下面的模型。

官方链接: https://jestjs.io/docs/en/expect#expectarraycontainingarray

const array1 = ['a', 'b', 'c'];
const array2 = ['a', 'b', 'c'];
const array3 = ['a', 'b'];




it("test two arrays, this will be true", () => {
expect(array1).toEqual(expect.arrayContaining(array2));
});


it("test two arrays, this will be false", () => {
expect(array3).toEqual(expect.arrayContaining(array1));
});

虽然这项工作仍在进行中,但应该会奏效,但错误信息可能并不清楚:

expect.extend({
arrayContainingExactly(receivedOriginal, expected) {
const received = [...receivedOriginal];


if (received.length !== expected.length) return {
message: () => `Expected array of length ${expected.length} but got an array of length ${received.length}`,
pass: false,
};


const pass = expected.every((expectedItem, index) => {
const receivedIndex = findIndex(received, receivedItem => {
if (expectedItem.asymmetricMatch) return expectedItem.asymmetricMatch(receivedItem);
return isEqual(expectedItem, receivedItem);
});
if (receivedIndex === -1) return false;
received.splice(receivedIndex, 1);
return true;
});


return {
message: () => 'Success',
pass,
}
}
});

然后像这样使用它:

expect(['foo', 'bar']).arrayContainingExactly(['foo']) // This should fail

或者

expect({foo: ['foo', 'bar']}).toEqual({
foo: expect.arrayContainingExactly(['bar', 'foo'])
}) // This should pass

我们循环遍历每个值,并将其从接收到的数组中删除,以便利用 Jest 提供的非对称匹配。如果我们只想做直接等价,这可以简化为只比较2个排序的数组。

注意: 此解决方案使用 lodash中的 findIndexisEqual

检查内容和长度怎么样?

  expect(resultArray).toEqual(expect.arrayContaining(expectedArray));
expect(resultArray.length).toEqual(expectedArray.length);

可以使用 jest 收容平等检查数组是否包含元素。然后对预期数组中的每个元素执行以下操作:

const actual = [{ foobar: 'C' }, { foo: 'A' }, { bar: 'B' }];
const expected = [{ foo: 'A' }, { bar: 'B' }, { foobar: 'C' }];


expect(actual).toContainEqual(expected[0]);
expect(actual).toContainEqual(expected[1]);
expect(actual).toContainEqual(expected[2]);

(或者,如果需要检查的元素太多,则将 expect语句放入一个循环中)