Equivalent of waitForVisible/waitForElementPresent in Selenium WebDriver tests using Java?
Asked Answered
M

6

59

With "HTML" Selenium tests (created with Selenium IDE or manually), you can use some very handy commands like WaitForElementPresent or WaitForVisible.

<tr>
    <td>waitForElementPresent</td>
    <td>id=saveButton</td>
    <td></td>
</tr>

When coding Selenium tests in Java (Webdriver / Selenium RC—I'm not sure of the terminology here), is there something similar built-in?

For example, for checking that a dialog (that takes a while to open) is visible...

WebElement dialog = driver.findElement(By.id("reportDialog"));
assertTrue(dialog.isDisplayed());  // often fails as it isn't visible *yet*

What's the cleanest robust way to code such check?

Adding Thread.sleep() calls all over the place would be ugly and fragile, and rolling your own while loops seems pretty clumsy too...

Medora answered 7/6, 2012 at 23:19 Comment(1)
You need to use the WebDriverWait class - check this out for more information - selenium.googlecode.com/svn/trunk/docs/api/java/index.htmlScrod
R
114

Implicit and Explicit Waits

Implicit Wait

An implicit wait is to tell WebDriver to poll the DOM for a certain amount of time when trying to find an element or elements if they are not immediately available. The default setting is 0. Once set, the implicit wait is set for the life of the WebDriver object instance.

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

Explicit Wait + Expected Conditions

An explicit waits is code you define to wait for a certain condition to occur before proceeding further in the code. The worst case of this is Thread.sleep(), which sets the condition to an exact time period to wait. There are some convenience methods provided that help you write code that will wait only as long as required. WebDriverWait in combination with ExpectedCondition is one way this can be accomplished.

WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement element = wait.until(
        ExpectedConditions.visibilityOfElementLocated(By.id("someid")));
Revolting answered 8/6, 2012 at 14:35 Comment(6)
Is ExpectedConditions a Class or Interface? If so, what package should be imported for that?Braggart
@RiponAlWasim You probably know now, but I try to answer all questions... As can be seen in the JavaDoc, it's a class with static methods and it's contained in org.openqa.selenium.support.ui package.Discretion
So do implicit waits also apply to elements that were tried to be clicked on but are still disabled? Say i click one button to make another button appear. Then i try to click this other button. Then WebDriver realises that this other button is disabled. What happens now? Does it throw an exception or does it wait for the amount of seconds configured in the implicit wait for the current driver and then try to click it again??Ilsa
@Ilsa You could easily try this yourself, but I'll save your time - it throws an exception. The button would be found, so WebDriver does NOT implicitly wait for it to become enabled. You need to write an explicit wait for this.Discretion
@Slanec I would have done so had it been easy for me to test. When something like this fails i can barely guess what is going wrong, as the website that i am testing also uses a lot of ... chaotic java script. I was trying to become clear about this. Thank you for your answer on clarifying this, it helps a lot.Ilsa
@blaszard you sure about that? I'm looking at the javadocs right now, and the method is still there. It's there even for the alpha version of the api, 4.0.0. That are you looking at?Discretion
G
10
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(ExpectedConditions.presenceOfElementLocated(By.id("myDynamicElement")));

This waits up to 10 seconds before throwing a TimeoutException or if it finds the element will return it in 0 - 10 seconds. WebDriverWait by default calls the ExpectedCondition every 500 milliseconds until it returns successfully. A successful return is for ExpectedCondition type is Boolean return true or not null return value for all other ExpectedCondition types.


WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));

Element is Clickable - it is Displayed and Enabled.

From WebDriver docs: Explicit and Implicit Waits

Geis answered 16/2, 2014 at 5:27 Comment(0)
L
0

Well the thing is that you probably actually don't want the test to run indefinitely. You just want to wait a longer amount of time before the library decides the element doesn't exist. In that case, the most elegant solution is to use implicit wait, which is designed for just that:

driver.manage().timeouts().implicitlyWait( ... )
Lori answered 7/6, 2012 at 23:24 Comment(4)
Thanks! This seems perfect.. except that for my waitForVisible use case it doesn't work. I suppose WebDriver applies the timeout in findElement(), but what if that returns successfully right away andisDisplayed subsequently fails as it isn't visible yet (see Java code in question)..?Medora
@Jonik: I've sort of answered this question before here: stackoverflow.com/a/6379817. The trick is to use WebDriverWait which you specify a callback which is polled. It's similar to polling yourself but abstracts it. It also deals with timeouts as well. The code in that answer needs to be adapted a little but you should get the idea.Lori
Just verified that this indeed works great as waitForElementPresent equivalent (directly). Thanks, I'll look into that other answer tomorrow (too tired to think now) :)Medora
Post-mortem hint: implicit waiting breaks ExpectedConditions, which use driver.findElement internally.Statement
C
0

Another way to wait for maximum of certain amount say 10 seconds of time for the element to be displayed as below:

(new WebDriverWait(driver, 10)).until(new ExpectedCondition<Boolean>() {
            public Boolean apply(WebDriver d) {
                return d.findElement(By.id("<name>")).isDisplayed();

            }
        });
Chromous answered 5/7, 2019 at 5:15 Comment(0)
J
0
public static boolean waitForUntilVisible(WebDriver driver, Integer time, By by ) {
    WebDriverWait wait = new WebDriverWait(driver,  Duration.ofSeconds(time));

    try {
        wait.until( ExpectedConditions.presenceOfElementLocated(by) ); 
    }catch(NoSuchElementException e) {
        return false;
    }catch (TimeoutException e) {
        return false;
    }
    return true;
}
Javierjavler answered 20/1, 2023 at 7:21 Comment(1)
What imports does this code need?Monroe
B
-4

For individual element the code below could be used:

private boolean isElementPresent(By by) {
        try {
            driver.findElement(by);
            return true;
        } catch (NoSuchElementException e) {
            return false;
        }
    }
for (int second = 0;; second++) {
            if (second >= 60){
                fail("timeout");
            }
            try {
                if (isElementPresent(By.id("someid"))){
                    break;
                }
                }
            catch (Exception e) {

            }
            Thread.sleep(1000);
        }
Braggart answered 16/11, 2012 at 7:54 Comment(2)
This code contains so many smells it's hard to take this seriously. 1. You re-engineer the wheel. See other answers for built-in waiting. 2. Thread.sleep is ugly and error-prone. 3. As is catching the generic Exception. 4. "if" without curly brackets which is a common source of bugs. 5. what is "fail()"? Better throw a meaningful exception in tests. 6. You're taking the loop condition out of the "for" statement. 7. Writing multiple statements in one line might seem cool but it isn't, really. Also indentation is broken on this post.Statement
I agree. The best one is to use Explicit wait (WebDriverWait). To use Thread.sleep() is not good. Based on your comment I have reorganized the code with curly braces in if statement so it has become more readable. Thanks for your comment.Braggart

© 2022 - 2024 — McMap. All rights reserved.