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

React组件添加AppNavbar后测试失败,Mock组件报错求解决

解决AppNavbar导致的测试全失败问题

问题原因

  1. 空值访问报错:AppNavbar组件初始化时直接执行AuthService.getCurrentlyAuthenticatedUser().userId,测试环境无登录用户,localStorage.getItem("authenticatedUser")返回null,JSON解析后仍是null,访问.userId触发Cannot read properties of null (reading 'userId')错误。
  2. Mock方法错误:mockComponent(AppNavbar)并非Jest或React Testing Library的官方API,导致出现Cannot read properties of undefined (reading 'render')异常。

方案1:直接Mock AppNavbar组件

用Jest的jest.mock替换整个AppNavbar,让它在测试中渲染一个空组件,彻底跳过原组件的逻辑:

修改LoginForm.test.js,在文件顶部添加Mock:

import AppNavbar from './AppNavbar'; // 确保路径与项目一致

// 将AppNavbar Mock为一个空占位组件
jest.mock('./AppNavbar', () => () => <div data-testid="mock-navbar"></div>);

// 后续测试代码保持不变
const server = setupServer(
  rest.post(config.URL + "/auth/login", (req, res, ctx) => {
    return res(ctx.json("Success."))
  }),
)
// ... 其余测试逻辑

这样LoginForm渲染时会使用Mock的空组件,不会触发原AppNavbar里的AuthService调用,测试即可正常执行。

方案2:Mock AuthService的返回值

如果需要保留AppNavbar的渲染逻辑,或者测试依赖Navbar存在,可以Mock AuthService的getCurrentlyAuthenticatedUser方法,返回模拟用户数据:

方式A:Mock AuthService模块

假设AuthService是独立模块,在LoginForm.test.js中添加:

import AuthService from './AuthService'; // 路径需匹配项目

// Mock指定方法,保留其他方法原有实现
jest.mock('./AuthService', () => ({
  ...jest.requireActual('./AuthService'),
  getCurrentlyAuthenticatedUser: () => ({ userId: 'test-123' }) // 返回带userId的模拟对象
}));

方式B:直接Mock localStorage

不想修改AuthService的话,可在测试前给localStorage添加模拟用户数据:

beforeEach(() => {
  // 设置模拟认证用户数据
  localStorage.setItem('authenticatedUser', JSON.stringify({ 
    userId: 'test-123', 
    accessToken: 'fake-token' 
  }));
});

afterEach(() => {
  // 测试后清空localStorage,避免影响其他用例
  localStorage.clear();
});

额外优化:让AppNavbar更健壮(推荐)

为避免生产环境也出现类似错误(比如未登录用户访问页面),给AppNavbar添加空值判断:

修改AppNavbar.js:

export const AppNavbar = () => {
  // 先获取用户对象,用可选链安全访问userId
  const authenticatedUser = AuthService.getCurrentlyAuthenticatedUser();
  const userId = authenticatedUser?.userId;

  const [isOpen, setIsOpen] = useState(false);
  const toggle = () => setIsOpen(!isOpen);

  return (
    <>
      <Navbar className="NavBar" color="dark" dark expand="sm">
        <NavbarBrand id="NavBarBrand" href="/">Po</NavbarBrand>
        <NavbarToggler onClick={toggle} />
        <Collapse isOpen={isOpen} navbar>
          <Nav navbar className="ml-auto" id="Nav">
            {/* 仅当userId存在时渲染Profile链接 */}
            {userId && (
              <NavItem className="NavLink">
                <NavLink href={`/profile/${userId}`} className="NavLink">Profile</NavLink>
              </NavItem>
            )}
            {/* 其余导航项保持不变 */}
            <UncontrolledDropdown nav inNavbar>
              <DropdownToggle nav caret>
                Play
              </DropdownToggle>
              <DropdownMenu end>
                <DropdownItem tag="a" href={'/players'}>
                  Players
                </DropdownItem>
                <DropdownItem tag="a" href={'/top-players'}>
                  Top Players
                </DropdownItem>
              </DropdownMenu>
            </UncontrolledDropdown>
            {/* ... 其他下拉菜单 */}
          </Nav>
        </Collapse>
      </Navbar>
    </>
  )
}

这样即使无登录用户,AppNavbar也不会报错,而是自动隐藏Profile链接,同时测试稳定性也会提升。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 21:21:36