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?
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();