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

如何使用Jest和React Testing Library模拟React组件的异步Redux Action调用

问题原因

你收到的 TypeError: Cannot read property 'then' of undefined 翻译为 类型错误:无法读取undefined的属性'then',触发原因是点击按钮调用的action()方法执行后没有返回Promise,导致后续调用.then()失败。核心问题出在两点:

  • 你的mock逻辑不符合Redux异步Action的执行规则
  • 测试代码存在两处笔误:组件名和props之间缺少空格、查询的按钮文本和组件实际的label不匹配
推荐解决方案

方案一:测试未连接的原始组件(单元测试首选,逻辑更简单)

单元测试只需要验证组件本身的逻辑即可,Redux的连接逻辑可以单独测试,这种写法不需要处理Redux相关的mock,实现成本最低:

  1. 先修改组件代码,增加未连接的原始组件的命名导出:
import { reduxAction } from 'store/actions';

// 增加命名导出
export function TestBtn(props) {
    const { href, action } = props;

    const onClick= () =>
        action ({
            method: 'post',
            path: href
        })
            .then(() => {
                //do something
            })
            .catch(() => {
                //do something
            });

    return (
            <Button
                variant={'outlined'}
                onClick={onClick}
                label='Click'
            />
    );
}

const mapDispatchToProps = dispatch => ({
    action : payload => dispatch(reduxAction(payload))
});

export default connect(null, mapDispatchToProps)(TestBtn);
  1. 测试代码直接导入原始组件,传入mock的action prop:
import React from 'react';
import { render, screen, fireEvent } from 'test-utils';
import '@testing-library/jest-dom';
import { TestBtn } from 'components'; // 导入未连接的原始组件

// 直接mock action方法,调用后返回Promise
const mockAction = jest.fn(() => Promise.resolve());
const href = '/test';

test('点击按钮后逻辑正常执行', async () => {
    render(<TestBtn href={href} action={mockAction} />);
    // 匹配组件实际的按钮label
    fireEvent.click(screen.getByText('Click'));
    
    // 验证action被正确传参调用
    expect(mockAction).toHaveBeenCalledWith({
        method: 'post',
        path: href
    });
    
    // 如果要验证then/catch内的逻辑,等待Promise执行完成即可
    await Promise.resolve();
    // 后续可以加DOM、状态相关的断言
});

方案二:测试连接后的完整组件

如果你需要验证Redux连接逻辑,需要修正mock和测试配置:

  1. 确保你的test-utils中的render方法已经配置了带redux-thunk的Redux Provider,因为只有配置了thunk中间件,dispatch异步Action的时候才会返回Promise:
// test-utils.js 参考配置
import { render } from '@testing-library/react';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '你的根reducer路径';

const renderWithProviders = (ui, { 
    preloadedState, 
    store = createStore(rootReducer, preloadedState, applyMiddleware(thunk)) 
} = {}) => {
  return render(ui, { 
    wrapper: ({ children }) => <Provider store={store}>{children}</Provider>
  });
}

export * from '@testing-library/react';
export { renderWithProviders as render };
  1. 修正reduxAction的mock,符合thunk的结构:

如果你用的是redux-thunk,异步Action创建函数返回的是一个接收dispatch、getState的函数,这个函数执行后才会返回Promise,不能直接返回Promise

import React from 'react';
import { render, screen, fireEvent } from 'test-utils';
import '@testing-library/jest-dom';
import TestBtn from 'components';
import * as actions from 'store/actions';

const mockReduxAction = jest
    .spyOn(actions , 'reduxAction')
    // 返回符合thunk格式的函数,执行后返回Promise
    .mockImplementation(() => (dispatch) => Promise.resolve());

const href = '/test';

test('点击按钮后逻辑正常执行', async () => {
    // 修正组件props的空格问题
    render(<TestBtn href={href} />);
    // 匹配组件实际的按钮label
    fireEvent.click(screen.getByText('Click'));
    
    expect(mockReduxAction).toHaveBeenCalledWith({
        method: 'post',
        path: href
    });
    
    await Promise.resolve();
    // 后续加其他断言
});

内容的提问来源于stack exchange,提问作者goscamp

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 09:00:02