redux-observable Promise 在单元测试中没有得到解决

IT技术 reactjs unit-testing react-native jestjs redux-observable
2021-04-26 13:42:50

我正在尝试测试这个史诗https://github.com/zarcode/unsplashapp/blob/master/src/epics/photos.js问题是map当我运行测试时永远不会发生(我认为这意味着 Promise 永远不会解决),所以photosSuccess动作也永远不会发生:

export const loadPhotosToList = (action$: Observable<Action>, state$: 
Object): Observable<Action> => {
  const state = (photosFilter: PhotosFilter) => state$.value.photos[photosFilter];
  return action$
  // .ofType(ACTION.FETCH_PHOTOS_REQUESTED)
    .pipe(
      filter((a: Action) =>
        a.type === ACTION.FETCH_PHOTOS_REQUESTED &&
        ((state(a.filter).loadingState === 'idle' && !state(a.filter).isLastPage) || a.refresh)),
      switchMap((a) => {
        const nextPage = !a.refresh ? state(a.filter).lastLoadedPage + 1 : 1;
        const loadingAction = of(photosActions.photosLoading(a.filter, a.refresh));
        const request = api.fetchPhotos({
          page: nextPage,
          per_page: perPage,
          order_by: a.filter,
        });
        const requestAction = from(request)
          .pipe(
            // tap(data => { console.log("data", data); }),
            map(data =>
              photosActions.photosSuccess(
                data,
                a.filter,
                nextPage,
                data.length < perPage,
                a.refresh,
              )),
            catchError(e => of(photosActions.photosFail(e.message, a.filter))),
          );
        // requestAction.subscribe(x => console.log("-------",x));
        return loadingAction
          .pipe(
            concat(requestAction),
            takeUntil(action$
              .pipe(filter(futureAction => futureAction.type === ACTION.FETCH_PHOTOS_REQUESTED))),
          );
      }),
    );
};

但是,如果我requestAction.subscribePromise得到解决并且我在控制台日志中得到结果。

注意:这仅在我运行此测试https://github.com/zarcode/unsplashapp/blob/master/src/epics/photos.test.js时发生,应用程序代码工作正常,数据获取正常。

问题是:如何正确编写此测试?

1个回答

请记住,在测试异步代码时,您需要使用不同的策略,如文档中所述

在尝试测试我的异步代码之前,我遇到了很多问题,大多数问题是测试在处理已解决的Promise之前断言了预期的行为,并且断言需要在事件的下一个滴答声中进行loop,我实际上是通过将断言放在 asetImmediate中来实现,这也可以用 a 来实现setTimeout

从 jest 的文档中,您可以更改测试并通过done回调,正常调度触发动作,但将断言放在setTimeout1 毫秒超时回调中,只是为了允许处理已解决的Promise,然后回调将是调用,它将断言所需的状态。

可以使用其他策略,例如async/await,或者您可以代替使用setTimeout,解析空的 Promise 并将断言放入then回调中。请记住,如果在测试流中存在更多 Promise,则需要在事件循环上进行更多滴答,直到实现所需的输出才能被断言。

编辑:实施:

// test
it('produces the photo model', (done) => {
...
// dispatch epic triggering action
store.dispatch(...);
// assertion
setImmediate(() => {
  expect(store.getActions()).toEqual([
  ...
  ]);
  done();
});