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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 18:01:06