The dragAndDrop extension simulates an HTML5 drag-and-drop interaction by locating a source element and a destination element, then dispatching dragstart, drop, and dragend events in the page context.
This is useful when a page uses a custom HTML5 drag-and-drop implementation and standard browser automation mouse actions do not trigger the exact JavaScript events expected by the application.
Parameters:
-
srcrequired, the source element to drag. Provide a CSS selector, XPath selector, element ID selector data, or Virtuoso stored element details object/string; -
dstrequired, the destination element to drop onto. Provide a CSS selector, XPath selector, element ID selector data, or Virtuoso stored element details object/string.
Note: When a plain string is provided, the extension treats values starting with / as XPath and other values as CSS selectors. When stored element details are provided, the extension reads the available selector list and tries supported selector types in order until an element is found.
How to apply this to your journey
Use the extension in a journey by calling dragAndDrop with the source and destination values. Pass each value to the matching extension input using as src and as dst when using the explicit execute syntax, or call the extension directly using the shorter library syntax.
Note: The extension does not return a value. Use a follow-up assertion against the page state, such as checking that the dragged item appears in the target list or that the source list has changed.
dragAndDrop(".from.selector", "#to.selector")store element details of "Element to drag from" in $from
store element details of "Element to drop to" in $to
dragAndDrop($from, $to)You can also pass stored variables to the extension when the elements are captured earlier in the journey.
execute "dragAndDrop" using "$from" as src and "$to" as dststore element details of "Element to drag from" in $from
store element details of "Element to drop to" in $to
dragAndDrop($from, $to)Example journey setup:
mouse over "Element to drag from"
dragAndDrop(".from.selector", "#to.selector")
wait 1 second
assert element "Dropped item" existsThis extension performs an action on the page and does not return a data object. A successful run means the source and destination elements were found and the drag-and-drop events were dispatched.
This extension does not require any external resource.
The extension should be configured as:
- Run asynchronously: No
- Scope: Global
Limitation: This extension dispatches synthetic HTML5 drag-and-drop events in the current browser page context. It can help with applications that listen for dragstart, drop, and dragend, but it does not reproduce every low-level browser, pointer, mouse, touch, accessibility, or framework-specific drag behavior. It creates a lightweight custom dataTransfer object, so applications that require a native DataTransfer, pointer movement coordinates, dragover/dragenter/dragleave events, files, touch gestures, canvas interactions, or framework-specific internal state may still not respond as expected. The source and destination elements must be present, visible enough for the application logic, and accessible in the same page context where the extension runs; elements inside cross-origin iframes, sandboxed frames, closed shadow DOM, browser-native controls, or protected third-party widgets may not be reachable from this script. The extension uses short setTimeout delays for drop and dragend but is configured as a synchronous extension because the source does not call done() or doneError(); add an explicit wait or follow-up page assertion if the application updates asynchronously after the drop. Cross-browser note: Drag-and-drop event behavior, synthetic event trust, focus handling, XPath/CSS selector behavior, and remote-grid or real-device interaction handling can differ between Virtuoso's default Chromium-based browser, Chrome, Firefox, Safari, Edge, iOS, Android, and remote-grid executions. Validate this extension in each browser/device configuration used by your plan rather than assuming one default-browser run represents all platforms.
Add the extension to your Virtuoso instance
Select the domain that matches your Virtuoso account.
View source
Last updated: 01/09/2025
Resources:
This extension does not require any external resource.
// Last updated: 01/09/2025, 11:11:34 UTC
/**
* Use this script providing "src" as stored element details that you want to drag,
* typically (draggable=true), and providing "dst" as stored element details where you will
* be dragging "src".
*/
const EVENT_TYPES = {
DRAG_END: 'dragend',
DRAG_START: 'dragstart',
DROP: 'drop'
}
function simulateDragDrop(src, dst) {
src.focus()
const event = createCustomEvent(EVENT_TYPES.DRAG_START)
dispatchEvent(src, EVENT_TYPES.DRAG_START, event)
setTimeout(() => {
const dropEvent = createCustomEvent(EVENT_TYPES.DROP)
dropEvent.dataTransfer = event.dataTransfer
dispatchEvent(dst, EVENT_TYPES.DROP, dropEvent)
}, "10");
setTimeout(() => {
const dragEndEvent = createCustomEvent(EVENT_TYPES.DRAG_END)
dragEndEvent.dataTransfer = event.dataTransfer
dispatchEvent(src, EVENT_TYPES.DRAG_END, dragEndEvent)
}, "20");
}
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)
}
}
function getElementByXpath(path) {
return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
}
function findElement(element) {
try {
element = JSON.parse(element)
} catch(e){}
var selectors
if (typeof element === 'string') {
var type = 'CSS_SELECTOR'
if (element.startsWith('//*')) {
type = 'XPATH_ID'
} else if (element.startsWith('/')) {
type = 'XPATH'
}
selectors = [{ type, value: element }]
} else {
selectors = element.selectors
}
for (var i in selectors) {
var selector = selectors[i]
if(!selector.type) continue
var el = null
switch(selector.type) {
case 'XPATH_ID':
case 'XPATH':
el = getElementByXpath(selector.value)
break
case 'CSS_SELECTOR':
el = document.querySelector(selector.value)
break
case 'ID':
el = document.getElementById(selector.value)
break
}
if (el) return el
}
return null
}
if (!src) throw new Error('src is required')
if (!dst) throw new Error('dst is required')
var fromElement = findElement(src)
if(!fromElement) throw new Error('Could not find from element: ' + src)
var toElement = findElement(dst)
if(!toElement) throw new Error('Could not find to element: ' + dst)
simulateDragDrop(
fromElement,
toElement,
)
Comments
0 comments
Please sign in to leave a comment.