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

测试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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:26:09