Selenium Actions dragAndDrop unexpectedly navigates to google search page - java

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.

Related

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

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.

How Can I Retrieve Text from a div using Cucumber?

I have been trying to get the text from various div and tables for some BDD's I am writing in Cucumber. Everytime I try to acquire anything from the frontend of the website I'm working on it just pulls nothing. I need to know what I specifically need to do to get this content.
The page element I'm trying to retrieve from is similar to this
<div id="statMsg" class="statusMsg">Your changes are saved.</div>
These are the 2 methods that are currently trying to retrieve the text from the div.
public WebElement savedText() {
return webdriver.findElement(By.className("statusMsg"));
public void UserClicksOnSave() throws InterruptedException {
daSave.saveOn().click();
daPage.savedText().getText();
Find the DIV by XPATH such that it contains the text you are looking for:
public WebElement savedText() {
String xpath = "//div[contains(#class, 'statusMsg'][contains(., 'Your changes are saved.')]";
return webdriver.findElement(By.xpath(xpath));
Selenium should implicitly wait for the DIV matching that class name, and containing the given text. The findElement method should return only when both conditions are true, which should combat race conditions in your test.

Selenium - The label is clicked (it changes colour for a moment) then the label reverts to the unclicked state

Screenshot
When I click on a button using XPath or CSS methods the button is highlighted for a moment. Then it changes back to the default colour as if the option is not chosen. When the automation is finished I get a user error that the button option was not selected.
I'm writing Java code with the latest Chrome driver. I've also tried Firefoxdriver. I've tried explicit wait and Thread.sleep and nothing worked.
This is the code - Insurance Cover Type Label
driver.findElement(By.xpath("//*[#id=\'content\']/div[4]/div/div[2]/div[14]/div[2]/ul/li[2]/label")).click();
Similar labels on the screen can be clicked and selected. I searched questions and answers on this topic but i can't find a solution. I've added code and front end screen shots.
The problem is that your locator is incorrect (some indexes are off), at least when I checked it in Chrome using $x().
While you can click the LABEL, I would suggest that you avoid the long XPath and instead use the ID for the contained INPUT and then reference the LABEL sibling. I tried it and it worked fine for me.
By.CssSelector("#itemInsured\\.coverSelected1 + label")
Your code seems to be clicking on a label, and not on a button. Even if the label is inside a button, the event may be captured while it bubbles and cancelled. I'd try selecting exactly the object you want to handle the event.
By looking at the screenshot Insurance Cover Type Label, it seems that the button element that you want to interact with, is inside the <lable> tag. So when you are clicking on the button, it is basically clicking on <label> not the <button>. Can you please provide a screenshot of the dom by expanding the tag.
Your locator should be like
By.xpath("//*[#id=\'content\']/div[4]/div/div[2]/div[14]/div[2]/ul/li[2]/label/button");
You just need to include the element in your xpath that is referring to the button element inside the label.
Work with this code (this xpath: //label[contains(text(), 'Comprehensive')]):
public class Sof {
/**
* Specific logger
*/
private static final Logger logger = LoggerFactory.getLogger(Sof.class);
public static void main(String[] args) throws Exception {
final OperatingSystem currentOperatingSystem = OperatingSystem.getCurrentOperatingSystem();
String pathWebdriver = String.format("src/test/resources/drivers/%s/googlechrome/%s/chromedriver%s", currentOperatingSystem.getOperatingSystemDir(),
SystemArchitecture.getCurrentSystemArchitecture().getSystemArchitectureName(), currentOperatingSystem.getSuffixBinary());
if (!new File(pathWebdriver).setExecutable(true)) {
logger.error("ERROR when change setExecutable on " + pathWebdriver);
}
System.setProperty("webdriver.chrome.driver", pathWebdriver);
final ChromeOptions chromeOptions = new ChromeOptions();
WebDriver driver = new ChromeDriver(chromeOptions);
driver.get("https://services.aviva.ie/direct/product/car.htm?_flowId=motor-flow&_flowExecutionKey=e1s1");
WebElement element = driver.findElement(By.xpath("//label[contains(text(), 'Comprehensive')]"));
element.click();
Thread.sleep(5000);
driver.quit();
}
}
Note:
If you do Web Interface tests with Java + Selenium, I advise you to use the NoraUi Open Source Framework
As per your code attempt you are trying to invoke click() method on the <label> tag which won't be accepting any click.
If you look into the HTML the <label> node have 2 child nodes, an <input> and another <label> node. You can invoke click() on the child <label> tag as follows :
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
options = Options()
options.add_argument("start-maximized")
options.add_argument("disable-infobars")
options.add_argument("--disable-extensions")
options.add_argument("--no-sandbox")
driver = webdriver.Chrome(chrome_options=options, executable_path=r'C:\WebDrivers\ChromeDriver\chromedriver_win32\chromedriver.exe')
driver.get('https://services.aviva.ie/direct/product/car.htm?_flowId=motor-flow&_flowExecutionKey=e1s1')
element = driver.find_element_by_xpath("//input[#class='radio coverType' and #name='itemInsured.coverSelected' and #value='0101']")
driver.execute_script("return arguments[0].scrollIntoView(true);", element)
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//label[#for='itemInsured.coverSelected1']"))).click()
Browser Snapshot :

Selenium Driver - How to click a value from a sub-dropdown

I'm sort of new to Web Automation and I'm having some trouble interacting with clicking a value from a sub-dropdown.
I'm able to select the span, click the "Apply Special" link to make the drop-down appear, but no matter what I do, I can't hit the specific "li". I can get all the text from the span, but I don't know how to actually make it so it clicks the specific special.
#FindBy(css = ".sub-dropdown")
protected List<WebElement> specialsTest;
#FindBy(id = "ctl00_ctl00_content_content_ucOrderWorkflow_upnlApplyDiscount")
protected Element specialItems;
public NewOrderPage addSpecificSpecialToOrder(String special) {
Reporter.log(String.format("Add special %s to order.", special), true);
//This clicks the Apply Special link
specialItems.waitUntilVisible().click();
//This prints the content of the span, just to make sure I'm hitting the right dropdown
String text = specialsDropDown.waitElementsReady().then().getText();
System.out.println("Dropdown getText " + text);
//This is my attempt to find the <li> text and click it, but it's not working :(
for (WebElement li : specialsTest){
System.out.println(li.getText());
if (li.getText().contains(special)) {
li.click();
break;
}
}
return this;
}
Any help, would be highly appreciate it.
Thank you in advance, and let me know if I need to add more info.
As I saw, the element which you are trying to click is an a tag ,so you need to use correct locator to point this element. We can use:
Link/ Partiallink locator
Xpath locator: .//a[contains(.,'Percentage Discount')]

GWT History - Why does it change the focus of my screen?

I have a simple application structure that will contain three composites at any one time - my header, footer and content composites. The composites are laid out in the follow manner.
<body>
<div id="header">
<div id="content">
<div id="footer">
</body>
The composites are assigned to the three <div>'s in my EntryPoint. The EntryPoint also contains a History Handler as follows.
History.addValueChangeHandler(new ValueChangeHandler<String>() {
#Override
public void onValueChange(ValueChangeEvent<String> event) {
String historyToken = event.getValue();
if(historyToken.isEmpty()) {
parseTokens();
ContentContainer.INSTANCE.setContent(new IndexScreen());
}
else if(historyToken.equalsIgnoreCase("registration")) {
ContentContainer.INSTANCE.setContent(new RegisterScreen());
}
else if(historyToken.equalsIgnoreCase("login")) {
ContentContainer.INSTANCE.setContent(new LoginScreen());
}
}
});
History.fireCurrentHistoryState();
In my Composites, I have several ClickEvent handlers that look similar to the following.
#UiHandler("registerLink")
public void handleClick(ClickEvent event) {
ContentContainer.INSTANCE.setContent(new RegisterScreen());
History.newItem("registration", true);
}
This registers the history very nicely. It also brings me to the appropriate pages when I click the back button. However, it has the very odd effect of focusing the browser on the content composite, with the effect of the browser being scrolled to the bottom. It's not a deal breaker but it kind of breaks the user experience a little. (Do let me know if the explanation isn't clear, I'll add images)
What exactly is causing this and how can I fix it?
GWT history tokens work with the hash # token. In html this was originally intended to use the browser to focus on a specific part of the page, if an element has a name or id with the string after the # token. Could it be you have an id matching your history token?
Also in you handleClick you call setContent. But if I'm correct the call after it triggers a change event and will end up in the onValueChange, which also calls the setContent. So it looks like you are calling setContent twice here.

Categories