JavaScript workaround for drag and drop in Selenium WebDriver

0
0

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:

“Cannot press more than one button or an already pressed button.’ when calling method: [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.

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.

  • You must to post comments
0
0

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:

JQuery/HTML5 Solution

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:

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

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

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:

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:

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

Another, non-jQuery solution

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.

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);
}
  • You must to post comments
Showing 1 result
Your Answer
Post as a guest by filling out the fields below or if you already have an account.
Name*
E-mail*
Website