WebDriver Drag-and-Drop does not work on the page - java

I have a very simple test
#Test
void dragAndDrop()
{
driver.get("https://www.testandquiz.com/selenium/testing.html");
driver.manage().window().maximize();
WebElement source = driver.findElement(By.id("sourceImage"));
WebElement target = driver.findElement(By.id("targetDiv"));
builder.dragAndDrop(source, target).perform();
}
The test passes without any exceptions. However, it does not perform drag-and-drop.
I tried on Chrome, Firefox, and Edge.
Appreciate any help.

There are issues with Drag and Drop in Selenium interacting with HTML5, I've tried using the following Actions class methods on HTML5 pages but they never seem to work
dragAndDrop() | clickAndHold() | moveToElement() | release()
On the other hand you can use a JS script
String filePath = "C:\\Users\\Wilfred\\Desktop\\drag_and_drop_helper.js";
StringBuffer buffer = new StringBuffer();
String line;
BufferedReader br = new BufferedReader(new FileReader(filePath));
while ((line = br.readLine()) != null)
buffer.append(line);
String javaScript = buffer.toString();
javaScript = javaScript + "$('#sourceImage').simulateDragDrop({ dropTarget: '#targetDiv'});";
((JavascriptExecutor) driver).executeScript(javaScript);
The same method doesn't work on this link and we had to resort to robot class which I wouldn't suggest. You can find more information here

The HTML of 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.
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.

Related

Selenium Actions dragAndDrop unexpectedly navigates to google search page

I've been trying to practice with drag and drop tests on following page https://www.seleniumeasy.com/test/drag-and-drop-demo.html
Here is the code of PageObject class with only one method, which drags and drops element of the list to the dropzone:
public class DragAndDropDemoPage extends Page {
public DragAndDropDemoPage(WebDriver driver) {
super(driver);
navigateTo();
}
#Override
public void navigateTo() {
driver.get(Urls.DRAG_AND_DROP_PAGE_URL);
}
public void dragAndDropElementWithIndex(int index) {
List<WebElement> elements = findElementsByCss("span[draggable=true]");
new Actions(driver).dragAndDrop(elements.get(index), findElementByCss("div#mydropzone")).build().perform();
}
}
after performing of such an action WebDriver eventually navigates to the Google Search page. And search request contains the name of the element I've been dragging.
What's wrong with this case? How did WebDriver managed to move to another page?
PS: Super class Page is:
public abstract class Page {
WebDriver driver;
public Page(WebDriver driver) {
this.driver = driver;
}
public abstract void navigateTo();
protected WebElement findElementByCss(String cssSelector) {
return driver.findElement(By.cssSelector(cssSelector));
}
protected List<WebElement> findElementsByCss(String cssSelector) {
return driver.findElements(By.cssSelector(cssSelector));
}
protected WebElement findByXpath(String xpath) {
return driver.findElement(By.xpath(xpath));
}
}
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);
});
}
References
A couple of references:
A working demo of drag and drop anything (source code)
Working example of Drag and Drop
Problem: source element is dropping to the mouse position and not to target element. Drag and drop works in other website, you can check here.
When you run script probably your mouse position is somewhere near tab bar of the browser, that's why google opens (same as you put drag any text to the browser bar).
You can try #DebanjanB solution or you can use Robot.

Selenium: how to get the value of hidden element which has all div tags

I would like to get the value of all div tags specified in attached. I have tried with all possible locators like classname etc, which is showing null. and tried with JavaScript also which is returning null.
Please see the screen shot and I need the selected text which is in blue color starts with "Enables enterprise IT to deploy networking services"
You need to research creating selectors as this isn't a difficult one. There are numerous approaches for this element, but here's one for you: $$("#offers-popover .description"). Obviously this is a CSS selector based on the $$ and you use getText from the Selenium API in order to scrape the element text, which is what I assume you are intending to do.
driver.findElement(By.css("#offers-popover .description")).getText();
Since your element is not visible you can try this:
String divText = driver.findElement(By.className("description")).getAttribute("textContent");
Or, if this is not the only element on the page with the class description:
WebElement popElement = driver.findElement(By.id("offers-popover"));
String divText = popElement.findElement(By.className("description")).getAttribute("textContent");

How to assert if the image is zoomed in selenium

Using selenium with java I want to vary whether an image is zoomed when the cursor is moved over the image. From the source code below, element changes:
Before zoom: <div class="powatag-zoom powatag-hidden">
After zoom: <div class="powatag-zoom">
Any help to assert the change with working code is welcome.
One possible approach would be to check the value of getAttribute("class") before and after the mouse move action:
WebElement we = webdriver.findElement(By.cssSelector("div.powatag-zoom"));
assertEquals(we.getAttribute("class"), "powatag-zoom powatag-hidden");
Actions action = new Actions(webdriver);
action.moveToElement(we).build().perform();
assertEquals(we.getAttribute("class"), "powatag-zoom");
You can also check the size of the element using getSize.

getByXpath() not working inside frame

i am new to Htmlunit and trying to extract data from a website http://capitaline.com/new/index.asp. I have logged into the website successfully. When we log into website there are three frames.
One on the top to search for the company(like ACC ltd.) for which we are extracting data.
2nd frame has a tree which provide links to various data we want to look at.
3rd frame has the resulted data outcome on the basis of link you clicked in frame.
I managed to get the frame i need below:
HtmlPage companyAtGlanceTopWindow =(HtmlPage)companyAtGlanceLink.click().getEnclosingWindow().getTopWindow().getEnclosedPage();
HtmlPage companyAtGlanceFrame = (HtmlPage)companyAtGlanceTopWindow.getFrameByName("mid2").getEnclosedPage();
System.out.println(companyAtGlanceFrame.toString()); // This line returns the frame URL as i can see in my browser.
Output of print statement is
HtmlPage(http://capitaline.com/user/companyatglance.asp?id=CGO&cocode=6)#1194282974
Now i want my code to navigate down to the table inside this frame and for that i am using getByXPath() but it gives me nullPointerException. Here is the code for that.
HtmlTable companyGlanceTable1 = companyAtGlanceFrame.getFirstByXPath("/html/body/table[4]/tbody/tr/td/table/tbody/tr/td[1]/table");
My XPath for the current webpage(after i clicked the link)from which i am trying to extract table is seems correct, as it is copied from chrome element inspect. Please suggest some way to extract the table. I have done this type of extraction before but there i had id of table so, i used it.
Here is the HTML code for the table in the webpage.
<table width="100%" class = "tablelines" border = "0" >
I want to know that can you see the inner contents of each iframes in console (print asXml()), are they nested iframes?
well try this
List<WebWindow> windows = webClient.getWebWindows();
for(WebWindow w : windows){
HtmlPage hpage = (HtmlPage) w.getEnclosedPage();
System.out.println(hpage.asXml());
}
once you can see the contents,
HtmlPage hpage = (HtmlPage)webClient.getWebWindowByName(some_name).getEnclosedPage();
then using xpath grab your table contents(make sure your xpath is correct). It will work.(worked for me)
Thank you RDD for your feedback.
I solved the problem. Actually issue was not with the frame but with the XPath provided by chrome.
XPath Provided by chrome is:
/html/body/**table[4]**/tbody/tr/td/table/tbody/tr/td[1]/table
But the XPath worked for me is:
/html/body/**table[3]**/tbody/tr/td/table/tbody/tr/td[1]/table
It seems as, XPath provided by chrome has some glitch when there is a table within the path(Or may be some bug in htmlunit itself). I did many experiments and found that chrome always gives ../../table[row+1]/.. as XPath, while working XPath for htmlunit is ../../table[row]/..
SO, this code is working fine for me
HtmlTable companyGlanceTable1 = companyAtGlanceFrame.getFirstByXPath("/html/body/table[3]/tbody/tr/td/table/tbody/tr/td[1]/table");

Reading dynamic web page content in java

I need help reading the contents of a webpage. Currently i am using the following method to read the contents
BufferedReader in = new BufferedReader(new InputStreamReader(page.openStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
{Content = Content + inputLine;}
However with this method there is a problem. . some jsp pages have ajax in them which randomly updates a css class of a webpage like so
Javascript code just to give an idea:
if (request.readyState === 4 && request.status === 200)
{
var type = request.getResponseHeader("Content-Type");
$('.update').empty();
$('.update').append(request.responseText); //update the css class
}
So as a result when this page reader is read through my java method as mentioned above i just get
<div class="update"></div>
although on the screen this class has a value.
Now however if i save the page first (by clicking save as in Firefox) then the values appended in the CSS class by jquery are also visible.
Is there a method or a way on how i could read the values or obtain the values like firefox does by saving the pages.. I want to read the contents of the entire webpage with the Ajax values present in the string.
On one side i read that this is difficult since the JAvascript in rendered and executed by the browser so i wanted to know does firefox have any apis that might help ? Any suggestions would be appreciated.
You may find the following project useful:
HTMLUnit
Here is also a very informative blog post from Data Big Bang.
Also check out PhantomJS. In the same way that Crowbar is a headless Mozilla browser, PhantomJS is a headless WebKit browser - the engine that Safari and Google Chrome use.

Categories