Jest中是否存在类似objectContaining的方法,使用toBe而非toEqual校验属性?
解决方案:严格检查对象属性的引用相等
你遇到的问题核心在于 expect.objectContaining 默认使用 值相等(toEqual) 来匹配属性,而 DOM 元素这类对象,即使是两个独立创建的空按钮,toEqual 会递归比较它们的结构和属性,认为二者相等。但你需要的是 引用相等(toBe) 检查——也就是确保传入的 button 属性是同一个对象引用。
这里有两种简单直接的方法实现你的需求:
方法1:直接获取调用参数并断言引用相等
最直观的方式是从 Jest mock 的调用记录中取出传入的参数,然后单独对 button 属性使用 toBe 断言:
test('foo', () => { const button1 = document.createElement('button'); const button2 = document.createElement('button'); const foo = jest.fn(); foo({button: button1}); // 获取 foo 第一次调用时传入的第一个参数 const [receivedObj] = foo.mock.calls[0]; // 严格断言 button 属性是 button1 的引用 expect(receivedObj.button).toBe(button1); });
这样修改后,如果传入的是 button2,测试会立即失败——因为 toBe 会检查两个对象是否是同一个内存引用,完全符合你的预期。
方法2:结合 objectContaining 和自定义匹配器
如果你想保留 toBeCalledWith 的写法,可以通过 Jest 的自定义匹配器来实现严格属性检查:
首先扩展 Jest 的匹配器:
expect.extend({ toBeStrictly(received, expected) { const pass = received === expected; return { pass, message: () => pass ? `expected ${received} not to be strictly equal to ${expected}` : `expected ${received} to be strictly equal to ${expected}` }; } });
然后在测试中使用:
test('foo', () => { const button1 = document.createElement('button'); const button2 = document.createElement('button'); const foo = jest.fn(); foo({button: button1}); expect(foo).toBeCalledWith(expect.objectContaining({ button: expect.toBeStrictly(button1) })); });
这个自定义的 toBeStrictly 匹配器会使用严格相等(===)来检查属性值,替代 objectContaining 默认的 toEqual 逻辑。
为什么原始测试会通过?
补充说明一下:你的原始测试中,expect.objectContaining({button: button2}) 能匹配到传入的 {button: button1},是因为 Jest 对 DOM 元素的 toEqual 比较会忽略对象引用,只递归检查元素的标签名、属性、子节点等结构信息。两个新创建的空按钮结构完全一致,所以被判定为“值相等”,但它们本质上是两个独立的对象引用。
内容的提问来源于stack exchange,提问作者Andy Shea
相关产品推荐
相关产品推荐

