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

如何测试组件中的隐藏Div?Jest+TypeScript下useState模拟问题

解决React组件useState测试覆盖率问题

要覆盖你组件中!isEditorLoading对应的渲染分支,核心是触发真实的状态更新逻辑,而非直接mock useState——直接mock useState会破坏React内部状态管理机制,导致无法正确跟踪状态变化,这也是你覆盖率不达标的常见原因。

测试思路

  1. 初始渲染时,验证按钮区域未显示(对应isEditorLoading=true的分支)。
  2. 模拟EmailEditor的onReady回调触发,这会调用setIsEditorLoading(false)改变状态。
  3. 重新渲染组件后,验证按钮区域已显示(覆盖isEditorLoading=false的分支)。

具体测试代码示例

import { render, screen } from '@testing-library/react';
import CustomEmailEditor from './CustomEmailEditor';
import { useTranslation } from 'react-i18next';

// Mock外部依赖,避免干扰测试
jest.mock('react-i18next', () => ({
  useTranslation: () => ({ t: (key: string) => key }),
}));

// Mock EmailEditor,重点模拟ref传递和onReady回调触发逻辑
jest.mock('react-email-editor', () => ({
  __esModule: true,
  default: jest.fn(({ ref, onReady }) => {
    // 给ref赋值,模拟真实组件的DOM引用
    if (ref.current === null) {
      ref.current = {
        addEventListener: jest.fn(),
      };
    }
    return <div data-testid="email-editor" />;
  }),
}));

// Mock CustomButton,简化渲染结果便于断言
jest.mock('../customButton/CustomButton', () => ({
  __esModule: true,
  default: ({ holder }: { holder: string }) => <button>{holder}</button>,
}));

describe('CustomEmailEditor', () => {
  it('renders button wrapper after editor is ready', () => {
    const mockSetFieldValue = jest.fn();
    const { rerender } = render(
      <CustomEmailEditor setFieldValue={mockSetFieldValue} />
    );

    // 初始状态:按钮区域不存在
    expect(screen.queryByText('CAMPAIGN.EXPORT_HTML')).not.toBeInTheDocument();

    // 获取EmailEditor的onReady回调并手动调用,模拟编辑器加载完成
    const EmailEditor = require('react-email-editor').default;
    const onReadyCallback = EmailEditor.mock.calls[0][0].onReady;
    onReadyCallback();

    // 重新渲染组件,触发状态更新后的视图变化
    rerender(<CustomEmailEditor setFieldValue={mockSetFieldValue} />);

    // 验证按钮区域已渲染
    expect(screen.getByText('CAMPAIGN.EXPORT_HTML')).toBeInTheDocument();
    expect(screen.getByText('CAMPAIGN.SHOW_PREVIEW')).toBeInTheDocument();

    // 验证onReady中的事件监听逻辑是否执行
    const emailEditorRef = require('./CustomEmailEditor').emailEditorRef;
    expect(emailEditorRef.current.addEventListener).toHaveBeenCalledWith('design:updated', expect.any(Function));
  });
});

关键注意事项

  • 禁止直接mock useState:比如jest.spyOn(React, 'useState').mockReturnValue([true, jest.fn()])这种写法会导致状态无法正常更新,因为useState是React内部钩子,多次渲染需要依赖正确的状态快照。
  • 模拟真实交互场景:通过触发组件内的真实回调(如onReady)改变状态,更贴合组件实际使用逻辑,能自然覆盖所有代码分支。
  • 覆盖onReady内部完整逻辑:如果需要覆盖design:updated事件处理函数,可以在调用onReady后,手动触发ref上的该事件,验证对应的setFieldValue是否被调用。

内容的提问来源于stack exchange,提问作者Baran Öden

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 18:33:30