如何使用React Testing Library监视AgGrid API调用
如何测试AgGrid的CSV导出按钮调用API的行为
问题场景
我有一个包含简易AgGrid的基础React组件,组件下方设置了调用AgGrid API(例如导出为CSV)的按钮:
const GridExample = () => { const api = useRef(null); const containerStyle = { width: '100%', height: '100%' }; const [rowData, setRowData] = useState([ { date: '12/12/2022 3:00PM' }, { date: '10/31/2022 7:00PM' }, { date: '10/30/2022 7:00AM' }, { date: '10/1/2022 8:00AM' }, { date: '8/31/2022 4:59PM' }, ]); const [columnDefs, setColumnDefs] = useState([ { field: 'date' }, ]); const gridReady = (params) => { api.current = params?.api; api.current.sizeColumnsToFit(); } const csv = () => { api.current.exportDataAsCsv({ filename: new Date() }); } return ( <div style={containerStyle}> <div style={containerStyle} className="ag-theme-alpine"> <AgGridReact rowData={rowData} columnDefs={columnDefs} onGridReady={gridReady} ></AgGridReact> </div> </div> <button onClick={csv}>CSV</button> ); };
在测试中,我可以断言网格已渲染,但难以mock上述api和exportDataAsCsv方法,无法验证点击按钮时该方法是否被调用。测试代码如下:
import React from 'react'; import { act, render, screen, fireEvent, RenderResult, waitFor } from '@testing-library/react'; import { GridExample } from './GridExample'; const waitForGridToBeInTheDOM=()=>{ return waitFor(() => { expect(document.querySelector(".ag-root-wrapper")).toBeInTheDocument(); }); } describe('GridTest', () => { it('should expect date grid to render with Date column', async function () { let grid; await act( async () => { grid = render(<GridExample/>); }); await waitForGridToBeInTheDOM(); expect(screen.getByText('Date')).toBeInTheDocument(); let btn = screen.getByText(/CSV/i); fireEvent.click(btn); // ..expect(api.export to CSV ).toHaveBeenCalled(); }); });
解决方案
核心思路
通过Mock AgGridReact组件,手动控制onGridReady回调传入的API对象,追踪exportDataAsCsv方法的调用情况,无需依赖真实的AgGrid渲染逻辑。
修改后的测试代码
import React from 'react'; import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import { GridExample } from './GridExample'; // Mock AgGridReact组件,自定义onGridReady传入的API jest.mock('ag-grid-react', () => ({ AgGridReact: (props) => { React.useEffect(() => { if (props.onGridReady) { // 创建带有mock方法的API对象 const mockApi = { sizeColumnsToFit: jest.fn(), exportDataAsCsv: jest.fn() }; props.onGridReady({ api: mockApi }); } }, [props.onGridReady]); // 返回模拟的网格DOM结构,保证原有渲染断言生效 return ( <div className="ag-root-wrapper"> <div> <span>Date</span> </div> </div> ); } })); describe('GridTest', () => { it('should render Date column and call exportDataAsCsv when CSV button is clicked', async () => { render(<GridExample/>); // 验证网格渲染完成 await waitFor(() => { expect(document.querySelector(".ag-root-wrapper")).toBeInTheDocument(); }); expect(screen.getByText('Date')).toBeInTheDocument(); // 触发CSV按钮点击 const csvBtn = screen.getByText(/CSV/i); fireEvent.click(csvBtn); // 获取mock的API对象并验证方法调用 const { AgGridReact } = require('ag-grid-react'); // 提取onGridReady回调中传入的mockApi const mockApiCall = AgGridReact.mock.calls[0][0].onGridReady.mock.calls[0][0].api; // 验证exportDataAsCsv被调用 expect(mockApiCall.exportDataAsCsv).toHaveBeenCalled(); // 可选:验证调用参数是否符合预期 expect(mockApiCall.exportDataAsCsv).toHaveBeenCalledWith(expect.objectContaining({ filename: expect.any(Date) })); }); });
关键说明
- Mock组件替代真实渲染:通过
jest.mock替换AgGridReact,避免加载真实的AgGrid库,提升测试速度。 - 控制API对象:在mock组件中创建带有jest mock函数的
api对象,传入onGridReady回调,让组件的api.current指向这个mock对象。 - 简化异步处理:移除原测试中多余的
act包裹,React Testing Library的render和waitFor已自动处理异步更新。 - 保留原有断言逻辑:mock组件返回的DOM结构包含
Date文本和ag-root-wrapper类,保证原有渲染断言能正常通过。
内容的提问来源于stack exchange,提问作者Oam Psy
相关产品推荐
相关产品推荐

