You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React Testing Library测试中成功触发ReactFlow的onSelectionChange?

React Flow测试中onSelectionChange返回空元素的解决方法

问题现象

实际运行React Flow组件时,选中元素能正常传递给onSelectionChange处理函数,但用react-testing-library测试时,返回的nodes和edges始终为空,控制台输出:

Selection changed { nodes: [], edges: [] }

问题原因

  1. 测试环境中mock的getBBox返回宽高为0的对象,React Flow无法正确计算节点边界范围,导致无法识别点击的节点。
  2. 直接点击文本节点元素,未触发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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 07:35:39