Element Not Interactable / Element not clickable - java

I tried using explicit wait, ExpectedConditions.elementToBeClickable and waitForVisibleElement but it ends up with time out and waiting for element to be clickable.
I also tried getting different locators (different div). Here is my code (and the ones I tried)
public void setSystemInformationSection() throws Exception {
scrollPageDownBy800();
//wait.until(ExpectedConditions.elementToBeClickable(INVERTERMANUFACTURERDRPDWN));
//click(INVERTERMANUFACTURERDRPDWN, "INVERTERMANUFACTURERDRPDWN;");
//click(INVERTERMANUFACTURERDRPDWN, "INVERTERMANUFACTURERDRPDWN;");
//waitForVisibleElement(driver, SMACORE1OPTION); click(SMACORE1OPTION,"SMACORE1OPTION");
Boolean wait = new WebDriverWait(driver,20).until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("//*[#id=\"SMA - Core1\"]")));
jse.executeScript("arguments[0].click()", INVERTERMANUFACTURERDRPDWN);
//waitForVisibleElement(driver, SMACORE1OPTION);
jse.executeScript("arguments[0].click()", SMACORE1OPTION);
}
Other dropdowns I tried worked fine with the last snippet of code (the ones not commented out)
I tried this with a different dropdown and it worked okay
public void setCommercialDealType() throws Exception {
Boolean wait = new WebDriverWait(driver, 20).until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("/html/body/app-root/ng-component/commercial-create-account/main/section[2]/opportunity-information/form/div[2]/div[1]/sp-dropdown/div/div/div[2]/ul/li[2]")));
jse.executeScript("arguments[0].click()", COMMERCIALDEALTYPEDROPDOWN);
waitForVisibleElement(driver, COMMERCIALHELIXPPA);
jse.executeScript("arguments[0].click()", COMMERCIALHELIXPPA);
}
When I try to check with isEnabled or isDisplayed, it gives TimeOut error. I'm stuck.

Sometimes an element is visible or clickable to you, but divs or spans (or other elements) are hiding it from Selenium perspective.
To overcome this:
First you find an element by ID, xpath or Css expression.
Try to move to the element (focus on it) using Selenium and then click it.
If step 2 failed - just do element.click
if step 3 failed - do a hard click using javaScript:
Code example:
public void clickLastFoundElement() {
try {
Actions builder = new Actions(browser);
builder.moveToElement(lastFoundElement).click().build().perform();
} catch (ElementNotInteractableException x1) {
try {
lastFoundElement.click();
}
catch (Exception x2) {
hardClickElement();
}
}
}
private void hardClickElement() {
JavascriptExecutor executor = (JavascriptExecutor) browser;
executor.executeScript("arguments[0].click();", lastFoundElement);
}

Related

Trying to resolve StaleElementReferenceException error [duplicate]

I am implementing a lot of Selenium tests using Java - sometimes, my tests fail due to a StaleElementReferenceException.
Could you suggest some approaches to making the tests more stable?
This can happen if a DOM operation happening on the page is temporarily causing the element to be inaccessible. To allow for those cases, you can try to access the element several times in a loop before finally throwing an exception.
Try this excellent solution from darrelgrainger.blogspot.com:
public boolean retryingFindClick(By by) {
boolean result = false;
int attempts = 0;
while(attempts < 2) {
try {
driver.findElement(by).click();
result = true;
break;
} catch(StaleElementException e) {
}
attempts++;
}
return result;
}
I was having this issue intermittently. Unbeknownst to me, BackboneJS was running on the page and replacing the element I was trying to click. My code looked like this.
driver.findElement(By.id("checkoutLink")).click();
Which is of course functionally the same as this.
WebElement checkoutLink = driver.findElement(By.id("checkoutLink"));
checkoutLink.click();
What would occasionally happen was the javascript would replace the checkoutLink element in between finding and clicking it, ie.
WebElement checkoutLink = driver.findElement(By.id("checkoutLink"));
// javascript replaces checkoutLink
checkoutLink.click();
Which rightfully led to a StaleElementReferenceException when trying to click the link. I couldn't find any reliable way to tell WebDriver to wait until the javascript had finished running, so here's how I eventually solved it.
new WebDriverWait(driver, timeout)
.ignoring(StaleElementReferenceException.class)
.until(new Predicate<WebDriver>() {
#Override
public boolean apply(#Nullable WebDriver driver) {
driver.findElement(By.id("checkoutLink")).click();
return true;
}
});
This code will continually try to click the link, ignoring StaleElementReferenceExceptions until either the click succeeds or the timeout is reached. I like this solution because it saves you having to write any retry logic, and uses only the built-in constructs of WebDriver.
Kenny's solution is good, however it can be written in a more elegant way
new WebDriverWait(driver, timeout)
.ignoring(StaleElementReferenceException.class)
.until((WebDriver d) -> {
d.findElement(By.id("checkoutLink")).click();
return true;
});
Or also:
new WebDriverWait(driver, timeout).ignoring(StaleElementReferenceException.class).until(ExpectedConditions.elementToBeClickable(By.id("checkoutLink")));
driver.findElement(By.id("checkoutLink")).click();
But anyway, best solution is to rely on Selenide library, it handles this kind of things and more. (instead of element references it handles proxies so you never have to deal with stale elements, which can be quite difficult). Selenide
Generally this is due to the DOM being updated and you trying to access an updated/new element -- but the DOM's refreshed so it's an invalid reference you have..
Get around this by first using an explicit wait on the element to ensure the update is complete, then grab a fresh reference to the element again.
Here's some psuedo code to illustrate (Adapted from some C# code I use for EXACTLY this issue):
WebDriverWait wait = new WebDriverWait(browser, TimeSpan.FromSeconds(10));
IWebElement aRow = browser.FindElement(By.XPath(SOME XPATH HERE);
IWebElement editLink = aRow.FindElement(By.LinkText("Edit"));
//this Click causes an AJAX call
editLink.Click();
//must first wait for the call to complete
wait.Until(ExpectedConditions.ElementExists(By.XPath(SOME XPATH HERE));
//you've lost the reference to the row; you must grab it again.
aRow = browser.FindElement(By.XPath(SOME XPATH HERE);
//now proceed with asserts or other actions.
Hope this helps!
The reason why the StaleElementReferenceException occurs has been laid out already: updates to the DOM between finding and doing something with the element.
For the click-Problem I've recently used a solution like this:
public void clickOn(By locator, WebDriver driver, int timeout)
{
final WebDriverWait wait = new WebDriverWait(driver, timeout);
wait.until(ExpectedConditions.refreshed(
ExpectedConditions.elementToBeClickable(locator)));
driver.findElement(locator).click();
}
The crucial part is the "chaining" of Selenium's own ExpectedConditions via the ExpectedConditions.refreshed(). This actually waits and checks if the element in question has been refreshed during the specified timeout and additionally waits for the element to become clickable.
Have a look at the documentation for the refreshed method.
In my project I introduced a notion of StableWebElement. It is a wrapper for WebElement which is able to detect if element is Stale and find a new reference to the original element. I have added a helper methods to locating elements which return StableWebElement instead of WebElement and the problem with StaleElementReference disappeared.
public static IStableWebElement FindStableElement(this ISearchContext context, By by)
{
var element = context.FindElement(by);
return new StableWebElement(context, element, by, SearchApproachType.First);
}
The code in C# is available on my project's page but it could be easily ported to java https://github.com/cezarypiatek/Tellurium/blob/master/Src/MvcPages/SeleniumUtils/StableWebElement.cs
A solution in C# would be:
Helper class:
internal class DriverHelper
{
private IWebDriver Driver { get; set; }
private WebDriverWait Wait { get; set; }
public DriverHelper(string driverUrl, int timeoutInSeconds)
{
Driver = new ChromeDriver();
Driver.Url = driverUrl;
Wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeoutInSeconds));
}
internal bool ClickElement(string cssSelector)
{
//Find the element
IWebElement element = Wait.Until(d=>ExpectedConditions.ElementIsVisible(By.CssSelector(cssSelector)))(Driver);
return Wait.Until(c => ClickElement(element, cssSelector));
}
private bool ClickElement(IWebElement element, string cssSelector)
{
try
{
//Check if element is still included in the dom
//If the element has changed a the OpenQA.Selenium.StaleElementReferenceException is thrown.
bool isDisplayed = element.Displayed;
element.Click();
return true;
}
catch (StaleElementReferenceException)
{
//wait until the element is visible again
element = Wait.Until(d => ExpectedConditions.ElementIsVisible(By.CssSelector(cssSelector)))(Driver);
return ClickElement(element, cssSelector);
}
catch (Exception)
{
return false;
}
}
}
Invocation:
DriverHelper driverHelper = new DriverHelper("http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp", 10);
driverHelper.ClickElement("input[value='csharp']:first-child");
Similarly can be used for Java.
Kenny's solution is deprecated use this, i'm using actions class to double click but you can do anything.
new FluentWait<>(driver).withTimeout(30, TimeUnit.SECONDS).pollingEvery(5, TimeUnit.SECONDS)
.ignoring(StaleElementReferenceException.class)
.until(new Function() {
#Override
public Object apply(Object arg0) {
WebElement e = driver.findelement(By.xpath(locatorKey));
Actions action = new Actions(driver);
action.moveToElement(e).doubleClick().perform();
return true;
}
});
I've found solution here. In my case element becomes inaccessible in case of leaving current window, tab or page and coming back again.
.ignoring(StaleElement...), .refreshed(...) and elementToBeClicable(...) did not help and I was getting exception on act.doubleClick(element).build().perform(); string.
Using function in my main test class:
openForm(someXpath);
My BaseTest function:
int defaultTime = 15;
boolean openForm(String myXpath) throws Exception {
int count = 0;
boolean clicked = false;
while (count < 4 || !clicked) {
try {
WebElement element = getWebElClickable(myXpath,defaultTime);
act.doubleClick(element).build().perform();
clicked = true;
print("Element have been clicked!");
break;
} catch (StaleElementReferenceException sere) {
sere.toString();
print("Trying to recover from: "+sere.getMessage());
count=count+1;
}
}
My BaseClass function:
protected WebElement getWebElClickable(String xpath, int waitSeconds) {
wait = new WebDriverWait(driver, waitSeconds);
return wait.ignoring(StaleElementReferenceException.class).until(
ExpectedConditions.refreshed(ExpectedConditions.elementToBeClickable(By.xpath(xpath))));
}
Clean findByAndroidId method that gracefully handles StaleElementReference.
This is heavily based off of jspcal's answer but I had to modify that answer to get it working cleanly with our setup and so I wanted to add it here in case it's helpful to others. If this answer helped you, please go upvote jspcal's answer.
// This loops gracefully handles StateElementReference errors and retries up to 10 times. These can occur when an element, like a modal or notification, is no longer available.
export async function findByAndroidId( id, { assert = wd.asserters.isDisplayed, timeout = 10000, interval = 100 } = {} ) {
MAX_ATTEMPTS = 10;
let attempt = 0;
while( attempt < MAX_ATTEMPTS ) {
try {
return await this.waitForElementById( `android:id/${ id }`, assert, timeout, interval );
}
catch ( error ) {
if ( error.message.includes( "StaleElementReference" ) )
attempt++;
else
throw error; // Re-throws the error so the test fails as normal if the assertion fails.
}
}
}
StaleElementReferenceException
StaleElementReferenceException indicates that the reference to an element is now stale i.e. the element no longer appears within the HTML DOM of the page.
Details
Every DOM Tree element is identified by the WebDriver by a unique identifying reference, known as a WebElement. The web element reference is a UUID used to execute commands targeting specific elements, such as getting an element's tag name or retrieving a property off an element.
When an element is no longer attached to the DOM, i.e. it has been removed from the document or the document has changed, it is said to be got stale. Staleness occurs for example when you have a web element reference and the document it was retrieved from navigates and due to navigation, all web element references to the previous document will be discarded along with the document. This will cause any subsequent interaction with the web element to fail with the stale element reference error.
Solution
The best approach to avoid StaleElementReferenceException is to induce WebDriverWait for the elementToBeClickable() before invoking click as follows:
new WebDriverWait(driver, Duration.ofSeconds(10)).until(ExpectedConditions.elementToBeClickable(By.cssSelector("elementCssSelector"))).click();
Note: You have to import the following:
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.By;
Create a wrapper function (Java)
As an alternative to the accepted answer, my approach is similar in that it catches the exception and makes a few attempts, but it's more generic, so you can throw any kinds of actions at it as long as they are wrapped in a void function.
Please feel free to copy and use this code:
public void doPreventingStaleElement(Runnable function)
{
int maxRetries = 3; // maximum number of retries
int retries = 0;
boolean stale;
// try/catch block attempts to fix a stale element
do {
try {
function.run();
stale = false;
}
catch (StaleElementReferenceException eStale) {
stale = true;
// Work-around for stale element reference when getting the first page
if (retries < maxRetries) {
retries++;
System.out.println(function.getClass().getSimpleName() + " failed due to stale element reference, retry=" + retries);
try {
// Exponential increase of wait time - 1, 4, 9, 16, 25 seconds
Thread.sleep(1000 * (int) Math.pow(retries,2));
} catch (final InterruptedException e) {
Thread.currentThread().interrupt();
}
}
else {
System.out.println(function.getClass().getSimpleName() + " failed due to stale element reference, too many retries");
eStale.printStackTrace();
throw(eStale);
}
}
} while (stale && retries < maxRetries);
return;
}
Note that it will still throw a StaleElementReferenceException after maxRetries attempts.
Example of usage
As an example I want to do this:
final List<WebElement> buttons = getDriver().findElements(By.xpath("//button[#testid='dismiss-me']"));
for (final WebElement closeButton : buttons) {
closeButton.click();
}
or this:
driver.findElement(By.id("login-form-username")).sendKeys(getUser());
driver.findElement(By.id("login-form-password")).sendKeys(getPassword());
driver.findElement(By.id("login-form-submit")).click();
Then I wrap them in void functions
private void clickButtons() {
final List<WebElement> buttons = getDriver().findElements(By.xpath("//button[#testid='dismiss-me']"));
for (final WebElement closeButton : buttons) {
closeButton.click();
}
}
private void performLogin() {
driver.findElement(By.id("login-form-username")).sendKeys(getUser());
driver.findElement(By.id("login-form-password")).sendKeys(getPassword());
driver.findElement(By.id("login-form-submit")).click();
}
and so I can just
doPreventingStaleElement(whateverObject::clickButtons);
doPreventingStaleElement(whateverObject::performLogin);
Try this
while (true) { // loops forever until break
try { // checks code for exceptions
WebElement ele=
(WebElement)wait.until(ExpectedConditions.elementToBeClickable((By.xpath(Xpath))));
break; // if no exceptions breaks out of loop
}
catch (org.openqa.selenium.StaleElementReferenceException e1) {
Thread.sleep(3000); // you can set your value here maybe 2 secs
continue; // continues to loop if exception is found
}
}
There could be a potential problem that leads to the StaleElementReferenceException that no one mentioned so far (in regard to actions).
I explain it in Javascript, but it's the same in Java.
This won't work:
let actions = driver.actions({ bridge: true })
let a = await driver.findElement(By.css('#a'))
await actions.click(a).perform() // this leads to a DOM change, #b will be removed and added again to the DOM.
let b = await driver.findElement(By.css('#b'))
await actions.click(b).perform()
But instantiating the actions again will solve it:
let actions = driver.actions({ bridge: true })
let a = await driver.findElement(By.css('#a'))
await actions.click(a).perform() // this leads to a DOM change, #b will be removed and added again to the DOM.
actions = driver.actions({ bridge: true }) // new
let b = await driver.findElement(By.css('#b'))
await actions.click(b).perform()
Usually StaleElementReferenceException when element we try to access has appeared but other elements may affect the position of element we are intrested in hence when we try to click or getText or try to do some action on WebElement we get exception which usually says element not attached with DOM.
Solution I tried is as follows:
protected void clickOnElement(By by) {
try {
waitForElementToBeClickableBy(by).click();
} catch (StaleElementReferenceException e) {
for (int attempts = 1; attempts < 100; attempts++) {
try {
waitFor(500);
logger.info("Stale element found retrying:" + attempts);
waitForElementToBeClickableBy(by).click();
break;
} catch (StaleElementReferenceException e1) {
logger.info("Stale element found retrying:" + attempts);
}
}
}
protected WebElement waitForElementToBeClickableBy(By by) {
WebDriverWait wait = new WebDriverWait(getDriver(), 10);
return wait.until(ExpectedConditions.elementToBeClickable(by));
}
In above code I first try to wait and then click on element if exception occurs then I catch it and try to loop it as there is a possibility that still all elements may not be loaded and again exception can occur.
This works for me using C#
public Boolean RetryingFindClick(IWebElement webElement)
{
Boolean result = false;
int attempts = 0;
while (attempts < 2)
{
try
{
webElement.Click();
result = true;
break;
}
catch (StaleElementReferenceException e)
{
Logging.Text(e.Message);
}
attempts++;
}
return result;
}
The problem is by the time you pass the element from Javascript to Java back to Javascript it can have left the DOM.
Try doing the whole thing in Javascript:
driver.executeScript("document.querySelector('#my_id')?.click()")
Maybe it was added more recently, but other answers fail to mention Selenium's implicit wait feature, which does all the above for you, and is built into Selenium.
driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS);
This will retry findElement() calls until the element has been found, or for 10 seconds.
Source - http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp

Can Selenium click only the visible element, if the xpath returns 2 WebElements

I have a responsive design, so many items I need to interact with have 2 WebElements. One for Desktop and one for Mobile, and I am trying to use PageFactory. Here's what I have now to identify and interact with the element.
//this returns 2 webelements, one for desktop and one for mobile
#FindBy(xpath = "//selector-dropdown/p")
private WebElement dropdown;
public void ClickDropdown() throws InterruptedException {
WebDriverWait wait = new WebDriverWait(driver, 15);
wait.until(ExpectedConditions.visibilityOf(dropdown)).click();
}
I was under the impression that ExpectedConditions.visibilityOf(WebElement) would find the first element visible. Right now when I open the app on Desktop, it finds the element (Desktop is first in the DOM). But on Mobile, it times out waiting for visibility, because it is stuck waiting for the first one to become visible.
My alternative is using #FindBy to declare every element twice, and making an if statement to decide which path to take. Is this extra work the only way to make it work?
Your assumption "... ExpectedConditions.visibilityOf(WebElement) would find the first element visible." is wrong! You will need to declare your WebElement as a List, find all of them, and pick the one that is visible. Here is a sample that I used successfully in the past:
#FindBy(xpath = "//input[#ng-model='loginData.username']")
private List<WebElement> txtUsername;
public String getUsername() {
driverWait.until(CustomExpectedConditions.presenceOfAllElements(txtUsername));
for (WebElement oneUsername : txtUsername) {
if (oneUsername.isDisplayed())
return oneUsername.getAttribute("value");
}
return null;
}
public void setUsername(String username) {
driverWait.until(CustomExpectedConditions.presenceOfAllElements(txtUsername));
for (WebElement oneUsername : txtUsername) {
if (oneUsername.isDisplayed()) {
oneUsername.clear();
oneUsername.sendKeys(username);
break;
}
}
}
Based on discussion elsewhere, here is the CustomExpectedConditions:
public class CustomExpectedConditions {
/**
* Based on {#link ExpectedConditions#presenceOfAllElementsLocatedBy(org.openqa.selenium.By)}.
*
* #param elements
* #return
*/
public static ExpectedCondition<List<WebElement>> presenceOfAllElements(
final List<WebElement> elements) {
return new ExpectedCondition<List<WebElement>>() {
#Override
public List<WebElement> apply(WebDriver driver) {
// List<WebElement> elements = findElements(locator, driver);
return elements.size() > 0 ? elements : null;
}
};
}
}
Combining #Andersons and #SiKing answers into a solution that can be used everywhere, you could make a method available to all of your PageObjects in a base class, which you might already have:
protected WebElement getVisibleElement(List<WebElement> elements)
{
//Need a guard clause here to ensure there are exactly two elements,
//Or make the wait check for all elements more safely. Either way,
//consider changing the method name to be clear about expectations
WebDriverWait wait = new WebDriverWait(driver, 15);
wait.until(
ExpectedConditions.or(
//This should be done more safely, unless already guarded to expect 2 elements
ExpectedConditions.visibilityOf(elements.get(0))),
ExpectedConditions.visibilityOf(elements.get(1)))
)
);
for (WebElement element : elements) {
if (element.isDisplayed())
{
return element;
}
}
//Throw element not visible exception or something
}
Then in your PageObject:
#FindBy(xpath = "//selector-dropdown/p")
private List<WebElement> dropdown;
public void ClickDropdown() throws InterruptedException {
getVisibleElement(dropdown)).click();
}
As I know in Java you can combine multiple conditions with ExpectedConditions.and() as below:
WebDriverWait wait = new WebDriverWait(driver, 15);
wait.until(
ExpectedConditions.and(
ExpectedConditions.visibilityOf(driver.findElement(By.xpath("(//selector-dropdown/p)[1]"))),
ExpectedConditions.visibilityOf(driver.findElement(By.xpath("(//selector-dropdown/p)[2]" )))
)
);
or just try
ExpectedConditions.visibilityOfAllElementsLocatedBy(By.xpath("//selector-dropdown/p"));
to wait until all elements matched by specified selector became visible
Also try to look for atribute in DOM, which makes the element visible. That's the fastes and should be prefered aproach.
For example your element in DOM might be or sit under element with 'display: none;' or 'position: fixed'
Then your x-path might for example look like:
//div[not(contains(#style,'display: none;')) ...
or
//div[contains(#style,'position: fixed') ...
Or there might be something else.
DOM by it self always tells you which element is visible and which is not.
This is the method I came up with, maybe someone can use the full solution. This will A. wait for the first element in a list to be visible, then B. assign the visible one as a single element. The wait is short because it shouldn't take more than a second to figure out which element is visible.
protected WebElement getVisibleElement(List<WebElement> elements) {
WebDriverWait wait = new WebDriverWait(driver, 1);
WebElement rE = null;
int elementsSize = elements.size();
for (int i = 0; i < elementsSize; i++) {
System.out.println("test" + i);
try {
wait.until(ExpectedConditions.or(ExpectedConditions.visibilityOf(elements.get(i))));
break;
} catch (Exception e) {
//handle exception however you like
}
}
for (WebElement element : elements) {
if (element.isDisplayed()) {
System.out.println("found and assigning to rE");
rE = element;
break;
}
}
return rE;
}

WebDriver synchronisation issue when waiting for an element

Using WebDriver, Junit 4.11, Maven, IntelliJ v.13
Im trying to find the correct method in writing this test which is to verify that once I have clicked an element, it takes me to the next page.
After researching the WaitTool, Im attempting to nullify the implicitlyWait() then execute the WebDriverWait() and then reset implicitlyWait() although I'm receiving initialisation errors.
Ultimately, my main goal is to stop the synchronisation issues Im experiencing by using the new WaitTool.
The problem Im having is that when I click a button, I occasionally receive an error in waiting for an element new WebDriverWait(chrome, 30).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div.listContainer")));to appear on the next page.
This is what my code has been when executing the test:
#Test
public void selectBlankProject(){
new WebDriverWait(chrome, 30).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[#id=\"templateGrid\"]/li[2]/img[1]")));
WebElement item1 = chrome.findElement(By.xpath("//*[#id=\"templateGrid\"]/li[2]/img[1]"));
WebElement item2 = chrome.findElement(By.xpath("//*[#id=\"templateGrid\"]/li[2]/img[2]"));
WebElement item3 = chrome.findElement(By.xpath("//*[#id=\"templateGrid\"]/li[2]/header/span"));
WebElement item4 = chrome.findElement(By.xpath("//*[#id=\"templateGrid\"]/li[2]"));
Actions click = new Actions(chrome);
click.moveToElement(item1).moveToElement(item2).moveToElement(item3).moveToElement(item4).click().build().perform();
System.out.println("Blank Project has been selected");
}
#Test
public void dragVideoCompoenentOnToTheCanvas(){
chrome.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
new WebDriverWait(chrome, 30).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div.listContainer")));
Actions dragAndDrop = new Actions(chrome);
//Dragging the video component onto the canvas
WebElement listContainerVideo = chrome.findElement(By.cssSelector("div.listContainer"));
WebElement componentListVideo = chrome.findElement(By.cssSelector("ul.componentList.j-componentList"));
WebElement videoComponent = chrome.findElement(By.cssSelector("li.componentItem.ui-draggable[data-id=\"c5\"]"));
WebElement componentThumbVideo = chrome.findElement(By.cssSelector("div.componentThumb"));
WebElement componentNameVideo = chrome.findElement(By.cssSelector("div.componentName.f-feature-A"));
//finds the canvas to drop the video component onto
WebElement canvas = chrome.findElement(By.cssSelector("div#page-c3"));
dragAndDrop.clickAndHold(videoComponent)
.moveToElement(listContainerVideo)
.moveToElement(componentListVideo)
.moveToElement(componentThumbVideo)
.moveToElement(componentNameVideo)
.release(canvas).perform();
WebElement draggableVideoComponent = chrome.findElement(By.cssSelector("div.t-component-A.videoComponent.component.draggableComponent.ui-draggable.layerSelected"));
Assert.assertEquals("video", draggableVideoComponent.getAttribute("data-type"));
}
I added chrome.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS); in the second test, then realised that this was also setting WebDriverWait(). So I came across WaitTool and I'm attempting to use this to see if it will solve my sync issue.
Reference here: WaitTool
However, this is causing me further problems. When I attempt to use the following code, I receive initialisation errors:
#Test
public int dragClickAreaComponentToStage(int element){
try{
chrome.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
new WebDriverWait(chrome, 30).until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("li.componentItem.ui-draggable[data-id=\"c3\"]")));
chrome.manage().timeouts().implicitlyWait(DEFAULT_WAIT_FOR_PAGE, TimeUnit.SECONDS);
return element;
}catch (StaleElementReferenceException e){
e.printStackTrace();
}
WebElement clickArea = chrome.findElement(By.cssSelector("li.componentItem.ui-draggable[data-id=\"c3\"]"));
WebElement arrowHead = chrome.findElement(By.cssSelector("div.componentThumb"));
WebElement imageHolderClickArea = chrome.findElement(By.cssSelector("div.imageHolder"));
WebElement componentNameClickArea = chrome.findElement(By.cssSelector("div.componentName.f-feature-A"));
WebElement canvas = chrome.findElement(By.cssSelector("div.j-page.t-page-A[id=\"page-c3\"]"));
Actions click = new Actions(chrome);
click.clickAndHold(clickArea).moveToElement(arrowHead).moveToElement(imageHolderClickArea).moveToElement(componentNameClickArea).moveToElement(canvas).release();
click.perform();
//checking that the draggable click area component has a data-type value as clickArea
WebElement clickAreaComp = chrome.findElement(By.cssSelector("div.t-componentImg-A.component.clickAreaComponent.draggableComponent.ui-draggable"));
Assert.assertEquals("clickArea", clickAreaComp.getAttribute("data-type"));
return element;
}
So in the stacktrace I'm getting
java.lang.Exception: Method cDragClickAreaComponentToStage() should be void
and
java.lang.Exception: Method cDragClickAreaComponentToStage should have no parameters
Okay, queue "So, what is your question?".
Firstly, I'd like to know where I'm going wring with setting my #Test public int. Usually I would have it declared as void, but in this case I want to return something which has to be an int, right?
Secondly, I'd like to know where am I going wrong with the synchronisation issue when it attempts to wait for an element.
About your exceptions, if you are using JUnit #Test annotation, the test method must be public void with no parameters. Reference. If you want to use parameters, I find this resource pretty helpful.
about setting the implicit wait
chrome.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
I really see no value in doing this. At least I never set it and never see any of the exceptions you are getting.
About staleness of elements - this is happening occasionaly when something like data binding or whatever occurs. You can choose to ignore it. The wait method that i am using is:
/**
* If no timeout is given, default to 60 sec.
*
* #param element - WebElement to wait for
*/
public void waitUntil(WebElement element) {
waitUntil(element, 60);
}
/**
* Waits for given WebElement to be present and visible (height and length > 1px) in DOM.
*
* #param element
* #param timeOutInSeconds
*/
public void waitUntil(WebElement element, long timeOutInSeconds) {
new WebDriverWait(driver, timeOutInSeconds)
.ignoring(NoSuchElementException.class)
.ignoring(StaleElementReferenceException.class)
.until(ExpectedConditions.visibilityOf(element));
}

How to resolve, Stale element exception? if element is no longer attached to the DOM?

I have a question regarding "Element is no longer attached to the DOM".
I tried different solutions but they are working intermittent. Please suggest a solution that could be permanent.
WebElement getStaleElemById(String id, WebDriver driver) {
try {
return driver.findElement(By.id(id));
} catch (StaleElementReferenceException e) {
System.out.println("Attempting to recover from StaleElementReferenceException ...");
return getStaleElemById(id, driver);
}
}
WebElement getStaleElemByCss(String css, WebDriver driver) {
try {
return driver.findElement(By.cssSelector(css));
} catch (StaleElementReferenceException e) {
System.out.println("Attempting to recover from StaleElementReferenceException ...");
return getStaleElemByCss(css, driver);
} catch (NoSuchElementException ele) {
System.out.println("Attempting to recover from NoSuchElementException ...");
return getStaleElemByCss(css, driver);
}
}
Thanks,
Anu
The problem
The problem you are probably facing is that the method returns the right (and valid!) element, but when you're trying to access it a second later, it is stale and throws.
This usually arises when:
You click something that loads a new page asynchronously or at least changes it.
You immediatelly (before the page load could finish) search for an element ... and you find it!
The page finally unloads and the new one loads up.
You try to access your previously found element, but now it's stale, even though the new page contains it, too.
The solutions
There are four ways to solve it I know about:
Use proper waits
Use proper waits after every anticipated page-load when facing asynchronous pages. Insert an explicit wait after the initial click and wait for the new page / new content to load. Only after that you can try to search for the element you want. This should be the first thing you'll do. It will increase the robustness of your tests greatly.
The way you did it
I have been using a variant of your method for two years now (together with the technique above in solution 1) and it absolutely works most of the time and fails only on strange WebDriver bugs. Try to access the found element right after it is found (before returning from the method) via a .isDisplayed() method or something. If it throws, you already know how to search again. If it passes, you have one more (false) assurance.
Use a WebElement that re-finds itself when stale
Write a WebElement decorator that remembers how it was found and re-find it when it's accessed and throws. This obviously forces you to use custom findElement() methods that would return instances of your decorator (or, better yet, a decorated WebDriver that would return your instances from usual findElement() and findElemens() methods). Do it like this:
public class NeverStaleWebElement implements WebElement {
private WebElement element;
private final WebDriver driver;
private final By foundBy;
public NeverStaleWebElement(WebElement element, WebDriver driver, By foundBy) {
this.element = element;
this.driver = driver;
this.foundBy = foundBy;
}
#Override
public void click() {
try {
element.click();
} catch (StaleElementReferenceException e) {
// log exception
// assumes implicit wait, use custom findElement() methods for custom behaviour
element = driver.findElement(foundBy);
// recursion, consider a conditioned loop instead
click();
}
}
// ... similar for other methods, too
}
Note that while I think that the foundBy info should be accessible from the generic WebElements to make this easier, Selenium developers consider it a mistake to try something like this and have chosen not to make this information public. It's arguably a bad practice to re-find on stale elements, because you're re-finding elements implicitly without any mechanism for checking whether it's justified. The re-finding mechanism could potentially find a completely different element and not the same one again. Also, it fails horribly with findElements() when there are many found elements (you either need to disallow re-finding on elements found by findElements(), or remember the how-manyeth your element was from the returned List).
I think it would be useful sometimes, but it's true that nobody would ever use options 1 and 2 which are obviously much better solutions for the robustness of your tests. Use them and only after you're sure you need this, go for it.
Use a task queue (that can rerun past tasks)
Implement your whole workflow in a new way!
Make a central queue of jobs to run. Make this queue remember past jobs.
Implement every needed task ("find an element and click it", "find an element and send keys to it" etc.) via the Command pattern way. When called, add the task to the central queue which will then (either synchronously or asynchronously, doesn't matter) run it.
Annotate every task with #LoadsNewPage, #Reversible etc. as needed.
Most of your tasks will handle their exceptions by themselves, they should be stand-alone.
When the queue would encounter a stale element exception, it would take the last task from the task history and re-run it to try again.
This would obviously take a lot of effort and if not thought through very well, could backfire soon. I used a (lot more complex and powerful) variant of this for resuming failed tests after I manually fixed the page they were on. Under some conditions (for example, on a StaleElementException), a fail would not end the test right away, but would wait (before finally time-outing after 15 seconds), popping up an informative window and giving the user an option to manually refresh the page / click the right button / fix the form / whatever. It would then re-run the failed task or even give a possibility to go some steps back in history (e.g. to the last #LoadsNewPage job).
Final nitpicks
All that said, your original solution could use some polishing. You could combine the two methods into one, more general (or at least make them delegate to this one to reduce code repetition):
WebElement getStaleElem(By by, WebDriver driver) {
try {
return driver.findElement(by);
} catch (StaleElementReferenceException e) {
System.out.println("Attempting to recover from StaleElementReferenceException ...");
return getStaleElem(by, driver);
} catch (NoSuchElementException ele) {
System.out.println("Attempting to recover from NoSuchElementException ...");
return getStaleElem(by, driver);
}
}
With Java 7, even a single multicatch block would be sufficient:
WebElement getStaleElem(By by, WebDriver driver) {
try {
return driver.findElement(by);
} catch (StaleElementReferenceException | NoSuchElementException e) {
System.out.println("Attempting to recover from " + e.getClass().getSimpleName() + "...");
return getStaleElem(by, driver);
}
}
This way, you can greatly reduce the amount of code you need to maintain.
I solve this by 1. keeping the stale element and poll it until it throws an exception, and then 2. wait until the element is visible again.
boolean isStillOnOldPage = true;
while (isStillOnOldPage) {
try {
theElement.getAttribute("whatever");
} catch (StaleElementReferenceException e) {
isStillOnOldPage = false;
}
}
WebDriverWait wait = new WebDriverWait(driver, 15);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("theElementId")));
If you are trying to Click on link, that taking you to new page. After that navigating back and clicking on other links. They below code may help you.
public int getNumberOfElementsFound(By by) {
return driver.findElements(by).size();
}
public WebElement getElementWithIndex(By by, int pos) {
return driver.findElements(by).get(pos);
}
/**click on each link */
public void getLinks()throws Exception{
try {
List<WebElement> componentList = driver.findElements(By.tagName("a"));
System.out.println(componentList.size());
for (WebElement component : componentList)
{
//click1();
System.out.println(component.getAttribute("href"));
}
int numberOfElementsFound = getNumberOfElementsFound(By.tagName("a"));
for (int pos = 0; pos < numberOfElementsFound; pos++) {
if (getElementWithIndex(By.tagName("a"), pos).isDisplayed()){
getElementWithIndex(By.tagName("a"), pos).click();
Thread.sleep(200);
driver.navigate().back();
Thread.sleep(200);
}
}
}catch (Exception e){
System.out.println("error in getLinks "+e);
}
}
Solutions to resolve them:
Storing locators to your elements instead of references
driver = webdriver.Firefox();
driver.get("http://www.github.com");
search_input = lambda: driver.find_element_by_name('q');
search_input().send_keys('hello world\n');
time.sleep(5);
search_input().send_keys('hello frank\n') // no stale element exception
Leverage hooks in the JS libraries used
# Using Jquery queue to get animation queue length.
animationQueueIs = """
return $.queue( $("#%s")[0], "fx").length;
""" % element_id
wait_until(lambda: self.driver.execute_script(animationQueueIs)==0)
Moving your actions into JavaScript injection
self.driver.execute_script("$(\"li:contains('Narendra')\").click()");
Proactively wait for the element to go stale
# Wait till the element goes stale, this means the list has updated
wait_until(lambda: is_element_stale(old_link_reference))
This solution, which worked for me
When a Stale Element Exception occurs!!
Stale element exception can happen when the libraries supporting those textboxes/ buttons/ links has changed which means the elements are same but the reference has now changed in the website without affecting the locators. Thus the reference which we stored in our cache including the library reference has now become old or stale because the page has been refreshed with updated libraries.
for(int j=0; j<5;j++)
try {
WebElement elementName=driver.findElement(By.xpath(“somexpath”));
break;
} catch(StaleElementReferenceException e){
e.toString();
System.out.println(“Stale element error, trying :: ” + e.getMessage());
}
elementName.sendKeys(“xyz”);
For Fitnesse you can use:
|start |Smart Web Driver| selenium.properties|
#Fixture(name = "Smart Web Driver")
public class SmartWebDriver extends SlimWebDriver {
private final static Logger LOG = LoggerFactory.getLogger(SmartWebDriver.class);
/**
* Constructs a new SmartWebDriver.
*/
#Start(name = "Start Smart Web Driver", arguments = {"configuration"}, example = "|start |Smart Web Driver| selenium.properties|")
public SmartWebDriver(String configuration) {
super(configuration);
}
/**
* Waits for an element to become invisible (meaning visible and width and height != 0).
*
* #param locator the locator to use to find the element.
*/
#Command(name = "smartWaitForNotVisible", arguments = {"locator"}, example = "|smartWaitForNotVisible; |//path/to/input (of css=, id=, name=, classname=, link=, partiallink=)|")
public boolean smartWaitForNotVisible(String locator) {
try {
waitForNotVisible(locator);
} catch (StaleElementReferenceException sere) {
LOG.info("Element with locator '%s' did not become invisible (visible but also width and height != 0), a StaleElementReferenceException occurred, trying to continue...", locator);
} catch (NoSuchElementException ele) {
LOG.info("Element with locator '%s' did not become invisible (visible but also width and height != 0), a NoSuchElementException occurred, trying to continue...", locator);
} catch (AssertionError ae) {
if (ae.getMessage().contains("No element found")) {
LOG.info("Element with locator '%s' did not become invisible (visible but also width and height != 0), a AssertionError occurred, trying to continue...", locator);
} else {
throw ae;
}
}
return true;
}
}
https://www.swtestacademy.com/selenium-wait-javascript-angular-ajax/ here is a good article about dynamic waiter strategies.
Your problem is not waiting properly all the ajax, jquery or angular calls.
Then you end up with StaleElementException.
If your approach is to use Try-Catch mechanism, I guess it has a flaw. You shouldn't rely on that structure as you'll never know it's gonna work in the catch clause.
Selenium gives you the opportunity to make javascript calls.
You can execute
"return jQuery.active==0"
return
angular.element(document).injector().get('$http').pendingRequests.length
=== 0"
"return document.readyState"
"return angular.element(document).injector() === undefined"
commands just to check the existence and states of those calls.
You can do that before any findBy operation so you always work with the latest page

Wait for page load in Selenium

How do you make Selenium 2.0 wait for the page to load?
You can also check pageloaded using following code
IWait<IWebDriver> wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver, TimeSpan.FromSeconds(30.00));
wait.Until(driver1 => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));
Use class WebDriverWait
Also see here
You can expect to show some element. something like in C#:
WebDriver _driver = new WebDriver();
WebDriverWait _wait = new WebDriverWait(_driver, new TimeSpan(0, 1, 0));
_wait.Until(d => d.FindElement(By.Id("Id_Your_UIElement")));
If you set the implicit wait of the driver, then call the findElement method on an element you expect to be on the loaded page, the WebDriver will poll for that element until it finds the element or reaches the time out value.
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
source: implicit-waits
In general, with Selenium 2.0 the web driver should only return control to the calling code once it has determined that the page has loaded. If it does not, you can call waitforelemement, which cycles round calling findelement until it is found or times out (time out can be set).
Ruby implementation:
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until {
#driver.execute_script("return document.readyState;") == "complete"
}
All of these solutions are OK for specific cases, but they suffer from at least one of a couple of possible problems:
They are not generic enough -- they want you to know, ahead of time, that some specific condition will be true of the page you are going to (eg some element will be displayed)
They are open to a race condition where you use an element that is actually present on the old page as well as the new page.
Here's my attempt at a generic solution that avoids this problem (in Python):
First, a generic "wait" function (use a WebDriverWait if you like, I find them ugly):
def wait_for(condition_function):
start_time = time.time()
while time.time() < start_time + 3:
if condition_function():
return True
else:
time.sleep(0.1)
raise Exception('Timeout waiting for {}'.format(condition_function.__name__))
Next, the solution relies on the fact that selenium records an (internal) id-number for all elements on a page, including the top-level <html> element. When a page refreshes or loads, it gets a new html element with a new ID.
So, assuming you want to click on a link with text "my link" for example:
old_page = browser.find_element_by_tag_name('html')
browser.find_element_by_link_text('my link').click()
def page_has_loaded():
new_page = browser.find_element_by_tag_name('html')
return new_page.id != old_page.id
wait_for(page_has_loaded)
For more Pythonic, reusable, generic helper, you can make a context manager:
from contextlib import contextmanager
#contextmanager
def wait_for_page_load(browser):
old_page = browser.find_element_by_tag_name('html')
yield
def page_has_loaded():
new_page = browser.find_element_by_tag_name('html')
return new_page.id != old_page.id
wait_for(page_has_loaded)
And then you can use it on pretty much any selenium interaction:
with wait_for_page_load(browser):
browser.find_element_by_link_text('my link').click()
I reckon that's bulletproof! What do you think?
More info in a blog post about it here
You may remove the System.out line. It is added for debug purposes.
WebDriver driver_;
public void waitForPageLoad() {
Wait<WebDriver> wait = new WebDriverWait(driver_, 30);
wait.until(new Function<WebDriver, Boolean>() {
public Boolean apply(WebDriver driver) {
System.out.println("Current Window State : "
+ String.valueOf(((JavascriptExecutor) driver).executeScript("return document.readyState")));
return String
.valueOf(((JavascriptExecutor) driver).executeScript("return document.readyState"))
.equals("complete");
}
});
}
Here is a Java 8 version of the currently most upvoted answer:
WebDriverWait wait = new WebDriverWait(myDriver, Duration.ofSeconds(15));
wait.until(webDriver -> "complete".equals(((JavascriptExecutor) webDriver)
.executeScript("return document.readyState")));
Where myDriver is a WebDriver object (declared earlier).
Note: Be aware that this method (document.readyState) only checks the DOM.
You can also use the class: ExpectedConditions to explicitly wait for an element to show up on the webpage before you can take any action further actions
You can use the ExpectedConditions class to determine if an element is visible:
WebElement element = (new WebDriverWait(getDriver(), 10)).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input#houseName")));
See ExpectedConditions class Javadoc for list of all conditions you are able to check.
Imran's answer rehashed for Java 7:
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver wdriver) {
return ((JavascriptExecutor) driver).executeScript(
"return document.readyState"
).equals("complete");
}
});
This seems to be a serious limitation of WebDriver. Obviously waiting for an element will not imply the page being loaded, in particular the DOM can be fully build (onready state) whereby JS is still executing and CSS and images are still loading.
I believe the simplest solution is to set a JS variable upon the onload event after everything is initialized and check and wait for this JS variable in Selenium.
If you want to wait for a specific element to load, you can use the isDisplayed() method on a RenderedWebElement :
// Sleep until the div we want is visible or 5 seconds is over
long end = System.currentTimeMillis() + 5000;
while (System.currentTimeMillis() < end) {
// Browsers which render content (such as Firefox and IE) return "RenderedWebElements"
RenderedWebElement resultsDiv = (RenderedWebElement) driver.findElement(By.className("gac_m"));
// If results have been returned, the results are displayed in a drop down.
if (resultsDiv.isDisplayed()) {
break;
}
}
(Example from The 5 Minute Getting Started Guide)
Man all these answers require too much code. This should be a simple thing as its pretty common.
Why not just inject some simple Javascript with the webdriver and check.
This is the method I use in my webscraper class. The Javascript is pretty basic even if you don't know it.
def js_get_page_state(self):
"""
Javascript for getting document.readyState
:return: Pages state. See doc link below.
"""
ready_state = self.driver.execute_script('return document.readyState')
if ready_state == 'loading':
self.logger.info("Loading Page...")
elif ready_state == 'interactive':
self.logger.info("Page is interactive")
elif ready_state == 'complete':
self.logger.info("The page is fully loaded!")
return ready_state
More Info in "Document.readyState" of MDN Web Docs: https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
Explicitly wait or conditional wait in this wait until given this condition.
WebDriverWait wait = new WebDriverWait(wb, 60);
wait.until(ExpectedConditions.elementToBeClickable(By.name("value")));
This will wait for every web element for 60 seconds.
Use implicitly wait for wait of every element on page till that given time.
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
This will wait for every web element for 60 seconds.
I'm surprised that predicates weren't the first choice as you typically know what element(s) you will next interact with on the page you're waiting to load. My approach has always been to build out predicates/functions like waitForElementByID(String id) and waitForElemetVisibleByClass(String className), etc. and then use and reuse these wherever I need them, be it for a page load or page content change I'm waiting on.
For example,
In my test class:
driverWait.until(textIsPresent("expectedText");
In my test class parent:
protected Predicate<WebDriver> textIsPresent(String text){
final String t = text;
return new Predicate<WebDriver>(){
public boolean apply(WebDriver driver){
return isTextPresent(t);
}
};
}
protected boolean isTextPresent(String text){
return driver.getPageSource().contains(text);
}
Though this seems like a lot, it takes care of checking repeatedly for you
and the interval for how often to check can be set along with the ultimate
wait time before timing out. Also, you will reuse such methods.
In this example, the parent class defined and initiated the WebDriver driver and the WebDriverWait driverWait.
I hope this helps.
Use implicitly wait for wait of every element on page till given time.
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
this wait for every element on page for 30 sec.
Another wait is Explicitly wait or conditional wait in this wait until given condition.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
In id give static element id which is diffidently display on the page, as soon as page is load.
The best way to wait for page loads when using the Java bindings for WebDriver is to use the Page Object design pattern with PageFactory. This allows you to utilize the AjaxElementLocatorFactory which to put it simply acts as a global wait for all of your elements. It has limitations on elements such as drop-boxes or complex javascript transitions but it will drastically reduce the amount of code needed and speed up test times. A good example can be found in this blogpost. Basic understanding of Core Java is assumed.
http://startingwithseleniumwebdriver.blogspot.ro/2015/02/wait-in-page-factory.html
Call below Function in your script , this will wait till page is not loaded using javascript
public static boolean isloadComplete(WebDriver driver)
{
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("loaded")
|| ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}
NodeJS Solution:
In Nodejs you can get it via promises...
If you write this code, you can be sure that the page is fully loaded when you get to the then...
driver.get('www.sidanmor.com').then(()=> {
// here the page is fully loaded!!!
// do your stuff...
}).catch(console.log.bind(console));
If you write this code, you will navigate, and selenium will wait 3 seconds...
driver.get('www.sidanmor.com');
driver.sleep(3000);
// you can't be sure that the page is fully loaded!!!
// do your stuff... hope it will be OK...
From Selenium Documentation (Nodejs):
this.get( url ) → Thenable<undefined>
Schedules a command to navigate to the given URL.
Returns a promise that will be resolved when the document has finished loading.
You can use the below existing method to set the pageLoadTimeout. In below example if the page is taking more than 20 seconds to load, then it will throw an exception of page reload:
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS);
/**
* Call this method before an event that will change the page.
*/
private void beforePageLoad() {
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("document.mpPageReloaded='notYet';");
}
/**
* Call this method after an event that will change the page.
*
* #see #beforePageLoad
*
* Waits for the previous page to disappear.
*/
private void afterPageLoad() throws Exception {
(new WebDriverWait(driver, 10)).until(new Predicate<WebDriver>() {
#Override
public boolean apply(WebDriver driver) {
JavascriptExecutor js = (JavascriptExecutor) driver;
Object obj = js.executeScript("return document.mpPageReloaded;");
if (obj == null) {
return true;
}
String str = (String) obj;
if (!str.equals("notYet")) {
return true;
}
return false;
}
});
}
You can change from the document to an element, in the case of where only part of a document is being changed.
This technique was inspired by the answer from sincebasic.
SeleniumWaiter:
import com.google.common.base.Function;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.WebDriverWait;
public class SeleniumWaiter {
private WebDriver driver;
public SeleniumWaiter(WebDriver driver) {
this.driver = driver;
}
public WebElement waitForMe(By locatorname, int timeout){
WebDriverWait wait = new WebDriverWait(driver, timeout);
return wait.until(SeleniumWaiter.presenceOfElementLocated(locatorname));
}
public static Function<WebDriver, WebElement> presenceOfElementLocated(final By locator) {
// TODO Auto-generated method stub
return new Function<WebDriver, WebElement>() {
#Override
public WebElement apply(WebDriver driver) {
return driver.findElement(locator);
}
};
}
}
And to you use it:
_waiter = new SeleniumWaiter(_driver);
try {
_waiter.waitForMe(By.xpath("//..."), 10);
}
catch (Exception e) {
// Error
}
You can explicitly wait for an element to show up on the webpage before you can take any action (like element.click()):
driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(new ExpectedCondition<WebElement>() {
#Override
public WebElement apply(WebDriver d) {
return d.findElement(By.id("myDynamicElement"));
}
}
);
This is what I used for a similar scenario and it works fine.
My simple way:
long timeOut = 5000;
long end = System.currentTimeMillis() + timeOut;
while (System.currentTimeMillis() < end) {
if (String.valueOf(
((JavascriptExecutor) driver)
.executeScript("return document.readyState"))
.equals("complete")) {
break;
}
}
You can use this snippet of code for the page to load:
IWait wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver,TimeSpan.FromSeconds(30.00));
wait.Until(driver1 => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));
Or you can use waiter for any element to be loaded and become visible/clickable on that page, most probably which is going to be load at the end of loading like:
Wait.Until(ExpectedConditions.ElementToBeClickable(By.XPath(xpathOfElement));
var element = GlobalDriver.FindElement(By.XPath(xpathOfElement));
var isSucceededed = element != null;
The best way I've seen is to utilize the stalenessOf ExpectedCondition, to wait for the old page to become stale.
Example:
WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement oldHtml = driver.findElement(By.tagName("html"));
wait.until(ExpectedConditions.stalenessOf(oldHtml));
It'll wait for ten seconds for the old HTML tag to become stale, and then throw an exception if it doesn't happen.
I use node + selenium-webdriver(which version is 3.5.0 now). what I do for this is:
var webdriver = require('selenium-webdriver'),
driver = new webdriver.Builder().forBrowser('chrome').build();
;
driver.wait(driver.executeScript("return document.readyState").then(state => {
return state === 'complete';
}))
You can use wait. there are basically 2 types of wait in selenium
Implicit wait
Explicit wait
- Implicit wait
This is very simple please see syntax below:
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
- Explicit wait
Explicitly wait or conditional wait in this wait until given condition is occurred.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
You can use other properties like visblityOf(), visblityOfElement()
If someone uses selenide:
public static final Long SHORT_WAIT = 5000L; // 5 seconds
$("some_css_selector").waitUntil(Condition.appear, SHORT_WAIT);
More Conditions can be found here:
http://selenide.org/javadoc/3.0/com/codeborne/selenide/Condition.html
In my case , I used the following to know the page load status. In our application loading gif(s) are present and, I listen to them as follows to eliminate unwanted wait time in the script.
public static void processing(){
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[#id='Msgpanel']/div/div/img")));
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("//div[#id='Msgpanel']/div/div/img")));
}
Where the xpath locates the gif in the HTML DOM.
After this, You may also implement your action methods Click.
public static void click(WebElement elementToBeClicked){
WebDriverWait wait = new WebDriverWait(driver, 45);
wait.until(ExpectedConditions.visibilityOf(element));
wait.until(ExpectedConditions.elementToBeClickable(element));
wait.ignoring(NoSuchElementException.class).ignoring(StaleElementReferenceException.class); elementToBeClicked.click();
}

Categories

Resources