How to handle StaleElementReferenceException - java

I am working for a mouse hover and i want to test all the links working condition by clicking each and every link using for loop.In my program the iteration is going once and for the next iteration it is not working and showing the "StaleElementReferenceException"..........
Please do modification in the code if required....
public static void main(String[] args) throws IOException
{
WebDriver driver = new FirefoxDriver();
Autoit.Authenti(driver);
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(20,TimeUnit.SECONDS);
driver.get("http://staging.zenrays.com");
Actions a1=new Actions(driver);
WebElement cl=driver.findElement(By.xpath(".//*[#id='menu-450-2']/a"));
a1.moveToElement(cl).perform();
WebDriverWait wait =new WebDriverWait(driver, 30);
List<WebElement> links=driver.findElements(By.xpath("//a[contains(#class,'sf-depth-2')]"));
for(int i=0;i<=links.size()-1;i++)
{
links.get(i).click();
driver.navigate().back();
}
}
}

Understand one fundamental thing: staleElementReferenceException, by it's name suggests that the reference to your elements on the page is stale (lost). You just have to refer to those elements again, if they are available, which is apt in this case as the page has been refreshed. Do 2 things:
once the page is refreshed (when you navigate back), use an explicit wait until an element you expect is visible
Then, newly refer to your elements(xpath locator that you have used) you wanna work with again
As a clean and elegant code use try-catch block in these scenarios
I'm not gonna give you the code directly:)Try it and come back with your code.
Refer here
for it's clear explanation of possible scenarios for this particular exception
One more thing: Your for loop gives IndexOutOfBoundsException. Modify that as well

You can use following modification in your code:-
List<WebElement> links=driver.findElements(By.xpath("//a[contains(#class,'sf-depth-2')]"));
for(int i=0;i<links.size();i++)
{
List<WebElement> allLinks=driver.findElements(By.xpath("//a[contains(#class,'sf-depth-2')]"));
allLinks.get(i).click();
driver.navigate().back();
}

Related

Going through Chrome://settings by Selenium

I am using Java and Selenium to write a test, I use the code below to get into Chrome:setting
driverChrome.manage().window().maximize();
driverChrome.get("chrome://settings");
But when the page is open I can not find any of its web Elements, for example when I try to find "show advanced setting...." by this code
driverChrome.findElement(By.xpath("//a[#id='advanced-settings-expander']")).click();
it throws an error saying that "no such element: Unable to locate element"
I tried to located other elements, but they all failed. I saw this post here but it did not help.
Find the code below:
driverChrome.manage().window().maximize();
driverChrome.get("chrome://settings");
Thread.sleep(5000);
WebElement w = driverChrome.findElement(By
.xpath("//iframe[#name='settings']"));
driverChrome = driverChrome.switchTo().frame(w);
Thread.sleep(1000);
while (true) {
try {
WebElement we = w.findElement(By
.xpath("//a[text()='Show advanced settings...']"));
if (we.isDisplayed()) {
we.click();
Thread.sleep(1000);
break;
}
} catch (Exception e) {
System.out.println(e.getMessage());
System.out.println("=========================");
}
}
I haven't tested this but I took your code snippet and cleaned it up a bit. Try this and see if it works. This should be pretty close.
Once you switch to the IFRAME context, you don't need to reference the IFRAME as you did with w.findElement().
In general, Thread.sleep() is not a good practice. You should prefer to use WebDriverWait with ExpectedConditions. Check the docs for all the different things you can wait for using ExpectedConditions. I used .elementToBeClickable() in my code below. This is perfect since you want to click an element. The .until() returns the element waited for so you can just append .click() on the end of the statement... or you can store the element in a WebElement variable and use it elsewhere.
driverChrome.manage().window().maximize();
driverChrome.get("chrome://settings");
WebElement w = driverChrome.findElement(By.xpath("//iframe[#name='settings']"));
driverChrome = driverChrome.switchTo().frame(w);
WebDriverWait wait = new WebDriverWait(driverChrome, 10);
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//a[text()='Show advanced settings...']"))).click();
// alternative example... store returned element and then click on a separate line... or use the variable elsewhere, etc.
// WebElement link = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//a[text()='Show advanced settings...']")));
// link.click();
You will need to identify Shadow roots to interact with a lot of Chromes native pages including the Settings page.
See this Thread on how to work with them properly:
How to interact with the elements within #shadow-root (open) while Clearing Browsing Data of Chrome Browser using cssSelector

Selenium click not always working

I have some tests which click on a tab, however the click is not always performed.
The xpath is correct as most of the times the test works
It is not a timing issue as I ve used thread.sleep() and other methods to ensure that the element is visible before clicking
The test believes that it is performing the click as it is not throwing an ElementNotFoundException or any other exceptions when 'performing' the click. The test fails later on after the click since the tab content would not have changed.
Further Info
I am using Selenium 2.44.0 to implement tests in Java which run on Chrome 44.0.2403.107 m.
Is there something else that I can do or could this be an issue with selenium?
There are several things you can try:
an Explicit elementToBeClickable Wait:
WebDriverWait wait = new WebDriverWait(webDriver, 10);
WebElement button = wait.until(ExpectedConditions.elementToBeClickable(By.id("myid")));
button.click()
move to element before making a click:
Actions actions = new Actions(driver);
actions.moveToElement(button).click().build().perform();
make the click via javascript:
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript("arguments[0].click();", button);
you can go with linkText if the tab name contains any unique string. And make sure your tab is not dynamic. It should be visible in source code(manual source code(ctrl+u)).
The following method work for me
WebElement button = SeleniumTools.findVisibleElement(By.cssSelector("#cssid"));
Actions actions = new Actions(driver);
actions.moveToElement(button).click().build().perform();
I have a similar problem. Tried all solutions from the top answer. Sometimes they work, sometimes don't.
But running code in an infinite loop works always.
For example, we need to click on element-two which is not visible until element-one is clicked.
WebDriverWait wait = new WebDriverWait(webDriver, 10);
while (true){
try {
WebElement elementOne =
wait.until(ExpectedConditions.elementToBeClickable(By.id("element-one")));
elementOne.click();
WebElement elementTwo =
wait.until(ExpectedConditions.elementToBeClickable(By.id("element-two")));
elementTwo.click();
break;
} catch (Exception e){
//log
}
}
I have a similar problem. Here is my solution:
table_button = driver.find_element(By.XPATH, insert your xpath)
try:
WebDriverWait(driver, 15).until(EC.element_to_be_clickable(table_button)).click()
except WebDriverException as e:
print('failed')
print(e)
Through code above, you can find the error message if your button is not clickable.
For example, my error message is 'nosuchelement' and 'clcik is not clickable', then I got back to check the table_button.accessible_name, found it print a 'null' value, so that means my XPATH is incorrect.

Selenium Wait for Page Source Contains

I was just wondering if there's an elegant way to utilize ExpectedConditions or something else to have my code wait for a page's source to contain a given string until a given timeout. I know I can use something like this if I wanted to use a specific element's locator ...
WebDriverWait wait = new WebDriverWait(driver,10);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.linkText("foobar")));
But I wanted to accomplish this without using a locator for a specific element, and just use the whole page source as my reference instead. Any suggestions?
You cant have the all elements as a condition for waiting. When switching page weddriver automaticly wait for the page to load. WHen it has finished loading the HTML elements it continues. But it doesnt wait for JavaScript to execute. A lot of webpages today uses JavaScript to populate the webpage after the HTML has loaded.
What you should do is wait for every element you want to use.
wait.until(ExpectedConditions.refreshed(ExpectedConditions.visibilityOfElementLocated(by)));
or
wait.until(ExpectedConditions.refreshed(ExpectedConditions.elementToBeClickable(element))h;
You can wait for document's readyState to become complete. Run the javascript return document.readyState").equals("complete") against the web page that is loading.
void waitForLoad(WebDriver driver) {
ExpectedCondition<Boolean> pageLoadCondition = new
ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return ((JavascriptExecutor)driver).executeScript("return document.readyState").equals("complete");
}
};
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(pageLoadCondition);
}
And then you can get the page source:
driver.getPageSource();
And then verify that the pageSource contains what you are looking for:
driver.getPageSource().contains("your element/tag");
I hope this helps!
Without depending on visibility, you could check if an element is present in the DOM:
WebDriverWait wait = new WebDriverWait(driver,10);
wait.until(ExpectedConditions.presenceOfElementLocated(By.tagName("html")));
If you want to refer to individual text, you can implement ExpectedCondition<T> and create your own condition class. The mentioned interface has access to the WebDriver (due to super-interface com.google.common.base.Function<WebDriver,T>).
In the method apply you could use the WebDriver and call method getPageSource() to have String presenting the page source. Check the String for whatever you prefer.

Same scenario - StaleElementReferenceException with Java, but Watir is fine

Scenario: Open website, obtain a reference to Webelement "About" , click About , navigate back and use the variable reference again -- Results in StaleElementReference Exception. This happens only with Selenium Java, however when using Watir, it works fine. Both the code snippets are posted below. Anyone got a damn clue what is going on ?
# Below Java code produces StaleElementReferenceException
public class StaleElementException {
public static void main(String[] args) {
ChromeDriver driver = new ChromeDriver();
driver.get("http://seleniumframework.com");
WebElement about = driver.findElementByLinkText("ABOUT");
System.out.println(about.getText());
about.click();
driver.navigate().back();
System.out.println(about.getText());
}
}
#Below Ruby Watir Code works fine
require 'watir-webdriver'
#browser = Watir::Browser.new :chrome
#browser.goto "http://seleniumframework.com"
about = #browser.link(text: 'ABOUT')
puts about.text
about.click
#browser.back
puts about.text
Watir automatically does another find element call after the refresh, which webdriver does not do, so you need to do what Saifur suggested.
I am not sure how Watir works here. But if you find an element click on it it navigates you to a different page and the DOM refreshes. You therefore going back with driver.navigate().back(); and try to use same about element to perform your action which is not valid anymore. The DOM refreshed means the reference to the element is lost and that's not a valid element anymore. What you should be doing is finding the same element again on the fly and perform your action. The complete code should look like the following:
public class StaleElementException {
public static void main(String[] args) {
ChromeDriver driver = new ChromeDriver();
driver.get("http://seleniumframework.com");
WebElement about = driver.findElementByLinkText("ABOUT");
System.out.println(about.getText());
about.click();
driver.navigate().back();
System.out.println(driver.findElementByLinkText("ABOUT").getText());
}
}
Note: The change in last line

How can I use Selenium 2 to look for two potential elements?

Super newbie here.
I am testing a page that either returns a list of tweets, or if none are available, a no results page. So I have two possible acceptable outcomes. I am trying to write an assert in Selenium 2 that tests for either element, but if neither appears, return an error.
I am using the page object model and I wrote the following:
Assert.assertTrue((iu.twitterUsername().isDisplayed()) || (iu.noData().isDisplayed()), "Page is not loading")
However, I am getting an element not found on the first part of my OR statement when the no data page is displayed. I thought the point of 'isDisplayed' was to check if the element is there. Why am I getting an element not found error? Obviously its not there, and I want to move onto the second part of my OR statement.
Is there a better way to write this when there are two possible acceptable results?
The WebElement.isDisplayed() method doesn't tell you whether or not an element is there; it tells you whether it is displayed on the page (as opposed to being hidden).
You can use the WebDriver.findElement() method to test whether or not an element has loaded; it will throw a NoSuchElementException if it hasn't. Your method might look like this:
public static boolean isElementLoaded(WebDriver driver, By findBy) {
try {
driver.findElement(findBy));
} catch (NoSuchElementException e) {
return false;
}
return true;
}
You can alter how long WebDriver waits for the element to load with something like the following, which changes it to five seconds:
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
Alternatively, you can create a method that will poll for the element until a timeout is reached.
It should be as simple as
WebDriver driver = new FirefoxDriver();
WebElement element = driver.findElement(By.id(id));
Assuming you're doing something before looking for the element I'd suggest using WebDriverWait then throw and catch exception if you don't find the element in the alloted time.
WebDriverWait wait = new WebDriverWait(driver, 10);
try {
wait.until(ExpectedConditions.elementToBeSelected(By.id(id)));
} catch (ElementNotFound e) {};
element = driver.findElement(By.id(id));

Categories