如何测试组件中的隐藏Div?Jest+TypeScript下useState模拟问题
解决React组件useState测试覆盖率问题
要覆盖你组件中!isEditorLoading对应的渲染分支,核心是触发真实的状态更新逻辑,而非直接mock useState——直接mock useState会破坏React内部状态管理机制,导致无法正确跟踪状态变化,这也是你覆盖率不达标的常见原因。
测试思路
- 初始渲染时,验证按钮区域未显示(对应
isEditorLoading=true的分支)。 - 模拟EmailEditor的
onReady回调触发,这会调用setIsEditorLoading(false)改变状态。 - 重新渲染组件后,验证按钮区域已显示(覆盖
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
相关产品推荐
相关产品推荐

