2017-04-03 49 views
0

我遵循從documentation步驟來測試史詩。Redux-observable:失敗的歌劇測試史詩

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

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

,但我得到失敗,因爲已經收到了一些後來像下面的第二個動作。

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. 

所以我想我應該知道什麼時候調度完成或者類似的。 我該如何解決這個問題?

我用取()和Rx.Observable.fromPromise代替ajax.getJSON()

這裏是我的史詩。

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

的原因是,承諾總是在next microtask解決讓你api.fetchUser()不同步發射。

您需要或是嘲笑它,使用類似Promise.resolve().then(() => expect(store.getActions).toEqual(...)要等到下一個microtask,或者您也可以直接與測試你的史詩不使用終極版實驗。

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和中間件,而是直接使用我們自己的模擬來調用史詩功能。更容易和更清潔。

用這種方法,我們可以利用的新的依賴注入功能終極版,可觀察到: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 
    }]); 
    }); 
+1

我看答案是正確的。我得到了「TypeError:無法讀取屬性'_location'null',儘管它不在問題之中。 – Oscar

+0

我在這上面敲了幾個小時......試過這個,得到了「...數組不是函數」的錯誤。 –

+0

好的,添加導入'rxjs/add/operator/toArray'解決了它... –