2017-02-28 73 views
0

說我有下列包裝部件:測試異步嵌套組件

'use strict' 

import React, {PropTypes, PureComponent} from 'react' 
import {update} from '../../actions/actions' 
import LoadFromServerButton from '../LoadFromServerButton' 
import {connect} from 'react-redux' 

export class FooDisplay extends PureComponent { 
    render() { 
    return (
     <p> 
     <span className='foo'> 
      {this.props.foo} 
     </span> 
     <LoadFromServerButton updateFunc={this.props.update} /> 
     </p> 
    ) 
    } 
} 

export const mapStateToProps = (state) => { 
    return {foo: state.foo.foo} 
} 

FooDisplay.propTypes = { 
    foo: PropTypes.string 
} 

export const mapDispatchToProps = (dispatch) => { 
    return { 
    update: (foo) => dispatch(update(foo)) 
    } 
} 

export default connect(mapStateToProps, mapDispatchToProps)(FooDisplay) 

和下面的內部部件:

'use strict' 

import React, {PropTypes, PureComponent} from 'react' 
import {get} from '../../actions/actions' 
import ActiveButton from '../ActiveButton' 
import {connect} from 'react-redux' 

export class LoadFromServerButton extends PureComponent { 
    doUpdate() { 
    return this.props.get().then(this.props.updateFunc) 
    } 

    render() { 
    return (
     <ActiveButton action={this.doUpdate.bind(this)} actionArguments={[this.props.foo]} text='fetch serverside address' /> 
    ) 
    } 
} 

export const mapStateToProps = (state) => { 
    return {foo: state.foo.foo} 
} 

export const mapDispatchToProps = (dispatch) => { 
    return { 
    get:() => dispatch(get()) 
    } 
} 

LoadAddressFromServerButton.propTypes = { 
    updateFunc: PropTypes.func.isRequired 
} 

export default connect(mapStateToProps, mapDispatchToProps)(LoadFromServerButton) 

ActiveButton是圍繞一個按鈕的非常薄的包裝用一個onclick和參數解構。

現在讓我們說,我我得到的動作寫如下:如果我寫一個測試,像這樣

export const get =() => dispatch => http('/dummy_route') 
     .spread((response, body) => dispatch(actOnThing(update, body))) 

現在:

/* global window, test, expect, beforeAll, afterAll, describe */ 

'use strict' 

import React from 'react' 
import FooDisplay from './index' 
import {mount} from 'enzyme' 
import {Provider} from 'react-redux' 
import configureStore from '../../store/configureStore' 
import nock, {uriString} from '../../config/nock' 
import _ from 'lodash' 


const env = _.cloneDeep(process.env) 
describe('the component behaves correctly when integrating with store and reducers/http',() => { 
    beforeAll(() => { 
    nock.disableNetConnect() 
    process.env.API_URL = uriString 
    }) 

    afterAll(() => { 
    process.env = _.cloneDeep(env) 
    nock.enableNetConnect() 
    nock.cleanAll() 
    }) 

    test('when deep rendering, the load event populates the input correctly',() => { 
    const store = configureStore({ 
     address: { 
     address: 'foo' 
     } 
    }) 
    const display = mount(<Provider store={store}><FooDisplay /></Provider>, 
     {attachTo: document.getElementById('root')}) 
    expect(display.find('p').find('.address').text()).toEqual('foo') 
    const button = display.find('LoadFromServerButton') 
    expect(button.text()).toEqual('fetch serverside address') 
    nock.get('/dummy_address').reply(200, {address: 'new address'}) 
    button.simulate('click') 
    }) 
}) 

這導致:

Unhandled rejection Error: Error: connect ECONNREFUSED 127.0.0.1:8080 

經過一番思考之後,這是由於測試沒有返回承諾,因爲按鈕點擊導致e承諾引擎蓋下,因此,afterAll馬上運行,清理nock,並通過真正的http連接通過電線。

我該如何測試這種情況?我似乎沒有一個簡單的方法來返回正確的承諾......我如何測試從這些更新產生的DOM更新?

+0

好像你不是用拒絕承諾處理,但只有當它滿足了。你是否打算模擬一個離線環境?如果刪除nock.disableNetConnect()及其對應部分,會發生什麼情況?如果您的測試正在執行任何異步操作,則應該包含done參數並在異步操作完成時調用它。作爲替代方案,您也可以返回測試承諾。請參閱https://facebook.github.io/jest/docs/asynchronous.html – nbkhope

+0

是的我不明白,但我怎樣才能返回正確的承諾?按鈕點擊會觸發一個異步操作,但我不清楚如何強制從測試返回正確的測試 –

+0

「更新」功能的定義在哪裏?我覺得this.props.getFoo()應該是this.props.get(),在LoadFromServerButton的doUpdate函數中? – nbkhope

回答

0

正如你所提到的問題是,你沒有承諾從測試返回。因此,爲了使get回報知道答應你可以嘲笑get的情況下直接使用箭扣:

import {get} from '../../actions/actions' 
jest.mock('../../actions/actions',() => ({get: jest.fn})) 

這將與對象替換動作模塊在測試{get: jestSpy}

,那麼你可以創建一個承諾,讓get返回這也從測試返回此承諾:

it('',()=>{ 
    const p = new Promise.resolve('success') 
    get.mockImplementation(() => p)//let get return the resolved promise 
    //test you suff 
    return p 
})