Jest测试中访问mock.calls[0][0]遇Unsafe member access类型错误
解决Jest mock调用参数断言的类型错误问题
你遇到的是TypeScript对confirmPaymentMock.mock.calls[0][0]的类型检查错误,根源是TypeScript无法确认mock.calls数组是否包含元素,直接访问索引会触发“对any类型值进行不安全的成员访问”提示。以下是几种解决方法:
方法1:先验证调用次数,再访问参数
先通过toHaveBeenCalledTimes断言mock函数确实被调用过,TypeScript会因此推断mock.calls[0]存在,消除类型错误:
it('should call onSubmit on button click', () => { const { getByTestId } = renderComponent('orderId'); fireEvent.click(getByTestId('submitPay')); // 先断言调用次数 expect(confirmPaymentMock).toHaveBeenCalledTimes(1); // 此时访问[0][0]不会有类型错误 expect(JSON.stringify(confirmPaymentMock.mock.calls[0][0])).toEqual(JSON.stringify({ elements: mockStripe().elements(), confirmParams: { return_url: `${window.location.origin}/${appRoutes.successfulOrder}` } })); });
方法2:使用可选链避免空访问
用可选链操作符?.处理可能为空的情况,同时配合expect.not.toBeUndefined()确保参数存在:
it('should call onSubmit on button click', () => { const { getByTestId } = renderComponent('orderId'); fireEvent.click(getByTestId('submitPay')); const firstCallArgs = confirmPaymentMock.mock.calls[0]?.[0]; expect(firstCallArgs).not.toBeUndefined(); expect(JSON.stringify(firstCallArgs)).toEqual(JSON.stringify({ elements: mockStripe().elements(), confirmParams: { return_url: `${window.location.origin}/${appRoutes.successfulOrder}` } })); });
方法3:给mock函数添加明确的类型定义
如果知道confirmPayment函数的参数类型,可以给mock函数指定类型,让TypeScript准确推断mock.calls的类型:
// 先定义参数类型 type ConfirmPaymentParams = { elements: ReturnType<typeof mockStripe.elements>; confirmParams: { return_url: string; }; }; // 给mock函数指定类型 const confirmPaymentMock = jest.fn<Promise<void>, [ConfirmPaymentParams]>(); it('should call onSubmit on button click', () => { const { getByTestId } = renderComponent('orderId'); fireEvent.click(getByTestId('submitPay')); // 此时访问[0][0]会自动推断为ConfirmPaymentParams类型,无错误 expect(JSON.stringify(confirmPaymentMock.mock.calls[0][0])).toEqual(JSON.stringify({ elements: mockStripe().elements(), confirmParams: { return_url: `${window.location.origin}/${appRoutes.successfulOrder}` } })); });
方法4:使用Jest内置的toHaveBeenCalledWith断言(推荐)
不用手动访问mock.calls,直接用Jest的匹配器断言调用参数,更简洁且避免类型问题:
it('should call onSubmit on button click', () => { const { getByTestId } = renderComponent('orderId'); const expectedReturnUrl = `${window.location.origin}/${appRoutes.successfulOrder}`; fireEvent.click(getByTestId('submitPay')); expect(confirmPaymentMock).toHaveBeenCalledWith(expect.objectContaining({ elements: expect.any(Object), // 如果需要更精确匹配,可以替换为mockStripe().elements()的实例断言 confirmParams: { return_url: expectedReturnUrl } })); });
这种方式不仅更符合Jest的最佳实践,还能避免手动处理数组索引的类型问题,同时断言逻辑更清晰。
内容的提问来源于stack exchange,提问作者tdimoff
相关产品推荐
相关产品推荐

