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"
      }
    },
    {
      "name" : "myDraggable",
      "type" : [ "clickable", "draggable" ],
      "selector" : {
        "css" : ".drag-me-too"
      }
    }
  ]
}

DragAndDrop API

The draggable type exposes the following API for an element:

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

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",
              "name": "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",
              "name" : "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 at an unknown target element location

You don't have to hardcode the target element in a compose method as an elementReference. The target can still be a parameter of type element. Let's also use a hold duration of 3 seconds this time.

{
  "elements": [
    {
      "name" : "myDraggable",
      "type" : ["draggable"],
      "selector" : { "css": ".foo" }
    }
  ],
  "methods": [
    {
      "name": "dragAndDropAtTarget",
      "compose": [
        {
          "element" : "myDraggable",
          "apply" : "dragAndDrop",
          "args" : [
            {
              "type" : "element",
              "name" : "dropTargetParameter"
            },
            {
              "value" : 3
            }
          ]
        }
      ]
    }
  ]
}

Generated JavaScript method declaration:

dragAndDropAtTarget(dropTargetParameter: _BaseUtamElement): Promise<unknown>;

Generated Java method declaration:

public void dragAndDropAtTarget(BasicElement dropTargetParameter);

Drop by offset

To compose dragAndDropByOffset, the offset is usually provided as parameters. The test writer provides the values. Let's also make hold duration a parameter.

{
  "elements": [
    {
      "name" : "myDraggable",
      "type" : ["draggable"],
      "selector": { "css": ".foo" }
    }
  ],
  "methods": [
    {
      "name": "dragAndDropByCoordinates",
      "compose": [
        {
          "element" : "myDraggable",
          "apply": "dragAndDropByOffset",
          "args": [
            {
              "type": "number",
              "name": "xOffset"
            },
            {
              "type": "number",
              "name": "yOffset"
            },
            {
              "type": "number",
              "name": "holdSec"
            }
          ]
        }
      ]
    }
  ]
}

Generated JavaScript method declaration:

dragAndDropByCoordinates(xOffset: number, yOffset: number, holdSec: number): Promise<unknown>;

Generated Java method declaration:

public void dragAndDropByCoordinates(Integer xOffset, Integer yOffset, Integer holdSec);