首页 > 解决方案 > 如何开玩笑地测试 redux-observable 史诗?

问题描述

所以,我在 redux 中有以下史诗般的设置:

export const getNotificationsEpic = (action$: ActionsObservable<any>): any =>
  action$
    .pipe(
      ofType(POLLING_START),
      switchMap(() =>
        timer(0, 3000)
          .pipe(
            takeUntil(action$.ofType(POLLING_STOP)),
            exhaustMap(() => from(NOTIFICATIONS_API.returnNotifications(0, 10))),
            map((response: PageResponseNotificationDTO) => getNotificationsSuccess(response)),
            catchError((error: FailureReason) => of([
              errorToastrAction('Error occurred when fetching notifications.'),
              getNotificationsFailure(error.reason),
              ])),
          ),
      ),
    );

其中 NOTIFICATIONS_API.returnNotifications 是转换为可观察的 Promise。我想为这部史诗写一个单元测试,但我不知道如何正确模拟 API 请求。我尝试过使用以下代码:

describe('getNotificationsEpic', () => {

  it('should call getNotificationsSuccess with correct argument', (done: any) => {
    const response: PageResponseNotificationDTO = createNotificationPage();
    NOTIFICATIONS_API.returnNotifications = jest.fn().mockResolvedValueOnce(response);
    const action$ = ActionsObservable.of({
      type: POLLING_START,
    });
    const expectedResult =
      {
        type: GET_NOTIFICATIONS_SUCCESS,
        value: response,
      } ;
    const result$: Observable<AnyAction[]> = getNotificationsEpic(action$).pipe(toArray());
    result$
      .subscribe((actions: AnyAction[]) => {
          expect(actions).toContainEqual(expectedResult);
          done();
      });

  });
});

但不幸的是,代码不正确,SUCCESS 和 ERROR 动作都进入了动作流。当我控制台记录 errorHandler 时,我可以看到以下消息:

at SafeSubscriber._next (src/epics/getNotificationsEpic.spec.tsx:29:27)
      at SafeSubscriber.Object.<anonymous>.SafeSubscriber.__tryOrUnsub (node_modules/rxjs/src/internal/Subscriber.ts:267:10)
      at SafeSubscriber.Object.<anonymous>.SafeSubscriber.next (node_modules/rxjs/src/internal/Subscriber.ts:209:14)
      at Subscriber.Object.<anonymous>.Subscriber._next (node_modules/rxjs/src/internal/Subscriber.ts:139:22)
      at Subscriber.Object.<anonymous>.Subscriber.next (node_modules/rxjs/src/internal/Subscriber.ts:99:12)
      at DefaultIfEmptySubscriber.Object.<anonymous>.DefaultIfEmptySubscriber._next (node_modules/rxjs/src/internal/operators/defaultIfEmpty.ts:75:22)
      at DefaultIfEmptySubscriber.Object.<anonymous>.Subscriber.next (node_modules/rxjs/src/internal/Subscriber.ts:99:12)
      at TakeLastSubscriber.Object.<anonymous>.TakeLastSubscriber._complete (node_modules/rxjs/src/internal/operators/takeLast.ts:108:21)
      at TakeLastSubscriber.Object.<anonymous>.Subscriber.complete (node_modules/rxjs/src/internal/Subscriber.ts:126:12)
      at ScanSubscriber.Object.<anonymous>.Subscriber._complete (node_modules/rxjs/src/internal/Subscriber.ts:148:22)
      at ScanSubscriber.Object.<anonymous>.Subscriber.complete (node_modules/rxjs/src/internal/Subscriber.ts:126:12)
      at SwitchMapSubscriber.Object.<anonymous>.Subscriber._complete (node_modules/rxjs/src/internal/Subscriber.ts:148:22)
      at SwitchMapSubscriber.Object.<anonymous>.SwitchMapSubscriber.notifyComplete (node_modules/rxjs/src/internal/operators/switchMap.ts:142:22)
      at InnerSubscriber.Object.<anonymous>.InnerSubscriber._complete (node_modules/rxjs/src/internal/InnerSubscriber.ts:26:17)
      at InnerSubscriber.Object.<anonymous>.Subscriber.complete (node_modules/rxjs/src/internal/Subscriber.ts:126:12)
      at CatchSubscriber.Object.<anonymous>.OuterSubscriber.notifyComplete (node_modules/rxjs/src/internal/OuterSubscriber.ts:21:22)
      at InnerSubscriber.Object.<anonymous>.InnerSubscriber._complete (node_modules/rxjs/src/internal/InnerSubscriber.ts:26:17)
      at InnerSubscriber.Object.<anonymous>.Subscriber.complete (node_modules/rxjs/src/internal/Subscriber.ts:126:12)
      at node_modules/rxjs/src/internal/util/subscribeTo.ts:19:20
      at Object.subscribeToResult (node_modules/rxjs/src/internal/util/subscribeToResult.ts:25:29)
      at CatchSubscriber.Object.<anonymous>.CatchSubscriber.error (node_modules/rxjs/src/internal/operators/catchError.ts:140:7)
      at MapSubscriber.Object.<anonymous>.Subscriber._error (node_modules/rxjs/src/internal/Subscriber.ts:143:22)
      at MapSubscriber.Object.<anonymous>.Subscriber.error (node_modules/rxjs/src/internal/Subscriber.ts:113:12)
      at ExhaustMapSubscriber.Object.<anonymous>.ExhaustMapSubscriber.tryNext (node_modules/rxjs/src/internal/operators/exhaustMap.ts:117:24)
      at ExhaustMapSubscriber.Object.<anonymous>.ExhaustMapSubscriber._next (node_modules/rxjs/src/internal/operators/exhaustMap.ts:107:12)
      at ExhaustMapSubscriber.Object.<anonymous>.Subscriber.next (node_modules/rxjs/src/internal/Subscriber.ts:99:12)
      at TakeUntilSubscriber.Object.<anonymous>.Subscriber._next (node_modules/rxjs/src/internal/Subscriber.ts:139:22)
      at TakeUntilSubscriber.Object.<anonymous>.Subscriber.next (node_modules/rxjs/src/internal/Subscriber.ts:99:12)
      at AsyncAction.dispatch (node_modules/rxjs/src/internal/observable/timer.ts:91:14)
      at AsyncAction.Object.<anonymous>.AsyncAction._execute (node_modules/rxjs/src/internal/scheduler/AsyncAction.ts:122:12)
      at AsyncAction.Object.<anonymous>.AsyncAction.execute (node_modules/rxjs/src/internal/scheduler/AsyncAction.ts:97:24)
      at AsyncScheduler.Object.<anonymous>.AsyncScheduler.flush (node_modules/rxjs/src/internal/scheduler/AsyncScheduler.ts:58:26)
      at Timeout.callback (node_modules/jsdom/lib/jsdom/browser/Window.js:678:19)

标签: reactjsreduxrxjsredux-observable

解决方案


推荐阅读