2017-09-26 73 views
2

我一直在玩rxjs和最近幾天可觀測的,並一直在努力尋找一種方法來測試Observable.ajax。我有以下的史詩,營造出請求https://jsonplaceholder.typicode.com/我該如何測試Observable.ajax(redux-observable)?

export function testApiEpic (action$) { 
    return action$.ofType(REQUEST) 
    .switchMap(action => 
     Observable.ajax({ url, method }) 
     .map(data => successTestApi(data.response)) 
     .catch(error => failureTestApi(error)) 
     .takeUntil(action$.ofType(CLEAR)) 
    ) 
} 

其中,

export const REQUEST = 'my-app/testApi/REQUEST' 
export const SUCCESS = 'my-app/testApi/SUCCESS' 
export const FAILURE = 'my-app/testApi/FAILURE' 
export const CLEAR = 'my-app/testApi/CLEAR' 

export function requestTestApi() { 
    return { type: REQUEST } 
} 
export function successTestApi (response) { 
    return { type: SUCCESS, response } 
} 
export function failureTestApi (error) { 
    return { type: FAILURE, error } 
} 
export function clearTestApi() { 
    return { type: CLEAR } 
} 

時在瀏覽器中運行,但玩笑測試時沒有代碼工作正常。

我有嘗試,

1)創建基於https://redux-observable.js.org/docs/recipes/WritingTests.html測試。 store.getActions()只返回{type:REQUEST}。

const epicMiddleware = createEpicMiddleware(testApiEpic) 
const mockStore = configureMockStore([epicMiddleware]) 

describe.only('fetchUserEpic',() => { 
    let store 

    beforeEach(() => { 
    store = mockStore() 
    }) 

    afterEach(() => { 
    epicMiddleware.replaceEpic(testApiEpic) 
    }) 

    it('returns a response,() => { 
    store.dispatch({ type: REQUEST }) 
    expect(store.getActions()).toEqual([ 
     { type: REQUEST }, 
     { type: SUCCESS, response } 
    ]) 
    }) 
}) 

2)根據Redux-observable: failed jest test for epic創建測試。它返回

超時 - 在jasmine.DEFAULT_TIMEOUT_INTERVAL指定的超時時間內未調用異步回調。

it('returns a response', (done) => { 
    const action$ = ActionsObservable.of({ type: REQUEST }) 
    const store = { getState:() => {} } 
    testApiEpic(action$, store) 
     .toArray() 
     .subscribe(actions => { 
     expect(actions).to.deep.equal([ 
      { type: SUCCESS, response } 
     ]) 
     done() 
     }) 
    }) 

有人能指出我什麼是測試Observable.ajax正確的方法是什麼?

回答

2

我會按照第二個例子,從StackOverflow。爲了使它工作,你需要做一些小的調整。您不需要直接在您的史詩文件中導入Observable.ajax並直接使用該引用,而需要使用某種形式的依賴注入。一種方法是在創建它時將其提供給中間件。

import { ajax } from 'rxjs/observable/dom/ajax'; 

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

我們作爲dependencies傳遞的對象將會給所有的史詩作爲第三個參數

export function testApiEpic (action$, store, { ajax }) { 
    return action$.ofType(REQUEST) 
    .switchMap(action => 
     ajax({ url, method }) 
     .map(data => successTestApi(data.response)) 
     .catch(error => failureTestApi(error)) 
     .takeUntil(action$.ofType(CLEAR)) 
    ); 
} 

或者,你不能使用中間件的dependencies選項,而是隻使用默認參數:

export function testApiEpic (action$, store, ajax = Observable.ajax) { 
    return action$.ofType(REQUEST) 
    .switchMap(action => 
     ajax({ url, method }) 
     .map(data => successTestApi(data.response)) 
     .catch(error => failureTestApi(error)) 
     .takeUntil(action$.ofType(CLEAR)) 
    ); 
} 

無論你選擇什麼,當我們測試史詩時,我們現在可以直接調用它,並提供我們自己的模擬。這裏是成功/錯誤/取消路徑這些未經測試,可能有問題,但應該給你的一般想法

it('handles success path', (done) => { 
    const action$ = ActionsObservable.of(requestTestApi()) 
    const store = null; // not used by epic 
    const dependencies = { 
    ajax: (url, method) => Observable.of({ url, method }) 
    }; 

    testApiEpic(action$, store, dependencies) 
    .toArray() 
    .subscribe(actions => { 
     expect(actions).to.deep.equal([ 
     successTestApi({ url: '/whatever-it-is', method: 'WHATEVERITIS' }) 
     ]) 

     done(); 
    }); 
}); 

it('handles error path', (done) => { 
    const action$ = ActionsObservable.of(requestTestApi()) 
    const store = null; // not used by epic 
    const dependencies = { 
    ajax: (url, method) => Observable.throw({ url, method }) 
    }; 

    testApiEpic(action$, store, dependencies) 
    .toArray() 
    .subscribe(actions => { 
     expect(actions).to.deep.equal([ 
     failureTestApi({ url: '/whatever-it-is', method: 'WHATEVERITIS' }) 
     ]) 

     done(); 
    }); 
}); 

it('supports cancellation', (done) => { 
    const action$ = ActionsObservable.of(requestTestApi(), clearTestApi()) 
    const store = null; // not used by epic 
    const dependencies = { 
    ajax: (url, method) => Observable.of({ url, method }).delay(100) 
    }; 
    const onNext = chai.spy(); 

    testApiEpic(action$, store, dependencies) 
    .toArray() 
    .subscribe({ 
     next: onNext, 
     complete:() => { 
     onNext.should.not.have.been.called();   
     done(); 
     } 
    }); 
});