测试MSAL React应用时如何Mock身份认证流程
@azure/msal-react 组件测试Mock方案
测试场景下不需要走真实身份认证流程,也不需要传入真实用户凭证发起外部网络请求,直接通过Mock MSAL实例的方式就可以覆盖所有测试场景,实现方式如下:
核心实现思路
测试环境不需要触发真实的登录跳转、令牌请求逻辑,只需要构造符合IPublicClientApplication接口规范的Mock实例,提前预置登录/未登录状态,包裹在被测组件的外层上下文即可,所有交互类方法全部用测试框架Mock掉,完全消除外部依赖。
步骤1:封装测试专用渲染工具
先创建可复用的Mock实例生成方法和自定义渲染函数,适配React Testing Library:
import { PublicClientApplication, InteractionType } from "@azure/msal-react"; import { render, fireEvent } from "@testing-library/react"; import { MsalProvider, MsalAuthenticationTemplate } from "@azure/msal-react"; // 测试用配置,不需要读取真实环境变量 const testMsalConfig = { auth: { clientId: "mock-client-id", authority: "https://login.microsoftonline.com/mock-tenant-id", redirectUri: "http://localhost:3000" }, cache: { cacheLocation: "sessionStorage", storeAuthStateInCookie: false } }; /** * 生成测试用MSAL实例 * @param {boolean} isAuthenticated 是否预置已登录状态 * @returns Mock后的MSAL实例 */ const createMockMsalInstance = (isAuthenticated = true) => { const instance = new PublicClientApplication(testMsalConfig); // 统一Mock所有会触发跳转/网络请求的方法 const mockNoop = jest.fn().mockResolvedValue(null); instance.loginRedirect = mockNoop; instance.loginPopup = mockNoop; instance.acquireTokenRedirect = mockNoop; instance.acquireTokenPopup = mockNoop; instance.acquireTokenSilent = jest.fn().mockResolvedValue({ accessToken: "mock-access-token", idToken: "mock-id-token", account: { homeAccountId: "mock-user-home-id", environment: "login.microsoftonline.com", tenantId: "mock-tenant-id", username: "test@example.com", name: "Test User" } }); // 预置账号状态 const mockAccount = { homeAccountId: "mock-user-home-id", environment: "login.microsoftonline.com", tenantId: "mock-tenant-id", username: "test@example.com", name: "Test User", localAccountId: "mock-local-account-id" }; if (isAuthenticated) { instance.getAllAccounts = jest.fn().mockReturnValue([mockAccount]); instance.getAccountByHomeId = jest.fn().mockReturnValue(mockAccount); instance.getAccountByUsername = jest.fn().mockReturnValue(mockAccount); } else { instance.getAllAccounts = jest.fn().mockReturnValue([]); instance.getAccountByHomeId = jest.fn().mockReturnValue(null); instance.getAccountByUsername = jest.fn().mockReturnValue(null); } return instance; }; /** * 带MSAL上下文的测试渲染方法 * @param {React.ReactNode} ui 被测组件 * @param {object} options 配置项 * @param {boolean} options.isAuthenticated 是否预置登录态 */ const renderWithMsal = (ui, { isAuthenticated = true } = {}) => { const msalInstance = createMockMsalInstance(isAuthenticated); return { msalInstance, ...render(<MsalProvider instance={msalInstance}>{ui}</MsalProvider>) }; };
步骤2:改造测试用例
直接用封装好的renderWithMsal替换原有的render方法即可,不需要额外传入用户凭证:
test('first test', () => { // 测试受保护组件时,直接包裹认证模板即可,默认走已登录状态 const { getByText } = renderWithMsal( <MsalAuthenticationTemplate interactionType={InteractionType.Redirect} errorComponent={() => <div>Auth Error</div>} loadingComponent={() => <div>Loading</div>} > <SampleComponentUnderTest /> </MsalAuthenticationTemplate> ); const someText = getByText('A line of text'); expect(someText).toBeInTheDocument(); });
扩展测试场景
- 测试未登录逻辑时,只需要传入
isAuthenticated: false即可,还可以校验登录方法是否被正确触发:
test('triggers login redirect when sign in button clicked', () => { const { getByText, msalInstance } = renderWithMsal(<UnauthenticatedHomePage />, { isAuthenticated: false }); const signInBtn = getByText('Sign in'); fireEvent.click(signInBtn); expect(msalInstance.loginRedirect).toHaveBeenCalled(); });
- 如果需要测试令牌获取失败、登录报错等异常场景,只需要把对应Mock方法的返回值改成
Promise.reject(new Error('mock error'))即可覆盖。
注意:这套方案完全适配@azure/msal-react的上下文逻辑,不会出现MSAL上下文缺失的报错,所有认证相关逻辑都在测试环境内闭环,不会请求真实的微软身份服务,不需要依赖测试租户、测试用户账号等外部资源。
内容的提问来源于stack exchange,提问作者savreline
相关产品推荐
相关产品推荐

