DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Aditya Padhi
Aditya Padhi

Posted on • Updated on

React Route Guards with Unit Testing

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'
}
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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} />
   )}/>
 )}/>
Enter fullscreen mode Exit fullscreen mode

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)

18 Useful Github Repositories Every Developer Should Bookmark

18 Useful GitHub repositories every developer should bookmark: everything from learning resources and roadmaps to best practices, system designs, and tools.