如何修复useEffect中使用axios CancelToken时的测试失败问题
没错,mock axios.CancelToken.source() 确实能解决这个测试失败的问题,咱们先理清楚问题出在哪:当测试用例执行完毕,RTL会卸载组件,触发useEffect的清理函数调用source.cancel()——这个操作会尝试取消MSW正在处理的请求,可能导致Promise被reject,哪怕你的catch分支判断了axios.isCancel(error),但MSW对取消请求的处理可能会抛出未被捕获的错误,最终导致测试失败。
下面是具体的实现方案:
方案一:全局mock axios的CancelToken
在测试文件的顶部添加全局mock,保留axios其他原有功能,只替换CancelToken相关逻辑:
jest.mock('axios', () => ({ ...jest.requireActual('axios'), // 保留axios原有的其他方法和属性 CancelToken: { source: jest.fn(() => ({ token: {}, // 只需提供一个组件能正常传入的token对象即可 cancel: jest.fn() // 空实现的cancel方法,不会真的触发请求取消 })) }, isCancel: jest.fn(() => false) // 可选:mock isCancel方法,避免进入cancel错误分支 }));
方案二:单个测试用例内局部mock
如果你不想影响其他测试用例,可以在当前测试里临时mock,测试结束后恢复原方法:
it('should render title to page', () => { // 保存原方法引用 const originalSource = axios.CancelToken.source; // 临时替换为mock函数 axios.CancelToken.source = jest.fn(() => ({ token: {}, cancel: jest.fn() })); const { getByText } = render(<EditIndex />); const heading = getByText('Edit Items'); expect(heading.textContent).toEqual('Edit Items'); // 测试完毕恢复原方法 axios.CancelToken.source = originalSource; });
额外注意:检查MSW配置的小问题
你提供的MSW服务器代码里有个笔误——rest.get('/api/data/'), 后面多了个逗号,正确的写法应该是:
const server = setupServer( rest.get('/api/data/', (req, res, ctx) => { return res( ctx.status(200), ctx.json({ data: data }) ); }) );
这个小错误也可能导致请求处理异常,进而影响测试结果,建议先修正。
总的来说,mock CancelToken.source后,组件卸载时的cancel操作变成了空执行,不会干扰MSW的请求流程,测试就能正常通过了。
内容的提问来源于stack exchange,提问作者GaB
相关产品推荐
相关产品推荐

