2015-05-14 8 views
8

Sto provando a testare un componente React che richiede il react-router separatamente da app.js.Avviso di Reazione: Tipi di contesto non riusciti: contesto obbligatorio `router` non specificato in` Componente`

Ho un componente che fa un redirect utilizzando il Router.Navigation mixin in questo modo:

var React = require('react'), 
    Router = require('react-router'); 

var Searchbar = React.createClass({ 

    mixins : [Router.Navigation], 

    searchTerm: function(e) { 
    if (e.keyCode !== 13) { 
     return; 
    } 

    this.context.router.transitionTo('/someRoute/search?term=' + e.currentTarget.value) 
    }, 

    render: function() { 
    return (
     <div className="searchbar-container"> 
     <input type="search" placeholder="Search..." onKeyDown={this.searchTerm} /> 
     </div> 
    ) 
    } 
}); 

module.exports = Searchbar; 

ho cercato di scrivere un test per questo, ma ha incontrato un muro. A parte il fatto che io sono in grado di testare che transitionTo funziona come previsto, ho anche incontrato questo messaggio di errore nel mio test Jest:

Avviso: impossibile tipi di contesto: contesto Richiesto router non è stato specificato in Searchbar.

Qualcuno sa come posso eliminare l'avviso e la domanda bonus, come posso verificare che la transizione funzioni come previsto?

Ho fatto ricerche su questa e su questa conversazione su Github qui: https://github.com/rackt/react-router/issues/400 è il più vicino che ho trovato sul problema. Sembra che ho bisogno di esportare il router separatamente, ma sembra un sacco di spese generali per eseguire solo test dei componenti senza l'avviso a la https://github.com/rackt/react-router/blob/master/docs/guides/testing.md

È davvero la strada da percorrere?

+0

Hai trovato una soluzione per questo? – Tom

+0

Nessuno, che sono riuscito a lavorare, ma ci sto ancora lavorando. Non è ultra urgente in quanto sono solo messaggi di avvertimento, ma sono fastidiosi. Lo otterrò comunque. – alengel

+0

Ciao @ Tom Ho finalmente trovato una soluzione perché l'ultimo paragrafo di BinaryMuse mi ha portato sulla giusta strada. Ho postato la mia risposta con il codice. – alengel

risposta

5

Nella versione 0.13 di React Router, i mixaggi Navigation e State sono stati ritirati. Invece, i metodi che forniscono esistono sull'oggetto this.context.router. I metodi non sono più deprecati, ma se stai usando this.context.router esplicitamente non hai bisogno del mixin (ma devi dichiarare lo contextTypes direttamente); oppure, è possibile utilizzare il mixin, ma non è necessario utilizzare direttamente this.context.router. I metodi di mixin lo accederanno per te.

In entrambi i casi, a meno che non si esegua il rendering del componente tramite React Router (tramite Router#run), l'oggetto router non viene fornito nel contesto e, naturalmente, non è possibile chiamare il metodo di transizione. Questo è ciò che l'avviso ti dice: il tuo componente si aspetta che il router venga passato, ma non riesce a trovarlo.

per testare questo in isolamento (senza creare un oggetto router o in esecuzione il componente attraverso Router#run), è possibile inserire un deriso router oggetto sul contesto del componente nel posto giusto, e la prova che si chiama transitionTo su di esso con il corretto valore.

+2

Anche questa risposta è deprecata: https://github.com/rackt/react-router/blob/master/UPGRADE_GUIDE.md Come molti altri nella comunità, abbiamo frainteso il sentimento di "mixin sta andando via". I mixins, insieme a React.createClass, non stanno andando via in qualunque momento presto, e sicuramente non prima che le classi ES6 abbiano risposte migliori per sostituire ciò che fanno i mix (come i decoratori). – Peter

+0

L'ultimo paragrafo di questa risposta mi ha dato la soluzione. Vedi la mia risposta per maggiori dettagli. – alengel

+0

nuova guida di aggiornamento è qui https://github.com/rackt/react-router/blob/latest/upgrade-guides/v2.0.0.md – Tom

3

Perché il router si basa pesantemente sul meno noto context caratteristica di Reagire è necessario stub piace descritto here

var stubRouterContext = (Component, props, stubs) => { 
    return React.createClass({ 
    childContextTypes: { 
     makePath: func, 
     makeHref: func, 
     transitionTo: func, 
     replaceWith: func, 
     goBack: func, 
     getCurrentPath: func, 
     getCurrentRoutes: func, 
     getCurrentPathname: func, 
     getCurrentParams: func, 
     getCurrentQuery: func, 
     isActive: func, 
    }, 

    getChildContext() { 
     return Object.assign({ 
     makePath() {}, 
     makeHref() {}, 
     transitionTo() {}, 
     replaceWith() {}, 
     goBack() {}, 
     getCurrentPath() {}, 
     getCurrentRoutes() {}, 
     getCurrentPathname() {}, 
     getCurrentParams() {}, 
     getCurrentQuery() {}, 
     isActive() {}, 
     }, stubs); 
    }, 

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

E utilizzare come:

var stubRouterContext = require('./stubRouterContext'); 
var IndividualComponent = require('./IndividualComponent'); 
var Subject = stubRouterContext(IndividualComponent, {someProp: 'foo'}); 
React.render(<Subject/>, testElement); 
4

Ecco il mio file Jest per un risposta completa a questa domanda. L'ultimo paragrafo di BinaryMuse mi ha portato sulla strada giusta, ma trovo che gli esempi di codice siano sempre i più utili, quindi qui è per riferimento futuro.

jest.dontMock('./searchbar'); 

describe('Searchbar', function() { 
    var React = require('react/addons'), 
     Searchbar = require('../../components/header/searchbar'), 
     TestUtils = React.addons.TestUtils; 

    describe('render', function() { 
    var searchbar; 

    beforeEach(function() { 
     Searchbar.contextTypes = { 
     router: function() { 
      return { 
      transitionTo: jest.genMockFunction() 
      }; 
     } 
     }; 

     searchbar = TestUtils.renderIntoDocument(
     <Searchbar /> 
    ); 
    }); 

    it('should render the searchbar input', function() { 
     var searchbarContainer = TestUtils.findRenderedDOMComponentWithClass(searchbar, 'searchbar-container'); 

     expect(searchbarContainer).toBeDefined(); 
     expect(searchbarContainer.props.children.type).toEqual('input'); 
    }); 

    }); 

}); 

Spero che questo aiuti qualcun altro in futuro.

2

La mia risposta non è specifica per Jest, ma potrebbe aiutare le persone a incontrare lo stesso problema. Ho creato una classe per avvolgere routercontext.

Poi, nel tuo test è sufficiente aggiungere
<ContextWrapper><YourComponent/></ContextWrapper>

può essere utile per avvolgere altre cose come ReactIntl.

Si noti che si perderà la possibilità di utilizzare il rendering superficiale, ma questo è già il caso con ReactIntl.

La speranza che aiuta qualcuno.


ContextWrapper.js

import React from 'react'; 

export default React.createClass({ 
    childContextTypes: { 
     router: React.PropTypes.object 
    }, 

    getChildContext() { 
     return { 
      router: {} 
     }; 
    }, 

    render() { 
     return this.props.children; 
    } 
});