Sole
Sole

Reputation: 3340

Testing routes with Jest / RTL for React Router

I am trying to test some routes using RTL and Jest for React, But the test seem to be failing as I don't think the test knows the routes? I have tried to follow the RTL docs I am using "react-router-dom": "^5.2.0"

My routes:

const Routing: React.FunctionComponent = () => {

  return (
    <>
        <BrowserRouter>
          <Header/>
          <div className="App">
            <Switch>
              <Route exact path="/">
                <Redirect to="/home" />
              </Route>
              <Route exact path={["/home", "/"]} component={Home} />
              <Route path="/account-details/:account?/:id" render={(props: RouteComponentProps<any>) => <AccountDetail {...props} />} />
              <Route component={NotFound} />
            </Switch>
          </div>
        </BrowserRouter>
    </>
  )
}

export default Routing;

My test:

const accountQuery = new QueryClient()
    it('Should test 404 route', async () => {
      const history = createMemoryHistory();
      history.push('/bad/route')
        await render(
            <QueryClientProvider client={accountQuery}>
            <Router history={history}>
                <App />
            </Router>,
        </QueryClientProvider>
        )
        expect(await screen.findByText(/404 error/i)).toBeInTheDocument();
    });

If I assert the following:

expect(history.location.pathname).toBe('/bad/route');

It passes, but it does not seem to be actually taking the routes from the App even though I have rendered it?

Any Idea's? I want it to actually get the routes from the App?

Upvotes: 1

Views: 5268

Answers (1)

Lin Du
Lin Du

Reputation: 102237

You need to do some refactoring, split into two parts: Routes and App components. The BrowserRouter will create browser history and pass it to the <Router/> component, your custom memory history will not be used. See BrowserRouter.js#L14

BrowserRouter.js (react-router-dom v5):

class BrowserRouter extends React.Component {
  history = createHistory(this.props);

  render() {
    return <Router history={this.history} children={this.props.children} />;
  }
}

routes.tsx:

import React from 'react';
import { Switch, Route, Redirect } from 'react-router-dom';

const Routing = () => {
  return (
    <Switch>
      <Route exact path="/">
        <Redirect to="/home" />
      </Route>
      <Route exact path={['/home', '/']} component={() => <div>home</div>} />
      <Route path="/account-details/:account?/:id" component={() => <div>account detail</div>} />
      <Route component={() => <div>404 error</div>} />
    </Switch>
  );
};

export default Routing;

routes.test.tsx:

import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { createMemoryHistory } from 'history';
import React from 'react';
import { Router } from 'react-router-dom';
import Routing from './routes';

describe('first', () => {
  it('Should test 404 route', async () => {
    const history = createMemoryHistory();
    history.push('/bad/route');
    render(
      <Router history={history}>
        <Routing />
      </Router>
    );
    expect(await screen.findByText(/404 error/i)).toBeInTheDocument();
  });

  it('should render home page', async () => {
    const history = createMemoryHistory();
    history.push('/home');
    render(
      <Router history={history}>
        <Routing />
      </Router>
    );
    expect(await screen.findByText(/home/i)).toBeInTheDocument();
  });
  it('should render account detail page', async () => {
    const history = createMemoryHistory();
    history.push('/account-details/admin/1');
    render(
      <Router history={history}>
        <Routing />
      </Router>
    );
    expect(await screen.findByText(/account detail/i)).toBeInTheDocument();
  });
});

app.tsx:

import React from 'react';
import { BrowserRouter } from 'react-router-dom';
import Routing from './routes';

const App = () => {
  return (
    <BrowserRouter>
      <header>app</header>
      <div className="App">
        <Routing />
      </div>
    </BrowserRouter>
  );
};
export default App;

In this way, you can test the Routing component with your own custom memory history.

Test result:

 PASS  stackoverflow/72897761/routes.test.tsx (10.422 s)
  first
    ✓ Should test 404 route (30 ms)
    ✓ should render home page (7 ms)
    ✓ should render account detail page (4 ms)

------------|---------|----------|---------|---------|-------------------
File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
------------|---------|----------|---------|---------|-------------------
All files   |     100 |      100 |     100 |     100 |                   
 routes.tsx |     100 |      100 |     100 |     100 |                   
------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        10.93 s, estimated 11 s

Upvotes: 3

Related Questions