问题
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