You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

测试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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 14:01:13