Jest如何使用toHaveBeenCalledWith断言调用参数属于指定数组
Jest 断言参数属于指定值集合的实现方案
你遇到的问题核心是expect.arrayContaining的设计目标是匹配数组类型的参数(校验目标数组包含预期数组的所有元素),并不适配单个值是否在给定集合内的校验场景,以下是两种可直接落地的方案:
注意:不要误用
expect.arrayContaining,该匹配器的适用场景是校验数组类型的参数是否包含指定的元素集合,对于单个基础类型值的归属校验完全不适用。
方案1:直接提取mock调用参数做断言(零配置通用)
jest.spyOn生成的监听函数会自动记录所有调用历史,挂载在mock.calls属性上,你可以直接取出实际传入的参数,用Jest原生的toContain匹配器做包含判断,代码如下:
describe("fn", () => { it("should pick one of items as arg", () => { // arrange const items:Item[] = [{ id: 'r1'}, { id: 'r2'}, { id: 'r3'}] const doSomething = jest.spyOn(m, 'doSomething') // act fn(items) // assert // 取doSomething第一次调用的第一个参数(也就是传入的id) const passedId = doSomething.mock.calls[0][0] const validIds = items.map(i => i.id) expect(validIds).toContain(passedId) }) })
如果你的逻辑里doSomething可能被多次调用,需要校验所有传入参数都合法,加个遍历即可:
doSomething.mock.calls.forEach(call => { expect(validIds).toContain(call[0]) })
方案2:自定义toBeOneOf匹配器(适合高频使用场景)
如果项目中大量存在「校验单个值属于指定集合」的需求,可以在Jest全局配置的setup文件中扩展自定义匹配器,后续可以直接在toHaveBeenCalledWith里链式使用:
// jest.config.js 中配置的setup文件内添加以下逻辑 expect.extend({ toBeOneOf<T>(received: T, expectedList: T[]) { const isPass = expectedList.includes(received) return { pass: isPass, message: () => isPass ? `期望参数不在可选列表内,实际传入值:${received}` : `期望参数属于可选列表,实际传入值:${received},可选值列表:${expectedList.join(', ')}` } } })
配置完成后,测试断言可以直接写成:
expect(doSomething).toHaveBeenCalledWith( expect.toBeOneOf(items.map(i => i.id)) )
内容的提问来源于stack exchange,提问作者yozibak
相关产品推荐
相关产品推荐

