Dan
Dan

Reputation: 51

I am not able to set a specefic path in test

Problem: My App component is responsible to render the other components based on the path. So inorder to test it, I need to be able to "set" the path. e.g I'd like to see the SignUp component is rendered when the path is /sign-up.

What I've done: I thought I could use initialEntries to give the MemoryRouter an initial path (unsuccessful) then I thought I might be able to use Route/Redirect directly in my test inside MemoryRouter to set the path, but that did not work either.

Specification:

Upvotes: 5

Views: 5804

Answers (2)

Atomicts
Atomicts

Reputation: 2396

I spent a while trying to figure this out myself. Simply put you cannot nest a <Router> within the <MemoryRouter> as they are both Routers.

Solution Example:

Routes.js - Remove <BrowserRouter> from this so you can test your code.

    import React from 'react';
    import { Route, Switch } from 'react-router-dom';
    import SignUp from '../SignUp/SignUp'; //your signup component
    import Home from '../Home/Home'; //some other component for an example

    const MyRoutes = () => (
        <Switch>
            <Route path="/" component={Home} />
            <Route path="/signup" component={SignUp} />
        </Switch>
    );

    export default MyRoutes;

index.js - Add <BrowserRouter> here as you will need to wrap a <Switch> in a <Router>.

    import React from 'react';
    import ReactDOM from 'react-dom';
    import { BrowserRouter } from 'react-router-dom';
    import Routes from './Components/Routes/Routes';

    ReactDOM.render(
      (
        <BrowserRouter>
          <Routes />
        </BrowserRouter>
      ), document.getElementById('root')
    );

tests/Routes.test.js - Now add the <MemoryRouter> in here for testing.

    import React from 'react';
    import ReactDOM from 'react-dom';
    import { MemoryRouter } from 'react-router-dom';
    import Routes from '../Components/Routes/Routes';

    const TestRoute = props => (
      <MemoryRouter initialEntries={props.initialEntries}>
          <Routes {...props} />
      </MemoryRouter>
    );

    it('at /signup it displays the signup page', () => {
      const div = document.createElement('div');
      ReactDOM.render(<TestRoute initialEntries={['/signup']} />, div); // render on the route "/signup"
      const elem = div.getElementsByClassName('signup')[0];
      expect(elem).not.toBe(undefined); // check an element exists with that class
      if(elem !== undefined) {
        expect(elem.innerHTML).toEqual('signup'); // check it has worked
      }
    });

In other words you are separating the Routes/Switch from the Router to enable you to be able to test it, as you cannot nest two Routers.

Upvotes: 8

Toby
Toby

Reputation: 13385

I'm having a similar issue, I have found that the following works for testing components whose behaviour changes based upon the route:

<MemoryRouter initialEntries={['/about']}>
  <Navigation {...props} />
</MemoryRouter>

In this instance, the snapshot shows that an .active className is added to the 'about' link in Navigation.

What does not seem to work is adding memory router around the component/container holding the initial routes. To keep things simple I have reduced my basic routing page to this:

<Router>
  <div className="App">
    <Navigation app={this.props.app} />
    <Switch>
      <Route exact path="/" component={Home} />
      <Route exact path="/about" component={About} />
      <Route exact path="/login" render={() => <Login app={this.props.app} />} />
      <Route exact path="/signup" render={() => <Signup app={this.props.app} />} />
      <Route exact path="/account" render={() => <Account app={this.props.app} />} />
      <Route component={ErrorPage} />
    </Switch>
  </div>
</Router>

The react-router team states in current testing docs:

We have a lot of tests that the routes work when the location changes, so you probably don’t need to test this stuff.

Upvotes: 2

Related Questions