ln09nv2
ln09nv2

Reputation: 1343

React Testing Library Invariant failed: You should not use <Route> outside a <Router>

I'm testing if my components render with Redux successfully with React Testing Library. I'm having trouble having my utility component to pass the renderWithRedux test. This is my App component.

function App() {
return (
    <>
        <Router>
            <NavBar />
            <div className="container">
                <Switch>
                    <Route exact path='/' component={Home}/>
                    <AuthRoute exact path='/login' component={Login} />
                    <AuthRoute exact path='/signup' component={Signup} />
                    <Route exact path='/users/:handle' component={UserProfile} />
                    <Route exact path='/users/:handle/post/:postId' component={UserProfile} />
                </Switch>
            </div>
        </Router>
    </>
);

}

Here is my AuthRoute utility component.

const AuthRoute = ({ component: Component, authenticated, ...rest }) => (
      // if authenticated, redirect to homepage, otherwise redirect to signup or login
        <Route
        {...rest}
        render={(props) =>
          authenticated === true ? <Redirect to='/' /> : <Component {...props} />
        }
      />
    );

AuthRoute.test.js

const renderWithRedux = () => render(
    <Provider store={myStore}>
        <AuthRoute />
    </Provider>
);

it('renders with Redux', () => {
    const {} = renderWithRedux(<AuthRoute />);
});

I've attempted the solutions from Invariant failed: You should not use <Route> outside a <Router>, but to no avail. I appreciate any help, thank you.

Upvotes: 4

Views: 4801

Answers (3)

Stefan Đikić
Stefan Đikić

Reputation: 73

Basically, you have two wrapper elements. It should go something like this, for example, renderWithReduxWrapp => renderWithRouter => YourTestingComponent.

I had a similar issue when trying to test Button render (which has a Link) depending on props, and was able to solve it by creating some helper functions.

Here is the example:

This is the main component, UserCard.js, which renders user data from redux, and only shows a button if withButton props is passed.

import React from "react";
import { Link } from "react-router-dom";
import { Button } from "react-bootstrap";

const CardComponent = ({ withButton }) => {
 const userInfo = useSelector((state) => getUserSelector(state));
  return (
   <div>
    <div>{userInfo}</div>
    {withButton && (
     <Link to="/settings" className="button-link">
      <Button block>EDIT CONTACT INFO</Button>
     </Link>
    )}
   </div>
  );
 };
export default CardComponent;

This is a CardComponent.test.js file. First, you need to add these lines of code

const ReduxWrapper = ({ children }) => {
 <Provider store={store}>{children} </Provider>;
}
const AppWrapper = ({ children }) => (
 <BrowserRouter>
  <ReduxWrapper>{children}</ReduxWrapper>
 </BrowserRouter>
);
const renderWithRouter = (ui, { route = '/' } = {}) => {
 window.history.pushState({}, 'Test page', route);
 return render(ui, { wrapper: AppWrapper });
};

After that, you need to start your test with renderWithRouter instead of just render method.

it('should render settings button if prop withButton is passed', () => {
 renderWithRouter(<CardComponent withButton />, { wrapper: ReduxWrapper });
 // apply you code here. I only needed to check if the button is renederd or not.
 const settingsButton = screen.queryByText(/edit contact info/i);
 expect(settingsButton).toBeInTheDocument();
});

Upvotes: 1

Drew Reese
Drew Reese

Reputation: 202761

Render the component under test into a router

import { MemoryRouter } from 'react-router-dom';

const renderWithRedux = ({ children }) => render(
    <Provider store={myStore}>
        {children}
    </Provider>
);

it('renders with Redux', () => {
    const {} = renderWithRedux(
      <MemoryRouter>
        <AuthRoute />
      </MemoryRouter>
    );
});

Upvotes: 9

Sheldon Oliveira
Sheldon Oliveira

Reputation: 1005

Just like the Provider to wrap redux things you have to wrap your components with routes using MemoryRouter for the tests.

import { MemoryRouter } from 'react-router';

Upvotes: 2

Related Questions