Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selenium WebDriver: wait for element to be present when locating with WebDriver.findElement is impossible

It's convenient to wait for an WebElement to be present with WebDriverWait and ExpectedConditions.

The problem is, what if WebElement.findElment was the only possible way to locate the element , 'cause it has no id, no name, no unique class?

WebDriverWait's constructor accepts only WebDriver as arguments, not WebElement.

I've set the implicitlyWait time, so it seems not a good idea to use try{} catch(NoSuchElementException e){}, 'cause I don't want to wait that long time for this element.

Here's the scenario:

There's one web page with a form containing many input tags. Each input tag has a format requirement.

A dynamic div tag would be present after this input tag when the format requirement is not satisfied.

As there're so many input tags, I create a general method like:

public WebElement txtBox(String name) {
    return driver.findElement(By.name(name));
}

instead of creating a data member for each input tag.

Then I create a method isValid to check whether user inputs in some input are valid. All I should do in isValid is to check whether a div tag is present after inputboxToCheck, with code like this:

public boolean isValid(WebElement inputboxToCheck) {
    WebElementWait wait = new WebElementWait(inputboxToCheck, 1);
    try {
        wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("./following-sibling::div")));
        return false;
    } catch (TimeOutException e) {
        return true;
    }    
}

WebElementWait is an imaginary (not exist) class which works the same way as WebDriverWait.

like image 396
user2432405 Avatar asked Nov 08 '13 04:11

user2432405


People also ask

How do you get Selenium to wait until the element is present?

Selenium: Waiting Until the Element Is Visiblevar wait = new WebDriverWait(driver, TimeSpan. FromSeconds(20)); As you can see, we give the WebDriverWait object two parameters: the driver itself and a TimeSpan object that represents the timeout for trying to locate the element.

What will happen if a findElement type call can't find the element?

The findElement method throws a NoSuchElementException exception when the element is not available on the page. Whereas, the findElements method returns an empty list when the element is not available or doesn't exist on the page.

How wait until element is not present in Selenium?

This can be achieved with synchronization in Selenium. We shall add an explicit wait criteria where we shall stop or wait till the element no longer exists. Timeout exception is thrown once the explicit wait time has elapsed and the expected behavior of the element is still not available on the page.

How do you handle no such element unable to locate an element in Selenium?

This type of exception is thrown when there is no element on the page which matches with the locator value. Check if there is any syntax error in our xpath expression. Add additional expected wait conditions for the element. Use an alternative xpath expression.


2 Answers

The WebElementWait class as metioned above:

package org.openqa.selenium.support.ui;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.NotFoundException;
import org.openqa.selenium.WebElement;

public class WebElementWait  extends FluentWait<WebElement>  {
    public final static long DEFAULT_SLEEP_TIMEOUT = 500;

      public WebElementWait(WebElement element, long timeOutInSeconds) {
            this(element, new SystemClock(), Sleeper.SYSTEM_SLEEPER, timeOutInSeconds, DEFAULT_SLEEP_TIMEOUT);
      }

      public WebElementWait(WebElement element, long timeOutInSeconds, long sleepInMillis) {
            this(element, new SystemClock(), Sleeper.SYSTEM_SLEEPER, timeOutInSeconds, sleepInMillis);
      }

      protected WebElementWait(WebElement element, Clock clock, Sleeper sleeper, long timeOutInSeconds,
              long sleepTimeOut) {
            super(element, clock, sleeper);
            withTimeout(timeOutInSeconds, TimeUnit.SECONDS);
            pollingEvery(sleepTimeOut, TimeUnit.MILLISECONDS);
            ignoring(NotFoundException.class);
      }

}

It's the same as WebDriverWait, except that the WebDriver argument is replaced with WebElement.

Then, the isValid method:

//import com.google.common.base.Function;
    //import org.openqa.selenium.TimeoutException;

public boolean isValid(WebElement e) {
    try {
        WebElementWait wait = new WebElementWait(e, 1);
        //@SuppressWarnings("unused")
        //WebElement icon = 
        wait.until(new Function<WebElement, WebElement>() {
                    public WebElement apply(WebElement d) {
                        return d.findElement(By
                                .xpath("./following-sibling::div[class='invalid-icon']"));
                    }
                });
        return false;
    } catch (TimeoutException exception) {
        return true;
    }
}
like image 85
user2432405 Avatar answered Nov 15 '22 17:11

user2432405


A more universal variant of user2432405's solution would be using SearchContext type rather then WebElement:

public class SearchContextWait  extends FluentWait<SearchContext>  {
    ...

This allows to do waits on both WebDriver and WebElement similarly as the SearchContext interface is the ancestor of both WebDriver and WebElement. The isValid method needs adjustment too:

...
        WebElement icon = wait
                .until(new Function<SearchContext, WebElement>() {
                    public WebElement apply(SearchContext d) {
...

Unfortunately, you lose all conveniences of ExpectedConditions.xxxx() methods as they use the WebDriver interface internally.

like image 41
Nik Avatar answered Nov 15 '22 18:11

Nik