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
动作也永远不会发生:
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
promise 得到解决并且我在控制台日志中得到结果。
注意:只有当我运行这个测试https://github.com/zarcode/unsplashapp/blob/master/src/epics/photos.test.js时才会发生这种情况,应用程序代码工作正常,数据获取正常。
问题是:如何正确编写这个测试?
请记住,在测试异步代码时,您需要使用不同的策略,如 documentation 中所述。
在尝试测试我的异步代码之前,我遇到了很多问题,大多数问题是测试在处理已解决的承诺之前断言了预期的行为,并且断言需要在event loop 的下一个勾号,我在实践中通过将断言放在 setImmediate
中来实现,这也可以通过 setTimeout
来实现。
根据 jest 的文档,您可以更改测试并通过 done
回调,正常分派触发操作,但将断言放在超时为 1 毫秒的 setTimeout
回调中,只是为了允许处理已解决的承诺,然后将调用回调并断言所需的状态。
可以使用其他策略,例如 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();
});
我正在尝试测试这部史诗 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.subscribe
promise 得到解决并且我在控制台日志中得到结果。
注意:只有当我运行这个测试https://github.com/zarcode/unsplashapp/blob/master/src/epics/photos.test.js时才会发生这种情况,应用程序代码工作正常,数据获取正常。
问题是:如何正确编写这个测试?
请记住,在测试异步代码时,您需要使用不同的策略,如 documentation 中所述。
在尝试测试我的异步代码之前,我遇到了很多问题,大多数问题是测试在处理已解决的承诺之前断言了预期的行为,并且断言需要在event loop 的下一个勾号,我在实践中通过将断言放在 setImmediate
中来实现,这也可以通过 setTimeout
来实现。
根据 jest 的文档,您可以更改测试并通过 done
回调,正常分派触发操作,但将断言放在超时为 1 毫秒的 setTimeout
回调中,只是为了允许处理已解决的承诺,然后将调用回调并断言所需的状态。
可以使用其他策略,例如 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();
});