2016-03-22 12 views
17

Sto provando a testare un componente che eredita il contesto da un componente radice, senza caricare/eseguire il rendering di tutto dalla radice in basso. Ho provato e cercato degli esempi su come prendere in giro il contesto ma non riesco a trovare nulla (almeno questo non usa il jest).React js - Come simulare il contesto durante il test del componente

Ecco un esempio semplificato di ciò che sto cercando di ottenere.

C'è un modo semplice in cui posso fingere di reagire a Ec.context per il test?

/** 
* 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

hanno a vedere questo modulo NPM ?: https://www.npmjs.com/package/react-stub-context – JordanHendrix

+0

Grazie @Omarjmh, ho visto che anche se assunto in passato a causa della Jest esempio. Ma penso che questa ipotesi possa essere errata. – patnz

risposta

3

Sono andato con una soluzione di creazione di un componente di avvolgimento con contesto. Non sono sicuro se questo è un grande approccio, ma sta lavorando per me in questo momento:

/** 
* 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

sono andato lo stesso problema come avete fatto e ho scoperto due modi di farlo.

Il primo è un copione di base a modo tuo: crea un wrapper attorno al mio componente e inseriscilo con un contesto dinamico. Ho messo il codice sorgente sotto per quelli interessati, perché è ES6 a differenza del tuo esempio. Ma è solo per mostrare come si farebbe in ES6 e NON raccomando a nessuno di usarlo (non l'ho ancora testato personalmente).

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); 

Come ho detto, l'ho scritto io, ma non prova, perché ho trovato un molto migliore modo di fare context-iniezione quando si tenta di scrivere test per questo simulato.

Utilizzando la libreria Enzyme, che è stata creata per supportare i test dei componenti React, è possibile eseguire il rendering del componente, a scopo di test, al numero shallow/mount/static. E ciascuno di questi metodi consente un secondo argomento: il contesto.

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'); 

piuttosto straight-forward. Non l'ho ancora usato, ma sembra quello che io (e tu) volevamo fare. Credo che dovrò solo buttare la mia implementazione nella spazzatura.

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

Problemi correlati