https://reacttraining.com/react-router/web/example/auth-workflow
My implementtaion of the Private-Route in the react-router-dom docs
function PrivateRoute({ authenticated, ownProps }) {
let {component:Component, ...rest} = ownProps
//PrivateRoute, If not authenicated ie false, redirect
return (
<Route
// JSX Spread sttributes to get path for Route
{...rest}
render={() => authenticated ? (
<Component />
) :
<Redirect
to={{pathname: "/" }}
/>
}
/>
);
}
export default PrivateRoute
PrivateRoute been a connected component getting authentication status from Redux-Store.
I am trying to test the connected component, using redux-mock-store and mount from enzyme.
import configureStore from 'redux-mock-store'
const mockStore = configureStore()
const authStateTrue = {auth: {AUTHENTICATED: true}};
test('Private path renders a component when auntentication is true', () => {
const store = mockStore(authStateTrue)
const AComponent = () => <div>AComponent</div>
const props = {path:"/aprivatepath" ,component:<AComponent/>};
let enzymeWrapper = mount(<Provider store={store}>
<BrowserRouter>
<PrivateRoute path="/aprivatepath" component={AComponent}/>
</BrowserRouter>
</Provider>);
expect(enzymeWrapper.exists(AComponent)).toBe(true)
});
The test is failing
Seems the component passed to the PrivateRoute is not existing even if the authentication in state is true.
How do I test a component is rendered or redirected in PrivateRoute.
Use the useLocation() hook to get the current route with React Router, e.g. const location = useLocation() . The hook returns the current location object. For example, you can access the pathname as location. pathname .
The /, /pricing, and /login routes will be publicly accessible while our /dashboard and /settings route will be private. For now, we’ll just render them like normal Route s though. At this point we’re not doing anything fancy. We’ve successfully mapped the app’s location to a few components, typical React Router stuff.
One advantage is that we can test the 404 route easily by passing a pathname in initial entry array which is not handled by any component, and assert that the NoMatch is present. So we saw both the ways to test the routes in react using jest - mapping the routes and creating the object, or using the memory router.
You could use auth-react-router package npmjs.com/package/auth-react-router It provides a really simple API to define your routes and few more configurations (like redirect routes for authorized and unauthorized routes, fallback component for each of the routes) Just define your routes path and pages component and it will work
In react-router-dom version 6 there is no render prop for the Route component. You can also simplify your PrivateRoute wrapper component a bit, it doesn't need to render more Routes and Route components. Conditionally render the component's children or navigate to log in.
Here is the unit test solution:
privateRoute.tsx
import React from 'react';
import { Route, Redirect } from 'react-router';
function PrivateRoute({ authenticated, ownProps }) {
const { component: Component, ...rest } = ownProps;
return <Route {...rest} render={() => (authenticated ? <Component /> : <Redirect to={{ pathname: '/' }} />)} />;
}
export default PrivateRoute;
privateRoute.test.tsx
:
import PrivateRoute from './privateRoute';
import React from 'react';
import { mount } from 'enzyme';
import { MemoryRouter, Redirect } from 'react-router';
describe('56730186', () => {
it('should render component if user has been authenticated', () => {
const AComponent = () => <div>AComponent</div>;
const props = { path: '/aprivatepath', component: AComponent };
const enzymeWrapper = mount(
<MemoryRouter initialEntries={[props.path]}>
<PrivateRoute authenticated={true} ownProps={props} />
</MemoryRouter>,
);
expect(enzymeWrapper.exists(AComponent)).toBe(true);
});
it('should redirect if user is not authenticated', () => {
const AComponent = () => <div>AComponent</div>;
const props = { path: '/aprivatepath', component: AComponent };
const enzymeWrapper = mount(
<MemoryRouter initialEntries={[props.path]}>
<PrivateRoute authenticated={false} ownProps={props} />
</MemoryRouter>,
);
const history: any = enzymeWrapper.find('Router').prop('history');
expect(history.location.pathname).toBe('/');
});
});
Unit test results with 100% coverage:
PASS src/stackoverflow/56730186/privateRoute.test.tsx (15.063s)
56730186
✓ should render component if user has been authenticated (96ms)
✓ should redirect if user is not authenticated (23ms)
------------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
------------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
privateRoute.tsx | 100 | 100 | 100 | 100 | |
------------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 17.053s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/56730186
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