Jest, Enzyme: Invariant Violation: You should not use <Route> or withRouter() outside a <Router> Jest, Enzyme: Invariant Violation: You should not use <Route> or withRouter() outside a <Router> reactjs reactjs

Jest, Enzyme: Invariant Violation: You should not use <Route> or withRouter() outside a <Router>


To test a component (with Jest) that contains <Route> and withRouter you need to import Router in you test, not in your component

import { BrowserRouter as Router } from 'react-router-dom';

and use it like this

app = shallow(    <Router>        <App />    </Router>);


Utility Function To Wrap Mount With Context

Wrapping mount with Router in tests works, but there are situations where you don't want Router to be the parent component in your mount. Therefore I'm currently injecting context into mount using a wrapper function:

import { BrowserRouter } from 'react-router-dom';import Enzyme, { shallow, mount } from 'enzyme';import { shape } from 'prop-types';// Instantiate router contextconst router = {  history: new BrowserRouter().history,  route: {    location: {},    match: {},  },};const createContext = () => ({  context: { router },  childContextTypes: { router: shape({}) },});export function mountWrap(node) {  return mount(node, createContext());}export function shallowWrap(node) {  return shallow(node, createContext());}

This could be in a file called, say contextWrap.js, in a test helpers directory.

Example describe block:

import React from 'react';import { TableC } from '../../src/tablec';import { mountWrap, shallowWrap } from '../testhelp/contextWrap';import { expectedProps } from './mockdata'describe('Table', () => {  let props;  let component;  const wrappedShallow = () => shallowWrap(<TableC {...props} />);  const wrappedMount = () => mountWrap(<TableC {...props} />);  beforeEach(() => {    props = {      query: {        data: tableData,        refetch: jest.fn(),      },    };    if (component) component.unmount();  });  test('should render with mock data in snapshot', () => {    const wrapper = wrappedShallow();    expect(wrapper).toMatchSnapshot();  });  test('should call a DeepTable with correct props', () => {    const wrapper = wrappedMount();    expect(wrapper.find('DeepTable').props()).toEqual(expectedProps);  });});

You can also use this pattern to wrap subcomponents in other types of context, for example if you are using react-intl, material-ui or your own context types.


You need to wrap the App with a BrowserRouter or an equivalent,see the below example of simple test case a component App that uses React Router

import React from "react";import ReactDOM from "react-dom";import { BrowserRouter } from "react-router-dom";import App from "./App";it("renders without crashing", () => {  const div = document.createElement("div");  ReactDOM.render(<BrowserRouter>  <App /></BrowserRouter>,div  );  ReactDOM.unmountComponentAtNode(div);})