redux-observable Promise在单元测试中没有得到解决 [英] redux-observable Promise is not getting resolved in unit test
问题描述
我正在尝试测试此史诗类 https://github .com/zarcode/unsplashapp/blob/master/src/epics/photos.js .问题是在运行测试时map
永远不会发生(我认为这意味着Promise永远不会解决),所以photosSuccess
动作也永远不会发生:
I am trying to test this epic https://github.com/zarcode/unsplashapp/blob/master/src/epics/photos.js . Problem is that map
never happens when I run test (which I assume means that Promise never resolves), so photosSuccess
action never happens also:
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.subscribe
,诺言就会得到解决,并且会在控制台日志中得到结果.
However, if I do requestAction.subscribe
promise gets resolved and I get the result in the console log.
Note: this happens only when I run this test https://github.com/zarcode/unsplashapp/blob/master/src/epics/photos.test.js, app code works fine, data is fetching fine.
问题是:如何正确编写此测试?
Question is: How to write this test properly?
推荐答案
Keep mind when testing async code you need to use different strategies, as noted in the documentation.
在尝试测试异步代码之前,我遇到了很多问题,大多数问题是测试在确定已解决的承诺被处理之前就断言了预期的行为,并且断言需要在下一个滴答声中进行. 事件循环 setImmediate
中的断言,也可以用setTimeout
来实现.
I crossed with a lot of problems before trying to test my async code, most of the problems were that the test was asserting the expected behavior before the resolved promise could be processed, and the assertion needed to be made in the next tick of the event loop, which I in practice achieve by putting the assertion inside a setImmediate
, which can be achieved with a setTimeout
too.
从玩笑的文档中,您可以更改测试并通过done
回调,像平常一样调度触发操作,但是将断言放入具有1 ms超时的setTimeout
回调中,只是允许已解决的承诺要进行处理,则将调用回调,并将断言所需的状态.
From the documentation of jest, you can change your test and pass the done
callback, dispatch the triggering action as normal, but put the assertion inside a setTimeout
callback with 1 ms timeout, just to allow the resolved promised to be processed, then the callback will be called and it will assert the desired state.
可以使用其他策略,例如async/await
,或者可以代替使用setTimeout
来解决一个空的Promise并将断言放入then
回调中.请记住,如果在测试流程中存在更多的Promises,则在实现所需的输出之前,必须在事件循环上添加更多的滴答声.
Other strategies can be used, like async/await
, or you can instead of using setTimeout
, resolve an empty Promise and put the assertion into the then
callback. Just keep in mind that if more Promises exist within the tested flow, more ticks on the event loop will be necessary until the desired output is achieved to be asserted.
实现:
// test
it('produces the photo model', (done) => {
...
// dispatch epic triggering action
store.dispatch(...);
// assertion
setImmediate(() => {
expect(store.getActions()).toEqual([
...
]);
done();
});
这篇关于redux-observable Promise在单元测试中没有得到解决的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!