React Redux组件单元测试遇Axios错误,求解决方案
React Redux Home组件单元测试Axios错误排查与解决
在为连接Redux的React Home组件编写单元测试时,持续遇到Axios相关错误。该组件用于展示数据、控制加载状态及错误弹窗显示,以下是组件代码、测试代码及错误截图,附上具体解决建议:
组件代码
import React, { FC, useEffect, useState } from 'react'; import { connect } from 'react-redux'; import { getRates } from '../store/action-creators/getRates'; import { Table, Button, Loading, Model } from 'components'; import { RootState } from 'store'; import { HomeProps } from './types/Home'; const Home: FC<HomeProps> = ({ rates, loading, error, getRates }) => { const [ showErrorModal, setShowErrorModal ] = useState<boolean>(false); useEffect( () => { if (error) { setShowErrorModal(true); } }, [ error ] ); const handleCloseErrorModal = () => { setShowErrorModal(false); }; return ( <div className="home"> <Button onClick={getRates} /> {loading ? <Loading /> : <Table rates={rates} />} {showErrorModal && <Model message={error} onClose={handleCloseErrorModal} />} </div> ); }; const mapStateToProps = (state: RootState) => ({ rates: state.rates.rates, loading: state.rates.loading, error: state.rates.error } ); const mapDispatchToProps = { getRates }; const connector = connect(mapStateToProps, mapDispatchToProps) as any; export default connector(Home);
测试代码
import React from 'react'; import { render, fireEvent, waitFor } from '@testing-library/react'; import { Provider } from 'react-redux'; import configureStore from 'redux-mock-store'; import Home from '../Home'; import { getRates } from '../../store/action-creators/getRates'; const mockStore = configureStore(); describe('Home component', () => { it('renders correctly when loading is true', () => { const initialState = { rates: { loading: true, }, }; const store = mockStore(initialState); const { getByTestId } = render( <Provider store={store}> <Home /> </Provider> ); const loadingElement = getByTestId('loading'); expect(loadingElement).toBeInTheDocument(); }); it('renders correctly when loading is false', () => { const initialState = { rates: { loading: false, rates: { USD: 1.0808, JPY: 158.35, }, }, }; const store = mockStore(initialState); const { getByTestId } = render( <Provider store={store}> <Home /> </Provider> ); const tableElement = getByTestId('rates-table'); expect(tableElement).toBeInTheDocument(); }); it('displays error modal when error is not null', async () => { const initialState = { rates: { loading: false, error: 'Network error', }, }; const store = mockStore(initialState); const { getByTestId, getByText } = render( <Provider store={store}> <Home /> </Provider> ); const errorButtonElement = getByTestId('error-button'); fireEvent.click(errorButtonElement); const errorModalElement = await waitFor(() => getByTestId('error-modal')); expect(errorModalElement).toBeInTheDocument(); const errorMessageElement = getByText('Network error'); expect(errorMessageElement).toBeInTheDocument(); }); it('dispatches getRates action when button is clicked', () => { const initialState = { rates: { loading: false, }, }; const store = mockStore(initialState); store.dispatch = jest.fn(); const { getByTestId } = render( <Provider store={store}> <Home /> </Provider> ); const buttonElement = getByTestId('get-rates-button'); fireEvent.click(buttonElement); expect(store.dispatch).toHaveBeenCalledWith(getRates()); }); });
错误截图

解决建议
1. Mock Axios避免实际网络请求
错误根源是getRates action creator中使用Axios发送真实请求,测试时需mock整个Axios模块,阻止真实请求发送。在测试文件最顶部添加:
jest.mock('axios'); // 假设getRates依赖axios
2. 配置Redux中间件处理异步Action
如果getRates是异步Action(比如使用redux-thunk),redux-mock-store默认不处理异步逻辑,需添加thunk中间件:
import thunk from 'redux-thunk'; const mockStore = configureStore([thunk]); // 初始化mockStore时加入thunk
也可直接mockgetRates的实现简化测试:
jest.mock('../../store/action-creators/getRates', () => ({ getRates: jest.fn(() => ({ type: 'GET_RATES' })) }));
3. 修正错误弹窗测试用例逻辑
原测试中点击error-button是错误的,组件会在error存在时通过useEffect自动打开弹窗,无需手动触发。修改该测试:
it('displays error modal when error is not null', async () => { const initialState = { rates: { loading: false, error: 'Network error', rates: {} // 补充缺失字段,避免组件报错 }, }; const store = mockStore(initialState); const { getByTestId, getByText } = render( <Provider store={store}> <Home /> </Provider> ); // 直接等待弹窗渲染 const errorModalElement = await waitFor(() => getByTestId('error-modal')); expect(errorModalElement).toBeInTheDocument(); const errorMessageElement = getByText('Network error'); expect(errorMessageElement).toBeInTheDocument(); });
4. 完善测试用例的InitialState
确保每个测试用例的initialState包含组件用到的所有字段(rates、loading、error),避免组件解构props时出现undefined:
// 示例:完善加载状态测试的initialState const initialState = { rates: { loading: true, rates: {}, error: null }, };
内容的提问来源于stack exchange,提问作者Amr Khaled
相关产品推荐
相关产品推荐

