In several threads here, there is a work-around posted for selenium drag and drop with pages that use HTML5 for drag and drop. This work-around involves using javascript to simulate the drag and drop, for example Unable to perform HTML5 drag and drop using javascript for Selenium WebDriver test, and https://gist.github.com/rcorreia/2362544. This solution works well on this page, http://the-internet.herokuapp.com/drag_and_drop.
The general approach is to read the javascript file here (https://gist.github.com/rcorreia/2362544#file-drag_and_drop_helper-js) into a string, referred to as 'jsfile' below.
then in selenium (with java), pass in the css selectors for the source and the destination, where #column-a is the id of the source and #column-b is the target.
((JavascriptExecutor) driver).executeScript(jsfile +"$('#column-a').simulateDragDrop({ dropTarget: '#column-b'});");
It works like a champ on that page.
However, a similar approach does not seem to work on this page, https://crossbrowsertesting.github.io/drag-and-drop.html. Nothing happens when I run
((JavascriptExecutor) driver).executeScript(jsfile +"$('#draggable').simulateDragDrop({ dropTarget: '#droppable'});");
I have pages that seem to behave like this second page (eg no drag and drop). As a first step in understanding this, I'd like to get an idea why this approach does not seem to work in the latter case here.
On re-testing https://crossbrowsertesting.github.io/drag-and-drop.html, it looks like the straight-forward use of the Actions class does the trick for drag and drop. In the particular app that I am testing, which is set up with some additional code to help with accessibility, I was able to get drag and drop happening by setting focus on the first element and hitting the return key, then setting the focus on the target element and hitting return again. I am fairly sure that this is custom event handling, so may not work in other applications. Just in case, I've posted code here which does this in selenium.
public void dndHtml5(String xPathSource, String xPathDestination) {
clickEnterKeyOnElement(xPathSource);
clickEnterKeyOnElement(xPathDestination);
}
public void clickEnterKeyOnElement(String xPath) {
setFocusOnElement(xPath);
WebElement target=element(xPath);
target.sendKeys(Keys.ENTER);
}
public void setFocusOnElement(String xPath) {
WebElement element = element(xPath);
Actions actions = new Actions(driver);
actions.moveToElement(element).build().perform();
}
public WebElement element(String xPath){
return driver.findElementByXPath(xPath);
}
Related
I am trying to automate drag and drop functionality in IE11 using Selenium Web Driver in Java. I am somehow able to achieve it on Chrome, but it's not happening in IE.
Before further explanation here is how I'm dragging and dropping:
Actions builder = new Actions(driver);
builder.clickAndHold(sourceElement)
.moveToElement(targetElement)
.release(targetElement)
.build().perform();
In IE: Instead of dragging and dropping it selects all the text from source to destination element. I thought this might be because it's pickup up the wrong element and tried the operation with some relevant parent and child elements but didn't work.
In Chrome: Works damn smooth.
In Firefox: Just performs click on holds and while dragging throws, element no longer attached to DOM exception. This might be because, I am dragging a row from a grid (kendo grid) and since dragging a row from a grid is not possible our devs have implemented it in such a way that when you drag a row a new dynamic element is created which moves along.
Just to add on more details:
I have already tried dragAndDrop() and other Javacript options.
I'm using the latest version of selenium and updated IE.
Our grid uses HTML5 components and I've discovered that there are few issues already there (not sure about what all issues though), but still since my scenario was working in one browser I hope this is not one of those issues.
I have made it possible somehow using Robot class but it is too unreliable and behaves weird, I would prefer giving up than using it.
Any help will be appreciated!
One solution if it's an HTML5 drag and drop is to simulate it with some javascript.
Here is a working example that drops an item to a bin:
final String JS_DnD =
"var src=arguments[0],tgt=arguments[1];var dataTransfer={dropEffe" +
"ct:'',effectAllowed:'all',files:[],items:{},types:[],setData:fun" +
"ction(format,data){this.items[format]=data;this.types.append(for" +
"mat);},getData:function(format){return this.items[format];},clea" +
"rData:function(format){}};var emit=function(event,target){var ev" +
"t=document.createEvent('Event');evt.initEvent(event,true,false);" +
"evt.dataTransfer=dataTransfer;target.dispatchEvent(evt);};emit('" +
"dragstart',src);emit('dragenter',tgt);emit('dragover',tgt);emit(" +
"'drop',tgt);emit('dragend',src);";
WebDriver driver = new InternetExplorerDriver();
driver.get("http://html5demos.com/drag");
WebElement ele_source = driver.findElement(By.id("two"));
WebElement ele_target = driver.findElement(By.id("bin"));
// drag and drop item two into the bin
((JavascriptExecutor)driver).executeScript(JS_DnD, ele_source, ele_target);
So I found that if you get the page source with WebDriver, you actually get the generated source of the entire DOM (not just the HTML source code of the page that loaded). You can then use this String to generate a Jsoup Document. This is cool, because Jsoup is much faster than WebDriver at searching for elements, it also has a much better API to do so.
So, is there anyway to turn a Jsoup Element into a WebDriver WebElement? I saw another post on stackoverflow about using a method to generate an xpath from the Jsoup document, but that's not what I'm looking for since WebDriver will still have to parse the page and use the Xpath to lookup the element, defeating the purpose (unless your porpuse is purely to use Jsoup for its superior Selector methods).
The reason I want to try and use Jsoup to find WebElements for WebDriver is because on some websites, WebDriver is very very slow (I work for a company that automation hundreds of 3rd party websites, we have no control over these sites).
There seems to be a confusion between interactive and non-interactive tools here.
WebDriver tests are very often slow (in my experience) due to unnecessary and defensive waits and delays, using improperly-understood frameworks, and often written by junior or outsourced developers - but fundamentally also because WebDriver is mimicking a real user's actions in 'real time' on a real browser, and communicating with the browser app using an API (based on a specification) and a protocol. It's interactive.
(Less so with HtmlUnit, PhantomJS etc.)
By contrast, Jsoup is just a glorified HTTP client with extra parsing capabilities. It's non-interactive, and ultimately works off a snapshot String of data. We'd expect it to be much faster for its particular use-cases.
Clearly both are HTTP clients of a sort, and can share static web content, which is why WebDriver could pass data off for processing by Jsoup (though I've never heard of this use-case before).
However, Jsoup can never turn one of its Elements (a Java snapshot object containing some properties) into a WebDriver WebElement, which is more a kind of 'live' proxy to a real and interactive object within a program like Firefox or Chrome. (Again, less so with HtmlUnit, PhantomJS etc.)
So you need to decide whether interactivity is important to you. If it's crucial to mimic a real user, WebDriver has to 'drive' the process using a real browser.
If it's not, then you can consider the headless browsers like HtmlUnit and (especially) PhantomJS, as they will be able to execute JavaScript and update the DOM in a way that the HTTP libraries and Jsoup can't. You can then pass the output to Jsoup etc.
Potentially, if you went down the PhantomJS route, you could do all your parsing there using the JavaScript API. See: Use PhantomJS to extract html and text etc.
For a lot of people, interactivity isn't important at all, and it's quicker to drop WebDriver completely and rely on the libraries.
I know this question is incredibly old, but just so anyone who comes to see this can find this answer. This will return an xpath from your Jsoup Element. This was translated to Java by me, but the original source I copied the code from was https://stackoverflow.com/a/48376038/13274510.
You can then use the xpath with WebDriver
Edit: Code works now
public static String jsoupToXpath(Element element) {
String xpath = "/";
List<String> components = new ArrayList<>();
Element child = element.tagName().isEmpty() ? element.parent() : element;
System.out.println(child.tag());
while (child.parent() != null){
Element parent = child.parent();
Elements siblings = parent.children();
String componentToAdd = null;
if (siblings.size() == 1) {
componentToAdd = child.tagName();
} else {
int x = 1;
for(Element sibling: siblings){
if (child.tagName().equals(sibling.tagName())){
if (child == sibling){
break;
} else {
x++;
}
}
}
componentToAdd = String.format("%s[%d]", child.tagName(), x);
}
components.add(componentToAdd);
child = parent;
}
List<String> reversedComponents = new ArrayList<>();
for (int i = components.size()-1; i > 0; i--){
reversedComponents.add(components.get(i));
}
xpath = xpath + String.join("/", reversedComponents);
return xpath;
}
I have a button on a website built with sencha/extjs. Currently the button id is savebutton-1550-btnEl, but this changes everytime the page is loaded. I know that the button is disabled, but for testing purposes, I'd like to set this button as enabled, and then click it.
How would I go about finding this element each time, and then disabling it and clicking it with Java Selenium?
I'm guessing I'll have to execute some javascript, but I'm having a hard time finding the target for the javascript.
To locate the element you will have to use part of the DOM surrounding the element as a unique locator. It is impossible to give a more specific answer without seeing the DOM you are working on, but you may try something like:
WebElement saveButton = driver.findElement(By.xpath("//button[text()='Save']");
For changing the element to enabled, take a look at this answer: Selenium Webdriver - click on hidden elements
Also a longer term solution might be to work with development to see if they can build in a unique locator especially since this probably wont be the only object that you have problems with. At my company we use the "class" field to uniquely identify objects in extjs.
I override the the class "AbstractComponent":
Ext.define('Foo.overrides.AbstractComponent', {
override: 'Ext.AbstractComponent',
onBoxReady: function () {
var me = this;
var el = me.getEl();
if (el && el.dom && me.itemId) {
el.dom.setAttribute('data-test', me.itemId);
}
me.callOverridden(arguments);
}
});
If you set in configuation of the button the "itemId", you
can be accessed the button via seleniumas follows:
IWebElement element = webDriver.FindElement(By.XPath($"//*[#data-test='{itemId}']"));
Is there any examples of Javascript or jQuery been used with Selenium Webdriver Java? I'm having issues with drag and drop using selenium. I'm hoping to use the following code with Javascript/jQuery to perform a drag and drop. I cannot use point and click in my test scripts to perform drag and drop so I'm hoping to use jQuery or java script to perform the drag and drop. I'm having trouble integrating the two. I only want suggestion for drag and drop using javascript or an example of javascript (any) and selenium webdriver code in the same script
public void test(){
driver.findElement(By.id("addService")).click();
driver.findElement(By.id("name")).sendKeys(name);
driver.findElement(By.id("identifier")).sendKeys(id);
driver.findElement(By.id("flowStatus")).clear();
driver.findElement(By.id("flowStatus")).sendKeys(flow);
}
public void dragAndDropElement(WebElement dragFrom, WebElement dragTo) throws Exception {
Actions actions = new Actions(driver);
actions.clickAndHold(dragFrom).release(dragTo).build().perform();;
}
public void test() throws Exception {
WebElement dragFrom = driver.findElement(By.xpath("/html/body/div/div[2]/div[1]/form/fieldset/table[1]/tbody/tr/td[1]/div/div[1]"));
WebElement dragTo = driver.findElement(By.id("drop"));
dragAndDropElement(dragFrom,dragTo);
}
Have tried using Actions class? Here are docs. There are multiple ways you could drag and drop elements using it,
Actions actions = new Actions(driver);
actions.dragAndDrop(source,target).build().perform();
or
actions.clickAndHold(source).release(target).build().perform();
There are other ways as well, check docs and see which one is applicable for you. In general using javascript should be avoided when using WebDriver. WebDriver uses browsers native api's and simulate user interactions which are very close to a real user. Think of this, your user is not going to execute a javascript to do a drag and drop. I would suggest use it only when all other WebDriver doors are closed for you.
I am using htmlunit in jython and am having trouble selecting a pull down link. The page I am going to has a table with other ajax links, and I can click on them and move around and it seems okay but I can't seem to figure out how to click on a pulldown menu that allows for more links on the page(this pulldown affects the ajax table so its not redirecting me or anything).
Here's my code:
selectField1 = page.getElementById("pageNumSelection")
options2 = selectField1.getOptions()
theOption3 = options2[4]
This gets the option I want, I verify its right. so I select it:
MoreOnPage = selectField1.setSelectedAttribute(theOption3, True)
and I am stuck here(not sure if selecting it works or not because I don't get any message, but I'm not sure what to do next. How do I refresh the page to see the larger list? When clicking on links all you have to do is find the link and then select linkNameVariable.click() into a variable and it works. but I'm not sure how to refresh a pulldown. when I try to use the webclient to create an xml page based on the the select variable, I still get the old page.
to make it a bit easier, I used htmlunit scripter and got some code that should work but its java and I'm not sure how to port it to jython. Here it is:
try
{
page = webClient.getPage( url );
HtmlSelect selectField1 = (HtmlSelect) page.getElementById("pageNumSelection");
List<HtmlOption> options2 = selectField1.getOptions();
HtmlOption theOption3 = null;
for(HtmlOption option: options2)
{
if(option.getText().equals("100") )
{
theOption3 = option;
break;
}
}
selectField1.setSelectedAttribute(theOption3, true );
Have a look at HtmlForm getSelectedByName
HtmlSelect htmlSelect = form.getSelectByName("stuff[1].type");
HtmlOption htmlOption = htmlSelect.getOption(3);
htmlOption.setSelected(true);
Be sure that WebClient.setJavaScriptEnabled is called. The documentation seems to indicate that it is on by default, but I think this is wrong.
Alternatively, you can use WebDriver, which is a framework that supports both HtmlUnit and Selenium. I personally find the syntax easier to deal with than HtmlUnit.
If I understand correctly, the selection of an option in the select box triggers an AJAX calls which, once finished, modifies some part of the page.
The problem here is that since AJAX is, by definition, asynchronous, you can't really know when the call is finished and when you may inspect the page again to find the new content.
HtmlUnit has a class named NicelyResynchronizingAjaxController, which you can pass an instance of to the WebClient's setAjaxController method. As indicated in the javadoc, using this ajax controller will automatically make the asynchronous calls coming from a direct user interaction synchronous instead of asynchronous. Once the setSelectedAttribute method is called, you'll thus be able to see the changed made to the original page.
The other option is to use WebClient's waitForBackgrounfJavascript method after the selection is done, and inspect he page once the background JavaScript has ended, or the timeout has been reached.
This isn't really an answer to the question because I've not used HtmlUnit much before, but you might want to look at Selenium, and in particular Selenium RC. With Selenium RC you are able to control the interactions with a page displayed in a native browser (Firefox for example). It has developer API's for Java and Python amongst others.
I understand that HtmlUnit uses its own javascript and web browser rendering engine and I'm wondering whether that may be a problem.