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

React中@azure/msal-react私有路由单元测试失败求助

解决@azure/msal-react私有路由单元测试失败问题

先确认私有路由的正确实现

先确保你的私有路由组件逻辑正确,这是测试的基础:

import { Navigate, Outlet } from 'react-router-dom';
import { useMsal } from '@azure/msal-react';

const PrivateRoute = () => {
  const { accounts } = useMsal();
  const isAuthenticated = accounts.length > 0;

  return isAuthenticated ? <Outlet /> : <Navigate to="/login" replace />;
};

export default PrivateRoute;

第一种测试:无法找到目标组件的解决

问题核心

测试时未正确挂载路由上下文与Msal认证上下文,导致私有路由无法正常渲染目标组件。

修复后的测试用例(React Testing Library)

import { render, screen } from '@testing-library/react';
import { MemoryRouter, Routes, Route } from 'react-router-dom';
import { MsalProvider } from '@azure/msal-react';
import { PublicClientApplication } from '@azure/msal-browser';
import PrivateRoute from './PrivateRoute';
import ProtectedComponent from './ProtectedComponent'; // 你的受保护业务组件

// 初始化测试用MSAL实例
const mockMsalInstance = new PublicClientApplication({
  auth: {
    clientId: 'test-client-id',
    authority: 'https://login.microsoftonline.com/common'
  }
});

test('已认证状态下渲染受保护组件', () => {
  // 模拟已登录账号
  jest.spyOn(mockMsalInstance, 'getAllAccounts').mockReturnValue([{ homeAccountId: 'test-account' }]);

  render(
    <MsalProvider instance={mockMsalInstance}>
      <MemoryRouter initialEntries={['/protected']}>
        <Routes>
          <Route element={<PrivateRoute />}>
            <Route path="/protected" element={<ProtectedComponent />} />
          </Route>
          <Route path="/login" element={<div>登录页</div>} />
        </Routes>
      </MemoryRouter>
    </MsalProvider>
  );

  // 验证目标组件渲染
  expect(screen.getByText('受保护内容')).toBeInTheDocument();
});

test('未认证状态下跳转到登录页', () => {
  // 模拟无登录账号
  jest.spyOn(mockMsalInstance, 'getAllAccounts').mockReturnValue([]);

  render(
    <MsalProvider instance={mockMsalInstance}>
      <MemoryRouter initialEntries={['/protected']}>
        <Routes>
          <Route element={<PrivateRoute />}>
            <Route path="/protected" element={<ProtectedComponent />} />
          </Route>
          <Route path="/login" element={<div>登录页</div>} />
        </Routes>
      </MemoryRouter>
    </MsalProvider>
  );

  // 验证跳转后的登录页渲染
  expect(screen.getByText('登录页')).toBeInTheDocument();
});

第二种测试:Mock Client传入MsalProvider报错的解决

常见报错原因及修复方案

  1. Mock实例缺少必要方法
    不要手动构造不完整的普通对象作为mock,直接基于PublicClientApplication实例mock关键方法,或全局mock整个模块:

    // 全局mock @azure/msal-browser
    jest.mock('@azure/msal-browser', () => ({
      PublicClientApplication: jest.fn().mockImplementation(() => ({
        getAllAccounts: jest.fn().mockReturnValue([]),
        acquireTokenSilent: jest.fn().mockResolvedValue({ accessToken: 'test-token' }),
        // 根据私有路由逻辑补充需要的方法
      }))
    }));
    
  2. MsalProvider实例类型不匹配
    必须传入PublicClientApplication的实例(真实或jest mock生成的实例),不能传入普通对象,否则会触发内部类型校验报错。

  3. 异步认证状态未等待
    如果私有路由包含异步认证逻辑,需使用waitFor等待状态更新:

    import { waitFor } from '@testing-library/react';
    
    test('异步认证完成后渲染受保护组件', async () => {
      const mockMsalInstance = new PublicClientApplication({ auth: { clientId: 'test' } });
      // 模拟异步获取账号的过程
      jest.spyOn(mockMsalInstance, 'getAllAccounts').mockImplementation(() => {
        setTimeout(() => mockMsalInstance.getAllAccounts.mockReturnValue([{ homeAccountId: 'test' }]), 100);
        return [];
      });
    
      render(
        <MsalProvider instance={mockMsalInstance}>
          <MemoryRouter initialEntries={['/protected']}>
            <Routes>
              <Route element={<PrivateRoute />}>
                <Route path="/protected" element={<ProtectedComponent />} />
              </Route>
            </Routes>
          </MemoryRouter>
        </MsalProvider>
      );
    
      await waitFor(() => {
        expect(screen.getByText('受保护内容')).toBeInTheDocument();
      });
    });
    

通用测试注意事项

  • 所有路由组件必须包裹在MemoryRouter中,避免依赖浏览器环境的window.location
  • 确保MsalProvider的instance属性是有效的PublicClientApplication实例
  • 使用jest.spyOn精准mock单个方法,避免替换整个模块导致其他依赖逻辑失效
  • 测试路由跳转时,通过initialEntries设置初始路由,验证最终渲染的目标组件

内容的提问来源于stack exchange,提问作者SDK

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 16:42:27