reactjsreact-routerreact-router-domtesting-library

How to test React Router V6 Outlet using @testing-library/react


I have a component that I am using in React Router v6 for managing private routes, that does some checks on an auth token, and will either render the Outlet component or will redirect to a login page.

I have -

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

export const CheckAuth = (props) => {
  const valid = ...;
  if (!valid) {
    window.location.replace(loginUrl);
    return null;
  }

  return <Outlet />;
};

and using it like -

<Route element={<CheckAuth token={authToken} />}>
   // ... private routes ...
</Route>

I can mock out window.location.replace with Jest

delete window.location;
window.location = { replace: jest.fn() };
...
render(<CheckAuth token={token} />)
expect(window.location.replace).toHaveBeenCalledWith(loginUrl);

but how can I test the Outlet component using Testing Library?


Solution

  • If it helps anyone, I ended up just wrapping the components in the test with a react router components, and passed a dummy component as a child to Route and asserted that some fake text in that component was or was not rendered

    Outside the test block -

    const FakeComponent = () => <div>fake text</div>;
    

    and for a failure scenario, where the outlet should not render -

        render(
          <MemoryRouter initialEntries={['/']}>
            <Routes>
              <Route element={<CheckAuth />}>
                <Route path="/" element={<FakeComponent />} />
              </Route>
            </Routes>
          </MemoryRouter>
        );
    
        await waitFor(() => expect(screen.queryByText('fake text')).not.toBeInTheDocument());
        await waitFor(() => expect(window.location.replace).toHaveBeenCalledWith(loginUrl));
    

    and for a success scenario, assert that the text is present -

    render(
          <MemoryRouter initialEntries={['/']}>
            <Routes>
              <Route element={<CheckAuth token={correctToken}/>}>
                <Route path="/" element={<FakeComponent />} />
              </Route>
            </Routes>
          </MemoryRouter>
        );
    
        expect(screen.getByText('fake text')).toBeInTheDocument();