如何在React Testing Library测试中成功触发ReactFlow的onSelectionChange?
React Flow测试中onSelectionChange返回空元素的解决方法
问题现象
实际运行React Flow组件时,选中元素能正常传递给onSelectionChange处理函数,但用react-testing-library测试时,返回的nodes和edges始终为空,控制台输出:
Selection changed { nodes: [], edges: [] }
问题原因
- 测试环境中mock的
getBBox返回宽高为0的对象,React Flow无法正确计算节点边界范围,导致无法识别点击的节点。 - 直接点击文本节点元素,未触发React Flow绑定在节点容器上的选中事件。
解决步骤
1. 修正SVGElement的getBBox Mock
修改mockReactFlow中的getBBox实现,返回贴近实际的节点尺寸:
export const mockReactFlow = () => { let init = false; if (init) return; init = true; global.ResizeObserver = ResizeObserver; global.DOMMatrixReadOnly = DOMMatrixReadOnly; Object.defineProperties(global.HTMLElement.prototype, { offsetHeight: { get() { return parseFloat(this.style.height) || 40; }, }, offsetWidth: { get() { return parseFloat(this.style.width) || 120; }, }, }); (global.SVGElement as any).prototype.getBBox = () => ({ x: 0, y: 0, width: 120, height: 40, }); };
2. 模拟正确的选中交互
React Flow的节点选中逻辑基于mousedown事件触发,需点击节点容器而非内部文本,同时模拟完整的鼠标交互流程:
import React from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; import ReactFlow from 'reactflow'; import { mockReactFlow } from '../../setupTests'; function MyComponent() { const onSelectionChange = (elements: any) => { console.log('Selection changed', elements); }; const nodes = [ { id: 'node-1', type: 'default', data: { label: 'Node 1' }, position: { x: 0, y: 0 } }, { id: 'node-2', type: 'default', data: { label: 'Node 2' }, position: { x: 200, y: 0 } }, ]; return <ReactFlow nodes={nodes} onSelectionChange={onSelectionChange} />; } describe('ReactFlow', () => { beforeEach(() => { mockReactFlow(); }); test('should trigger onSelectionChange with selected node', async () => { const mockOnSelection = jest.fn(); render(<ReactFlow nodes={[ { id: 'node-1', type: 'default', data: { label: 'Node 1' }, position: { x: 0, y: 0 } }, ]} onSelectionChange={mockOnSelection} />); // 找到节点容器元素(默认节点类为react-flow__node-default) const nodeContainer = await screen.findByRole('figure', { name: /node 1/i }); // 模拟完整的选中交互流程 fireEvent.mouseDown(nodeContainer); fireEvent.mouseUp(nodeContainer); // 验证回调触发及选中结果 expect(mockOnSelection).toHaveBeenCalled(); expect(mockOnSelection.mock.calls[0][0].nodes).toHaveLength(1); expect(mockOnSelection.mock.calls[0][0].nodes[0].id).toBe('node-1'); }); });
3. 额外提示
- 优先选择节点容器元素(带
react-flow__node-[type]类名)进行交互,避免直接点击内部文本。 - 使用jest mock函数替代console.log,更方便在测试中验证回调的调用细节。
内容的提问来源于stack exchange,提问作者stacker
相关产品推荐
相关产品推荐

