I'm running code that fetches a span by the value of its text and then goes to rightclick it using this function:
public void rightClickElement(WebElement element) {
Actions action = new Actions(driver);
actions.contextClick(element).perform();
}
Basically I iterate over a list of filenames and select the element I want to manipulate by its filename by using the following XPATH:
//span[contains(text(), 'PLACEHOLDER')]
with a function that replaces PLACEHOLDER by the current value of the array of filenames I'm iterating over.
This is my code:
*Note: getAssertedElement is just a function I wrote that asserts an element's existence and returns it at the same time.
List<WebElement> textFilesElements = driver.findElements(By.xpath("//span[(#class='document') and contains(text(), '.txt')]"));
ArrayList<String> filesToDelete = new ArrayList<String>();
waitSeconds(1);
for (int i = 0; i < textFilesElements.size(); i++) {
filesToDelete.add(textFilesElements.get(i).getText());
}
for (int i = 0; i < filesToDelete.size(); i++) {
WebElement elementToDelete = getAssertedElement("Cannot find the current element",
replacePlaceholderInString(
"//span[contains(text(), 'PLACEHOLDER')]",
filesToDelete.get(i)
),
"xpath");
System.out.println("FICHIER TO DELETE" + elementToDelete.getText());
rightClickElement(elementToDelete);
// do things with element
...
}
This works fine the first time through the second for statement, but when I move on to the next filename, even though the element is visible and clickable, the test fails with the following error when it reaches the rightClickElement call:
javascript error: Failed to execute 'elementsFromPoint' on 'Document': The provided double value is non-finite.
I don't understand why, much less how to fix it.
Related
from the table each row collect the td[3] value, below is my java source code
WebElement biboSection = driver.findElement(By.xpath("//*#id='Label1']/div/table[2]/tbody"));
List<WebElement>rowsCount = biboSection.findElements(By.tagName("tr"));
for (int k =1;k<=rowsCount.size();k++){
String biblioTable = driver.findElement(By.xpath("//*#id='Label1']/div/table[2]/tbody/tr["+k+"]/td[3]")).getText().trim();
}
problem is if any one of the row td[3] tag not available, so its becomes failed, getting the below error
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"//*[#id='Label1']/div/table[2]/tbody/tr[5]/td[3]"}
In general - single element we can use explicit wait to avoid the above exception, but in table how can i continue with rest of the rows if particular tab not available (i.e if tr[5]/td[3] not available then move to next set tr[6]/td[3])
What you need to do is, you need to return a value when you get a NoSuchElementException. The risk of this is, you can get a false positive, so you need to make sure you do something with the exception.
What you could do is, you could take the string biblioTable elsewhere, allowing you to check for the element first. Try the following (I'm typing this without IDE, so excuse any mistakes etc):
var el;
String exception;
for (int k =1;k<=rowsCount.size();k++){
try
{
el = driver.findElement(By.xpath("//*#id='Label1']/div/table[2]/tbody/tr["+k+"]/td[3]"));
return el;
}
catch (NoSuchElementException)
{
exception = "Whatever you want"
return exception;
}
if(exception == "Whatever you want")
{
Console.Writeline.....
}
else{
String biblioTable = el.getText().trim();
}
}
So what you are doing is:
First you are creating a var and a string which you are going to return in your try/catch. Then in the try/catch, you are first going to try to return the webelement el. If you get a NoSuchElementException, you are going to return the string exception with a value, which you are going to use as a condition to create the string biblioTable. If its filled, it means that the webelement el was not there. So you can do whatever else you want and end the loop. Else, you can create the string biblioTable.
First, I think you have a typo in two places: your xpath is missing the open square bracket "[" after "//*"
Secondly, I think you can accomplish what you want with one declaration:
List<WebELement> biblioTable = driver.findElements(By.xpath("//*[#id='Label1']/div/table[2]/tbody/tr/td[3]"));
Then you can access the text elements via:
for (WebElement text : biblioTable)
String name = text.getText();
What I expect to happen: The program should find the expected Web Element from the list, click on it, find the contract id and match with the given contract id. If yes, break the loop else click back button and proceed until the conditions are satisfied.
Actual issue :
On running this for each loop; the program finds the first web element in the list and it passes the first if condition. While after clicking the web Element, as the second if condition is not satisfied it gets out of the loop and checks for each loop once again but the program or the code break here and throws error like" stale element reference: element is not attached to the page document ":(
how to get over this error?
Note :-" Where as my required Web Element is 3 rd in the List for the given contract id ".
// Selenium Web Driver with Java-Code :-
WebElement membership = driver.findElement(By.xpath(".//*[#id='content_tab_memberships']/table[2]/tbody"));
List<WebElement> rownames = membership.findElements(By.xpath(".//tr[#class='status_active']/td[1]/a"));
// where rownames contains list of webElement with duplicate webElement names eg:- {SimpleMem, SimpleMem , SimpleMem ,Protata} but with unique contarct id (which is displayed after clicking webElement)
for (WebElement actual_element : rownames) {
String Memname = actual_element.getAttribute("innerHTML");
System.out.println("the membershipname"+ Memname);
if (Memname.equalsIgnoreCase(memname1)) {
actual_element.click();
String actualcontractid = cp.contarct_id.getText();
if (actualcontractid.equalsIgnoreCase(contractid)) {
break;
} else {
cp.Back_Btn.click();
Thread.sleep(1000L);
}
}
}
After clicking on row element, you are navigating away from current page DOM. On the new page, if Contract Id is not matched, you are navigating back to the previous page.
You are expecting that you should be able to access the element from the list [rows] which was present earlier when you performed foreach loop. But now that DOM is reloaded earlier elements are not accessible hence the Stale Element Reference Exception.
Can you please try below sample code?
public WebElement getRowOnMatchingMemberNameAndContractID(String memberName, String contractId, int startFromRowNo){
WebElement membership = driver.findElement(By.xpath(".//*[#id='content_tab_memberships']/table[2]/tbody"));
List<WebElement> rowNames = membership.findElements(By.xpath(".//tr[#class='status_active']/td[1]/a"));
// where rownames contains list of webElement with duplicate webElement names eg:- {SimpleMem, SimpleMem , SimpleMem ,Protata} but with unique contarct id (which is displayed after clicking webElement)
for(int i=startFromRowNo; i<=rowNames.size(); i++){
String actualMemberName = rowNames.get(i).getAttribute("innerHTML");
if(actualMemberName.equalsIgnoreCase(memberName)){
rowNames.get(i).click();
String actualContractId = cp.contarct_id.getText();
if(actualContractId.equalsIgnoreCase(contractId)){
return rowNames.get(i);
}else {
cp.Back_Btn.click();
return getRowOnMatchingMemberNameAndContractID(i+1);
}
}
}
return null;
}
I have used the recursion and additional parameter to handle the previously clicked row. You can call above method with 0 as starting row like-
WebElement row = getRowOnMatchingMemberNameAndContractID(expectedMemberName, expectedContractID,0);
I am trying to crawl trip advisor reviews. Some reviews have the more link, which displays the entire text of the review when clicked. However, when I imitate the click using Selenium, the DOM changes, which gives me the Stale Element Exception. I am trying to work around it by getting the DOM again, but the error still exists. Where am I going wrong?
List reviews = driver.findElements(By.className("review"));
for (int x = 0; x < reviews.size(); x++) {
WebElement element = driver.findElements(By.className("review")).get(x);
try {
if (element.findElements(By.className("expandLink")).size() > 0)
if (element.findElement(By.className("expandLink")).findElement(By.className("ulBlueLinks")).getText().startsWith("More")) {
element.findElement(By.className("ulBlueLinks")).click();
if (driver.findElements(By.className("ui_overlay")).size() > 0)
driver.findElement(By.className("ui_overlay")).findElement(By.className("ui_close_x")).click();
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
while (driver.findElements(By.className("ui_close_x")).size() > 0)
driver.findElement(By.className("ui_close_x")).click();
element = driver.findElements(By.className("review")).get(x);
String rating = element.findElement(By.className("ui_bubble_rating")).getAttribute("class").split(" ")[1].replaceAll("bubble_", "");
String review = element.findElement(By.className("entry")).getAttribute("innerHTML").replaceAll("<[^>]*>", "").replaceAll("[,\n]", " ");
I faced same thing, this is due to sometimes problems with DOM elements which are not reachable by selenium causing exception.
I come with this solution and it worked for me.
http://darrellgrainger.blogspot.in/2012/06/staleelementexception.html
Have you considered using the #FindBy annotation for declaring WebElements? Using this annotation, each time you make a call to a WebElement the driver searches the DOM for that WebElement.
This methodology means you only need to declare each element once and a reference to the WebElement is stored. It also allows you to make use of the Page Object Pattern, which will give you clean separation between page and test logic.
Here is a write up on it:
https://www.toptal.com/selenium/test-automation-in-selenium-using-page-object-model-and-page-factory
I'm using Selenium to test action on a html page. The one i'm working on contains multiple list of check box. My selenium script do the following actions :
-Click on the dropdown list to display the check box list
-Click on all the check box
-Click on the dropdown list to close the check box list
-Repeat for the next list
The problem is that somtimes the script goes too fast for the browser and some box are not checked, it happens really often since i make multiple test
To resolve my problem i tried to make a method that check if the
checkbox is checked, if not then i click again but it's not working and it increases the time of my test. Here my code so far :
public void clickClearanceListBox(int numberInList) throws InterruptedException {
int iteration = countTheNumberOfElement("//div[5]/div["+numberInList+"]/div[2]");
for(int i = 1; i <= iteration; i++) {
String xpathBox ="//div["+numberInList+"]/div[2]/div["+i+"]/div/div/label/span/span[2]";//xpath de la checkbox
String xpathInput = "//div["+numberInList+"]/div[2]/div["+i+"]/div/div/label/input";
clickTheDOMbyJs(xpathBox);
while(!checkBoxChecked(xpathInput)) {
Thread.sleep(200);
clickTheDOMbyJs(xpathBox);
}
}
}
Or :
public void clickClearanceListBox(int numberInList) throws InterruptedException {
int iteration = countTheNumberOfElement("//div[5]/div["+numberInList+"]/div[2]");
for(int i = 1; i <= iteration; i++) {
String xpathBox ="//div["+numberInList+"]/div[2]/div["+i+"]/div/div/label/span/span[2]";//xpath de la checkbox
String xpathInput = "//div["+numberInList+"]/div[2]/div["+i+"]/div/div/label/input";
clickTheDOMbyJs(xpathBox);
while(!checkBoxChecked(xpathInput)) {
Thread.sleep(200);
}
}
}
It looks like you need to use WebDriverWait in here. First, wait for the dropdown list to load completely, then wait for the checkbox to be visible.
A word of warning to you though. These xpaths are likely to be very brittle, and your tests will break quite easily. You should consider finding these various elements using ids, classes, or other attributes.
I manage to do it by checking if the attribute "value" of my checkbox has the value "true". While the attribute value is false, it means that the checkbox is still not checked for the browser so i wait... This extremly slow but at least it's working everytime. After the script clicked on the checkbox i do this :
while(!getAnElementAttribute(xpathInput, "value").equals("true")) {
}
I've been researching this error for a while and have tried many things and nothing seems to work...
while(!driver.findElements(By.className("next")).isEmpty()) {
//elements = driver.findElements(By.xpath("//a[#class='name']"));
elements = findDynamicElements("//a[#class='name']");
for (WebElement e : elements) {
userName = e.getText(); //<--EXCEPTION HERE
check_visitor_profile(userName);//<--WE LEAVE THE PAGE HERE
Thread.sleep(3000); //<--NO TRY/CATCH BLOCK FOR READABILITY
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
elements = findDynamicElements("//a[#class='name']");
}
driver.findElement(By.xpath("VisitsNext")).click();
}
protected List<WebElement> findDynamicElements(String path) {
List<WebElement> result;
String xPath = path;
new WebDriverWait(driver, 25).until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.xpath(xPath)));
//new WebDriverWait(driver, 25).until(elementIdentified(By.id(path)));
try {
result = driver.findElements(By.xpath(xPath));
return result;
}
catch(WebDriverException e) {
return null;
}
);
}
My code craps out on the first line of the for loop where userName is assigned. I've seen on this forum that you should use 'presenceOfElementLocated' and explicitly wait for the element to come back but that doesn't work either. I used 'presenceOfAllElementsLocatedBy' for a list but I have a method that uses 'presenceOfElementLocated' which doesn't work either.
I know stuff like the Thread.sleep and the implicitlyWait line is probably unnecessary at this point but I've literally tried everything and it doesn't work...
The error occurs because when I call 'check_visitor_profile' it leaves the page - when it comes back the elements are out of place so I have to find them again. Which I do but it still throws the exception.
Any Ideas?
Thanks.
The problem might occur because you are changing elements in the middle of the loop. It will cause you trouble even without the StaleElementReferenceException. Use a for loop instead of the for each loop
elements = findDynamicElements("//a[#class='name']");
int size = elements.size();
for (int i = 0 ; i < size ; ++i) {
elements = findDynamicElements("//a[#class='name']");
userName = elements.get(i).getText();
check_visitor_profile(userName);
}
Handle the exception explicitly as the element is no longer attached to the DOM or has changed at that moment you call "check_visitor_profile"
See the link below might help
catch(StateElementException e){
System.out.println("StaleElement dealt with since you successfully left page ");
}
http://docs.seleniumhq.org/exceptions/stale_element_reference.jsp