enzyme: Invariant Violation: You should not use or withRouter() outside a
I’m trying to mount
my Application
component in a Jest/Enzyme test, but it’s giving me an error:
Invariant Violation: You should not use <Route> or withRouter() outside a <Router>
According to react router 4 docs, the components are considered valid, where I can create components composed of <Route>
s, then import them into another component and place inside a <Router>
. Anyone else experience this or have a fix?
// versions
"jest": "^21.0.2",
"enzyme": "^2.9.1",
"react-router-dom": "^4.2.2",
"sinon": "^1.17.7",
Code if that matters:
My Application component
// Application.js
...
render() {
return (
<div>
<Route path="/a" component={a} />
<Route path="/b" component={b} />
<Route path="/c" component={c} />
<Route path="/d" component={d} />
</div>
);
}
...
My app that’s consuming the Application component
// app.js
...
render((
<Provider store={store}>
<I18nextProvider i18n={i18n}>
<main>
<Router history={browserHistory}>
<Route component={Application} history={browserHistory} />
</Router>
</main>
</I18nextProvider>
</Provider>
), document.getElementById('app'));
...
My test case:
// application.spec.js
import React from 'react';
import { I18nextProvider } from 'react-i18next';
import sinon from 'sinon';
import { mount } from 'enzyme';
import Application from '../../../path/to/application';
import i18n from '../../../path/to/utils/i18n';
describe('<Application />', () => {
const history = {
push: jest.fn(),
}
it('calls componentDidMount', () => {
sinon.spy(Application.prototype, 'componentDidMount');
const wrapper = mount(<Application history={history} />);
expect(Application.prototype.componentDidMount.calledOnce).to.equal(true);
});
});
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 39
- Comments: 44 (7 by maintainers)
You can try
<MemoryRouter>
. I fixed a similar problem.Did a bit of digging through react-router codebase to see where I could get the correct context objects so withRouter thinks it is wrapped by Router in tests… Using this to wrap all mount functions with context, seems to be working for me:
createContext is a function because you can also use it to pass arguments to change context as necessary, eg if you are using react-intl and wish to test ‘en’ language in context, you can pass it in when you mount:
mountWrap(node, lang)
but it is not necessary 😀@mven probably something like this:
Note that I export the higher order component as a default while also exporting the class. I my app I use the default export (
withRouter
). And in my tests I do:Something like that
@CWSites It could be in a separate file called, say contextWrapper.js in a test helpers directory. Here is an example describe block:
@LukasBombach would you recommend your approach for testing a component that has <Link to={“/somepath”}>Link</Link>? We are using Jest, and I’m getting this error. Warning: Failed context type: The context
router
is marked as required inLink
, but its value isundefined
.@abhinavkashyap92 must have stripped it out accidentally - it is just a PropType that should be imported at the top:
import { shape } from 'prop-types';
Solved my issue by doing this:
@951565664 and others using memory router in snapshot tests. Keep in mind you’re probably attempting to test the component not the component + the router, so if you snapshot your component you’ll have more predictable snapshots. Here’s an example:
@mven take a look here #4795. it seems to be a expected behavior from RR4. I am exporting my component without withRouter and importing it in my test.
@SoccerGee you can do this:
<MemoryRouter keyLength={0}>
Usage of Router and Route from the react-router-dom solved this problem to me.
import { Router } from ‘react-router-dom’; import { Route } from ‘react-router-dom’;
instead of: import { Router } from ‘react-router’; import { Route } from ‘react-router-dom’;
@dani-media I am not familiar with the issue but it appears to me that
Link
internally makes use of React’s Context. You probably need to mock that context when mounting your component. Check this out https://reactjs.org/docs/context.htmlMaybe this also helps: http://airbnb.io/enzyme/docs/api/ShallowWrapper/setContext.html
@luk82 you wouldn’t generally use
ReactDOM.render
in an enzyme test - usemount
instead