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.

1{
2  "elements": [
3    {
4      "name": "onlyDraggable",
5      "type": ["draggable"],
6      "selector": {
7        "css": ".drag-me"
8      },
9      "public": true
10    },
11    {
12      "name": "myDraggable",
13      "type": ["clickable", "draggable"],
14      "selector": {
15        "css": ".drag-me-too"
16      },
17      "public": true
18    }
19  ]
20}

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:

1const source = await pageObject.getMyDraggable();
2const target = await pageObject.getDropTarget();
3// drag and drop without hold
4await source.dragAndDrop(target);

Usage in a Java test:

1Draggable source = pageObject.getMyDraggable();
2BasicElement target = pageObject.getDropTarget();
3// drag and drop with 3 sec hold
4source.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:

1const source = await pageObject.getMyDraggable();
2// drag and drop with 3 sec hold
3await source.dragAndDropByOffset(100, 100, 3);

Usage in a Java test:

1Draggable source = pageObject.getMyDraggable();
2// drag and drop without hold
3source.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:

1{
2  "elements": [
3    {
4      "name": "myDraggable",
5      "type": ["draggable"],
6      "selector": { "css": ".foo" }
7    },
8    {
9      "name": "dropTarget",
10      "selector": { "css": ".moo" }
11    }
12  ],
13  "methods": [
14    {
15      "name": "dragAndDropAtTarget",
16      "compose": [
17        {
18          "element": "myDraggable",
19          "apply": "dragAndDrop",
20          "args": [
21            {
22              "type": "elementReference",
23              "value": "dropTarget"
24            }
25          ]
26        }
27      ]
28    }
29  ]
30}

The generated method declarations have no parameters because the target element is referenced inside the statement of the dragAndDropAtTarget method.

Generated JavaScript method declaration:

1dragAndDropAtTarget(): Promise<unknown>;

Generated Java method declaration:

1public 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.

1{
2  "elements": [
3    {
4      "name": "myDraggable",
5      "type": ["draggable"],
6      "selector": { "css": ".foo" }
7    },
8    {
9      "name": "dropTarget",
10      "selector": {
11        "css": "target[class='%s']",
12        "args": [
13          {
14            "name": "classStr",
15            "type": "string"
16          }
17        ]
18      }
19    }
20  ],
21  "methods": [
22    {
23      "name": "dragAndDropAtTarget",
24      "compose": [
25        {
26          "element": "myDraggable",
27          "apply": "dragAndDrop",
28          "args": [
29            {
30              "type": "elementReference",
31              "value": "dropTarget",
32              "args": [{ "value": "myClass" }]
33            }
34          ]
35        }
36      ]
37    }
38  ]
39}

If we omitted the "value" : "myClass" hardcoded value for the dropTarget element, it would be inferred and added to the method parameters.

JavaScript example:

1dragAndDropAtTarget(classStr: string): Promise<unknown>;

Java example:

1public 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:

1// get source element coordinates
2ElementRectangle source = sourceElement.getRect();
3
4// enter frame and get target coordinates
5MyPageObject targetPageObjectInsideFrame = utam.enterFrameAndLoad(frameElement, MyPageObject.class);
6ElementRectangle target = targetPageObjectInsideFrame.getTargetElement().getRect();
7utam.exitFrame();
8
9// offset is a difference between element centers
10int xOffset = (target.getX() + target.getWidth()/2) - (source.getX() + source.getWidth()/2);
11int yOffset = (target.getY() + target.getHeight()/2) - (source.getY() + source.getHeight()/2);
12
13// drag and drop with a 5 second pause
14source.dragAndDropByOffset(xOffset, yOffset, 5);

We don’t show JavaScript code here but it’s similar and uses the same methods.