как проверить RxJs опровергнутые эпопеи? - PullRequest
3 голосов
/ 19 марта 2019

Я пытаюсь написать тестовую функцию для эпопеи, наблюдаемой в редуксе.Эпопея прекрасно работает внутри приложения, и я могу проверить, правильно ли она снимает действия и ждет 300 мсек перед отправкой.Но по какой-то причине, пока я пытаюсь протестировать его с шуткой, оператор debounce срабатывает немедленно.Поэтому мой контрольный пример, чтобы убедиться, что debounce работает, не удался.

Это контрольный пример

it('shall not invoke the movies service neither dispatch stuff if the we invoke before 300ms', done => {
    const $action = ActionsObservable.of(moviesActions.loadMovies('rambo'));

    loadMoviesEpic($action).subscribe(actual => {
        throw new Error('Should not have been invoked');
    });

    setTimeout(() => {
        expect(spy).toHaveBeenCalledTimes(0);
        done();
    }, 200);

});

, это мое определение шпиона.

jest.mock('services/moviesService');

const spy = jest.spyOn(moviesService, 'searchMovies');

beforeEach(() => {
    moviesService.searchMovies.mockImplementation(keyword => {
        return Promise.resolve(moviesResult);
    });
    spy.mockClear();
});

и этоэто эпопея

import { Observable, interval } from 'rxjs';
import { combineEpics } from 'redux-observable';

import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/debounce';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/from';
import 'rxjs/add/observable/of';
import 'rxjs/add/observable/interval';
import 'rxjs/add/observable/concat';

import actionTypes from 'actions/actionTypes';
import * as moviesService from 'services/moviesService';
import * as moviesActions from 'actions/moviesActions';

const DEBOUNCE_INTERVAL_IN_MS = 300;
const MIN_MOVIES_SEARCH_LENGTH = 3;

export function loadMoviesEpic($action) {
  return $action
    .ofType(actionTypes.MOVIES.LOAD_MOVIES)
    .debounce(() => Observable.interval(DEBOUNCE_INTERVAL_IN_MS))
    .filter(({ payload }) => payload.length >= MIN_MOVIES_SEARCH_LENGTH)
    .switchMap(({ payload }) => {
      const loadingAction = Observable.of(moviesActions.loadingMovies());

      const moviesResultAction = Observable.from(
        moviesService.searchMovies(payload)
      )
        .map(moviesResultList => moviesActions.moviesLoaded(moviesResultList))
        .catch(err => Observable.of(moviesActions.loadError(err)));

      return Observable.concat(loadingAction, moviesResultAction);
    });
}

const rootEpic = combineEpics(loadMoviesEpic);

export default rootEpic;

, поэтому в принципе эта вещь не должна называться, потому что время отката составляет 300 мс, и я пытаюсь проверить шпиона через 200 мс.Но через 10 мс вызывается шпион.

Как правильно проверить этот эпос?Я принимаю любые предложения, но желательно избегать испытаний мрамора и полагаться только на таймеры и фальшивые таймеры.

Спасибо: D

Ответы [ 2 ]

2 голосов
/ 19 марта 2019

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

Так как вы излучаете с of, конец наблюдаемого достигнут, и debounce сразу пропускает последнее излученное значение.

Вот простой тест, демонстрирующий поведение:

import { of } from 'rxjs';
import { debounceTime } from 'rxjs/operators';

test('of', () => {
  const spy = jest.fn();
  of(1, 2, 3)
    .pipe(debounceTime(1000000))
    .subscribe(v => spy(v));
  expect(spy).toHaveBeenCalledWith(3);  // 3 is emitted immediately
})

Кдля эффективного тестирования debounce или debounceTime вам нужно использовать наблюдаемую, которая продолжает излучать и не заканчивает использовать что-то вроде interval:

import { interval } from 'rxjs';
import { debounceTime } from 'rxjs/operators';

test('interval', done => {
  const spy = jest.fn();
  interval(100)
    .pipe(debounceTime(500))
    .subscribe(v => spy(v));
  setTimeout(() => {
    expect(spy).not.toHaveBeenCalled();  // Success!
    done();
  }, 1000);
});
1 голос
/ 19 марта 2019

Вместо setTimeout попробуйте advanceTimersByTime

...