如何用Jest编写测试用例覆盖依赖AppContext的React useEffect逻辑
测试实现方案
我们使用React Testing Library + Jest的通用技术栈完成测试,核心思路是模拟useAppContext自定义Hook的返回值,主动控制依赖项nextData的输入,验证useEffect触发后的组件行为是否符合预期,具体实现如下:
1. 前置准备
首先确保已安装测试依赖:
npm install @testing-library/react @testing-library/jest-dom jest -D
2. 可测试性改造(可选,推荐)
原组件的topic状态和generateEmail逻辑为内部私有,为了避免测试侵入内部实现,建议给渲染的按钮增加测试专用属性,方便直接断言结果:
return ( <a download="meeting.eml" onClick={generateEmail} data-testid="send-email-btn" data-topic-list={JSON.stringify(topics)} > send </a> );
3. 编写测试用例
测试覆盖3个核心场景:
- 初始渲染时useEffect正常触发,正确过滤出
flag=false的主题 nextData更新时useEffect重新触发,主题列表同步更新- 点击发送按钮时,能拿到正确的第一个主题
测试代码示例:
import { render, screen, fireEvent } from '@testing-library/react'; import { ShareEmail } from './ShareEmail'; // 替换为你项目中useAppContext的实际存放路径 import { useAppContext } from './app-context'; // 模拟自定义Hook,控制nextData的返回值 jest.mock('./app-context'); const mockUseAppContext = useAppContext as jest.Mock; describe('ShareEmail组件useEffect逻辑测试', () => { // 每次用例执行前清空mock缓存 beforeEach(() => jest.clearAllMocks()); test('初始渲染时useEffect触发,正确过滤未标记的主题', () => { const mockNextData = [ { id: 1, name: '需求评审', flag: false }, { id: 2, name: '已归档主题', flag: true }, { id: 3, name: '迭代排期', flag: false }, ]; mockUseAppContext.mockReturnValue({ nextData: mockNextData }); render(<ShareEmail />); const sendBtn = screen.getByTestId('send-email-btn'); const topicList = JSON.parse(sendBtn.getAttribute('data-topic-list')); // 断言过滤结果符合预期:只保留flag为false的2条 expect(topicList.length).toBe(2); expect(topicList[0].name).toBe('需求评审'); }); test('nextData更新时useEffect重新触发,主题列表同步更新', () => { // 首次渲染传入旧数据 mockUseAppContext.mockReturnValue({ nextData: [{ id: 1, name: '旧主题', flag: false }] }); const { rerender } = render(<ShareEmail />); // 模拟nextData更新,重新渲染组件 mockUseAppContext.mockReturnValue({ nextData: [{ id: 2, name: '新主题', flag: false }] }); rerender(<ShareEmail />); const sendBtn = screen.getByTestId('send-email-btn'); const topicList = JSON.parse(sendBtn.getAttribute('data-topic-list')); // 断言主题列表已更新为新数据 expect(topicList.length).toBe(1); expect(topicList[0].name).toBe('新主题'); }); test('点击发送按钮时,正确取到第一个主题', () => { // 这里可以根据你实际generateEmail的业务逻辑扩展断言,比如验证生成的邮件内容、下载链接等 const mockNextData = [{ id: 1, name: '测试主题', flag: false }]; mockUseAppContext.mockReturnValue({ nextData: mockNextData }); render(<ShareEmail />); // 模拟点击发送 fireEvent.click(screen.getByTestId('send-email-btn')); // 补充你的业务逻辑断言即可 }); });
内容的提问来源于stack exchange,提问作者prabhakaran s
相关产品推荐
相关产品推荐

