测试componentDidMount时axiosRequest Mock返回undefined问题排查
测试componentDidMount时mock axiosRequest始终返回undefined,问题出在哪?
我想测试组件的componentDidMount生命周期方法,确保axiosRequest函数返回一个数组,但不管怎么mock这个函数,它始终返回undefined,我忽略了什么?
axiosRequest包装函数
export const axiosRequest = (type, url, body, headers) => { return axios[type](url, { ...body, sharedLinkToken: store.getState()?.token ? store.getState()?.token : null, activeWorkspace: body?.activeWorkspace ? body?.activeWorkspace : store.getState()?.auth?.org?.activeWorkspace, }, { ...headers }, ).then((res) => res?.data); };
componentDidMount中的调用代码
async componentDidMount() { try { const fieldTypes = await axiosRequest('post', '/api/custom-fields/types'); console.log('fieldTypes: ', fieldTypes); this.setState({ fieldTypes }); } catch (e) { this.setState({ disable: true }); } }
我的测试代码(尝试过多种mock方式)
import * as axiosRequest from '../../../../utilities/utilities'; let mockAxiosRequest; // jest.mock('axios'); // jest.mock('../../../../utilities/utilities', () => ({ // axiosRequest: jest.fn(), // })); beforeEach(() => { props = {}; wrapper = shallow(<CreateCustomField {...props} />); instance = wrapper.instance(); mockAxiosRequest = jest.spyOn(axiosRequest, 'axiosRequest'); }); it('Should find the wrapper', async () => { mockAxiosRequest.mockResolvedValue(['stuff']); // mockAxiosRequest.mockResolvedValue(() => ['stuff']); // mockAxiosRequest.mockResolvedValueOnce(['stuff']); // mockAxiosRequest.mockReturnThis(['stuff']); // mockAxiosRequest.mockImplementation(() => ['stuff']); // mockAxiosRequest.mockImplementation(() => Promise.resolve(['stuff'])); expect(wrapper.find('.create-custom-fields-modal').length).toBe(1); expect(instance.state.fieldTypes.length).toBe(1); });
问题根源及解决方法
核心问题
- mock时机滞后:你是在组件实例创建完成后才mock
axiosRequest,但componentDidMount在shallow渲染组件时已经执行,此时mock还未生效,实际调用的是原函数,导致返回undefined。 - 异步测试未等待:测试逻辑是异步的,但你没有等待
componentDidMount中的异步请求完成就断言状态,此时setState还未执行,fieldTypes仍是初始值。
修正后的测试代码
import * as axiosRequest from '../../../../utilities/utilities'; let mockAxiosRequest; let props; let wrapper; let instance; // 提前mock整个模块,确保组件导入时就使用mock函数 jest.mock('../../../../utilities/utilities', () => ({ axiosRequest: jest.fn(), })); beforeEach(() => { props = {}; // 先设置mock返回值,再创建组件 mockAxiosRequest = axiosRequest.axiosRequest; mockAxiosRequest.mockResolvedValue(['stuff']); wrapper = shallow(<CreateCustomField {...props} />); instance = wrapper.instance(); }); it('Should fetch field types and update state', async () => { // 等待componentDidMount中的异步操作完成 await instance.componentDidMount(); // 强制更新组件,确保state变化同步到wrapper wrapper.update(); expect(wrapper.find('.create-custom-fields-modal').length).toBe(1); expect(instance.state.fieldTypes).toEqual(['stuff']); expect(mockAxiosRequest).toHaveBeenCalledWith('post', '/api/custom-fields/types'); });
关键调整点
- 用
jest.mock提前mock整个工具模块,替代jest.spyOn,保证组件从一开始就使用mock函数。 - 在创建组件之前配置mock的返回值,确保
componentDidMount执行时mock已生效。 - 显式调用
await instance.componentDidMount()等待异步操作完成,再进行断言。 - 调用
wrapper.update()触发组件重新渲染,避免断言时拿到旧的state。
内容的提问来源于stack exchange,提问作者Alex S
相关产品推荐
相关产品推荐

