Chai断言库to.deep.equal方法对URLSearchParams对象判断不准确的问题
问题分析与解决方案
我之前也碰到过Chai的deep.equal对URLSearchParams判断不准确的问题,这其实是因为Chai默认的深度比较逻辑没有适配这类内置的特殊对象。
为什么会出现这个问题?
URLSearchParams是浏览器/Node.js提供的内置对象,它的内部结构和普通JavaScript对象不同——本质上是一个类数组的键值对集合,而非普通的键值对象。Chai的deep.equal在比较对象时,对于这类非普通对象,默认的遍历逻辑没有深入到它实际存储的参数条目里,反而可能只比较了对象的原型、构造函数等表面属性,导致明明参数不同的两个实例被误判为相等。
可行的解决方案
1. 比较toString()的结果(最简单直接)
URLSearchParams的toString()方法会返回标准化的查询字符串,能准确反映所有参数的差异,这也是你已经验证有效的方法:
test('via string', () => { expect(getIncorrectParams().toString()).not.to.equal( new URLSearchParams({ from: '2020', to: '2021', ids: ['abc-1', 'abc-2'], }).toString() ); });
2. 转换为普通对象后比较
通过Object.fromEntries()把URLSearchParams转换成普通键值对象,这样Chai的deep.equal就能正常工作了:
test('deep equal plain objects', () => { expect(Object.fromEntries(getIncorrectParams().entries())).not.to.deep.equal({ from: '2020', to: '2021', ids: ['abc-1', 'abc-2'], }); });
注意:如果存在重复键(比如
ids=abc-1&ids=abc-2),Object.fromEntries()会保留最后一个值,这时候可以考虑转换成数组来对比。
3. 直接对比键值对数组
如果需要保留多值参数的完整信息,可以把两个URLSearchParams都转换成条目数组,再用Chai的断言对比:
test('compare entries array', () => { const actualEntries = [...getIncorrectParams().entries()]; const expectedEntries = [...new URLSearchParams({ from: '2020', to: '2021', ids: ['abc-1', 'abc-2'], }).entries()]; // 严格对比顺序和内容 expect(actualEntries).not.to.deep.equal(expectedEntries); // 如果不关心参数顺序,用deep.members忽略顺序 // expect(actualEntries).not.to.have.deep.members(expectedEntries); });
4. 自定义Chai断言(进阶)
如果经常需要测试URLSearchParams,可以自定义一个Chai断言来封装对比逻辑:
chai.use((chai, utils) => { const Assertion = chai.Assertion; Assertion.addMethod('equalURLSearchParams', function(expected) { const actual = this._obj; // 先校验类型 new Assertion(actual).to.be.instanceOf(URLSearchParams); new Assertion(expected).to.be.instanceOf(URLSearchParams); const actualEntries = [...actual.entries()]; const expectedEntries = [...expected.entries()]; this.assert( actualEntries.length === expectedEntries.length && actualEntries.every(([key, val]) => expected.get(key) === val), 'expected #{act} to equal #{exp}', 'expected #{act} not to equal #{exp}', expected.toString(), actual.toString() ); }); }); // 使用方式 test('custom assertion', () => { expect(getIncorrectParams()).not.to.equalURLSearchParams( new URLSearchParams({ from: '2020', to: '2021', ids: ['abc-1', 'abc-2'], }) ); });
内容的提问来源于stack exchange,提问作者Elias
相关产品推荐
相关产品推荐

