如何在 Redux 中测试递归调度

How to test a recursive dispatch in Redux

我实现了自己的方式来处理 access/refresh 令牌。基本上当 accessToken 过期时,它等待另一个动作的调度,如果成功,它会再次调度自己。下面的代码更好地解释了它:

export const refresh = () => async (dispatch) => {
  dispatch({
    type: REFRESH_USER_FETCHING,
  });

  try {
    const user = await api.refresh();

    dispatch({
      type: REFRESH_USER_SUCCESS,
      payload: user,
    });
    return history.push("/");
  } catch (err) {
    const { code } = err;
    if (code !== "ACCESS_TOKEN_EXPIRED") {
      dispatch({
        type: REFRESH_USER_ERROR,
        payload: err,
      });

      const pathsToRedirect = ["/signup"];

      const {
        location: { pathname },
      } = history;

      const path = pathsToRedirect.includes(pathname) ? pathname : "/login";
      return history.push(path);
    }

    try {
      await dispatch(refreshToken());
      return dispatch(refresh());
    } catch (subErr) {
      dispatch({
        type: REFRESH_USER_ERROR,
        payload: err,
      });
      return history.push("/login");
    }
  }
};

export const refreshToken = () => async (dispatch) => {
  dispatch({
    type: REFRESH_TOKEN_FETCHING,
  });

  try {
    await api.refreshToken();
    dispatch({
      type: REFRESH_TOKEN_SUCCESS,
    });
  } catch (err) {
    dispatch({
      type: REFRESH_TOKEN_ERROR,
      payload: err,
    });
  }
};

问题是我发现很难用 Jest 进行测试。其实我已经实现了这个测试:

import configureMockStore from "redux-mock-store";
import thunk from "redux-thunk";
import * as actionCreators from "./actionCreators";
import * as actions from "./actions";
import api from "../../api";
jest.mock("../../api");

const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);

describe("authentication actionCreators", () => {
  it("runs refresh, both token expired, should match the whole flow", async () => {
    api.refresh.mockRejectedValue({
      code: "ACCESS_TOKEN_EXPIRED",
      message: "jwt expired",
    });

    api.refreshToken.mockRejectedValue({
      code: "REFRESH_TOKEN_EXPIRED",
      message: "jwt expired",
    });

    const expectedActions = [
      { type: actions.REFRESH_USER_FETCHING },
      { type: actions.REFRESH_TOKEN_FETCHING },
      { type: actions.REFRESH_TOKEN_ERROR },
      { type: actions.REFRESH_USER_ERROR },
    ];
    const store = mockStore({ auth: {} });

    await store.dispatch(actionCreators.refresh());

    expect(store.getActions()).toEqual(expectedActions);
  });
});

但是测试并没有完成,而是无限期地运行。当我手动测试时没有发生这个问题,所以我认为 Jest 中缺少一些东西,所以我的问题是:有没有办法测试这种递归行为?

谢谢

问题是 await you use with dispatch,调度 returns 一个动作,而不是 Promise,请改用 Promise.resolve