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

React Testing Library渲染Login组件仅返回空结构,无法获取表单内容

解决React Testing Library测试Login组件时仅渲染空div的问题

问题根源

直接用render(<Login/>)测试时,组件依赖的多个上下文缺失,且内部逻辑触发了跳转,导致最终只渲染空div:

  • 路由上下文缺失:组件使用useNavigate、useLocation,但测试时未提供React Router上下文,<Navigate>组件无有效上下文时不会渲染内容
  • Redux上下文缺失:useAppDispatch需要Redux Provider包裹才能正常工作
  • 国际化上下文缺失:useTranslation依赖i18n上下文,缺失会导致组件渲染异常
  • Token判断逻辑触发跳转:测试环境中getTokenFromLocalStorage可能返回值,或decodeToken解析错误,导致组件提前返回<Navigate>

解决步骤

1. 为测试组件添加必要的上下文包裹

需要用MemoryRouter提供路由上下文,用mock的Redux Provider提供状态管理上下文,用I18nextProvider提供国际化上下文。

2. Mock localStorage相关方法

让getTokenFromLocalStorage和getRefreshTokenFromLocalStorage返回null,避免触发跳转逻辑:

jest.mock('../utils/localStorage', () => ({
  getTokenFromLocalStorage: jest.fn(() => null),
  getRefreshTokenFromLocalStorage: jest.fn(() => null),
}));

3. Mock decodeToken函数

避免解析无效token导致的错误:

jest.mock('jwt-decode', () => ({
  decodeToken: jest.fn(() => null),
}));

4. Mock自定义hook

对于useYupTranslation、useDocumentTitle这类不影响表单渲染的自定义hook,直接mock为空函数:

jest.mock('../hooks/useYupTranslation', () => jest.fn());
jest.mock('../hooks/useDocumentTitle', () => jest.fn());

5. 配置mock Redux Store

创建一个简单的mock store,让useAppDispatch能正常返回函数:

import { configureStore } from '@reduxjs/toolkit';
import authReducer from '../slices/authSlice';

const mockStore = configureStore({
  reducer: {
    auth: authReducer,
  },
});

完整测试代码示例

import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom/extend-expect";
import Login from "../views/Login";
import { MemoryRouter } from "react-router-dom";
import { Provider } from "react-redux";
import { configureStore } from '@reduxjs/toolkit';
import authReducer from '../slices/authSlice';
import { I18nextProvider } from 'react-i18next';
import i18n from '../i18n'; // 引入你的i18n配置文件

// Mock localStorage方法
jest.mock('../utils/localStorage', () => ({
  getTokenFromLocalStorage: jest.fn(() => null),
  getRefreshTokenFromLocalStorage: jest.fn(() => null),
}));

// Mock decodeToken
jest.mock('jwt-decode', () => ({
  decodeToken: jest.fn(() => null),
}));

// Mock自定义hook
jest.mock('../hooks/useYupTranslation', () => jest.fn());
jest.mock('../hooks/useDocumentTitle', () => jest.fn());

// 创建mock Redux store
const mockStore = configureStore({
  reducer: {
    auth: authReducer,
  },
});

it("should render input elements", () => {
  render(
    <I18nextProvider i18n={i18n}>
      <Provider store={mockStore}>
        <MemoryRouter>
          <Login />
        </MemoryRouter>
      </Provider>
    </I18nextProvider>
  );
  
  // 现在可以正常获取表单元素
  expect(screen.getByLabelText(/email/i)).toBeInTheDocument();
  expect(screen.getByLabelText(/password/i)).toBeInTheDocument();
  expect(screen.getByRole('button', { name: /submit/i })).toBeInTheDocument();
  
  screen.debug();
});

额外说明

  • 如果你的i18n配置比较复杂,可以简化mock,比如直接返回固定的翻译值:
    jest.mock('react-i18next', () => ({
      useTranslation: () => ({
        t: (key: string) => key.split(':')[1], // 比如t("common:form.email")返回"form.email"
        i18n: {},
      }),
    }));
    
  • 确保所有依赖的上下文都被正确包裹,否则组件可能无法正常渲染。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 16:31:03