Drag and drop not working using Actions when draggable=true using Selenium and C#

拥有回忆 提交于 2021-02-13 17:37:38

问题


Elements are identified correctly and i can see mouse moving between this two elements but drag and drop not happening. Ui not displayed any highlights when click and hold. No errors also.

I have tried different solutions suggested on different discussions none of them working for me

My code

_actions = new Actions(Driver.WebDriver);
        var dragAndDrop = _actions.ClickAndHold(parentRow)
                                  .MoveToElement(childRow )
                                  .Release(target)
                                  .Build();
        dragAndDrop.Perform();
        Driver.Wait();

This is how i am identifying elements

 var childList =Driver.WebDriver.FindElements(By.ClassName("itl-treeNode-title"));
     var parentRow = childList.FirstOrDefault(x => x.Text.Equals(parentSrc)).FindElement(By.XPath("following-sibling::*[1]"));
     var childRow = childList.FirstOrDefault(x => x.Text.Equals(childSrc)).FindElement(By.XPath("following-sibling::*[1]"));

Same code works on another ui on our application.

I have now changed my code like below and now i am getting stale element exception- Since i need to identify this element dynamically i can not use the POM solution mentioned here https://www.softwaretestingmaterial.com/stale-element-reference-exception-selenium-webdriver/#How-To-Overcome-Stale-Element-Reference-Exception-in-Selenium

var childList = Driver.WebDriver.FindElements(By.ClassName("itl-treeNode-title"));
     var parent = childList.FirstOrDefault(x => x.Text.Equals(parentSrc)).FindElement(By.XPath("parent::*"));
     var parentRow = parent.FindElement(By.ClassName("itl-treenode-content-cover"));
     var child = childList.FirstOrDefault(x => x.Text.Equals(childSrc)).FindElement(By.XPath("parent::*"));
     var childRow = child.FindElement(By.ClassName("itl-treenode-content-cover"));         
     childRow.Click();
     //try
     //{
     //   (new Actions(Driver.WebDriver)).DragAndDrop(childRow, parent).Perform();
     //}         
     //catch (Exception ex)
     //{
     //   throw new Exception("Failed to perform drag and drop ");
     //}
     new Actions(Driver.WebDriver).ClickAndHold(childRow)
               .MoveToElement(parent)
               .Release(parent)
               .Build()
               .Perform();
     Driver.Wait();

Exception

OpenQA.Selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document
  (Session info: chrome=77.0.3865.120)
   at OpenQA.Selenium.Remote.RemoteWebDriver.UnpackAndThrowOnError(Response errorResponse)
   at OpenQA.Selenium.Remote.RemoteWebDriver.Execute(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.Remote.RemoteWebDriver.PerformActions(IList`1 actionSequenceList)
   at OpenQA.Selenium.Interactions.Actions.Perform()

回答1:


As per the HTML you have shared the WebElement which you want to DragAndDrop() contains the attribute draggable=true


draggable

draggable is a attribute that indicates whether an element can be dragged, either with native browser behavior or the HTML Drag and Drop API. draggable can have the following values:

  • true: the element can be dragged.
  • false: the element cannot be dragged.

Note: This attribute is enumerated and not Boolean. A value of true or false is mandatory, and shorthand like <img draggable> is forbidden. The correct usage is <img draggable="false">.

If this attribute is not set, its default value is auto which means drag behavior is the default browser behavior: only text selections, images, and links can be dragged. For other elements, the event ondragstart must be set for drag and drop to work.


Native HTML5 Drag and Drop

Eric Bidelman in the article Native HTML5 Drag and Drop mentioned, making an object draggable is simple as you only need to set the draggable=true attribute on the element you want to make moveable. As an example:

<div id="cols">
  <div class="col" draggable="true"><header>X</header></div>
  <div class="col" draggable="true"><header>Y</header></div>
  <div class="col" draggable="true"><header>Z</header></div>
</div>

To enable other types of content to be draggable you can leverage the HTML5 DnD APIs. However, using CSS3 you can spruce up the markup to look like columns and adding cursor gives users a visual indicator that something is moveable but most browsers will create a ghost image of the content being dragged and draggable won't do anything. Some browser, FF in particular will require that some data be sent in the drag operation.

Further, Remy Sharp in the article Dragging Anything mentioned:

The HTML 5 spec says it should be as simple as adding the following attributes to the markup of the elements in question:

draggable="true"

However, this doesn’t work completely for Safari or Firefox. For Safari you need to add the following style to the element:

[draggable=true] {
  -khtml-user-drag: element;
}

This will start working in Safari, and as you drag it will set a default, empty value with the dataTransfer object. However, Firefox won’t allow you to drag the element unless you manually set some data to go with it.


Solution

To solve this, we need a dragstart event handler, and we’ll give it some data to be dragged around with:

var dragItems = document.querySelectorAll('[draggable=true]');

for (var i = 0; i < dragItems.length; i++) {
  addEvent(dragItems[i], 'dragstart', function (event) {
    // store the ID of the element, and collect it on the drop later on
    event.dataTransfer.setData('Text', this.id);
  });
}

Here you can find a working demo of drag and drop anything (source code)


This usecase

The realtime HTML would have helped us to analyze the issue in a better way. However you can try either of the following chained methods as solution:

  • Using ClickAndHold(), MoveToElement() and Release():

    new Actions(Driver.WebDriver).ClickAndHold(parentRow).MoveToElement(childRow ).Release(target).Build().Perform();
    
  • Using DragAndDrop():

    new Actions(Driver.WebDriver).DragAndDrop(parentRow, childRow).Build().Perform();
    

Note: Induce WebDriverWait to ensure that the element to be dragged is clickable.




回答2:


After clicking on childRow, build the webelement again to avoid stale element reference exception, sample code below.

var childList = Driver.WebDriver.FindElements(By.ClassName("itl-treeNode-title"));
var parent = childList.FirstOrDefault(x => x.Text.Equals(parentSrc)).FindElement(By.XPath("parent::*"));
var parentRow = parent.FindElement(By.ClassName("itl-treenode-content-cover"));
var child = childList.FirstOrDefault(x => x.Text.Equals(childSrc)).FindElement(By.XPath("parent::*"));
var childRow = child.FindElement(By.ClassName("itl-treenode-content-cover"));    
childRow.Click();
childRow = child.FindElement(By.ClassName("itl-treenode-content-cover"));    
new Actions(Driver.WebDriver).ClickAndHold(childRow)
           .MoveToElement(parent)
           .Release(parent)
           .Build()
           .Perform();
Driver.Wait();


来源:https://stackoverflow.com/questions/59205188/drag-and-drop-not-working-using-actions-when-draggable-true-using-selenium-and-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!