React-beautiful-dnd: How to test / automate drag and drop of an element using Selenium in Java?

Created on 3 Feb 2019  路  6Comments  路  Source: atlassian/react-beautiful-dnd

I have tried various options, but have been unable to simulate a mouse click to drag an element from one position to another in a browser using Selenium. When the test runs, I see the element get selected, but it does not move to the specified drop point. Any advice on how to test drag & drop using Selenium is immensely appreciated!

React: v16.4.2
react-beautiful-dnd: v10.0.0
Issue observed across multiple browsers: Chrome (v71.0), Firefox (v64.0.2), Edge (v42)

Here's how I defined the function in my latest attempt (variations on this theme also tried and failed):

private void dragAndDrop(WebElement dragPoint, WebElement dropPoint, WebDriver driver) {
    Actions builder = new Actions(driver);
    builder.clickAndHold(dragPoint).perform();
    builder.pause(Duration.ofSeconds(1));
    builder.moveByOffset(10,0).perform(); 
    builder.moveToElement(dropPoint).perform();
    builder.moveByOffset(10,0).perform(); 
    builder.pause(Duration.ofSeconds(1));
    builder.release();
    builder.build();
    builder.perform();
}

Also tried the following (same result):

private void dragAndDrop(WebElement dragPoint, WebElement dropPoint, WebDriver driver) {
    Actions builder = new Actions(driver);
    Action dragAndDrop = builder.dragAndDrop(dragPoint, dropPoint).build();
    dragAndDrop.perform();
}

In the test, the 2 elements are identified uniquely using xpath and the function is called:

WebElement dragPoint = driver.findElement(By.xpath(".../div[3]/...(etc.)/div[@class='rst__moveHandle']"));
WebElement dropPoint = driver.findElement(By.xpath(".../div[5]/...(etc.)/div[@class='rst__moveHandle']"));

dragAndDrop(dragPoint, dropPoint, driver);

Relevant libraries:

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Action;
import org.openqa.selenium.interactions.Actions;

Most helpful comment

So I just implemented this in our Ruby framework that sits on top of Selenium.

Here's what it looks like:

    def drag_and_drop_to(destination)
      target = self

      # target and destination are Selenium::WebDriver::Elements in this case
      selenium_actions(target, destination) do |target, destination|
        # react-beautiful-dnd looks for a click, hold, and small movement to initiate a drag event
        click_and_hold(target)
        move_by(0, -5)

        move_to(destination) # now that the drag has started, move to your destination

        release # drop the target at it's destination
      end
      sleep 1 # allow for a rerender
    end

The main learnings from trying to get this to work was:

  • You need a slight movement to trigger a drag event before you try to move to your actual destination
  • After the release, our test runner was running assertions before the DOM had a chance to update leading to false negatives

All 6 comments

So I just implemented this in our Ruby framework that sits on top of Selenium.

Here's what it looks like:

    def drag_and_drop_to(destination)
      target = self

      # target and destination are Selenium::WebDriver::Elements in this case
      selenium_actions(target, destination) do |target, destination|
        # react-beautiful-dnd looks for a click, hold, and small movement to initiate a drag event
        click_and_hold(target)
        move_by(0, -5)

        move_to(destination) # now that the drag has started, move to your destination

        release # drop the target at it's destination
      end
      sleep 1 # allow for a rerender
    end

The main learnings from trying to get this to work was:

  • You need a slight movement to trigger a drag event before you try to move to your actual destination
  • After the release, our test runner was running assertions before the DOM had a chance to update leading to false negatives

@MikaelCarpenter Yes, thank you! That worked for one aspect of the app that renders tables where rows can be dragged & dropped. Here's how the Java method ended up:

private void dragAndDrop(WebElement dragPoint, WebElement dropPoint, WebDriver driver) {
new Actions(driver)
.clickAndHold(dragPoint)
.moveByOffset(-10, 0)
.moveToElement(dropPoint)
.release()
.perform();
}

But, another section of the app renders nodes in a resource tree structure where each node is draggable. In this case, the above method does NOT work. I have not yet found a workable solution for this problem using Selenium, but I did find an alternative workaround using the UiPath Studio tool.

@MikaelCarpenter thanks for the solution, I was planning to raise a ticket for the same, Thank god I found you 馃憤
@OP - Even I had the same issue - Selenium was not able to drag drop objects,

Moving element slightly and then performing a drag operation worked.

````
Actions actions = new Actions(driver);

actions
.clickAndHold(iataCard)
.moveByOffset(0, 10)
.moveToElement(cityCard, 0, -10)
.release().build().perform();

``````

Below is a code which I performed on their template

`````

System.setProperty("webdriver.chrome.driver", "chromedriver");
WebDriver driver = new ChromeDriver();
driver.get("https://react-beautiful-dnd.netlify.com/iframe.html?selectedKind=single%20vertical%20list&selectedStory=basic");
TimeUnit.SECONDS.sleep(3);

WebElement source = driver.findElement(By.xpath("//[text()='Sometimes life is scary and dark']"));
WebElement target = driver.findElement(By.xpath("//
[text()='Sucking at something is the first step towards being sorta good at something.']"));

Actions actions = new Actions(driver);
actions.clickAndHold(source).moveByOffset(0, 100).moveToElement(target, 0, 100).release().build().perform();

`````

For those looking in the future, here is how we do it using cypress.io:

https://github.com/atlassian/react-beautiful-dnd/blob/master/cypress/integration/reorder.spec.js

Please reopen if you think there is more to answer on this one

@MikaelCarpenter thanks! Your solution worked for me with a modification. My scenario was:

  • We have two lists
  • I move one item from the first list into the second list
  • First list updates
  • Second list doesn't fully update - the item appears in the list but still in the 'isDragging' state (my tests fail as a result)
  • I move another item from the first list to the second list
  • Second list updates, now the first item is actually in the list. The second item is in that 'isDragging' state.

Adding this second item was the only way I could get the second list to update and actually include the first item. Sleeps and pauses didn't work

Not ideal at all, but was a temporary workaround for me... I'm hoping there's a better way to resolve this

Was this page helpful?
0 / 5 - 0 ratings