сокращение-наблюдаемое обещание не разрешается в модульном тесте
Я пытаюсь проверить этот эпический 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
будет разрешено, и я получаю результат в журнале консоли.
Примечание: это происходит только тогда, когда я запускаю этот тест https://github.com/zarcode/unsplashapp/blob/master/src/epics/photos.test.js, код приложения работает нормально, данные извлекаются нормально.
Вопрос: как правильно написать этот тест?
Ответы
Ответ 1
Не забывайте, что при тестировании асинхронного кода вам нужно использовать разные стратегии, как указано в документации.
Я столкнулся с множеством проблем, прежде чем пытаться проверить мой асинхронный код, большинство проблем состояло в том, что тест утверждал ожидаемое поведение до того, как разрешенное обещание могло быть обработано, и утверждение необходимо было сделать в следующем тике события цикл, который я на практике достигаю, помещая утверждение внутри setImmediate
, которое может быть достигнуто с помощью setTimeout
.
Из документации шутки вы можете изменить свой тест и передать done
обратный вызов, отправить действие запуска как обычно, но поставить утверждение внутри обратного вызова setTimeout
с тайм-аутом 1 мс, чтобы разрешить разрешенное обещание для обработки, затем обратный вызов будет вызываться и будет утверждать желаемое состояние.
Могут использоваться другие стратегии, такие как async/await
, или вы можете вместо использования setTimeout
разрешить пустое обещание и поместить это утверждение в then
обратный вызов. Просто имейте в виду, что если в тестируемом потоке будет больше обещаний, потребуется больше тиков в цикле событий, пока не будет достигнут желаемый результат.
EDIT: Реализация:
// test
it('produces the photo model', (done) => {
...
// dispatch epic triggering action
store.dispatch(...);
// assertion
setImmediate(() => {
expect(store.getActions()).toEqual([
...
]);
done();
});