Redux-observable Promise не разрешается в модульном тесте

Пытаюсь протестировать эту эпопею 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.info("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.info("-------",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, код приложения работает нормально, данные загружаются нормально.

Вопрос: как правильно написать этот тест?

Когда я запускаю ваш набор тестов, я получаю Invalid variable access: console, и все 6 не работают, знаете почему?

Tarun Lalwani 24.05.2018 12:25

Не могли бы вы попробовать заменить return loadingAction на вернуть Observable.fromPromise (loadingAction)?

dentemm 24.05.2018 19:34

@TarunLalwani, возможно, это как-то связано с версией узла, я запускаю его на v9.2.0

zarcode 25.05.2018 08:35

@dentemm photosActions.photosLoading(a.filter, a.refresh) - это объект, а не обещание, поэтому выполнение return Observable.fromPromise (loadingAction) или from (loadingAction) с помощью rxjs v6 вызывает ошибку такого рода: TypeError: You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.

zarcode 25.05.2018 08:41

@zarcode, сейчас работает, я был на 10.1.0, может в нем что-то изменилось

Tarun Lalwani 25.05.2018 09:50

@zarcode, срок действия награды истекает. Пожалуйста, посмотрите на существующий ответ

Tarun Lalwani 30.05.2018 18:16
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
16
6
931
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Помните, что при тестировании асинхронного кода вам необходимо использовать разные стратегии, как указано в документация.

Я столкнулся с множеством проблем, прежде чем попытаться протестировать свой асинхронный код, большинство проблем заключались в том, что тест утверждал ожидаемое поведение до того, как разрешенное обещание могло быть обработано, и утверждение необходимо было сделать в следующем тике цикл событий , чего я на практике добиваюсь, помещая утверждение в setImmediate, чего можно добиться и с setTimeout.

Из документации jest вы можете изменить свой тест и передать обратный вызов done, отправить триггерное действие как обычно, но поместить утверждение внутри обратного вызова setTimeout с тайм-аутом 1 мс, просто чтобы разрешенное обещанное было обработано, затем обратный вызов будет вызван, и он подтвердит желаемое состояние.

Можно использовать другие стратегии, такие как async/await, или вместо использования setTimeout разрешить пустое обещание и поместить утверждение в обратный вызов then. Просто имейте в виду, что если в тестируемом потоке существует больше обещаний, потребуется больше тиков в цикле событий, пока не будет достигнут желаемый результат для утверждения.

Обновлено: Реализация:

// test
it('produces the photo model', (done) => {
...
// dispatch epic triggering action
store.dispatch(...);
// assertion
setImmediate(() => {
  expect(store.getActions()).toEqual([
  ...
  ]);
  done();
});

У вас есть репо в вопросе, вместо того, чтобы давать теоретический ответ, было бы здорово, если бы вы могли просто исправить тест и обновить то же самое в своем ответе. Я попробовал вашу рекомендацию и не смог ее исправить. Так что лучше всего, если вы просто проверите это один раз

Tarun Lalwani 27.05.2018 07:34

Я не согласен с «вместо», потому что для меня нет смысла исправлять проблему, не объясняя, почему проблема возникает и как ее исправить, это лучший вариант для всех, в том числе и для меня. Но нет проблем в том, чтобы помочь больше, если проблема не исчезнет, ​​это на самом деле быстрее, и я опубликовал решение в этом пул реквест.

rodgobbi 27.05.2018 18:25

И так же, как я написал в ответе, передайте обратный вызов done, который предоставляет jest, подтвердите внутри обратного вызова setImmediate и вызовите done внутри него, я обновлю ответ, чтобы показать реализацию, чтобы она была более наглядной.

rodgobbi 27.05.2018 18:31

Другие вопросы по теме