Тестирование epi c, который потребляет задержку и от операторов - PullRequest
1 голос
/ 14 марта 2020

У меня есть этот epi c, нужна помощь для тестирования, epi c вызывает метод asyn c (от оператора), и он использует оператор задержки

export const getAll$ = (
  action$: any,
  state: { value: TStore },
  { stock, Error }: TDependencies
) => {
  return action$.pipe(
    ofType(getAll.toString()),
    map(({ meta: { failures} }) => ({
      failures,
    })),
    switchMap(({ failures }) => {
      return merge(
        of(getAllStart()),
        // call api service stock.getAll, this is async
        from(stock.getAll()).pipe(
          // wait a 1 second, not matter if stock.getAll finish early
          delay(OPERATION_DELAY),
          switchMap((response: TGetAllResponse) => {
            if(response instanceof Error) {
              return throwError(response);
            }
            return of(
              getAllSuccess()
            );
          }),
          catchError((error) => {
            return failures === 0 ?
              of(getAllFailure({ error }))
              :
              of(getAll({
                failures: failures + 1,
              })).pipe(
                delay(FAILURE_RETRY_TIME),
              );
          }),
          // "cancel" this epic if getAllAbort action is emitted
          takeUntil(
            action$.ofType(
              getAllAbort.toString()
            )
          )
        )
      )
    })
  )
};

Вот мой test


import { ActionsObservable } from 'redux-observable';

// some mocking

const state = { value: {} };

const dependencies = {
  api: {},
  stock: {
    getAll() {
      return [];
    }
  },
  Error: class Error {},
};

describe('stock epic', () => {
  it('should return all products', (done) => {
    // start epic getAll$
    getAll$(ActionsObservable.of(getAll()), state, dependencies).subscribe((action) => {
      console.log(action); //  { type: 'STOCK/GET_ALL_START' }
      done();
    });
  });
});

Если вы видите console.log(action); только возвращает { type: 'STOCK/GET_ALL_START' } Если я использую .toArray() test никогда не заканчивается *

Lorem Ipsum Dolor Sit Amet, Concetetur Adipiscing Elit. Проин c Блэндит Лео. Phasellus non turpis eu mi finibus pharetra ne c Vel ante. Phasellus non feugiat lorem, ne c ultricies quam. В porttitor bibendum facilisis. Совершено c Euismod Imperdiet Tincidunt. Mauris enim ante, suscipit iaculis mi et, convallis fermentum ante. Vestibulum eget purus pharetra, finibus Velit in, Porta metus. Vivamus interdum lobortis elit, dignissim tempor sem. Namtricies, odio sed tempus convallis, nibh lectus maximus tortor, non sollicitudin enim ex sit amet justo. Namvel lacus feugiat lorem venenatis interdum.

1 Ответ

0 голосов
/ 14 марта 2020

Через несколько часов я нашел решение, если ваш epi c использует оператор from, вы не можете его протестировать, вам нужно смоделировать этот оператор, в моем случае я просто сопоставляю этот оператор с оператором of С помощью jest это легко, создайте в папке проекта root папку с именем __mocks__ и создайте внутри нее файл js с именем rxjs.js и поместите этот код в

const rxjs = jest.requireActual('rxjs');
rxjs.from = rxjs.of;
module.exports = rxjs;

Затем для тестирования вам нужно использовать класс TestScheduler, он доступен в rxjs/testing как экспорт const

Код будет выглядеть так:

import { ActionsObservable } from 'redux-observable';
import { TestScheduler } from 'rxjs/testing';

// your epics to be tested
import epics from './stock';

// actions that you epic will emit
import {
  getAll,
  getAllStart,
  getAllSuccess,
} from '../actions/stock';

// mock the state param (if your epic use it)
import { initialState } from '../reducers/stock';

const state = {
  value: {
    stock: initialState,
  },
};

// mock your dependencies param
const dependencies = {
  api: {},
  stock: {
    getAll() { // in my real code, this is a promise, here is just a normal function, perfect to be use with the of operator
      return [];
    },
  },
  Error: class Error {},
};

describe('stock epic', () => {

  it('should return all products', (done) => {

    // this is just copy-paste
    const testScheduler = new TestScheduler((actual, expected) => {
      expect(actual).toStrictEqual(expected);
    });

    testScheduler.run(({ cold, hot, expectObservable, expectSubscriptions, flush }) => {
      expectObservable(
        epics.getAll$(
          ActionsObservable.of(getAll()), // transform action to action$
          state, // pass mocked state
          dependencies // pass mocked dependencies
        )
      ).toBe(
        // my epic has a delay(1000) call
        'a 999ms (b|)', {
          a: getAllStart(),
          b: getAllSuccess()
        }
      );
      done();
    });
  });

});
...