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

如何为使用Okta的React应用编写Jest单元测试并解决Security组件act警告

解决Okta React应用Jest测试act警告并编写AppRouter单元测试

act(...)警告出现的根本原因是@okta/okta-react的Security组件初始化时会执行异步状态更新(比如校验登录状态、初始化认证实例),测试执行结束时这些异步更新还没完成,没有被React的act包裹。

前置准备

确保已安装@testing-library/react、@testing-library/jest-dom依赖。

方案一:完整模拟Okta认证逻辑(推荐,可覆盖认证相关场景)

第一步:Mock Okta相关依赖

在测试文件顶部添加Mock逻辑,避免调用真实Okta接口,同时固定认证状态:

import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import AppRouter from './AppRouter';

// 模拟全局history,解决你代码中history未导入的报错问题
global.history = {
  replace: jest.fn()
};

// Mock Okta认证核心类
jest.mock('@okta/okta-auth-js', () => {
  return {
    OktaAuth: jest.fn().mockImplementation(() => {
      return {
        start: jest.fn(),
        signInWithRedirect: jest.fn(),
        // 可修改返回值切换已登录/未登录场景
        isAuthenticated: jest.fn().mockResolvedValue(true),
        getUser: jest.fn().mockResolvedValue({ name: 'Test User' }),
        token: {
          get: jest.fn().mockResolvedValue({ accessToken: 'test-token' })
        }
      }
    }),
    toRelativeUrl: jest.fn().mockReturnValue('/')
  }
});

第二步:编写异步测试用例

通过waitFor等待Security组件内部异步更新完成,自动消除act警告:

// 测试已登录场景下根路由渲染Comp组件
test('root path renders Comp when user is authenticated', async () => {
  render(
    <MemoryRouter initialEntries={['/']}>
      <AppRouter />
    </MemoryRouter>
  );

  // 等待异步更新完成,所有更新会自动被act包裹
  await waitFor(() => {
    // 替换为你Comp组件内实际存在的文本或测试ID
    expect(screen.getByText('Comp组件的标识文本')).toBeInTheDocument();
  });
});

// 测试登录回调路由渲染
test('login callback path renders LoginCallback component', async () => {
  render(
    <MemoryRouter initialEntries={['/login/callback']}>
      <AppRouter />
    </MemoryRouter>
  );

  // LoginCallback组件默认会加载提示文本,可根据实际情况调整断言
  await waitFor(() => {
    expect(screen.getByText(/loading/i)).toBeInTheDocument();
  });
});

方案二:简化Mock(仅测试路由逻辑时使用)

如果不需要测试Okta认证逻辑,仅验证路由匹配规则,可以直接Mock Okta组件跳过内部异步逻辑:

// 替换之前的Okta mock逻辑
jest.mock('@okta/okta-react', () => ({
  ...jest.requireActual('@okta/okta-react'),
  // 直接返回子组件,跳过Security内部初始化逻辑
  Security: ({ children }) => children,
  // 把SecureRoute替换为普通Route,跳过登录校验
  SecureRoute: ({ component: Component, ...rest }) => <Route {...rest} component={Component} />
}));

// 测试用例可以直接写同步逻辑,不会触发act警告
test('root path renders Comp', () => {
  render(
    <MemoryRouter initialEntries={['/']}>
      <AppRouter />
    </MemoryRouter>
  );
  expect(screen.getByText('Comp组件的标识文本')).toBeInTheDocument();
});

核心注意点

  • 只要用到了真实的Security组件,就必须用waitFor或者findBy*这类异步查询方法等待状态更新完成,警告会自动消除。
  • 必须明确指定isAuthenticated的Mock返回值,避免出现不确定的跳转逻辑。
  • 所有路由组件测试都要用MemoryRouter包裹,指定初始路径,避免依赖浏览器环境的路由API。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 09:06:03