测试调用其他史诗的 Observable 史诗

Testing Observable epic which invokes other epic

我正在尝试测试一个 Redux Observable 史诗,它调度一个动作来调用另一个史诗。不知何故调用的史诗没有被调用。

假设我的 epics 看起来像这样;

const getJwtEpic = (action$, store, { api }) =>
  action$.ofType('GET_JWT_REQUEST')
    .switchMap(() => api.getJWT()
      .map(response => {
        if (response.errorCode > 0) {
          return {
            type: 'GET_JWT_FAILURE',
            error: { code: response.errorCode, message: response.errorMessage },
          };
        }

        return {
          type: 'GET_JWT_SUCCESS',
          idToken: response.id_token,
        };
      })
    );

const bootstrapEpic = (action$, store, { api }) =>
  action$.ofType('BOOTSTRAP')
    .switchMap(() =>
      action$.filter(({ type }) => ['GET_JWT_SUCCESS', 'GET_JWT_FAILURE'].indexOf(type) !== -1)
        .take(1)
        .mergeMap(action => {
          if (action.type === 'GET_JWT_FAILURE') {
            return Observable.of({ type: 'BOOTSTRAP_FAILURE' });
          }

          return api.getProfileInfo()
            .map(({ profile }) => ({
              type: 'BOOTSTRAP_SUCCESS', profile,
            }));
        })
        .startWith({ type: 'GET_JWT_REQUEST' })
    );

当我尝试使用以下代码在 Jest 中测试 bootstrapEpic 时;

const response = {};

const api = { getJWT: jest.fn() };
api.getJWT.mockReturnValue(Promise.resolve(response));

const action$ = ActionsObservable.of(actions.bootstrap());
const epic$ = epics.bootstrapEpic(action$, null, { api });

const result = await epic$.toArray().toPromise();
console.log(result);

console.log 调用给我以下输出;

[ { type: 'GET_JWT_REQUEST' } ]

不知何故 getJwtEpic 根本没有被调用。我想这与 action$ observable 不调度 GET_JWT_REQUEST 操作有关,但我不明白为什么。欢迎所有帮助!

假设 actions.rehydrate() returns 类型为 BOOTSTRAP 的操作并且 gigya 内容是错字,

getJwtEpic 没有被调用,因为你没有自己调用它 当你通过手动调用它们来测试 epics 时,那么它只是一个 returns 一个 Observable 的函数,没有中间件或其他任何知识。作为根史诗的一部分连接 getJwtEpic 并为它提供 (action$, store) 的管道是中间件的一部分,您不会在测试中使用它。

这是正确的方法,在没有 redux/middleware 的情况下单独测试它们。因此,您通过向它提供操作和依赖项,然后断言它发出的操作和它调用的依赖项来单独测试每个史诗。

您将像这样测试成功路径:

const api = {
  getProfileInfo: () => Observable.of({ profile: 'mock profile' })
};
const action$ = ActionsObservable.of(
  actions.rehydrate(),
  { type: 'GET_JWT_SUCCESS', idToken: 'mock token' }
);

const epic$ = epics.bootstrapEpic(action$, null, { api });

const result = await epic$.toArray().toPromise();

expect(result).toEqual([
  { type: 'GET_JWT_REQUEST' },
  { type: 'BOOTSTRAP_SUCCESS', profile: 'mock profile' }
]);

然后你将在另一个测试中测试失败路径,方法是做同样的事情,除了给它 GET_JWT_FAILURE 而不是 GET_JWT_SUCCESS。然后您也可以单独测试 getJwtEpic


顺便说一句,ofType 接受任意数量的类型,所以你可以只做 action$.ofType('GET_JWT_SUCCESS', 'GET_JWT_FAILURE')