Skip to content

Testing Routing

Naveed Elahi edited this page Apr 16, 2021 · 1 revision

Oftentimes you may wish to test that your application is routing appropriately. This section lays out the different scenarios related to testing routing.

Which Router to use in testing?

It is important to note that in the test environment, IonReactRouter when paired with IonRouterOutlet results in the following output on JSDOM

<body>
  <div>
    <ion-router-outlet />
  </div>
</body>

This results in all test cases failing. Therefore for the test, environment, instead of using IonReactRouter, you can use the Routers provided by react router e.g. Router, BrowserRouter or MemoryRouter. The next section discusses the differences between these three routers.

Router vs MemoryRouter vs BrowserRouter

TLDR; use Router when you need access to the history object (usually for asserting on history.location.pathname), else use MemoryRouter.

Router

Testing URL navigation

You need access to the history object so Router would be the best choice as it takes it as a props. To create the history object you can use createMemoryHistory provided by the history package.

it("should take user to the appropriate URL", () => {
  const history = createMemoryHistory({ initialEntries: ["/home"] });
  render(
    <Router history={history}>
      <MainRouter />
    </Router>
  );

  expect(history.location.pathname).toEqual("/home");
});

MemoryRouter

Testing that the correct UI is loaded

In this case you may not need access to the history object so MemoryRouter would be adequate.

it("should show user the contents of Home", () => {
  render(
    <MemoryRouter initialEntries={["/home"]}>
      <MainRouter />
    </MemoryRouter>
  );

  expect(screen.getByTestId(/home/i));
});

However, do note that when using MemoryRouter you cannot test for URL change. Therefore in most scenarios when we want to assert that both the URL as well as the content has changed we just use Router

What about BrowserRouter and using window.history?

Why not just test our components as follows:

window.history.pushState({}, "", '/');
return render(
  <AuthProvider initialAuthState={false}>
    <BrowserRouter>
      <MainRouter />
    </BrowserRouter>
  </AuthProvider>
);
...
expect(window.location.pathname).toBe('/login')

This works, however, you need to find a way to ensure test isolation because the same window object is used in subsequent tests. This means when you print out window.history.length you would see an increasing value for every test in which window.history.pushState was called. The object cannot be cleared or reset apparently due to security reasons. You could mock out the window object if you really wanted though but using Router while passing in our own history seems to be the simpler solution.

Useful Links

https://testing-library.com/docs/example-react-router/ https://github.com/ReactTraining/history/blob/v4/docs/GettingStarted.md