React Warning: Failed Context Types: Required `router` context was not specified in` Component`

I am trying to test the React component, which requires interaction with the router separately from app.js.

I have a component that redirects using mixin Router.Navigation as follows:

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; 

I tried to write a test for this, but ran into a wall. Besides the fact that I can’t verify that the transition works as expected, I also came across this error message in Jest tests:

Warning: broken context types: a required router context is not specified in the Searchbar .

Does anyone know how I can get rid of the warning and bonus question, how can I verify that the transition is working as expected?

I did research on this and this talk on Github here: https://github.com/rackt/react-router/issues/400 is the closest I found to the problem. It seems like I need to export the router separately, but it seems like a lot of overhead to just run component tests without warning a la https://github.com/rackt/react-router/blob/master/docs/guides/testing.md

Is this really the way to go?

+8
reactjs react-router jestjs
source share
4 answers

In 0.13 React Router, the Navigation and State mixes are deprecated. Instead, the methods they provide exist on this.context.router . The methods are no longer deprecated, but if you use this.context.router explicitly, you do not need mixin (but you need to declare contextTypes directly); or you can use mixin, but you do not need to use this.context.router directly. Mixin methods will access it for you.

In any case, if you do not pass your component through the React Router (via Router#run ), the router object will not be passed to the context, and, of course, you cannot call the transition method. This is what a warning alerts you - your component expects the router to be handed over to it, but it will not be able to find it.

To test this in isolation (without creating a router object or launching a component through Router#run ), you could put the selected router object in the component context in the right place and verify that you call transitionTo on it with the correct value.

+5
source share

Here is my Jest file for a complete answer to this question. The last paragraph of BinaryMuses gave me the right way, but I believe that code examples are always the most useful, so here for reference in the future.

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

Hope this helps someone else in the future.

+4
source share

Since router relies heavily on React's lesser-known context function, you need to drown it out as described 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} /> } }); }; 

And use like:

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

My answer is not dependent on Jest, but it can help people facing the same problem. I created a class to wrap the router context .

Then in your test just add <ContextWrapper><YourComponent/></ContextWrapper>

It may be useful to wrap other things, such as ReactIntl .

Note that you will lose the ability to use small rendering, but this is already the case with ReactIntl .

Hope this helps someone.


ContextWrapper.js

 import React from 'react'; export default React.createClass({ childContextTypes: { router: React.PropTypes.object }, getChildContext () { return { router: {} }; }, render () { return this.props.children; } }); 
+2
source share

All Articles