2

ドキュメンテーションからエピックをテストする手順に従いました。

...
store.dispatch({ type: FETCH_USER });

expect(store.getActions()).toEqual([
   { type: FETCH_USER },
   { type: FETCH_USER_FULFILLED, payload }
]);
...

しかし、次のように2番目のアクションが後で受信されたため、失敗します。

Test failed
    Expected value to equal:
      [{"type": "FETCH_USER"}, {"type": "FETCH_USER_FULFILLED", "payload": [some]}]
    Received:
      [{"type": "FETCH_USER"}]

    Difference:

    - Expected
    + Received

    @@ -1,20 +1,5 @@
     Array [
       Object {"type": "FETCH_USER"},
       Object {"type": "FETCH_USER_FULFILLED", "payload": [some]} ] // this is what should be.

ですから、発送がいつ終わるかなどを知る必要があると思います。どうすればこれを解決できますか?

ajax.getJSON() の代わりに fetch() と Rx.Observable.fromPromise を使用しました

これが私の叙事詩です。

const fetchUserEpic = (action$) =>
  action$
    .ofType(FETCH_USER)
    .mergeMap(() => {
      return Rx.Observable.fromPromise(api.fetchUser())
        .map((users) => ({
          type: FETCH_USER_FULFILLED,
          payload: { users }
        }))
        .catch((error) => Rx.Observable.of({
          type: FETCH_USER_ERROR,
          payload: { error }
        }))
        .takeUntil(action$.ofType(FETCH_USER_CANCELLED))
    })
4

2 に答える 2

6

その理由は、プロミスは常に次のマイクロタスクapi.fetchUser()で解決されるため、同期的に発行されないためです。

モックアウトするかPromise.resolve().then(() => expect(store.getActions).toEqual(...)、次のマイクロタスクまで待機するようなものを使用するか、 redux を使用せずにエピックを直接テストして実験する必要があります。

it('Epics with the appropriate input and output of actions', (done) => {
  const action$ = ActionsObservable.of({ type: 'SOMETHING' });

  somethingEpic(action$, store)
    .toArray() // collects everything in an array until our epic completes
    .subscribe(actions => {
      expect(actions).to.deep.equal([
        { type: 'SOMETHING_FULFILLED' }// whatever actions
      ]);

      done();
    });
});

これは、私 (または他の誰か) がそれらを書く時間があるときに、ドキュメントで推奨されるテスト ストーリーになります。したがって、テストで redux とミドルウェアを使用する代わりに、独自のモックを使用して epic 関数を直接呼び出すだけです。はるかに簡単でクリーン。

そのアプローチにより、redux-observable の新しい依存性注入機能を活用できます: https://redux-observable.js.org/docs/recipes/InjectingDependenciesIntoEpics.html


import { createEpicMiddleware, combineEpics } from 'redux-observable';
import { ajax } from 'rxjs/observable/dom/ajax';
import rootEpic from './somewhere';

const epicMiddleware = createEpicMiddleware(rootEpic, {
  dependencies: { getJSON: ajax.getJSON }
});

// Notice the third argument is our injected dependencies!
const fetchUserEpic = (action$, store, { getJSON }) =>
  action$.ofType('FETCH_USER')
    .mergeMap(() =>
      getJSON(`/api/users/${payload}`)
        .map(response => ({
          type: 'FETCH_USER_FULFILLED',
          payload: response
        }))
    );

import { ActionsObservable } from 'redux-observable';
import { fetchUserEpic } from './somewhere/fetchUserEpic';

const mockResponse = { name: 'Bilbo Baggins' };
const action$ = ActionsObservable.of({ type: 'FETCH_USERS_REQUESTED' });
const store = null; // not needed for this epic
const dependencies = {
  getJSON: url => Observable.of(mockResponse)
};

// Adapt this example to your test framework and specific use cases
fetchUserEpic(action$, store, dependencies)
  .toArray() // buffers all emitted actions until your Epic naturally completes()
  .subscribe(actions => {
    assertDeepEqual(actions, [{
      type: 'FETCH_USER_FULFILLED',
      payload: mockResponse
    }]);
  });
于 2017-04-03T15:25:23.333 に答える