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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19384710/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 16:40:46  来源:igfitidea点击:

JavaScript workaround for drag and drop in Selenium WebDriver

javajavascriptseleniumselenium-webdriver

提问by Selena

clickAndHold is not working for me in my test environment setup. I keep getting this error when trying to execute it using the Advanced User Interactions:

clickAndHold 在我的测试环境设置中对我不起作用。尝试使用高级用户交互执行它时,我不断收到此错误:

"Cannot press more than one button or an already pressed button.' when calling method: [wdIMouse::down]"

“不能按下多个按钮或一个已经按下的按钮。” 调用方法时:[wdIMouse::down]"

I've tested numerous versions of Firefox with selenium versions 2.31.0-2.35.0 and Firefox 21 with selenium 2.35 has the fewest issues. Other combinations have problems with click() failing silently and visible elements being treated as invisible.

我已经测试了许多带有 selenium 版本 2.31.0-2.35.0 的 Firefox 和带有 selenium 2.35 的 Firefox 21 的问题最少。其他组合存在 click() 静默失败并且可见元素被视为不可见的问题。

I want to use a JavaScript workaround for drag and drop of one element to another, but I can't find any decent examples anywhere after googling extensively.

我想使用 JavaScript 解决方法将一个元素拖放到另一个元素,但在广泛使用谷歌搜索后,我在任何地方都找不到任何像样的示例。

回答by djangofan

I think the way you should do it is the same as Richard suggested in the comment off your original question. Use the Action class. Just search this forum for "Action Selenium". If you get silent failures, then all you need to do is make sure your on the very latest Selenium (2.35 that you reference is not the latest). Also , if your using IE or Chrome, make sure the binary you are using also corresponds to the latest version.

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

IE11 and Chrome and Firefox all will auto-upgrade on you and so if you don't follow with a driver update, its possible you can get wierd behavior from the Actions class that does not throw any human readable error. For example, using the 2.30 driver on the latest Chrome 31 will open a browser and the .get() will hang on you.

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

回答by Bill

Try this

尝试这个

Actions act = new Actions(driver); act.clickAndHold(scroll).moveByOffset( x, 200).build().perform(); seems to wort

行动行动 = 新行动(驱动程序);act.clickAndHold(scroll).moveByOffset(x, 200).build().perform(); 似乎麦汁

回答by jibbs

I had exactly the same issue with Firefox which led me here. Playing around with the suggestions on Stack, finally I was able to resolve the issue using

我在 Firefox 上遇到了完全相同的问题,这导致我来到这里。玩弄堆栈上的建议,最后我能够使用

actions.DragAndDropToOffset(element, x, y).Perform();

I know that's not the Javascript workaround you asked for but hopefully it will work for you, as it did for me. These quirky issues can be really frustrating.

我知道这不是您要求的 Javascript 解决方法,但希望它对您有用,就像对我一样。这些古怪的问题真的很令人沮丧。

回答by Selena

Since I posted this question, I've found a few different solutions to this problem. I'm posting them here for reference so that this question is useful to others:

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

When drag and drop in Selenium failed to work for HTML5, a defect was entered against Selenium and some people commented on the defect with suggested Javascript work around solutions:

当 Selenium 中的拖放无法为 HTML5 工作时,针对 Selenium 输入了一个缺陷,并且一些人通过建议的 Javascript 解决方案对该缺陷进行了评论:

JQuery/HTML5 Solution

JQuery/HTML5 解决方案

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

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

This is a ruby-based solution, which could be translated into Java, C#, or any other language supported by Selenium. It requires JQuery to be on the page, as is clear from many of the comments from other users trying to use this solution, and it seems this only works for HTML5 pages:

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

The workaround we put together is working for us. It's been a life saver for testing our Ember.js app.

attached is the latest version of what we are using...

this is what we have in our test_helper:

我们放在一起的解决方法对我们有用。它是测试我们 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

The source code for the referenced Javascript drag and drop simulation is posted here:

引用的Javascript拖放模拟的源代码张贴在这里:

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

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);

Another user posted additional code when it didn't work completely for him, along with some instructions for injecting JQuery into the page:

另一位用户在对他不起作用时发布了额外的代码,以及将 JQuery 注入页面的一些说明:

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

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

We had trouble with the original drag_and_drop_helper.js posted as a workaround for this issue. The workaround is 99% correct, but I needed to modify the workaround to include the dropTarget in the options propagated via the 'coord' object in simulateDrag.

i.e. I need to change:

我们在发布作为解决此问题的解决方法的原始 drag_and_drop_helper.js 时遇到了问题。解决方法是 99% 正确,但我需要修改解决方法以将 dropTarget 包含在通过模拟拖动中的“坐标”对象传播的选项中。

即我需要改变:

  coord = { clientX: x, clientY: y }

to:

到:

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

Also, a note for those following the example usage, if the app under test does not already alias the jQuery function to $, you will need to spell-out jQuery:

i.e., after injecting the drag and drop helper onto the page, we have a method that accepts jQuery selectors to use the simulated drag and drop functions (Java):

另外,对于遵循示例用法的人的注意事项,如果被测应用程序尚未将 jQuery 函数别名为 $,则您需要拼出 jQuery:

即,在将拖放助手注入页面后,我们有一个方法可以接受 jQuery 选择器来使用模拟的拖放功能(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");
}

Another, non-jQuery solution

另一个非 jQuery 解决方案

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

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

Javascript based drag and drop which works across browsers.

Mouse move stopped working after version 2.3 while using RemoteWebDriver in selenium. The below function drags element 1 to element 2 position and releases the mouse down.

基于 Javascript 的拖放,可跨浏览器工作。

在 selenium 中使用 RemoteWebDriver 时,鼠标移动在 2.3 版之后停止工作。下面的函数将元素 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);
}