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

如何在Jest中测试基于Axios的Redux异步Action?

问题修复方案

核心问题分析

  1. 异步Action未返回Promise:someFn没有返回axios.get的Promise链,导致store.dispatch(someFn(...))返回undefined,无法调用.then()方法,直接触发TypeError。
  2. 测试用例错误:
    • expectedActions格式错误,应该是两个独立的action对象(先LOGIN,再LOGIN_SUCCESS/LOGIN_FAILURE),而非合并成一个对象。
    • 测试中使用未定义的response变量,应该用store.getActions()获取已派发的action列表。
  3. Reducer逻辑错误:LOGIN_SUCCESS/LOGIN_FAILURE分支的状态更新写法错误,会生成无效的state结构。

修复后的代码

1. 修正异步Action(someFn)

必须返回Promise链,让dispatch能拿到thenable对象:

const someFn = (email, password) => (dispatch) => {
  dispatch(login(email, password));
  // 关键:return axios的Promise链
  return axios.get("some API")
    .then(response => dispatch(loginSuccess()))
    .catch(error => dispatch(loginFailure()));
};

2. 修正Reducer逻辑

调整状态更新方式,生成合理的state结构:

const reducers = (state = { isLoading: false, isLoggedIn: false, error: null }, action) => {
  switch(action.type) {
    case LOGIN:
      return {...state, isLoading: true, user: action.user};
    case LOGIN_SUCCESS:
      return {...state, isLoading: false, isLoggedIn: true};
    case LOGIN_FAILURE:
      return {...state, isLoading: false, isLoggedIn: false, error: action.error || true};
    default:
      return state;
  }
};

3. 修正测试用例

调整expectedActions格式,使用store.getActions()获取派发的actions:

const middleware = [thunk];
const mockStore = configureStore(middleware);
const mock = new MockAdapter(axios);

it('TEST CASE 5 - 登录成功场景', () => {
    mock.onGet("...someapi").reply(200, { /* mock payload */ });

    const expectedActions = [
      // 第一个派发的LOGIN action
      {
        type: 'LOGIN',
        user: { email: 'test@test', password: 123 }
      },
      // 第二个派发的LOGIN_SUCCESS action
      {
        type: 'LOGIN_SUCCESS'
      }
    ];

    const store = mockStore({});
    
    // 返回dispatch的Promise,确保测试等待异步完成
    return store.dispatch(someFn("test@test", 123)).then(() => {
      // 用store.getActions()获取所有已派发的action
      expect(store.getActions()).toEqual(expectedActions);
    });
});

// 新增登录失败测试用例
it('TEST CASE 6 - 登录失败场景', () => {
    mock.onGet("...someapi").reply(500);

    const expectedActions = [
      {
        type: 'LOGIN',
        user: { email: 'test@test', password: 123 }
      },
      {
        type: 'LOGIN_FAILURE'
      }
    ];

    const store = mockStore({});
    
    return store.dispatch(someFn("test@test", 123)).then(() => {
      expect(store.getActions()).toEqual(expectedActions);
    });
});

额外说明

  • 测试时每个用例应该单独初始化store,避免不同测试间的状态污染。
  • 你的预期输出存在误解:Redux中每次dispatch是独立的action,最终的state是reducer根据这些action依次更新后的结果,而非把多个action合并成一个对象。

内容的提问来源于stack exchange,提问作者Moez Ben Rebah

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 06:52:35