Jest:如何模拟组件子元素的函数?附React组件示例
如何用Jest模拟React组件子元素的相关函数?
先来看看你提供的Columns组件代码:
class Columns extends React.Component { fetchCSVData = async () => { const { ownerId } = this.props; const CSVTrackResponse = await getCSVClientReport({ ownerId }); fileDownload(CSVTrackResponse, 'lifetimeTracks.csv'); }; render() { const children = React.Children.map(this.props.children, child => { return React.cloneElement(child, { onDownload: () => this.fetchCSVData() }); }); return <ColumnsContainer>{children}</ColumnsContainer>; } }
这个组件的核心逻辑是给所有子元素传递onDownload属性,当子元素触发这个方法时,会执行异步的CSV下载流程。咱们可以分步骤用Jest来测试这个逻辑,同时模拟子元素的交互。
步骤1:模拟外部依赖
首先得把组件里用到的外部函数getCSVClientReport和fileDownload给mock掉,这样测试时不会真的发起网络请求或者触发浏览器下载行为:
// 替换成你实际的文件路径 jest.mock('../utils/getCSVClientReport', () => jest.fn(() => Promise.resolve('mock-csv-content'))); // 假设fileDownload来自file-saver库,根据你的实际依赖调整 jest.mock('file-saver', () => ({ fileDownload: jest.fn() }));
步骤2:创建模拟子组件
为了测试子元素是否正确接收并触发onDownload,咱们可以写一个极简的模拟子组件,比如一个点击就调用onDownload的按钮:
const MockChild = ({ onDownload, 'data-testid': testId }) => ( <button onClick={onDownload} data-testid={testId}> 下载CSV </button> );
步骤3:编写测试用例
这里咱们用@testing-library/react来编写测试(你也可以用Enzyme,不过Testing Library更贴近用户真实行为):
import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import Columns from './Columns'; import getCSVClientReport from '../utils/getCSVClientReport'; import { fileDownload } from 'file-saver'; describe('Columns组件', () => { // 每次测试前清空mock的调用记录,避免测试相互干扰 beforeEach(() => { jest.clearAllMocks(); }); it('应该给子元素传递onDownload属性,点击时触发下载流程', async () => { // 渲染Columns组件,并传入模拟子元素 render( <Columns ownerId="user-123"> <MockChild /> </Columns> ); // 找到下载按钮并模拟点击 const downloadBtn = screen.getByText('下载CSV'); fireEvent.click(downloadBtn); // 验证getCSVClientReport是否用正确的参数调用了 expect(getCSVClientReport).toHaveBeenCalledWith({ ownerId: 'user-123' }); // 等待异步操作完成,验证fileDownload是否被正确调用 await waitFor(() => { expect(fileDownload).toHaveBeenCalledWith('mock-csv-content', 'lifetimeTracks.csv'); }); }); it('应该给所有子元素都传递onDownload属性', () => { // 渲染带有多个子元素的Columns组件 render( <Columns ownerId="user-456"> <MockChild data-testid="child-btn-1" /> <MockChild data-testid="child-btn-2" /> </Columns> ); // 点击第一个子按钮,验证调用 const btn1 = screen.getByTestId('child-btn-1'); fireEvent.click(btn1); expect(getCSVClientReport).toHaveBeenCalledWith({ ownerId: 'user-456' }); // 清空mock记录,测试第二个子按钮 jest.clearAllMocks(); const btn2 = screen.getByTestId('child-btn-2'); fireEvent.click(btn2); expect(getCSVClientReport).toHaveBeenCalledWith({ ownerId: 'user-456' }); }); });
关键要点说明
jest.clearAllMocks():每次测试前清空mock的调用记录,确保不同测试用例之间不会互相干扰。waitFor:因为fetchCSVData是异步函数,必须用waitFor等待异步操作完成后再验证结果。- 模拟子组件:通过自定义模拟子组件,咱们可以精准控制交互行为,验证父组件是否正确传递了回调属性。
内容的提问来源于stack exchange,提问作者Tomas Eglinskas
相关产品推荐
相关产品推荐

