Draggable actions
A draggable element can be selected by the user with a mouse, dragged to a droppable element, and dropped by releasing the mouse button.
Draggable element declaration
A draggable element must include draggable
in its type
property. In this example, one element is just draggable, but usually an element is both clickable and draggable because a user needs to click before they can drag.
{
"elements": [
{
"name": "onlyDraggable",
"type": ["draggable"],
"selector": {
"css": ".drag-me"
},
"public": true
},
{
"name": "myDraggable",
"type": ["clickable", "draggable"],
"selector": {
"css": ".drag-me-too"
},
"public": true
}
]
}
DragAndDrop API
The draggable
type exposes the following API for an element:
dragAndDrop(target: Element, hold: number)
clicks and drags an element to the location of the target element, then drops. The target element is provided as a parameter and doesn't have to be draggable.
A second optional parameter defines a hold duration in seconds that is applied after the click and before the drag. This hold duration can be useful to simulate a real user in some cases.
Usage in a JavaScript test:
const source = await pageObject.getMyDraggable();
const target = await pageObject.getDropTarget();
// drag and drop without hold
await source.dragAndDrop(target);
Usage in a Java test:
Draggable source = pageObject.getMyDraggable();
BasicElement target = pageObject.getDropTarget();
// drag and drop with 3 sec hold
source.dragAndDrop(target, 3);
dragAndDropByOffset(xOffset: number, yOffset: number, hold: number)
drops an element using coordinates relative to the current location of the element. It has an optional parameter for hold duration in seconds.
Usage in a JavaScript test:
const source = await pageObject.getMyDraggable();
// drag and drop with 3 sec hold
await source.dragAndDropByOffset(100, 100, 3);
Usage in a Java test:
Draggable source = pageObject.getMyDraggable();
// drag and drop without hold
source.dragAndDropByOffset(100, 100);
Compose dragAndDrop
It's a good practice to compose a UI interaction as a public method inside a page object. Here are some examples of how to compose dragAndDrop
and dragAndDropByOffset
and how to provide a target element as a parameter.
Drop at a known target element
The most common use case is to drop an element at a known target element location.
To do that, we pass elementReference
to a known element as an argument:
{
"elements": [
{
"name": "myDraggable",
"type": ["draggable"],
"selector": { "css": ".foo" }
},
{
"name": "dropTarget",
"selector": { "css": ".moo" }
}
],
"methods": [
{
"name": "dragAndDropAtTarget",
"compose": [
{
"element": "myDraggable",
"apply": "dragAndDrop",
"args": [
{
"type": "elementReference",
"value": "dropTarget"
}
]
}
]
}
]
}
The generated method declarations have no parameters because the target element is referenced inside the statement of the dragAndDropAtTarget
method.
Generated JavaScript method declaration:
dragAndDropAtTarget(): Promise<unknown>;
Generated Java method declaration:
public void dragAndDropAtTarget();
Drop at a known target element with hardcoded arguments
It's possible that the target element needs arguments for the selector or filter. Those arguments can be hardcoded in a compose statement. This example passes a hardcoded myClass
value to the dropTarget
in the dragAndDropAtTarget
method.
{
"elements": [
{
"name": "myDraggable",
"type": ["draggable"],
"selector": { "css": ".foo" }
},
{
"name": "dropTarget",
"selector": {
"css": "target[class='%s']",
"args": [
{
"name": "classStr",
"type": "string"
}
]
}
}
],
"methods": [
{
"name": "dragAndDropAtTarget",
"compose": [
{
"element": "myDraggable",
"apply": "dragAndDrop",
"args": [
{
"type": "elementReference",
"value": "dropTarget",
"args": [{ "value": "myClass" }]
}
]
}
]
}
]
}
If we omitted the "value" : "myClass"
hardcoded value for the dropTarget
element, it would be inferred and added to the method parameters.
JavaScript example:
dragAndDropAtTarget(classStr: string): Promise<unknown>;
Java example:
public void dragAndDropAtTarget(String classStr);
Drop by offset inside a frame
It's always more reliable to dragAndDrop
with a target element as shown in the previous section. However, that's not possible if the target element is inside a frame. Here's an example for Java:
// get source element coordinates
ElementRectangle source = sourceElement.getRect();
// enter frame and get target coordinates
MyPageObject targetPageObjectInsideFrame = utam.enterFrameAndLoad(frameElement, MyPageObject.class);
ElementRectangle target = targetPageObjectInsideFrame.getTargetElement().getRect();
utam.exitFrame();
// offset is a difference between element centers
int xOffset = (target.getX() + target.getWidth()/2) - (source.getX() + source.getWidth()/2);
int yOffset = (target.getY() + target.getHeight()/2) - (source.getY() + source.getHeight()/2);
// drag and drop with a 5 second pause
source.dragAndDropByOffset(xOffset, yOffset, 5);
We don't show JavaScript code here but it's similar and uses the same methods.