2016-03-22 5 views
17

ルートコンポーネントからコンテキストを継承するコンポーネントを、ルートからすべてをロード/レンダリングせずにテストしようとしています。私はコンテキストを模倣する方法についての例を試してみましたが、何も見つけることができません(少なくとも冗談を使わない)。React js - コンポーネントをテストするときにコンテキストをモックする方法

ここに私が達成しようとしている簡単な例があります。

私はreactEl.contextをテスト用に模倣する簡単な方法はありますか?

/** 
* Root Element that sets up & shares context 
*/ 
class Root extends Component { 
    getChildContext() { 
    return { 
     language: { text: 'A String'} 
    }; 
    } 

    render() { 
    return (
     <div> 
     <ElWithContext /> 
     </div> 
    ); 
    } 
} 

Root.childContextTypes = { language: React.PropTypes.object }; 

/** 
* Child Element which uses context 
*/ 
class ElWithContext extends React.Component{ 
    render() { 
    const {language} = this.context; 
    return <p>{language.text}</p> 
    } 
} 

ElWithContext.contextTypes = { language: React.PropTypes.object } 



/** 
* Example test where context is unavailable. 
*/ 
let el = React.createElement(ElWithContext) 

element = TestUtils.renderIntoDocument(el); 
// ERROR: undefined is not an object (evaluating 'language.text') 

describe("ElWithContext",() => { 
    it('should contain textContent from context',() => { 
    const node = ReactDOM.findDOMNode(element); 
    expect(node.textContent).to.equal('A String'); 
    }); 
}) 
+0

は、あなたがこのNPMモジュール?:https://www.npmjs.com/package/react-stub-context – JordanHendrix

+0

おかげ@Omarjmhを見てきた、しかし私はそれが理由の冗談を使用想定していることがわかりました例。しかし、私は仮定が間違っていると思う。 – patnz

答えて

3

私は、コンテキストでラッピングコンポーネントを作成するソリューションを使いました。私はあなたがやったのと同じ問題に行き、それを行うための二つの方法を見つけた

/** 
* Helper function to wrap component with a component that has context 
*/ 
function wrapWithContext(context, contextTypes, children, React){ 

    const wrapperWithContext = React.createClass({ 
     childContextTypes: contextTypes, 
     getChildContext: function() { return context }, 
     render: function() { return React.createElement('div', null, children) } 
    }); 

    return React.createElement(wrapperWithContext); 
} 

/** 
* Usage 
*/ 

// in setup function of test framework 
const el = React.createElement(ElWithContext); 

const context = { language: { text: 'A String' } }; 
const contextTypes = { language: React.PropTypes.object }; 
const wrapper = wrapWithContext(context, contextTypes, [el], React); 
const ElWithContext = TestUtils.renderIntoDocument(wrapper); 

// do tests 
describe('ElWithContext',() => { 
    it('should contain textContent from context',() => { 
     const node = ReactDOM.findDOMNode(element); 
     expect(node.textContent).to.equal('A String'); 
    }); 
}) 
10

:これは偉大なアプローチですが、今の私のために働いているかどうかわかりません。

最初の1つは、独自の方法の基本的なコピーキットです。コンポーネントの周りにラッパーを作成し、動的コンテキストで注入します。あなたの例とは違ってES6なので、興味のある人のためにソースコードを以下に載せました。しかし、それはES6とでそれがどのように行われるかを示しているだけです(私は実際に自分自身でそれをテストしていない)それを使用している人はお勧めしません。

のsrc/testUtils/mockWithContext.js

import React, { Component } from 'react'; 
import wrapDisplayName from 'recompose/wrapDisplayName'; 
import hoistStatics from 'recompose/hoistStatics'; 

export const defaultContext = { 
    permissions: [ 

    ], 
    user: { 
    id: '1', 
    display_name: 'Default user', 
    email: '<your.email>[email protected]', // Trick with "+" for infinite aliases using gmail. 
    username: 'default_user', 
    created: '2016-08-01T15:50:13.246Z', 
    }, 
}; 

export const defaultContextType = { 
    permissions: React.PropTypes.array, 
    user: React.PropTypes.shape({ 
    id: React.PropTypes.string.isRequired, 
    display_name: React.PropTypes.string.isRequired, 
    email: React.PropTypes.string.isRequired, 
    username: React.PropTypes.string.isRequired, 
    created: React.PropTypes.string.isRequired, 
    }), 
}; 

/** 
* HOC for context 
*/ 
const withContext = ({ context = defaultContext, contextType = defaultContextType }) => (WrappedComponent) => { 
    class WithContext extends Component { 
    getChildContext() { 
     return context; 
    } 

    render() { 
     return <WrappedComponent {...this.props} />; 
    } 
    } 

    WithContext.displayName = wrapDisplayName(WrappedComponent, 'WithContext'); 
    WithContext.WrappedComponent = WrappedComponent; 
    WithContext.childContextTypes = contextType; 

    return WithContext; 
}; 

export default hoistStatics(withContext); 

私が言ったように、私はそれを書いたが、私はコンテキスト注入を行うもっと良い方法を見つけたので、それをテストしていませんこのモックのテストを書くとき。

Reactコンポーネントテストをサポートするために構築されたEnzymeライブラリを使用すると、テスト目的でコンポーネントをレンダリングする機能があります。shallow/mount/staticそして、これらのメソッドのそれぞれは第2引数を許します:コンテキスト。

SimpleComponent.js

const SimpleComponent = React.createClass({ 
    contextTypes: { 
    name: React.PropTypes.string, 
    }, 
    render() { 
    return <div>{this.context.name}</div>; 
    }, 
}); 

SimpleComponent.test.js

const context = { name: 'foo' }; 
const wrapper = mount(<SimpleComponent />, { context }); 
expect(wrapper.text()).to.equal('foo'); 
wrapper.setContext({ name: 'bar' }); 
expect(wrapper.text()).to.equal('bar'); 
wrapper.setContext({ name: 'baz' }); 
expect(wrapper.text()).to.equal('baz'); 

かなりストレートフォワード。私はまだそれを使用していないが、私は(そしてあなたが)したいと思ったように見えます。私は自分の実装をゴミに投げ入れる必要があるだろうと思う。

http://airbnb.io/enzyme/docs/api/ReactWrapper/setContext.html

関連する問題