react-router-domreact-testing-libraryazure-ad-msalmsal.jsmsal-react

How to write unit test case for react msal library private router in reactjs


I am trying to write the unit test case for the private route we created, using @azure/msal-react

below is the code for the private route

import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import {
    AuthenticatedTemplate,
    UnauthenticatedTemplate,
} from '@azure/msal-react';

export const PrivateRoute = (props) => {
    const {
        component: Component,
        ...restProps
    } = props;

    if (!Component) return null;
    return (
        <Route
            exact
            {...restProps}
            render={(routeRenderProps) => (
                <>
                    <AuthenticatedTemplate>
                        <Component
                            {...routeRenderProps}
                            {...restProps}
                        />
                    </AuthenticatedTemplate>
                    <UnauthenticatedTemplate>
                        <Redirect
                            to={{
                                pathname: '/auth/signin',
                                state: { from: routeRenderProps.location },
                            }}
                        />
                    </UnauthenticatedTemplate>
                </>
            )}
        />
    );
};

below is the unit test case I wrote using react testing library

import React from 'react';
import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import { MsalAuthenticationTemplate } from '@azure/msal-react';
import { PrivateRoute } from '../privateRoute';

describe('PrivateRoute', () => {
  test('renders the component when the user is authenticated', () => {
    const Component = () => <div>My Component</div>;
    render(
      <MemoryRouter initialEntries={['/']}>
        <MsalAuthenticationTemplate>
          <PrivateRoute
            path="/"
            component={Component}
          />
        </MsalAuthenticationTemplate>
      </MemoryRouter>,
    );

    const componentElement = screen.getByText('My Component');
    expect(componentElement).toBeInTheDocument();
  });
});

but this test case doesn't work, as it was not able to find the component.

pls refer to the attached image,

enter image description here

Could please help me to resolve this issue?

another test case I tried like this below, here I am setting an authentication status by passing a mockClient to the msal provider

import React from 'react';
import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import { MsalProvider } from '@azure/msal-react';
import { PrivateRoute } from '../privateRoute';

describe('PrivateRoute', () => {
  test('renders the component when the user is authenticated', () => {
    const Component = () => <div>My Component</div>;

    // Create an instance of MsalProvider with a mocked instance
    const mockClient = {
      getAllAccounts: jest.fn(() => [{ name: 'Test User' }]),
    };
    render(
      <MsalProvider instance={mockClient}>
        <MemoryRouter initialEntries={['/']}>
          <PrivateRoute path="/" component={Component} />
        </MemoryRouter>
      </MsalProvider>,
    );

    const componentElement = screen.getByText('My Component');
    expect(componentElement).toBeInTheDocument();
  });

});

but it shows the below error message

enter image description here


Solution

  • Found the way to set the authentication status

    Please find the below code for it. msal-react-tester this library helps to set the authentication status.

    import React from 'react';
    import { render, screen } from '@testing-library/react';
    import { MemoryRouter } from 'react-router-dom';
    import { MsalProvider } from '@azure/msal-react';
    import { MsalReactTester } from 'msal-react-tester';
    import { PrivateRoute } from '../privateRoute';
    
    describe('PrivateRoute', () => {
        let msalTester;
    
        beforeEach(async () => {
            // new instance of msal tester for each test:
            msalTester = new MsalReactTester();
    
            // Ask msal-react-tester to handle and mock all msal-react processes:
            await msalTester.spyMsal();
        });
    
        afterEach(async () => {
            // reset msal-react-tester
            await msalTester.resetSpyMsal();
        });
    
        test('renders the component when the user is authenticated', async () => {
            const Component = () => <div>My Component</div>;
    
            // Set the user as logged in
            await msalTester.isLogged();
    
            render(
                <MsalProvider instance={msalTester.client}>
                    <MemoryRouter initialEntries={['/']}>
                        <PrivateRoute path="/" component={Component} />
                    </MemoryRouter>
                </MsalProvider>,
            );
    
            // Wait for the authentication redirect to resolve
            await msalTester.waitForRedirect();
    
            const componentElement = screen.getByText('My Component');
            expect(componentElement).toBeInTheDocument();
        });
           
    });