How do I unit test the component in react router v4? I am unsuccessfully trying to unit test a simple component with a redirect using jest and enzyme.
My component:
const AppContainer = ({ location }) =>
(isUserAuthenticated()
? <AppWithData />
: <Redirect
to={{
pathname: "/login",
state: { from: location }
}}
/>);
My attempt to test it:
function setup() {
const enzymeWrapper = mount(
<MemoryRouter initialEntries={["/"]}>
<AppContainer />
</MemoryRouter>
);
return {
enzymeWrapper
};
}
jest.mock("lib/authAPI", () => ({
isUserAuthenticated: jest.fn(() => false)
}));
describe("AppContainer component", () => {
it("renders redirect", () => {
const { enzymeWrapper } = setup();
expect(enzymeWrapper.find("<Redirect></Redirect>")).toBe(true);
});
});
You’ve set up react-testing-library with Jest and react-router. You want to check that a component successfully redirects to another page. But how? Your React application comes with a protected route. If a user is not authenticated, the app should redirect the user to the login screen.
MemoryRouter works when you don't need access to the history object itself in the test, but just need the components to be able to render and navigate. If you do need to change the history, you could use BrowserRouter. import { MemoryRouter } from 'react-router-dom' test('full app rendering/navigating', () => {
Your React application comes with a protected route. If a user is not authenticated, the app should redirect the user to the login screen. You’ve managed to set up react-router-dom for your component. For example, here’s an excerpt from a UserStatus.jsx component that only an authenticated user should be able to access:
Answering my own question. Basically I'm making a shallow render of my component and verifying that if authenticated is rendering the redirect component otherwise the App one. Here the code:
function setup() {
const enzymeWrapper = shallow(<AuthenticatedApp />);
return {
enzymeWrapper
};
}
describe("AuthenticatedApp component", () => {
it("renders Redirect when user NOT autheticated", () => {
authApi.isUserAuthenticated = jest.fn(() => false);
const { enzymeWrapper } = setup();
expect(enzymeWrapper.find(Redirect)).toHaveLength(1);
});
it("renders AppWithData when user autheticated", () => {
authApi.isUserAuthenticated = jest.fn(() => true);
const { enzymeWrapper } = setup();
expect(enzymeWrapper.find(AppWithData)).toHaveLength(1);
});
});
Neither of these answers worked for me and took a fair bit of digging so I thought I'd chip in my experience here.
export const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={(props) => (
auth.isAuthenticated
? <Component {...props} />
: <Redirect to={{
pathname: '/',
state: { from: props.location }
}} />
)} />
)
This test worked for me with no problems whatsoever, it rendered the PrivateComponent
when auth.isAuthenticated
evaluated to true.
it('renders the component when the user is authorised', () => {
auth.login()
expect(auth.isAuthenticated).toBe(true)
const privateRoute = mount(
<MemoryRouter initialEntries={['/privateComponent']}>
<PrivateRoute path='/privateComponent' component={PrivateComponent} />
</MemoryRouter>
)
expect(privateRoute.find('PrivateComponent').length).toEqual(1)
})
This was the test that gave me a lot of issues. At first I was checking for the Redirect
component.
I tried to just do something like
expect(privateRoute.find('Redirect').length).toEqual(1)
But that just wouldn't work, no matter what I did, it just couldn't find the Redirect
component. In the end, I ended up checking the history but couldn't find any reliable documentation online and ended up looking at the React Router codebase.
In MemoryRouter.js (line 30) I saw that it rendered a Router
component. I noticed that it was also passing it's history
as a prop to Router
so I figured I would be able to grab it from there.
I ended up grabbing the history prop from Router
using privateRoute.find('Router').prop('history')
which then finally gave me evidence that a redirect had actually happened, to the correct location, no less.
it('renders a redirect when the user is not authorised', () => {
auth.logout()
expect(auth.isAuthenticated).toBe(false)
const privateRoute = mount(
<MemoryRouter initialEntries={['/privateComponent']}>
<PrivateRoute path='/privateComponent' component={PrivateComponent} />
</MemoryRouter>
)
expect(privateRoute.find('PrivateComponent').length).toEqual(0)
expect(
privateRoute.find('Router').prop('history').location.pathname
).toEqual('/')
})
With this test, you're testing the actual functionality of the PrivateRoute
component and ensuring that it goes where it's saying it's going.
The documentation leaves a lot to be desired. For example, it took a fair bit of digging for me to find out about initialEntries
as a prop for MemoryRouter
, you need this so it actually hits the route and executes the conditional, I spent too long trying to cover both branches only to realise this was what was needed.
Hope this helps someone.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With