In this blog post I would like to share my approach to create manageable Route Guards as well as to write unit test cases for that specific implementation.
We will be testing Route Guards & the way it behaves based on the user roles.
We will be using jest & @testing-library/react for writing unit test cases.
I will also share a cleaner approach to test a component that returns redirect URL which will be helpful to test in a lot of scenarios like failed login testing, session timeout testing etc.
While creating any web application there is a scenario where we need to add guards to route or prevent unauthorized access to certain URLs.
There are many ways to do it, however one of the cleaner ways is to handle it on the client side.
Let us take a hypothetical case where the roles are “viewer, publisher, admin”.
The viewer will not have any access to the admin pages while the later will have access to all the pages.
In a typical scenario when the user successfully logs into the application the server sends some information like this:-
{
token: 'qwqwqw',
fullName: 'qwq ee',
role: 'viewer'
}
We can utilize the above response & create a simple route guard.
Step 1 could be to store the role in localStorage in an encrypted manner using an awesome npm module pako.
However in this article I am simply using local Storage.
Step 2 could be to create a route guard.
import React from "react";
import { Redirect } from "react-router";
function RouteGuard(props) {
let userRole = localStorage.getItem("userRole") || "viewer";
if (props.allowedRoles.indexOf(userRole) > -1) {
return props.render({ userRole: userRole });
}
return <Redirect to="/unauthorized" />;
}
export default RouteGuard;
In this simple functional module we created a logic to check for the role & return the component passed to the render props of the RouteGuard component. So basically we are using render props property of React.
So in index.js we can import this component & use it like:-
<Route
path="/welcome"
render={props => (
<RouteGuard
allowedRoles={["admin", "publisher", "viewer"]}
render={guardProps => (
<GenericComponent greet="user" {...guardProps} {...props} />
)}/>
)}/>
The GenericComponent is a simple hello world component and nothing else. This RouteGuard works perfectly with Lazy loading as we are just using the render props property of react-router-dom.
The advantage of this approach is we have full access to router props & routeGuard props.
Testing is also pretty clean for these Route Guards. As it is not possible to see the test tab in the embedded version of CodeSandbox you can click on this https://codesandbox.io/s/objective-jennings-hlzf0?from-embed & then click on Open Sandbox on the bottom right corner to get a clearer picture.
To check for the test cases click on the Test tab. (I know CodeSandbox is an awesome tool & everyone knows it :) )
I have added comments in test cases & code for more clarity.
Let me know your views in comments :)
Top comments (0)