如何使用Chai判断嵌套数组属性顺序不同的对象数组相等
Chai判断对象数组相等时忽略嵌套数组元素顺序的实现方法
问题描述
现有两个结构一致的对象数组,仅嵌套的otherNames数组内元素顺序不同,其余内容完全一致:
array1 = [ { name: 'Kitty, Hello', otherNames: [ '(1) One', '(2) Two' ] }, { name: 'Cat, Garfield', otherNames: [ '(3) Three' ] } ]; array2 = [ { name: 'Kitty, Hello', otherNames: [ '(2) Two', '(1) One' ] }, { name: 'Cat, Garfield', otherNames: [ '(3) Three' ] } ]
使用Chai默认的深度相等断言无法通过校验:
array1.to.be.eql(array2) // 返回false array1.to.have.deep.members(array2) // 返回false
需要实现忽略指定嵌套数组元素顺序的相等判断。
实现方案
方案1:零依赖自定义逻辑(推荐,灵活可控)
不需要安装额外插件,根据需求选择对应写法:
- 如果仅需要忽略
otherNames字段的顺序,其他数组仍然校验顺序,可以先对目标字段排序预处理,再做常规深度相等判断:
// 预处理:统一对otherNames数组按相同规则排序 const normalize = arr => arr.map(item => ({ ...item, otherNames: [...item.otherNames].sort() })); // 断言 expect(normalize(array1)).to.deep.equal(normalize(array2)); // 校验通过
该写法仅适用于otherNames内元素为字符串、数字等可直接排序的基础类型,复杂对象需要自定义排序规则。
- 如果顶层数组的元素顺序也可能变动,可以用
satisfy自定义完整校验逻辑:
const isEqual = (a, b) => { if (a.length !== b.length) return false; // 按唯一标识name做索引映射,消除顶层顺序影响 const bMap = new Map(b.map(i => [i.name, i.otherNames])); return a.every(itemA => { const otherNamesB = bMap.get(itemA.name); if (!otherNamesB || itemA.otherNames.length !== otherNamesB.length) return false; // 校验嵌套数组成员完全匹配,忽略顺序 return itemA.otherNames.every(name => otherNamesB.includes(name)); }) } // 断言 expect(array1).to.satisfy(val => isEqual(val, array2)); // 校验通过
方案2:插件实现全局忽略数组顺序
如果项目中大量存在需要忽略数组顺序的深度比较场景,可以使用chai-like插件配置全局规则:
- 安装插件后在测试初始化文件中注册:
const chai = require('chai'); const chaiLike = require('chai-like'); chai.use(chaiLike); // 扩展规则:所有数组比较时忽略元素顺序 chaiLike.extend({ match: val => Array.isArray(val), assert: (actual, expected) => { if (actual.length !== expected.length) return false; return expected.every(exp => actual.some(act => chaiLike(act, exp))); } })
- 直接使用
like断言即可:
expect(array1).to.like(array2); // 校验通过
注意:该方案会递归对所有层级的数组应用忽略顺序的规则,若部分数组需要严格校验顺序请勿使用。
内容的提问来源于stack exchange,提问作者webdesignnoob
相关产品推荐
相关产品推荐

