Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Create the `simulateDragDrop` function which can be used to simulate clicking and dragging one DOM Node onto another
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]
}
}
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)
}
@douglaslise
Copy link

douglaslise commented Apr 18, 2016

Forked in https://gist.github.com/douglaslise/884692bb54cdf8e76702c01bc18defbd with a fix, making it running in IE11 and also in automated tests using PhantomJS on CircleCI

@vickyzeng
Copy link

vickyzeng commented Apr 30, 2016

I tried the file but got the error: java.util.HashMap cannot be cast to java.lang.String. Any idea?
var textToSelect_begin = element.all(by.css('.numberingLevel1')).get(0);
var textToSelect_end = element.all(by.css('.numberingLevel1')).get(1);
browser.executeScript(dragNDrop, textToSelect_begin.getWebElement(), textToSelect_end.getWebElement());

@Nikhil0538
Copy link

Nikhil0538 commented May 25, 2016

I don't a element where i need to drop, it is a canvas and i need to drop at particular location, how can i achieve this?
droppable location is something "{x:-950, y:50}" like this.
I did try this way but it is navigating to droppable location but it could not drop:
browser.actions().mouseDown(element(by.css('.dragableElement'))).mouseMove({x:-950, y:50}).mouseUp().perform();

Help would be greatly appreciated.

@kymmeh
Copy link

kymmeh commented Jun 29, 2016

Amazing! Thank you for this script, I finally have a test passing. I adapted it slightly to reflect the exact events I was using in my drag/drop component (I also needed 'dragover').

@sekhar4
Copy link

sekhar4 commented Jul 28, 2016

Hi Marina,
Is there a solution for the same when using selenium ? The Drag and Drop action doesn't work in selenium for html5 ( firefox driver ). I wish to code a custom drag and drop action using java for html5; I have tried these 3 methods and none of them work, (a) Trying to click-and-hold then release onto the drop co-ordinates (b) Using iframes ( works only with frames, but I want a general solution ) (c) Saving all the drag and drop helper code in a js file and then calling this in the main java program ( this seems to be the most hyped solution to this problem in stackoverflow and github; doesn't work or maybe I messed up ).
Is there a work around to this ? Using selenium in RedwoodHQ, custom actions coded in java , any help would be appreciated.

@hughes
Copy link

hughes commented Oct 21, 2016

cool beans

@elenatosheva
Copy link

elenatosheva commented Nov 2, 2016

@pidupuis - did you resolve the duplication of elements?
I have the similar issue with the script above..

@leesaxby
Copy link

leesaxby commented Nov 3, 2016

@elenatosheva - Not sure what your exact setup is but i was getting the same duplication issue when using https://github.com/marceljuenemann/angular-drag-and-drop-lists.
This was due to the dnd-moved callback not firing so not removing the original element.
Looking at the source code this is due to dropEffect of move not being specified in the dataTransfer object.
Adding dropEffect: 'move' to the object fixed the issue, however this has only been tested on chrome 54 / linux.


        event.dataTransfer = {
            data: {
            },
            setData: function(type, val) {
                this.data[type] = val
            },
            getData: function(type) {
                return this.data[type]
            },
            dropEffect: 'move'
        }

@elenatosheva
Copy link

elenatosheva commented Nov 9, 2016

@leesaxby - Thank very much for the reply. I'm using protractor on windows/chrome to test an angular application, which
have html 5 drag and drop implementation.
I'll try your suggestion soon in the coming days, because now we are busy with testing :(
Otherwise I searched everywhere for a similar problem, but to no avail :(
I'll inform you about the results.

Regards,
Elena

@elenatosheva
Copy link

elenatosheva commented Dec 1, 2016

Many thanks, @leesaxby , your solution appears to work in my case too.

Now I can continue writing drag&drop tests.

Regards,
Elena

@kkrishan
Copy link

kkrishan commented Apr 4, 2017

@leesaxby @elenatosheva
While using above gist to automate https://github.com/marceljuenemann/angular-drag-and-drop-lists only click is happening on source div.

Issue
Even after event.dataTransfer.setData(mimeType, angular.toJson(item));

dataTransfer.types is not set or probably not allowed to read in dragstart and drop event

Observation : during manual drag drop dragstart event

dataTransfer {dropEffect: "none", effectAllowed: "move", items: DataTransferItemList, types: Array(1), files: FileList}
    dropEffect:"move"
    effectAllowed:"move"
    files:FileList
    items:DataTransferItemList
    types:Array(0)
    __proto__:DataTransfer

DataTransferItemList {0: DataTransferItem, length: 1}
    length: 0
    __proto__: DataTransferItemList

 DataTransferItem {kind: "string", type: "application/x-dnd"}
    kind: ""type: ""
    __proto__: DataTransferItem

**Observation : when using above script - custom event **

dataTransfer:Object
    data:Object
        application/x-dnd:"[{"id":"706","title":"Ab 2","drag":false,"selected":true}]"
        __proto__:Object
    dropEffect:"move"
    effectAllowed:"move"
   getData:function (type)
    setData:function (type,val)
    files:Object
    items:Object
    types:Array(0)	

I am using

	 var event = new CustomEvent("CustomEvent", {"cancelable": true})
        event.initCustomEvent(type, true, true, null);
        event.dataTransfer = {
            data: {
            },
            setData: function(type,val) {
                this.data[type] = val
            },
            getData: function(type) {
                return this.data[type]
            },
			dropEffect: 'move',
			effectAllowed:'move',
			types: [],
			items:{},
			files:{}
				
			
        }

@kkrishan
Copy link

kkrishan commented Apr 18, 2017

Solved above issue by changing . Now working fine in chrome for ruby for angular drag drop lists

    setData: function(type,val) {
        this.data[type] = val
        this.types[0] = type
    }

@mike123vn
Copy link

mike123vn commented May 27, 2017

it does not work with dragular:
http://valor-software.com/ng2-dragula/

     p_Login.openUrl("http://valor-software.com/ng2-dragula/");
            let ele1=element(by.xpath("//example-app//div[contains(text(),'You can move')]"));
            let ele2=element(by.xpath("//example-app//div[contains(text(),'This is the default use case')]/.."));
            browser.driver.executeScript(dragAndDropFn, ele1.getWebElement(), ele2.getWebElement());

@leesaxby
Copy link

leesaxby commented Jul 27, 2017

As of angular-drag-and-drop-lists version >= 2.0.0 the above work around no longer seems to work as is, due to the directive using a custom MIME type.

Iv'e forked the gist and updated it, allowing drag and drop of html elements in protractor tests.
https://gist.github.com/leesaxby/fabc59c82569a225f8d833b5924e23c6

Basic app to test the fix.
https://github.com/leesaxby/protractor-drag-drop/blob/master/README.md

@jcsmit17
Copy link

jcsmit17 commented Sep 26, 2017

@druska What is the licensing on this code?

@sergsol
Copy link

sergsol commented Aug 20, 2018

Can someone give me an example how to use it in Python script please

@ElliotPalmer-94
Copy link

ElliotPalmer-94 commented Jun 2, 2019

Thank you, the solution above works fine in Protractor

@sridattasp
Copy link

sridattasp commented Nov 6, 2019

Amazing! Thank you for this script, I finally have a test passing. I adapted it slightly to reflect the exact events I was using in my drag/drop component (I also needed 'dragover').

Can you share the dragover event changes done in javascript?

@lpnam0201
Copy link

lpnam0201 commented Jan 29, 2020

Brilliant solution. Thanks a lot.
I was simulating dropping files onto Facebook's chat window and adding files: [] property to event.dataTransfer with arbitrary File() objects actually upload these files.

@vitobotta
Copy link

vitobotta commented Feb 26, 2020

Hi! I am trying to use this with Sortable.js but nothing happens. No errors and the drag and drop doesn't happen. Is this supposed to work with current browsers?

@david-stefan
Copy link

david-stefan commented Mar 24, 2020

Hi! I am trying to use this with Sortable.js but nothing happens. No errors and the drag and drop doesn't happen. Is this supposed to work with current browsers?

Same here. Doesn't seem to work with Sortable.js.

@hdanske
Copy link

hdanske commented Apr 3, 2020

Great. Works fine with selenium + java

@EugeneShchur
Copy link

EugeneShchur commented May 12, 2020

This is amazing! Works perfectly with Selenium JavascriptExecutor =)

@nehasuman24
Copy link

nehasuman24 commented Aug 12, 2020

Can anybody please help me to know how can we drag and drop by offset using Javascript executor in Python?

@knurum
Copy link

knurum commented Mar 15, 2021

how to drag element to offset?

@rjurado01
Copy link

rjurado01 commented May 21, 2021

Thanks !!

@Praveer-grover
Copy link

Praveer-grover commented Jun 1, 2021

If someone is doing this in 2021, and is having trouble with data transfer object (in the above example dataTransfer object is a very trimmed down version of the actual object in 2021, so some of the application implementation could reject this object) then the following would work. Just replaced the Custom event with DragEvent and used the actual DataTransfer object instead of the dummy one.

function simulateDragDrop(sourceNode, destinationNode) {
    var EVENT_TYPES = {
        DRAG_END: 'dragend',
        DRAG_START: 'dragstart',
        DROP: 'drop'
    }

    function createCustomEvent(type, dataTransfer) {
        var event = new DragEvent(type,  {dataTransfer});
        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, new DataTransfer())
    dispatchEvent(sourceNode, EVENT_TYPES.DRAG_START, event)

    var dropEvent = createCustomEvent(EVENT_TYPES.DROP, event.dataTransfer)
    dispatchEvent(destinationNode, EVENT_TYPES.DROP, dropEvent)

    var dragEndEvent = createCustomEvent(EVENT_TYPES.DRAG_END, event.dataTransfer)
    dispatchEvent(sourceNode, EVENT_TYPES.DRAG_END, dragEndEvent)
}

@csbalazs-inst
Copy link

csbalazs-inst commented Nov 23, 2021

I was using Selenide and Kotlin. Also had to add a few extra props for my page to the transfer event and a few extra events:
It's both usable with SelenideElements or css selectors if you keep the commented line in the script:
The script:

function simulateDragDrop(sourceNode, destinationNode) {
    var EVENT_TYPES = {
        MOUSE_DOWN: 'mousedown',
        MOUSE_UP: 'mouseup',
        DRAG: 'drag',
        DRAG_END: 'dragend',
        DRAG_OVER: 'dragover',
        DRAG_START: 'dragstart',
        DROP: 'drop'
    }

    function createCustomEvent(type) {
        var event = new CustomEvent("CustomEvent")
        event.initCustomEvent(type, true, true, null)
        event.dataTransfer = {
            dropEffect: 'move',
            effectAllowed: 'all',
            files :[],
            items: [],
            types: [],
            data: {
            },
            setData: function(type, val) {
                this.data[type] = val
                this.items.push(val);
                this.types.push(type);
            },
            getData: function(type) {
                return this.data[type]
            }
        }
        return event
    }

    function dispatchEvent(node, type, event) {
        if (node.dispatchEvent) {
            return node.dispatchEvent(event)
        }
        if (node.fireEvent) {
            return node.fireEvent("on" + type, event)
        }
    }


    var mouse_down = createCustomEvent(EVENT_TYPES.MOUSE_DOWN)
    dispatchEvent(sourceNode, EVENT_TYPES.MOUSE_DOWN, mouse_down)

    var event = createCustomEvent(EVENT_TYPES.DRAG_START)
    dispatchEvent(sourceNode, EVENT_TYPES.DRAG_START, event)

    var drag = createCustomEvent(EVENT_TYPES.DRAG)
    dispatchEvent(sourceNode, EVENT_TYPES.DRAG, drag)

    drag_over = createCustomEvent(EVENT_TYPES.DRAG_OVER)
    drag_over.dataTransfer = event.dataTransfer
    dispatchEvent(destinationNode, EVENT_TYPES.DRAG_OVER, drag_over)

    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 mouse_up = createCustomEvent(EVENT_TYPES.MOUSE_UP)
    dispatchEvent(sourceNode, EVENT_TYPES.MOUSE_UP, mouse_up)
    return 1
}
// simulateDragDrop(document.querySelector(arguments[0]),document.querySelector(arguments[1]))
simulateDragDrop(arguments[0],arguments[1])

usage:

 val file = File("src/test/resources/js_drag_and_drop.js")
 val js = file.readText()
 Selenide.executeJavaScript<String>(js, loginIdCard, uniqueIdDropField)

@Wooqo
Copy link

Wooqo commented Feb 11, 2022

@csbalazs-inst Thank you very much!!!

@csbalazs-inst
Copy link

csbalazs-inst commented Feb 21, 2022

@mufasalg0 you can use the script above, save it in your repo and read the file into a String object.
I don't know exactly what stack you're using but selenium or most drivers have options for executing javascript directly.
look for "selenium javascript executor" for example.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment