Skip to content
This repository has been archived by the owner on Nov 29, 2018. It is now read-only.

HTML5 Drag and Drop with Selenium Webdriver #3604

Open
lukeis opened this issue Mar 3, 2016 · 69 comments
Open

HTML5 Drag and Drop with Selenium Webdriver #3604

lukeis opened this issue Mar 3, 2016 · 69 comments

Comments

@lukeis
Copy link
Member

lukeis commented Mar 3, 2016

Originally reported on Google Code with ID 3604

Are there any work arounds to getting HTML5 Drag and Drop working with Selenium Webdriver
with Ruby? I am using Selenium-Webdriver 2.20.0 with Ruby 1.9.2

Here is a simple test to reproduce the issue:

require "selenium-webdriver"
require "test/unit"

class Html5DragAndDropTest < Test::Unit::TestCase

  def setup
    @driver = Selenium::WebDriver.for :firefox
    @driver.manage.timeouts.implicit_wait = 30
    @verification_errors = []
  end

  def teardown
    @driver.quit
    assert_equal [], @verification_errors
  end

  def test_html5_drag_and_drop
    @driver.get("http://html5demos.com/drag")
    target = @driver.find_element(:id, "one")
    source = @driver.find_element(:id, "bin")
    @driver.action.drag_and_drop(target, source).perform
    assert target.displayed? == false
  end
end

Reported by rcorreia@blurb.com on 2012-03-21 19:59:17

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Reported by barancev on 2012-03-27 06:12:04

  • Labels added: Component-WebDriver

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Here is a temporary workaround that could help the community with testing in the meantime...

1) drag_and_drop_helper.js to your test/helpers directory

2) Create a new method in your test_helper.rb

  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

Reported by rcorreia@blurb.com on 2012-04-16 21:21:42


- _Attachment: [drag_and_drop_helper.js](https://storage.googleapis.com/google-code-attachments/selenium/issue-3604/comment-4/drag_and_drop_helper.js)_

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Where actually  this test/helpers directory located?. While running the script, I am
getting error (ERROR) jQuery is not defined

Reported by checkitoutkarthik on 2012-05-03 03:43:48

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

this requires the implementation in the atoms of the events:

dragstart, dragover, dragenter, dragleave, drop


with native events this *could* work as is... although my attempt failed miserably.

Reported by luke.semerau on 2012-06-02 04:45:56

  • Status changed: Accepted
  • Labels added: Type-Enhancement, Browser-Atoms
  • Labels removed: Type-Defect

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

I'm seeing a similar issue with drag and drop using html 5 events. Can a developer confirm
that selenium drag and drop does not support html 5 drag and drop events?

Reference: http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html

Reported by catphive@catphive.net on 2012-09-12 02:14:51

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

(i am a selenium developer) and yes, I'll confirm that html5 drag/drop is not currently
supported/implemented.

Reported by luke.semerau on 2012-09-12 04:46:15

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

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:

  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





Reported by rcorreia@blurb.com on 2012-09-12 15:35:59


- _Attachment: [drag_and_drop_helper.js](https://storage.googleapis.com/google-code-attachments/selenium/issue-3604/comment-9/drag_and_drop_helper.js)_

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Issue 4455 has been merged into this issue.

Reported by a.u.savchuk on 2013-07-19 23:55:10

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Issue 5953 has been merged into this issue.

Reported by a.u.savchuk on 2013-07-19 23:56:18

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

When will it be available in `selenium-webdriver` core?

Reported by tuka.08 on 2013-07-20 06:09:41

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Is there any planning date for this feature?
HTML 5 drag&drop is still not working and it will be very useful tho have it.

Reported by m.machniak on 2013-08-06 12:01:05

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Issue 5707 has been merged into this issue.

Reported by a.u.savchuk on 2013-08-13 19:03:43

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Issue 6222 has been merged into this issue.

Reported by a.u.savchuk on 2013-09-07 17:25:55

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Issue 6315 has been merged into this issue.

Reported by barancev on 2013-09-25 11:57:42

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

I agree with m.machn... I would also be interested in whether there are any plans to
fix this bug?

Reported by mherrmann.at on 2013-09-25 12:12:38

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

There is a workaround - the mouse just needs to move twice - for example once you click
and hold, move to any position on screen, then move to final destination, then release
and it works.

Reported by byatt.chris on 2013-09-25 12:26:48

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Thanks for your reply Byatt. I can't seem to get this workaround to work (Selenium 2.35.0,
FF 23.0.1, 64 bit Win 7). Here's what I tried:

    element_location = element.location
    to_location = to.location
    dx = to_location['x'] - element_location['x']
    dy = to_location['y'] - element_location['y']
    ActionChains(driver).click_and_hold(element).perform()
    ActionChains(driver).move_by_offset(dx / 2, dy / 2).perform()
    ActionChains(driver).move_to_element(to).perform()
    ActionChains(driver).release(to).perform()

Do you happen to have a working example?

Many thanks,
Michael

Reported by mherrmann.at on 2013-09-25 13:56:33

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

I used a mixture of selenium and java robot. My code also allows for an x offset if
you want to drag it apst something. Should be easily modifiable.

public void dragAndDropElement(WebElement dragFrom, WebElement dragTo, int xOffset)
throws Exception {
        //Setup robot
        Robot robot = new Robot();
        robot.setAutoDelay(50);

        //Fullscreen page so selenium coordinates work
        robot.keyPress(KeyEvent.VK_F11);
        Thread.sleep(2000);

        //Get size of elements
        Dimension fromSize = dragFrom.getSize();
        Dimension toSize = dragTo.getSize();

        //Get centre distance
        int xCentreFrom = fromSize.width / 2;
        int yCentreFrom = fromSize.height / 2;
        int xCentreTo = toSize.width / 2;
        int yCentreTo = toSize.height / 2;

        //Get x and y of WebElement to drag to
        Point toLocation = dragTo.getLocation();
        Point fromLocation = dragFrom.getLocation();

        //Make Mouse coordinate centre of element
        toLocation.x += xOffset + xCentreTo;
        toLocation.y += yCentreTo;
        fromLocation.x += xCentreFrom;
        fromLocation.y += yCentreFrom;

        //Move mouse to drag from location
        robot.mouseMove(fromLocation.x, fromLocation.y);

        //Click and drag
        robot.mousePress(InputEvent.BUTTON1_MASK);

        //Drag events require more than one movement to register
        //Just appearing at destination doesn't work so move halfway first
        robot.mouseMove(((toLocation.x - fromLocation.x) / 2) + fromLocation.x, ((toLocation.y
- fromLocation.y) / 2) + fromLocation.y);

        //Move to final position
        robot.mouseMove(toLocation.x, toLocation.y);

        //Drop
        robot.mouseRelease(InputEvent.BUTTON1_MASK);
    }

Reported by byatt.chris on 2013-09-25 13:59:46

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Reported by barancev on 2013-11-02 17:39:46

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

hi all,

or the proposed solution based on the drag_and_drop_helper.js script, is it possible
to use something similar to this to simulate dragging a set of files from outside of
the browser into an element?

Thx!

L.

Reported by leonardo.ramirez on 2014-01-06 17:32:49

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Hi,

after a lot of hard work, I eventually figured this out. It's implemented in a tool
of mine that makes tasks like this one-liners: http://heliumhq.com/docs/api_documentation#helium.api.drag_file.
No java.awt.robot is required, just any WebDriver object.

The idea for the implementation is the following: You need to simulate the following
JavaScript events:
i.  A `dragenter` event on the JavaScript document object.
ii. A `dragover` event on the JavaScript document object.
iii.    A `drop` event on the target element

All of these events include as a parameter a JavaScript `File` object that contains
information about the file being attached. The problem is that because of security
reasons, the browser does not allow creating such objects via JavaScript.

To work around the security constraints, we perform a little trick: We use JavaScript
to create an <input type="file"> element on the page. Then, we use Selenium's `send_keys`
command to send the path of the file to be dragged to this element. This automatically
sets a JavaScript property on the file input element that contains a `File` object
representing our file. Since we can read this property via JavaScript, we have succeeded
in obtaining the `File` object that is required to properly simulate the three events
above.

Hope this helps anyone wanting to implement this for himself.

Cheers,
Michael
heliumhq.com

Reported by michael.herrmann@open-closure.com on 2014-01-07 07:55:25

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

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

    /**
     * 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");
    }


rcorr...@blurb.com thanks for sharing your workaround!

Reported by skuenzli on 2014-02-04 17:58:38


- _Attachment: [drag_and_drop_helper.propagate-dropTarget.js](https://storage.googleapis.com/google-code-attachments/selenium/issue-3604/comment-25/drag_and_drop_helper.propagate-dropTarget.js)_

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Thanks for the drag_and_drop_helper.js! It worked perfectly for my needs. You can see
a full write-up along with my example code here: http://elementalselenium.com/tips/39-drag-and-drop


Cheers,
Dave H
@TourDeDave

Reported by dave@arrgyle.com on 2014-02-26 17:09:49

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Thanks for the contribution!  I will review and update the existing gist.

Reported by rcorreia@blurb.com on 2014-07-24 16:57:30

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Hi all,

Please note if your website has JQuery enabled then comment out the following line:
 Object o1 = js.executeScript(load_jquery);
from drag_and_drop_js function. this call is only necessary if your webpage does not
have JQuery loaded.

Running the above code if your site already uses JQuery risks changing the functionality
of the page for instance right click menu options.

Reported by arad@qaworks.com on 2014-07-25 09:20:36

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

I've created a more versatile HTML5 Drag and Drop simulator. It uses native JavaScript
and not jQuery. It allows for Cross-Window drag and drop (example provided in file)
and dragging to a specific position. The attached file is written for Java WebDiver,
but could easily be converted, and has been tested on Firefox 24 and Firefox 17 on
RHEL 6.4, Windows 7, and Mac.

Reported by salomj9 on 2014-07-30 16:46:44


- _Attachment: [HTML5DragAndDropSimulator.txt](https://storage.googleapis.com/google-code-attachments/selenium/issue-3604/comment-58/HTML5DragAndDropSimulator.txt)_

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

salo... had a little trouble with HTML5DragAndDropSimulator.txt with the chrome driver
until swapping
var event = document.createEvent("DragEvent");
for
var event = document.createEvent('HTMLEvents');
event.initEvent('DragEvent', true, true);

Reported by dan.roon on 2014-08-11 11:54:02

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

#52 , is not working if source and target are xpath. Is this a limitation of the script
?

I read in another mail thread that webelements must be in CSS , is it true ? 

I've got dynamic webelements and I use dynamic xpath for those. I'm not sure how to
use dynamic CSS

This is just to update @ a...@qaworks.com and others.


Reported by vikram.silk on 2014-08-22 16:24:57

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

#60, can you provide examples of what you mean by dynamic XPath? If it can be translated
to CSS, then it should be ok.

Reported by mangaroo on 2014-08-22 20:05:41

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

manga...@gmail.com

Please find more info as below


//div[@class='tasks-scroll']//ol[1]/li["+OriginalPositionToBeMoved+"]/div/div/span

//div[@class='tasks-scroll']//ol[1]/li["+DestinationPositionToBeMoved+"]/div/div/span

I get value of variables on run time.


Thanks & Regards,
Vikram


Reported by vikram.silk on 2014-08-25 08:28:17

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Vikram, I believe that roughly translates to this CSS

"div[class='tasks-scroll'] ol:nth-child(1) > li:nth-child("+OriginalPositionToBeMoved+")
> div > div > span"

and if nth-child() doesn't seem to work, you can give nth-of-type() instead, but generally
nth-child() is used.

Reported by mangaroo on 2014-08-25 17:31:14

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Hi manga...@gmail.com,

sorry I forgot to update yesterday

I figured out CSS locators and did as below


source = getDriver().findElement(By.cssSelector("div.tasks-scroll ol:nth-child(1) >
li:nth-child("+OriginalItemPositionToBeMoved+") div > div > span"));

target = getDriver().findElement(By.cssSelector("div.tasks-scroll ol:nth-child(1) >
li:nth-child(5) div > div > span"));

But this is only clicking first element , after that no action / exception taking place.


I'm not able to figure out what else am I doing wrong here ?

Thanks,
Vikram

Reported by vikram.silk on 2014-08-26 10:40:57

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Still I'm not able to get this working. It just clicks first element but doesn't initiate
drag action.

what step can be going wrong here ?

Thanks,
Vikram

Reported by vikram.silk on 2014-09-03 16:04:28

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Hive Mind,

Is it fixed now?
I am still not able to drop the Element..

When is the plan to fix this?


Reported by varunas@thoughtworks.com on 2014-09-23 05:45:08

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Issue 7976 has been merged into this issue.

Reported by barancev on 2014-09-30 21:13:03

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

I am also facing this issue can we have any fix for this in next release.

Thanks
Jag

Reported by jagmoahn.jackisback on 2014-11-21 13:39:15

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Hi, 

I would like to know if the issue is already addressed.
I tried to do the work around using javascript and actions but none works.

Thanks,

Shin

Reported by cmentrada on 2014-11-26 03:04:24

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Reported by jmleyba on 2014-11-27 16:28:07

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

The solution I added here is still working for us using 2.41.0 currently and I'm pretty
sure we wrote it using 2.18.0 but I still spent some time looking at 2.44.0 and everything
seems to be working. 

I spent some time looking at a few blogs that have shared the solution and everyone
seems to be able to get it working ok.  

The gist has gotten some comments as early as 20 days ago with happy implementations:

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

And apparently it is compatible with Zepto which is pretty cool to hear :-)

Don't give up! 



Reported by rcorreia@blurb.com on 2014-12-10 19:27:48

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Hi,

Is the drag drop for native events issue fixed in web driver 2.44.0

Reported by pratibha.maram22 on 2015-02-05 02:12:40

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Issue 5807 has been merged into this issue.

Reported by barancev on 2015-03-16 05:47:41

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

I tried the java helper method in post#25 and used the attached js file

but I am getting 

wgen-selenium dlee$ org.openqa.selenium.WebDriverException: missing ) after argument
list

my dragSourceJQuerySelector = #group_1
my dropTargetJQuerySelector = #group_0 div:contains('BC')

Am I doing anything wrong..?

Reported by dlee@amplify.com on 2015-03-27 17:43:43

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Cross-referencing the StackOverflow post with a working workaround solution (Python):

 http://stackoverflow.com/questions/29381233/how-to-simulate-html5-drag-and-drop-in-selenium-webdriver-in-python/29381532#29381532

Reported by AfanasieffAV on 2015-04-01 02:23:15

@lukeis
Copy link
Member Author

lukeis commented Mar 3, 2016

Reported by luke.semerau on 2015-09-17 17:44:48

  • Labels added: Restrict-AddIssueComment-Commit

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant