You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 15:32:32