如何在React组件测试中阻止useEffect内的Redux Dispatch触发请求
问题
我有一个React组件,当状态为"idle"时显示骨架屏,同时通过react-redux的dispatch发起请求获取数据。编写该组件的测试文件时,我希望渲染骨架屏并验证其是否正常渲染,但由于mock store的状态为"idle",渲染组件时触发了dispatch,进而出现错误:Unknown Error: Error: Error: connect ECONNREFUSED 127.0.0.1:443。请问如何避免该dispatch以阻止测试中的请求?
简化后的组件代码
export default function MyComponent() { const dispatch = useAppDispatch(); [...] useEffect(() => { if ("idle" === status) { // my query dispatch(fetchData(query)); } }, [dispatch]); if ("idle" === status) { return <MyComponentSkeleton />; }
测试代码
describe("MyComponent component", () => { let store: ReturnType<typeof createMockStore>; it("renders correctly when status is IDLE", () => { store = createMockStore(); render( <Provider store={store}> <MyComponent /> </Provider> ); const skeletonElement = screen.getByTestId("my-component-skeleton"); expect(skeletonElement).toBeInTheDocument(); });
解决方案
方法1:Mock fetchData action creator
直接在测试文件中mock掉fetchData,让它返回一个空的action,避免实际触发请求逻辑:
// 假设fetchData在./actions文件中导出 jest.mock('./actions', () => ({ ...jest.requireActual('./actions'), fetchData: jest.fn(() => ({ type: 'MOCK_FETCH_DATA' })) })); describe("MyComponent component", () => { let store: ReturnType<typeof createMockStore>; it("renders correctly when status is IDLE", () => { store = createMockStore(); render( <Provider store={store}> <MyComponent /> </Provider> ); const skeletonElement = screen.getByTestId("my-component-skeleton"); expect(skeletonElement).toBeInTheDocument(); // 可选:验证fetchData是否被正确调用 expect(fetchData).toHaveBeenCalled(); }); });
方法2:通过初始状态跳过请求触发
如果组件中的status来自redux store,可先设置初始状态为非"idle",渲染后再更新为"idle",这样就能绕过useEffect的请求触发逻辑:
describe("MyComponent component", () => { let store: ReturnType<typeof createMockStore>; it("renders correctly when status is IDLE", () => { // 初始状态设为非idle,避免组件挂载时触发请求 store = createMockStore({ yourSliceName: { status: 'loading' } }); render( <Provider store={store}> <MyComponent /> </Provider> ); // 更新状态为idle,此时组件渲染骨架屏,但useEffect不会重复触发(依赖仅为dispatch) store.dispatch({ type: 'yourSliceName/setStatus', payload: 'idle' }); const skeletonElement = screen.getByTestId("my-component-skeleton"); expect(skeletonElement).toBeInTheDocument(); }); });
方法3:拦截底层网络请求
如果不想改动action或store状态,可直接拦截fetch或axios等请求工具,从根源阻止请求发送:
拦截axios:
jest.mock('axios', () => ({ get: jest.fn(() => Promise.resolve({ data: {} })) }));
拦截全局fetch:
global.fetch = jest.fn(() => Promise.resolve({ json: () => Promise.resolve({}), ok: true, }) ) as jest.Mock;
内容的提问来源于stack exchange,提问作者Johan
相关产品推荐
相关产品推荐

