Selenium:Selenium 中的 DragAndDrop 在 chrome 中不起作用 (C#)

Selenium: DragAndDrop in selenium not working in chrome (C#)

提问人:Beardy 提问时间:11/15/2023 最后编辑:Beardy 更新时间:11/16/2023 访问量:42

问:

我想在 chrome 中的 selenium 自动化测试期间模拟 DragAndDrop

AFAIK,由于各种原因,selenium 提供的 DragAndDrop 方法不再起作用(HTML5,Chrome 不再支持它?!

所以我现在正在寻找使用 Java 脚本的解决方法。

我已经在这里浏览了所有 DragAndDrop 主题,但大多数解决方案都是几年前的,并没有真正给我答案。

有一个答案,在一个较旧的问题中有一个 Java 脚本:Drag_and_drop什么都不做

我直接在“google chrome - inspect - console”中尝试了 java 脚本并对其进行了一点修改,但我仍然遇到太多错误(请参阅下面的代码)。我认为出现错误是因为过去有许多 chrome 更新。

我感谢任何帮助!

源元素 id:ATest_DragDropElement

目标元素 ID:ATest_DropZone

function simulateDragDrop(sourceNode, destinationNode) {
                  var EVENT_TYPES = {DRAG_END: 'dragend',DRAG_START: 'dragstart',DROP: 'drop'};
                  function createCustomEvent(type) {
                      var event = new CustomEvent('CustomEvent');
                      event.initCustomEvent(type, true, true, null);
                      event.dataTransfer = 
                      {
                          data: {},
                          setData: function(type, val) {this.data[type] = val;},
                          getData: function(type) {return this.data[type];},
                          files: {},
                          items: {}
                      };
                      return event;
                  };
                  function dispatchEvent(node, type, event) {
                      if (node.dispatchEvent) {
                          return node.dispatchEvent(event);
                      }
                      if (node.fireEvent) {
                          return node.fireEvent('on' + type, event);
                      }
                  };
                  var event = createCustomEvent(EVENT_TYPES.DRAG_START);
                  dispatchEvent(sourceNode, EVENT_TYPES.DRAG_START, event);
                  var dropEvent = createCustomEvent(EVENT_TYPES.DROP);
                  dropEvent.dataTransfer = event.dataTransfer;
                  dispatchEvent(destinationNode, EVENT_TYPES.DROP, dropEvent);
                  var dragEndEvent = createCustomEvent(EVENT_TYPES.DRAG_END);
                  dragEndEvent.dataTransfer = event.dataTransfer;
                  dispatchEvent(sourceNode, EVENT_TYPES.DRAG_END, dragEndEvent);
               };

var sourceNode = document.getElementById("ATest_DragDropElement");
var destinationNode = document.getElementById("ATest_DropZone");

simulateDragDrop(sourceNode, destinationNode);

inspect 中元素的屏幕截图enter image description here

js 执行的 console.logs 屏幕截图:enter image description here

JavaScript C# 硒-webdriver

评论

0赞 pcalkins 11/17/2023
这取决于站点,但我认为一般来说,如果有一个事件处理程序正在寻找“ondragstart”或“ondragend”,您需要触发 javascript 来创建自定义事件。不过,通常 actions 的“dragAndDropBy”方法有效。这需要一个元素,以及 x 和 y 偏移量。你能包含更多的DOM标记以及哪些元素有拖放处理程序吗?

答:

0赞 Infern0 11/15/2023 #1

对于 Selenium,您可以尝试使用鼠标事件调度原始事件。

提供 selenium JavaScript 实现。 以下是您可以尝试的代码:

要调用的函数(注意 dispatchDND 是字符串函数,可以在下面找到它)

async function dragAndDropEvent(selectorDrag: string, selectorDrop: string | null, options: any = {}) {
    return driver.executeScript(dispatchDND, selectorDrag, selectorDrop, options);
}

参数图例:

selectorDrag: 拖拽元素的CSS选择器

selectorDrop:drop 元素的 Css 选择器。如果要将元素放入 指定位置只需发送 null 作为第二个参数。

options:这里可以设置【dragElemIndex】选项 如果有多个元素与 [selectorDrag] 匹配。再来一个 如果要使 [selectorDrag] 元素,则选项为 [makeDraggable: true] 可拖动。[dropLocation] (丢弃位置)使用 dropLocation.x dropLocation.y dropLocation.z 作为放置元素的特定坐标。

原生 js 函数来执行拖放。

const dispatchDND = `function dragAndDrop(selectorDrag, selectorDrop, options) {

    let elemDrag, elemDrop;

    if (!selectorDrag) {
        throw new Error('Error! Element [selectorDrop] selector not defined.');
    }

    if (!options) {
        throw new Error('Options not specified! Please add options or just send <{}>.');
    }

    if (options.dragElemIndex != undefined) {
        const elements = document.querySelectorAll(selectorDrag);
        elemDrag = elements[options.dragElemIndex];
    } else {
        elemDrag = document.querySelector(selectorDrag);
    }

    elemDrop = (selectorDrop === null && options.dropLocation) ? null : document.querySelector(selectorDrop);

    if (options.makeDraggable)
         makeDraggable(elemDrag);

    function makeDraggable(elm) {
        elm.draggable = true;
    }

    if (elemDrag === undefined || elemDrag === null) {
        throw new Error('Error!Cannot get element with specified selector.');
    }

    function fireMouseEvent(type, elem, dataTransfer) {
        const evt = document.createEvent('MouseEvents');
        evt.initMouseEvent(type, true, true, window, 1, 1, 1, 0, 0, false, false, false, false, 0, elem);
        if (/^dr/i.test(type)) {
            evt.dataTransfer = dataTransfer || createNewDataTransfer();
        }
        (elem === null) ? document.body.dispatchEvent(evt) : elem.dispatchEvent(evt);
    }

    function createNewDataTransfer() {
        let data = {};
        return {
            clearData: function(key) {
                if (key === undefined) {
                    data = {};
                } else {
                    delete data[key];
                }
            },
            getData: function(key) {
                return data[key];
            },
            setData: function(key, value) {
                data[key] = value;
            },
            setDragImage: function() {},
            dropEffect: 'none',
            files: [],
            items: [],
            types: [],
        };
    }

    function mouseMove() {
        const evt = document.createEvent('MouseEvents');
        if (elemDrop === null) {
            evt.initMouseEvent('mousemove', true, true, window, 1, 1, 1, options.dropLocation.x,
             options.dropLocation.y, false, false, false, false, 0, null);
        } else {
             evt.initMouseEvent('mousemove', true, true, window, 1, 1, 1, 0, 0, false, false, false,
                false, 0, elemDrop);
        }
        if (/^dr/i.test('mousemove')) {
            evt.dataTransfer = dataTransfer || createNewDataTransfer();
        }
        (elemDrop === null) ? document.body.dispatchEvent(evt) : elemDrop.dispatchEvent(evt);
    }

    function drop() {
        if (elemDrop === null) {
            const evt = document.createEvent('MouseEvents');
            evt.initMouseEvent('mouseup', true, true, window, 1, options.dropLocation.x, options.dropLocation.y,
                options.dropLocation.x, options.dropLocation.y, false, false, false, false, 0, null);
            document.body.dispatchEvent(evt);
        } else {
            fireMouseEvent('mouseup', elemDrop);
        }

    }

    fireMouseEvent('mousedown', elemDrag);
    mouseMove();
    drop();

    return true;
}

dragAndDrop(arguments[0], arguments[1], arguments[2]);
`;

评论

0赞 Beardy 11/15/2023
您有机会为我提供一段代码,我可以在访问 Inspect-Console 时直接在浏览器中进行测试吗?我可以在那里执行js,看看脚本是否有效。我的 CSSSelector 是:[id='ATest_DragDropElement'] 和 [id='ATest_DropZone']
0赞 Infern0 11/15/2023
使用包装在字符串变量 dispatchDND 中的代码。一切都是函数,并在浏览器控制台中声明它们。之后,使用带有相关参数的 dragAndDrop 函数进行测试。
0赞 Beardy 11/16/2023
我能够在 chrome 控制台中成功执行代码,结果是“true”,但 selectorDrag 元素根本没有移动。知道我接下来能做什么吗?
0赞 Beardy 11/16/2023
我为 elemDrop 和 elemDrag 添加了一个控制台 .log,两者都可以找到。我上传了上面日志的截图
0赞 Infern0 11/16/2023
它可能嵌套在 <div> 中的元素,以接受事件和/或由其他事件触发。上面提供的解决方案是使用鼠标事件。所以这很奇怪。