在Selenium WebDriver中拖放的JavaScript解决方法

时间:2013-10-15 15:07:37

标签: java javascript selenium selenium-webdriver

在我的测试环境设置中,

clickAndHold对我不起作用。尝试使用高级用户交互执行它时,我一直收到此错误:

“无法按下多个按钮或已按下的按钮。”调用方法时:[wdIMouse :: down]“

我已经测试了许多版本的Firefox与selenium版本2.31.0-2.35.0和Firefox 21与selenium 2.35的问题最少。其他组合有问题,click()无声地失败,可见元素被视为不可见。

我想使用JavaScript解决方法将一个元素拖放到另一个元素,但在广泛搜索后我无法在任何地方找到任何体面的例子。

5 个答案:

答案 0 :(得分:7)

自从我发布此问题以来,我发现了一些针对此问题的不同解决方案。我将它们发布在这里供参考,以便这个问题对其他人有用:

当Selenium中的拖放无法用于HTML5时,针对Selenium输入了一个缺陷,有些人通过建议的Javascript解决了这个缺陷:

JQuery / HTML5解决方案

http://code.google.com/p/selenium/issues/detail?id=3604#c9

这是一个基于ruby的解决方案,可以翻译成Java,C#或Selenium支持的任何其他语言。它需要JQuery在页面上,从试图使用此解决方案的其他用户的许多评论中可以清楚地看出,这似乎只适用于HTML5页面:

  

我们整理的解决方法对我们有用。这是一种生活   用于测试我们的Ember.js应用程序的保护程序。

     

附件是我们正在使用的最新版本......

     

这就是我们在test_helper中的内容:

  def drag_and_drop(source,target)

    js_filepath=File.dirname(__FILE__)+"/drag_and_drop_helper.js"
    js_file= File.new(js_filepath,"r")
    java_script=""

    while (line=js_file.gets)
      java_script+=line
    end

    js_file.close

    @driver.execute_script(java_script+"$('#{source}').simulateDragDrop({ dropTarget: '#{target}'});")

    rescue Exception => e
      puts "ERROR :" + e.to_s

  end

引用的Javascript拖放模拟的源代码在此处发布:

https://gist.github.com/rcorreia/2362544

(function( $ ) {
    $.fn.simulateDragDrop = function(options) {
        return this.each(function() {
            new $.simulateDragDrop(this, options);
        });
    };
    $.simulateDragDrop = function(elem, options) {
        this.options = options;
        this.simulateEvent(elem, options);
    };
    $.extend($.simulateDragDrop.prototype, {
        simulateEvent: function(elem, options) {
            /*Simulating drag start*/
            var type = 'dragstart';
            var event = this.createEvent(type);
            this.dispatchEvent(elem, type, event);

            /*Simulating drop*/
            type = 'drop';
            var dropEvent = this.createEvent(type, {});
            dropEvent.dataTransfer = event.dataTransfer;
            this.dispatchEvent($(options.dropTarget)[0], type, dropEvent);

            /*Simulating drag end*/
            type = 'dragend';
            var dragEndEvent = this.createEvent(type, {});
            dragEndEvent.dataTransfer = event.dataTransfer;
            this.dispatchEvent(elem, type, dragEndEvent);
        },
        createEvent: function(type) {
            var event = document.createEvent("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];
                }
            };
            return event;
        },
        dispatchEvent: function(elem, type, event) {
            if(elem.dispatchEvent) {
                elem.dispatchEvent(event);
            }else if( elem.fireEvent ) {
                elem.fireEvent("on"+type, event);
            }
        }
    });
})(jQuery);

另一个用户在完全没有为他工作时发布了额外的代码,以及一些将JQuery注入页面的说明:

http://code.google.com/p/selenium/issues/detail?id=3604#c25

  

我们发布的原始drag_and_drop_helper.js遇到了问题   解决此问题的方法。解决方法是99%正确,但我   需要修改变通方法以包含dropTarget   选项通过simulateDrag中的'coord'对象传播。

     

即。我需要改变:

  coord = { clientX: x, clientY: y }
  

为:

coord = { clientX: x, clientY: y , dropTarget: options.dropTarget || undefined }
  

此外,如果应用程序位于以下,请注意以下示例用法   test还没有将jQuery函数别名为$,你需要   拼写jQuery:

     

即,在将拖放助手注入页面后,我们有   接受jQuery选择器以使用模拟拖动的方法   drop functions(Java):

/**
 * Drag and drop via the JQuery-based drag and drop helper -- the helper
 * must have been injected onto the page prior to calling this method.
 *
 * @param dragSourceJQuerySelector a JQuery-style selector that identifies the source element to drag;
 * <em>will be passed directly to jQuery(), perform all quoting yourself</em>
 * @param dropTargetJQuerySelector a JQuery-style selector that identifies the target element to drop the source onto;
 * <em>will be passed directly to jQuery(), perform all quoting yourself</em>
 */
protected void dragAndDropViaJQueryHelper(String dragSourceJQuerySelector, String dropTargetJQuerySelector) {
    String javascript =
        "var dropTarget = jQuery(" + dropTargetJQuerySelector + ");" +
        "\n" +
        "jQuery("+ dragSourceJQuerySelector + ").simulate('drag', { dropTarget: dropTarget });";

    getLogger().info("executing javascript:\n" + javascript);
    this.executeScript(javascript);
    getLogger().info("executed drag-n-drop action via javascript");
}

另一种非jQuery解决方案

http://ynot408.wordpress.com/2011/09/22/drag-and-drop-using-selenium-webdriver/

  

基于浏览器的基于Javascript的拖放功能。

     

鼠标移动在使用2.3版之后停止工作   在selenium中的RemoteWebDriver。下面的函数将元素1拖动到   元素2的位置并释放鼠标。

public void dragdrop(By ByFrom, By ByTo) {
    WebElement LocatorFrom = driver.findElement(ByFrom);
    WebElement LocatorTo = driver.findElement(ByTo);
    String xto=Integer.toString(LocatorTo.getLocation().x);
    String yto=Integer.toString(LocatorTo.getLocation().y);
    ((JavascriptExecutor)driver).executeScript("function simulate(f,c,d,e){var b,a=null;for(b in eventMatchers)if(eventMatchers[b].test(c)){a=b;break}if(!a)return!1;document.createEvent?(b=document.createEvent(a),a==\"HTMLEvents\"?b.initEvent(c,!0,!0):b.initMouseEvent(c,!0,!0,document.defaultView,0,d,e,d,e,!1,!1,!1,!1,0,null),f.dispatchEvent(b)):(a=document.createEventObject(),a.detail=0,a.screenX=d,a.screenY=e,a.clientX=d,a.clientY=e,a.ctrlKey=!1,a.altKey=!1,a.shiftKey=!1,a.metaKey=!1,a.button=1,f.fireEvent(\"on\"+c,a));return!0} var eventMatchers={HTMLEvents:/^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/,MouseEvents:/^(?:click|dblclick|mouse(?:down|up|over|move|out))$/}; " +
    "simulate(arguments[0],\"mousedown\",0,0); simulate(arguments[0],\"mousemove\",arguments[1],arguments[2]); simulate(arguments[0],\"mouseup\",arguments[1],arguments[2]); ",
    LocatorFrom,xto,yto);
}

答案 1 :(得分:5)

我和Firefox有同样的问题导致我来到这里。玩弄Stack上的建议,最后我能够使用

解决问题
actions.DragAndDropToOffset(element, x, y).Perform();

我知道这不是你要求的Javascript解决方法,但希望它能为你工作,就像它对我一样。这些古怪的问题可能非常令人沮丧。

答案 2 :(得分:0)

我认为你应该这样做的方式与理查德在原始问题的评论中提出的相同。使用Action类。只需在这个论坛上搜索“Action Selenium”。如果你得到无声的失败,那么你需要做的就是确保你最近的Selenium(你引用的2.35不是最新的)。此外,如果您使用的是IE或Chrome,请确保您使用的二进制文件也与最新版本相对应。

IE11以及Chrome和Firefox都将自动升级,因此如果您不遵循驱动程序更新,可能会从Actions类中获得不会引发任何人类可读错误的奇怪行为。例如,在最新的Chrome 31上使用2.30驱动程序将打开浏览器,并且.get()将挂起。

答案 3 :(得分:0)

在这篇关于 Safari 14 的帖子的背面,我正在测试一个剑道应用程序并尝试了 Selena 的答案中的解决方案,但这是一个最终对我有用的不同解决方案。

Test application

Working drap and drop(使用 WebElements 而不是 CSS 字符串的小改动):

2021-01-01T00:00:00+01:00

根据上述 Selena 答案中的解决方案注入 javascript(将文件读入变量 var triggerDragAndDrop = function (elemDrag, elemDrop) { /* function for triggering mouse events */ var fireMouseEvent = function (type, elem, centerX, centerY) { var evt = document.createEvent('MouseEvents'); evt.initMouseEvent( type, true, true, window, 1, 1, 1, centerX, centerY, false, false, false, false, 0, elem ); elem.dispatchEvent(evt); }; /* calculate positions*/ var pos = elemDrag.getBoundingClientRect(); var center1X = Math.floor((pos.left + pos.right) / 2); var center1Y = Math.floor((pos.top + pos.bottom) / 2); pos = elemDrop.getBoundingClientRect(); var center2X = Math.floor((pos.left + pos.right) / 2); var center2Y = Math.floor((pos.top + pos.bottom) / 2); /* mouse over dragged element and mousedown*/ fireMouseEvent('mousemove', elemDrag, center1X, center1Y); fireMouseEvent('mouseenter', elemDrag, center1X, center1Y); fireMouseEvent('mouseover', elemDrag, center1X, center1Y); fireMouseEvent('mousedown', elemDrag, center1X, center1Y); /* start dragging process over to drop target*/ fireMouseEvent('dragstart', elemDrag, center1X, center1Y); fireMouseEvent('drag', elemDrag, center1X, center1Y); fireMouseEvent('mousemove', elemDrag, center1X, center1Y); fireMouseEvent('drag', elemDrag, center2X, center2Y); fireMouseEvent('mousemove', elemDrop, center2X, center2Y); /* trigger dragging process on top of drop target*/ fireMouseEvent('mouseenter', elemDrop, center2X, center2Y); fireMouseEvent('dragenter', elemDrop, center2X, center2Y); fireMouseEvent('mouseover', elemDrop, center2X, center2Y); fireMouseEvent('dragover', elemDrop, center2X, center2Y); /* release dragged element on top of drop target*/ fireMouseEvent('drop', elemDrop, center2X, center2Y); fireMouseEvent('dragend', elemDrag, center2X, center2Y); fireMouseEvent('mouseup', elemDrag, center2X, center2Y); return true; }; )。针对现有的 WebElements(java_scriptdrag)执行:

drop

答案 4 :(得分:-2)

试试这个

动作行为=新行动(司机);  act.clickAndHold(scroll).moveByOffset(x,200).build()。perform();似乎麦芽汁