在测试MSAL React应用程序时模拟身份验证



我们的应用程序以标准的方式封装在@azure/msal-react的MSAL认证模板中-关键代码段总结如下。

我们想测试应用程序的各个组件使用react测试库(或类似的东西)。当然,当像SampleComponentUnderTest这样的React组件要被测试正确呈现时(如下面的简单测试所示),它也必须包装在MSAL组件中。

是否有合适的方法来模拟MSAL身份验证过程?无论如何,在MSAL中包装一个正在测试的组件,并直接提供测试用户的凭据给这个正在测试的组件?如能提供有用的文档、博客、视频等资料,为我们指出正确的方向,我们将不胜感激。

简单测试

test('first test', () => {
const { getByText } = render(<SampleComponentUnderTest />);
const someText = getByText('A line of text');
expect(someText).toBeInTheDocument();
});

配置

export const msalConfig: Configuration = {
auth: {
clientId: `${process.env.REACT_APP_CLIENT_ID}`,
authority: `https://login.microsoftonline.com/${process.env.REACT_APP_TENANT_ID}`,
redirectUri:
process.env.NODE_ENV === 'development'
? 'http://localhost:3000/'
: process.env.REACT_APP_DEPLOY_URL,
},
cache: {
cacheLocation: 'sessionStorage',
storeAuthStateInCookie: false,
},
system: {
loggerOptions: {
loggerCallback: (level, message, containsPii) => {
if (containsPii) {
return;
}
switch (level) {
case LogLevel.Error:
console.error(message);
return;
case LogLevel.Info:
console.info(message);
return;
case LogLevel.Verbose:
console.debug(message);
return;
case LogLevel.Warning:
console.warn(message);
return;
default:
console.error(message);
}
},
},
},
};

主应用组件

const msalInstance = new PublicClientApplication(msalConfig);
<MsalProvider instance={msalInstance}>
{!isAuthenticated && <UnauthenticatedHomePage />}
{isAuthenticated && <Protected />}
</MsalProvider>
<<p>未经身份验证的组件/strong>
const signInClickHandler = (instance: IPublicClientApplication) => {
instance.loginRedirect(loginRequest).catch((e) => {
console.log(e);
});
};
<UnauthenticatedTemplate>
<Button onClick={() => signInClickHandler(instance)}>Sign in</Button>
</UnauthenticatedTemplate>
<<p>保护组件/strong>
<MsalAuthenticationTemplate
interactionType={InteractionType.Redirect}
errorComponent={ErrorComponent}
loadingComponent={LoadingComponent}
>
<SampleComponentUnderTest />
</MsalAuthenticationTemplate>

关于组件在msal-react下的测试,我有与您相同的问题。我花了几天时间才弄清楚如何实现正确的验证模拟。这就是为什么我在这里创建了一个包,它封装了所有的样板代码:https://github.com/Mimetis/msal-react-tester

基本上,您可以在几行中完成多个场景(用户已登录,用户未登录,用户必须登录等),而无需配置任何内容,当然也无需在任何情况下到达Azure AD:

describe('Home page', () => {
let msalTester: MsalReactTester;
beforeEach(() => {
// new instance of msal tester for each test
msalTester = new MsalReactTester();
// spy all required msal things
msalTester.spyMsal();
});
afterEach(() => {
msalTester.resetSpyMsal();
});
test('Home page render correctly when user is logged in', async () => {
msalTester.isLogged();
render(
<MsalProvider instance={msalTester.client}>
<MemoryRouter>
<Layout>
<HomePage />
</Layout>
</MemoryRouter>
</MsalProvider>,
);
await msalTester.waitForRedirect();
let allLoggedInButtons = await screen.findAllByRole('button', { name: `${msalTester.activeAccount.name}` });
expect(allLoggedInButtons).toHaveLength(2);
});
test('Home page render correctly when user logs in using redirect', async () => {
msalTester.isNotLogged();
render(
<MsalProvider instance={msalTester.client}>
<MemoryRouter>
<Layout>
<HomePage />
</Layout>
</MemoryRouter>
</MsalProvider>,
);
await msalTester.waitForRedirect();
let signin = screen.getByRole('button', { name: 'Sign In - Redirect' });
userEvent.click(signin);
await msalTester.waitForLogin();
let allLoggedInButtons = await screen.findAllByRole('button', { name: `${msalTester.activeAccount.name}` });
expect(allLoggedInButtons).toHaveLength(2);
});

我也很好奇,但是从一个稍微不同的角度。我试图避免在代码库中直接使用来自msal的组件,以防我们在某些时候想要替换身份提供程序。实现此目的的主要方法是使用钩子作为抽象层,例如通过该钩子而不是msal组件库本身暴露isAuthenticated。

useAuth钩子将直接使用MSAL包。然而,对于包装器组件,我认为我们必须创建一个单独的组件,该组件要么返回MsalProvider,要么返回您选择的模拟验证提供者。因为MsalProvider在底层使用了useContext,所以我认为你不需要把它包装在另一个上下文提供程序中。

希望这些想法在你思考如何做到这一点时有所帮助。要知道这不是对你问题的直接回答。

最新更新