react-testing-library测试dispatch action报then未定义错误解决
报错根因
抛出Cannot read properties of undefined (reading 'then')是三个问题叠加导致的:
- 引用不匹配:测试文件里导入react-redux的命名空间是
redux,spy时却用了未定义的reactRedux变量,spy逻辑根本没生效 - mock链路断裂:只创建了
mockDispatchFn,但没有配置useDispatch钩子返回这个mock函数,组件中拿到的dispatch还是原生未mock的版本 - 返回值类型错误:你的代码里在Promise链上调用
.then,但mock的dispatch返回的是普通数组,没有then方法;另外你业务代码的括号位置写错了,异步action的.then应该挂在dispatch()的返回值上,不是someActionMethod()的返回值上。
修复方案
第一步:修正业务代码的写法
调整MyComponent.js里的异步调用逻辑,修正括号位置,去掉数字前的无效前导0:
const somefunction = () => { if (someCondition) { dispatch(someActionMethod({ id: 1, empName: 'Adam' })).then((result) => { setSomeState(result.data); }) } }
注:数字字面量加前导0(比如你写的01)会被JS解析为八进制数值,存在隐式转换风险,不要这么写。
第二步:修正测试文件的mock逻辑
正确配置useDispatch的spy、mock函数返回值,注意测试生命周期里的mock重置和恢复:
import React from 'react'; import * as reactRedux from 'react-redux'; // 变量名和spy时保持一致 import { render } from '@testing-library/react'; import MyComponent from './MyComponent'; // 补全组件导入 import { someActionMethod } from '@/store/your-action-path'; // 导入要mock的action方法 // mock action所在模块 jest.mock('@/store/your-action-path', () => ({ someActionMethod: jest.fn() })); describe('<MyComponent />', () => { const mockDispatchFn = jest.fn(); let useDispatchSpy; const props = {}; let componentRendering; beforeEach(() => { // 每个用例执行前重置所有mock状态,避免用例间污染 jest.clearAllMocks(); // 挂载spy,让useDispatch返回我们自定义的mock函数 useDispatchSpy = jest.spyOn(reactRedux, 'useDispatch').mockReturnValue(mockDispatchFn); // mock dispatch返回Promise,对应异步action的链式then调用 mockDispatchFn.mockResolvedValue({ data: { /* 替换为你业务需要的mock返回结构 */ } }); componentRendering = render( <MyComponent {...props} /> ); }); afterEach(() => { // 用例执行完恢复原生useDispatch实现,避免影响其他测试文件 useDispatchSpy.mockRestore(); }); it('test component', ()=> { expect(componentRendering.container.innerHTML).not.toBeNull(); // 可选:增加调用断言,验证逻辑执行符合预期 expect(someActionMethod).toHaveBeenCalledWith({ id: 1, empName: 'Adam' }); expect(mockDispatchFn).toHaveBeenCalled(); }); });
注意事项
- 所有mock初始化、spy挂载逻辑不要直接写在describe顶层,必须放在
beforeEach生命周期里,配合afterEach做恢复,避免多个测试用例之间状态互相干扰 - 凡是需要链式调用
.then/.catch的场景,mock函数必须返回Promise对象:用mockResolvedValue模拟请求成功,mockRejectedValue模拟请求失败,不能返回普通同步值 - spy模块方法时,必须保证导入的命名空间、变量名完全一致,否则spy不会生效
- 如果你用的是Redux Toolkit的
createAsyncThunk创建异步action,上述mock逻辑可以直接复用;如果是手写的thunk函数,只需要调整mockResolvedValue的返回结构和业务代码预期一致即可。
内容的提问来源于stack exchange,提问作者Uzair Khan
相关产品推荐
相关产品推荐

