jest.js 中有忽略元素位置的数组相等匹配函数吗?

问题描述 投票:0回答:11

我知道

.toEqual()
检查普通对象的所有字段是否相等:

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

所以这就过去了。

但数组不一样:

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

在开玩笑的文档中似乎没有匹配器函数可以执行此操作,即测试两个数组是否相等,而不管它们的元素位置如何。我是否必须针对另一个数组中的所有元素测试一个数组中的每个元素,反之亦然?或者有别的办法吗?

jasmine jestjs
11个回答
191
投票

没有内置的方法来比较数组而不比较顺序,但是您可以在进行比较之前使用

.sort()
简单地对数组进行排序:

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

您可以查看this fiddle中的示例。


47
投票

如前所述,

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
中不存在的额外元素。


36
投票

将元素放入集合中。 Jest 知道如何搭配这些。

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

19
投票

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

如果您只关心数组的子集具有某些元素,请使用

expect.arrayContaining()
https://jestjs.io/docs/en/expect#expectarraycontainingarray

例如,

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

11
投票

另一种方法是使用来自

jest-community/jest-extended
的自定义匹配器.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' }]);
});

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


9
投票

检查内容和长度呢?

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

5
投票

如果你想在 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));
});

4
投票

您可以将this answer中所述的使用集与检查实际结果和期望的长度结合起来。这将忽略元素位置并同时保护您免受重复元素的影响。

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

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

编辑:正如下面评论中所建议的,这仅适用于具有唯一值的数组。


3
投票

您可以使用 jest toContainEqual 来检查数组是否包含元素。然后对预期数组中的每个元素执行此操作:

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
语句放入循环中)


1
投票

如果你没有对象数组,那么你可以在比较之前简单地使用 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)

希望有一天能对某人有所帮助。


1
投票

仍在进行中,但这应该可以工作,错误消息可能不清楚:

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 个排序数组。

注意:此解决方案使用

findIndex
isEqual
来自
lodash
.

© www.soinside.com 2019 - 2024. All rights reserved.