Mikhail Ramendik
Mikhail Ramendik

Reputation: 1115

A wrapper for WebDriverWait that could take all kinds of ExpectedConditon?

I am using Selenium 3.4 with Java. I am testing a UI that is not very fast and use an implicit wait so that I don't have to care about manual explcit waiting every time something can take a couple of seconds to load.

However, sometimes I need an explicit wait anyway. And for that, I need to disable the implicit wait temporarily. To avoid cluttering up the code, I put the following method in my driver manager class:

public static void waitFor(ExpectedCondition<Boolean> condition,int timeoutSeconds) throws Exception {
    setImplicitWait(0);
    try {
        (new WebDriverWait(driver, timeoutSeconds)).until(condition);
    } finally {
        setImplicitWait(WAIT_REGULAR);
    }
}

The setImplicitWait method is simple:

public static void setImplicitWait(int TimeoutSeconds) {
    logger.debug("Setting implicit wait to {} seconds",TimeoutSeconds);
    driver.manage().timeouts().implicitlyWait(TimeoutSeconds, TimeUnit.SECONDS);
}

So, this setup works for some waits, like this one:

DriverManager.waitFor(ExpectedConditions.invisibilityOfElementLocated(By.className("gridxLoad")), DriverManager.WAIT_HUGE);

However, if I try this one:

DriverManager.waitFor(ExpectedConditions.visibilityOfElementLocated(By.className("gridxMain")), DriverManager.WAIT_HUGE);

I get a compile error:

The method waitFor(ExpectedCondition, int) in the type DriverManager is not applicable for the arguments (ExpectedCondition, int)

If I change the parameter type in the definition of the method to ExpectedCondition<WebElement> , then, of course, the second wait suceeds and the first one throws a compile error. If I try creating the same method for both ExpectedCondition<WebElement> and ExpectedCondition<Boolean>, I get a compile error:

Erasure of method waitFor(ExpectedCondition, int) is the same as another method in type DriverManager

Finally, if I try to define the parameter as just ExpectedCondition, I get loads of compile warnings in the same small method:

ExpectedCondition is a raw type. References to generic type ExpectedCondition should be parameterized

Type safety: The expression of type ExpectedCondition needs unchecked conversion to conform to Function

Type safety: Unchecked invocation until(ExpectedCondition) of the generic method until(Function) of type FluentWait

I did also try defining the method like this:

public static void waitFor(Function<? super WebDriver,Object> condition,int timeoutSeconds) throws Exception {

But then both invocations of the method throw compiler errors.

What should I do? Go with a raw ExpectedCondition parameter and just ignore the warnings?

Upvotes: 1

Views: 1093

Answers (5)

Kushal Bhalaik
Kushal Bhalaik

Reputation: 3384

One example of what you are asking can be following:

public WebElement waitFor(WebElement elem, String waitType, long waitInSeconds ) {

    Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
            .withTimeout(waitInSeconds, TimeUnit.SECONDS)
            .pollingEvery(500, TimeUnit.MILLISECONDS)
            .ignoring(NoSuchElementException.class);

    try{
        switch(waitType) 
        {
        case "elementToBeClickable":
            wait.until(ExpectedConditions.elementToBeClickable(elem));
            break;

        case "visibilityOf":
            wait.until(ExpectedConditions.visibilityOf(elem));
            break;

        case "elementToBeSelected":
            wait.until(ExpectedConditions.elementToBeSelected(elem));
            break;

        default:
            wait.until(ExpectedConditions.visibilityOf(elem));
            break;

        }

    }
    catch(TimeoutException e) {

        e.printStackTrace();

    }

    return elem;
}

Similarly if ExpectedCondition acts on By or requires extra parameters this can be changed as per the requirement.

Upvotes: 0

Indrapal Singh
Indrapal Singh

Reputation: 364

I am using these wrapper methods to handle synchronization at the time of locating elements. Try this:

public static void expWait_elementclick(WebDriver driver,By by){        
    try {
        (new WebDriverWait(driver, 10)).until(ExpectedConditions.elementToBeClickable(by));
        driver.findElement(by).click();
    } catch (StaleElementReferenceException  ser) {
        // TODO Auto-generated catch block
        driver.findElement(by).click();
    }
}


public static void expWait_elementlocated(WebDriver driver,By by){
    try {
        (new WebDriverWait(driver, 10)).until(ExpectedConditions.presenceOfElementLocated(by));
        driver.findElement(by).click();
    } catch (StaleElementReferenceException  ser) {
        // TODO Auto-generated catch block
        driver.findElement(by).click();
    }
}

Upvotes: 1

HWentzke
HWentzke

Reputation: 11

We have a very nice customized wait-method in our projects that can be easily adapted to any condition you might wanna wait for

public static void waitForElementToBeVisible(WebDriver driver, int seconds, WebElement element) {
        WebDriverWait wait = (WebDriverWait) new WebDriverWait(driver, seconds)
                .ignoring(StaleElementReferenceException.class);
        wait.withMessage(ERROR_START + element + ERROR_MIDDLE + seconds + ERROR_END);
        wait.until((ExpectedCondition<Boolean>) webDriver -> element.isDisplayed());
}

Just replace element.isDisplayed() with any boolean condition you want. The int param is the max. Timeout you wanna wait for a condition to become true.

Using it with Selenium 3.4 and it works like a charm.

Upvotes: 0

Mikhail Ramendik
Mikhail Ramendik

Reputation: 1115

I did eventually find what I think is the right solution:

public static void waitFor(ExpectedCondition<?> condition,int timeoutSeconds) throws Exception {
    setImplicitWait(0);
    try {
        (new WebDriverWait(driver, timeoutSeconds)).until(condition);
    } finally {
        setImplicitWait(WAIT_REGULAR);
    }
}

Upvotes: 1

Florent B.
Florent B.

Reputation: 42518

The methods visibilityOfElementLocated and invisibilityOfElementLocated don't return the same type:

public static ExpectedCondition<Boolean> invisibilityOfElementLocated(final By locator) { ... }

public static ExpectedCondition<WebElement> visibilityOfElementLocated(final By locator) { ... }

When the condition is applied, the first one returns a Boolean while the second one returns a WebElement.

So to make it work, you need to implement both:

public static void waitFor(ExpectedCondition<Boolean> condition,int timeoutSeconds) throws Exception {
    setImplicitWait(0);
    try {
        (new WebDriverWait(driver, timeoutSeconds)).until(condition);
    } finally {
        setImplicitWait(WAIT_REGULAR);
    }
}

public static WebElement waitFor(ExpectedCondition<WebElement> condition,int timeoutSeconds) throws Exception {
    setImplicitWait(0);
    try {
        return (new WebDriverWait(driver, timeoutSeconds)).until(condition);
    } finally {
        setImplicitWait(WAIT_REGULAR);
    }
}

Upvotes: 0

Related Questions