如何用React Testing Library和Jest测试React组件中的D3缩放行为?
解决方案
1. 确保事件监听器完成绑定
D3的事件绑定在useEffect中执行,React Testing Library的render完成后可能需要等待DOM更新完成。可以用requestAnimationFrame确保绑定完成,同时补充D3需要的事件属性:
import { render, fireEvent, waitFor } from '@testing-library/react'; import MyD3Component from './MyD3Component'; test('zoom behavior triggers on wheel event', async () => { const { getByTestId } = render(<MyD3Component />); const svgElement = getByTestId('graph-container'); // 等待D3完成事件绑定 await new Promise(resolve => requestAnimationFrame(resolve)); fireEvent.wheel(svgElement, { deltaY: -100, deltaMode: 0, // D3依赖该属性判断缩放单位(0=像素) clientX: 150, // 提供缩放中心点,D3默认需要这个计算变换 clientY: 150, bubbles: true, cancelable: true }); // 此处添加你的断言逻辑 });
2. 显式跟踪缩放状态,便于断言
在组件中用useState跟踪缩放比例,同时渲染可查询的元素,让测试能直接验证状态变化:
修改后的组件
import React, { useMemo, useRef, useEffect, useState } from 'react'; import * as d3 from 'd3'; const MyD3Component = () => { const svgRef = useRef(null); const [scale, setScale] = useState(1); const zoomBehavior = useMemo(() => d3.zoom() .on('zoom', (event) => { setScale(event.transform.k); // 其他缩放逻辑... }), []); useEffect(() => { const svg = d3.select(svgRef.current); svg.call(zoomBehavior); }, [zoomBehavior]); return ( <svg ref={svgRef} data-testid="graph-container" width={300} height={300}> {/* 渲染缩放值,供测试查询 */} <text data-testid="current-scale" x={10} y={20}>{scale.toFixed(2)}</text> </svg> ); }; export default MyD3Component;
修改后的测试
test('zoom increases scale on wheel event', async () => { const { getByTestId } = render(<MyD3Component />); const svgElement = getByTestId('graph-container'); await new Promise(resolve => requestAnimationFrame(resolve)); fireEvent.wheel(svgElement, { deltaY: -100, deltaMode: 0, clientX: 150, clientY: 150 }); // 等待缩放状态更新 await waitFor(() => { expect(getByTestId('current-scale').textContent).toBeGreaterThan('1.00'); }); });
3. 直接调用D3缩放方法(绕过原生事件)
如果原生事件模拟存在环境兼容问题,可以直接通过D3的API触发缩放变换,跳过事件模拟步骤:
import { render, waitFor } from '@testing-library/react'; import * as d3 from 'd3'; import MyD3Component from './MyD3Component'; test('zoom behavior updates scale correctly', async () => { const { getByTestId } = render(<MyD3Component />); const svgElement = getByTestId('graph-container'); const d3Svg = d3.select(svgElement); // 直接应用缩放变换 d3Svg.call(d3.zoom().transform, d3.zoomIdentity.scale(2)); await waitFor(() => { expect(getByTestId('current-scale').textContent).toBe('2.00'); }); });
内容的提问来源于stack exchange,提问作者Syed Usama Amer
相关产品推荐
相关产品推荐

