The MSAL React Tester is a NPM package to allows you creating unit tests for any of your components that need to be authenticated (or not) using the msal-react
package and Azure AD.
The MSAL React Tester package is able to run by default with different javascript test runners like:
- vitest if you are creating a React application using vite.
- jest if you are creating a React application using Create React Application.
The MSAL React Tester package allows you to test your components in any of these scenario:
- Testing a react component when a user "is not" authenticated.
- Testing a react component when a user "is" authenticated.
- Testing a react component when a user "tries" to log in.
- Testing a react component when a user "tries" to log out.
- Testing a react component when a user authentication request has "failed".
- You are building a react application using Create React Application or vite.
- You are using
@azure/msal-react
to authenticate your users on Azure AD. - You are using the built in
@testing-library/react
package to create and run your tests (you are basically using the built in"test": "react-scripts test"
script to execute your tests). - You want to create unit tests without having to depends on a connection to Azure AD.
- You want to run your tests in your CI/CD.
The MSAL React Tester package is available on NPM.
npm install --save-dev msal-react-tester
If you are using the vitest test runner, you need to add this to your config
import { MsalReactTesterPlugin } from 'msal-react-tester'
import { waitFor } from "@testing-library/react";
import { vi, expect } from 'vitest'
MsalReactTesterPlugin.init({
spyOn: vi.spyOn,
expect: expect,
resetAllMocks: vi.resetAllMocks,
waitingFor: waitFor
})
If you are using jest this step is not necessary.
Creates a [component].test.tsx
and import the msal-react-tester package:
import { MsalReactTester } from 'msal-react-tester';
- Create a new instance of
MsalReactTester
before each test.- Depending on your setup, you can create your instance to mock a Redirect authentication or a Popup authentication.
- Call the
spyMsal()
method to mock all the MSAL React required methods & events. - Don not forget to call
resetSpyMsal
after each test.
let msalTester: MsalReactTester;
beforeEach(() => {
// new instance of msal tester for each test:
msalTester = new MsalReactTester();
// or new MsalReactTester("Redirect") / new MsalReactTester("Popup")
// Ask msal-react-tester to handle and mock all msal-react processes:
msalTester.spyMsal();
});
afterEach(() => {
// reset msal-react-tester
msalTester.resetSpyMsal();
});
In each of your test, you can now:
- Mock an unauthenticated user, calling
await msalTester.isNotLogged()
. - Mock an authenticated user, calling
await msalTester.isLogged()
. - Creates a
<MsalProvider />
using themsalTester.client
as theIPublicClientApplication
instance. - Call
msalTester.waitForRedirect()
to let MSAL React Tester handling MSAL React processes - Then makes any tests or assertions.
Here is an example where we are testing a <HomePage />
component during a first visit by an authenticated user:
test('Home page render correctly when user is not logged', async () => {
// Mock a guest user, not yet authenticated:
await msalTester.isNotLogged();
// Render the <HomePage /> component using a <MsalProvider />
// with the mock IPublicClientApplication instance:
render(
<MsalProvider instance={msalTester.client}>
<MemoryRouter>
<Layout>
<HomePage />
</Layout>
</MemoryRouter>
</MsalProvider>,
);
// Wait for msal-react-tester to handle events from msal-react:
await msalTester.waitForRedirect();
// Test your <HomePage /> component:
expect(screen.getByText(/Please sign-in/)).toBeInTheDocument();
});
On the other side, you can test the same component assuming your user is "already logged", using await msalTester.isLogged()
.
If you want to test a component during the authentication process, you can use await msalTester.waitForLogin()
:
test('Home page render correctly when user logs in', async () => {
// Mock a guest user, not yet authenticated:
await msalTester.isNotLogged();
// Render the <HomePage /> component using a <MsalProvider />
// with the mock IPublicClientApplication instance:
render(
<MsalProvider instance={msalTester.client}>
<MemoryRouter>
<Layout>
<HomePage />
</Layout>
</MemoryRouter>
</MsalProvider>,
);
// Wait for msal-react-tester to handle events from msal-react:
await msalTester.waitForRedirect();
// Getting the log in button.
// Mock a user click to launch the log in process:
const signin = screen.getByRole('button', { name: 'Sign In' });
userEvent.click(signin);
// Wait for msal-react-tester to handle the login process from msal-react:
await msalTester.waitForLogin();
// From here, your user is supposed to be logged in the component:
expect(screen.getByRole('button',
{ name: msalTester.activeAccount.name })).toBeInTheDocument();
});
On the other side, if you want to test component during a log out process, use msalTester.waitForLogout()
You will find a full example in the ../example
folder.
Take a look on the pages tests:
root
├── example
├──── src
├────── pages
├──────── HomePage.test.tsx
├──────── SearchPage.test.tsx
Licensed under the MIT License.
Feel free to contact me through twitter : @sebpertus