测试Redux Thunk+Axios Action Creator遇then未定义错误求解决方案
解决Redux-Thunk异步Action测试的"Cannot read property 'then' of undefined"错误
看起来你遇到的问题核心是你的redux-thunk action creator没有返回异步请求的Promise链,导致测试里调用.then()时拿到了undefined,触发了TypeError。我来一步步帮你解决这个问题:
一、错误原因分析
redux-thunk的异步action creator本质是返回一个函数,这个函数里执行axios请求。如果这个内部函数没有return axios的Promise链,那么store.dispatch(yourAction())就会返回undefined,当你在测试里尝试调用.then()时自然会报错。
比如错误的写法:
// ❌ 错误:没有return axios请求的Promise export const login = (credentials) => { dispatch => { axios.post('/api/login', credentials) .then(res => dispatch({ type: 'AUTH', payload: res.data.token })) .catch(err => dispatch({ type: 'UNAUTH' })) } }
二、修正Action Creator
只需要让内部的thunk函数return axios的Promise链即可:
// ✅ 正确:返回Promise链,让测试可以等待异步完成 import axios from 'axios'; export const AUTH = 'AUTH'; export const UNAUTH = 'UNAUTH'; export const login = (credentials) => { return (dispatch) => { // 关键:return这个axios请求的Promise return axios.post('/api/login', credentials) .then(response => { dispatch({ type: AUTH, payload: response.data.token }); }) .catch(error => { dispatch({ type: UNAUTH }); }); }; };
三、完整测试示例
我们用redux-mock-store模拟Redux store,用Jest配合axios-mock-adapter来模拟请求的成功/失败场景:
1. 安装依赖
首先确保你安装了测试所需的库:
npm install --save-dev redux-mock-store axios-mock-adapter jest
2. 测试代码
import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; import { login, AUTH, UNAUTH } from './authActions'; // 配置带thunk中间件的mock store const mockStore = configureMockStore([thunk]); // 创建axios mock实例 const mockAxios = new MockAdapter(axios); describe('Auth Action Creator Tests', () => { let store; beforeEach(() => { // 每次测试前初始化mock store store = mockStore({}); // 清除之前的mock请求记录 mockAxios.reset(); }); test('AUTH ACTION成功时返回token', async () => { // 模拟登录接口成功返回token const testToken = 'fake-jwt-token-123'; mockAxios.onPost('/api/login').reply(200, { token: testToken }); // 派发action并等待异步完成 await store.dispatch(login({ username: 'test-user', password: 'test-pass' })); // 获取store中被派发的所有actions const dispatchedActions = store.getActions(); // 断言action类型和payload正确 expect(dispatchedActions[0]).toEqual({ type: AUTH, payload: testToken }); // 断言axios请求被正确调用 expect(mockAxios.history.post[0].data).toBe(JSON.stringify({ username: 'test-user', password: 'test-pass' })); }); test('请求失败时派发UNAUTH', async () => { // 模拟登录接口失败 mockAxios.onPost('/api/login').reply(401); await store.dispatch(login({ username: 'wrong-user', password: 'wrong-pass' })); const dispatchedActions = store.getActions(); // 断言派发了UNAUTH类型的action expect(dispatchedActions[0]).toEqual({ type: UNAUTH }); }); });
四、关键测试要点
- 必须返回Promise:action creator的thunk函数一定要return axios的请求Promise,这样测试才能通过
await或.then()等待异步操作完成 - Mock外部依赖:不要在测试中真的调用后端接口,用axios-mock-adapter或Jest mock来模拟请求的成功/失败
- 验证派发的Actions:用
store.getActions()获取所有被派发的action,断言它们的类型和payload符合预期
内容的提问来源于stack exchange,提问作者Tinus Wagner
相关产品推荐
相关产品推荐

