How to test race condition of a redux observable epic

霸气de小男生 提交于 2020-01-06 05:47:32

问题


I have a use case where I need to cancel an Ajax call and do something else in an epic. There's an example in the redux-observable doc which fits my need exactly. However, when I try to test the racing condition in my epic, the "cancelation" doesn't seem to work.

The example code is like:

import { ajax } from 'rxjs/ajax';

const fetchUserEpic = action$ => action$.pipe(
  ofType(FETCH_USER),
  mergeMap(action => race(
    ajax.getJSON(`/api/users/${action.payload}`).pipe(
      map(response => fetchUserFulfilled(response))
    ),
    action$.pipe(
      ofType(FETCH_USER_CANCELLED),
      map(() => incrementCounter()),
      take(1)
    )
  ))
);

My epic has the same structure as the example above, which is like:

initViewsEpic = (action$, state$, { ajaxGet }) => action$
  .ofType(INIT_VIEWS)
  .pipe(
    mergeMap(() => race(
      ajaxGet('/api/views/...')
        .pipe(
          switchMap(response => of(
            initViewsFulFilled(response),
            taskCompleted(INIT_VIEWS),
          )),
          startWith(taskInProgress(INIT_VIEWS)),
          catchError(error => of(
             notification(),
             taskCompleted(INIT_VIEWS),
           )),
        ),
      action$.pipe(
        ofType(INIT_VIEWS_CANCEL),
        map(() => taskCompleted(INIT_VIEWS),
        take(1),
      ),
    )),
  );

And my test is like:

test('should ignore the ajax call response when INIT_VIEWS_CANCEL action is fired', (done) => {
    const action$ = ActionsObservable.of({ type: 'INIT_VIEWS' }, { type: 'INIT_VIEWS_CANCEL' });
    const ajaxGet = () => timer(3000);

   initViewsEpic(action$, state$, { ajaxGet })
      .pipe(toArray()).subscribe((actions) => {
        expect(actions).toEqual([
          {
            type: 'TASK_IN_PROGRESS',
            payload: { id: 'INIT_VIEWS' },
          },
          {
            type: 'TASK_COMPLETED',
            payload: { id: 'INIT_VIEWS' },
          },
        ]);
        done();
      });
  });

I suppose that since the INIT_VIEWS_CANCEL action follows the INIT_VIEWS action synchronously, it should "win" the ajaxGet and there should not be any initViewsFulFilled goes out. But the result of this test always returns initViewsFulFilled as the second output action of my epic (I am using jest to test the epic).

Is there anything I did wrong in my test? If so, how can I test this race condition in a redux-observable epic properly?


回答1:


I will say I'm going to give a suggestion to test redux observable epics (that's what I've done) -- Use TestScheduler in rxjs/testing. So that we don't have to scratch the head dealing with ascyn things of other test frameworks

Hope this can help someone who have the same problem as I did.



来源:https://stackoverflow.com/questions/52832980/how-to-test-race-condition-of-a-redux-observable-epic

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!