118

I'm working on a Java Selenium-WebDriver. I added

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

and

WebElement textbox = driver.findElement(By.id("textbox"));

because my Applications takes few seconds to load the User Interface. So I set 2 seconds implicitwait. but I got unable to locate element textbox

Then I add Thread.sleep(2000);

Now it works fine. Which one is a better way?

kenorb
  • 155,785
  • 88
  • 678
  • 743
Gnik
  • 7,120
  • 20
  • 79
  • 129
  • 3
    possible duplicate of [selenium webdriver - explicit wait vs implicit wait](http://stackoverflow.com/questions/10404160/selenium-webdriver-explicit-wait-vs-implicit-wait) – Lesmana Jan 22 '15 at 08:23

13 Answers13

135

Well, there are two types of wait: explicit and implicit wait. The idea of explicit wait is

WebDriverWait.until(condition-that-finds-the-element);

The concept of implicit wait is

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

You can get difference in details here.

In such situations I'd prefer using explicit wait (fluentWait in particular):

public WebElement fluentWait(final By locator) {
    Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
            .withTimeout(30, TimeUnit.SECONDS)
            .pollingEvery(5, TimeUnit.SECONDS)
            .ignoring(NoSuchElementException.class);

    WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
        public WebElement apply(WebDriver driver) {
            return driver.findElement(locator);
        }
    });

    return  foo;
};

fluentWait function returns your found web element. From the documentation on fluentWait: An implementation of the Wait interface that may have its timeout and polling interval configured on the fly. Each FluentWait instance defines the maximum amount of time to wait for a condition, as well as the frequency with which to check the condition. Furthermore, the user may configure the wait to ignore specific types of exceptions whilst waiting, such as NoSuchElementExceptions when searching for an element on the page. Details you can get here

Usage of fluentWait in your case be the following:

WebElement textbox = fluentWait(By.id("textbox"));

This approach IMHO better as you do not know exactly how much time to wait and in polling interval you can set arbitrary timevalue which element presence will be verified through . Regards.

Community
  • 1
  • 1
eugene.polschikov
  • 7,254
  • 2
  • 31
  • 44
  • 3
    That's `import com.google.common.base.Function;`, not `import java.util.function.Function;` – haventchecked Jun 22 '16 at 21:05
  • haventchecked, actually using intelij IDEA for development, it's helping with auto-imports (when working in maven-based project) – eugene.polschikov Jun 28 '16 at 10:47
  • 1
    I was just calling that out for others who may be wondering which `Function` was being used. It wasn't obvious to me at first. Thanks for the answer. – haventchecked Jun 28 '16 at 21:51
  • 1
    Or you could just use a lambda expression: `driver -> driver.findElement(locator)`. When using this you won't need an import statement at all. – Thibstars Oct 05 '16 at 11:40
  • Does somebody has a complete working example to look at eg. on Github? – lony Jul 24 '18 at 10:03
  • Can anyone translate the above to C#? – Heike Apr 09 '19 at 15:48
  • 2
    Now it is: `.withTimeout(Duration.ofSeconds(30)).pollingEvery(Duration.ofSeconds(5))` in stead of: `.withTimeout(30, TimeUnit.SECONDS).pollingEvery(5, TimeUnit.SECONDS)` – SuperRetro Nov 15 '19 at 09:26
18

If using webdriverJs (node.js),

driver.findElement(webdriver.By.name('btnCalculate')).click().then(function() {
    driver.sleep(5000);
});

The code above makes browser wait for 5 seconds after clicking the button.

Anup
  • 600
  • 3
  • 9
18

This thread is a bit older, but thought I'd post what I currently do (work in progress).

Though I'm still hitting situations where the system is under heavy load and when I click a submit button (e.g., login.jsp), all three conditions (see below) return true but the next page (e.g., home.jsp) hasn't started loading yet.

This is a generic wait method that takes a list of ExpectedConditions.

public boolean waitForPageLoad(int waitTimeInSec, ExpectedCondition<Boolean>... conditions) {
    boolean isLoaded = false;
    Wait<WebDriver> wait = new FluentWait<>(driver)
            .withTimeout(waitTimeInSec, TimeUnit.SECONDS)
            .ignoring(StaleElementReferenceException.class)
            .pollingEvery(2, TimeUnit.SECONDS);
    for (ExpectedCondition<Boolean> condition : conditions) {
        isLoaded = wait.until(condition);
        if (isLoaded == false) {
            //Stop checking on first condition returning false.
            break;
        }
    }
    return isLoaded;
}

I have defined various reusable ExpectedConditions (three are below). In this example, the three expected conditions include document.readyState = 'complete', no "wait_dialog" present, and no 'spinners' (elements indicating async data is being requested).

Only the first one can be generically applied to all web pages.

/**
 * Returns 'true' if the value of the 'window.document.readyState' via
 * JavaScript is 'complete'
 */
public static final ExpectedCondition<Boolean> EXPECT_DOC_READY_STATE = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        String script = "if (typeof window != 'undefined' && window.document) { return window.document.readyState; } else { return 'notready'; }";
        Boolean result;
        try {
            result = ((JavascriptExecutor) driver).executeScript(script).equals("complete");
        } catch (Exception ex) {
            result = Boolean.FALSE;
        }
        return result;
    }
};
/**
 * Returns 'true' if there is no 'wait_dialog' element present on the page.
 */
public static final ExpectedCondition<Boolean> EXPECT_NOT_WAITING = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        Boolean loaded = true;
        try {
            WebElement wait = driver.findElement(By.id("F"));
            if (wait.isDisplayed()) {
                loaded = false;
            }
        } catch (StaleElementReferenceException serex) {
            loaded = false;
        } catch (NoSuchElementException nseex) {
            loaded = true;
        } catch (Exception ex) {
            loaded = false;
            System.out.println("EXPECTED_NOT_WAITING: UNEXPECTED EXCEPTION: " + ex.getMessage());
        }
        return loaded;
    }
};
/**
 * Returns true if there are no elements with the 'spinner' class name.
 */
public static final ExpectedCondition<Boolean> EXPECT_NO_SPINNERS = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        Boolean loaded = true;
        try {
        List<WebElement> spinners = driver.findElements(By.className("spinner"));
        for (WebElement spinner : spinners) {
            if (spinner.isDisplayed()) {
                loaded = false;
                break;
            }
        }
        }catch (Exception ex) {
            loaded = false;
        }
        return loaded;
    }
};

Depending on the page, I may use one or all of them:

waitForPageLoad(timeoutInSec,
            EXPECT_DOC_READY_STATE,
            EXPECT_NOT_WAITING,
            EXPECT_NO_SPINNERS
    );

There are also predefined ExpectedConditions in the following class: org.openqa.selenium.support.ui.ExpectedConditions

Jeff Vincent
  • 433
  • 5
  • 10
  • 1
    Great answer! I've never seen someone pass a ExpectedCondition item in via the method constructor. What a great idea. +1 – djangofan Apr 28 '16 at 16:56
  • Jeff Vincent, can you please tell me will this work for page to wait 5 minutes if yes then please suggest which place parameter needs to send? – khanam Oct 20 '16 at 14:10
  • This is a great answer. I have similar function like this, however, I have to call it in every function so that my script waits until page load (spinner). Is there way that I can hook this waitForSpinner function silently into ImplicitWait so that i need not call it everytime in my function? Like define the function, hook it to driver once and boom. – Bhuvanesh Mani Apr 03 '19 at 15:49
11

Using Thread.sleep(2000); is an unconditional wait. If your test loads faster you will still have to wait. So in principle using implicitlyWait is the better solution.

However, I don't see why implicitlyWait does not work in your case. Did you measure if the findElement actually takes two seconds before throwing an exception. If so, can you try to use WebDriver's conditional wait as described in this answer?

Community
  • 1
  • 1
Valentin
  • 7,874
  • 5
  • 33
  • 38
2

I like to use custom conditions. Here's some code in Python:

def conditions(driver):
    flag = True
    ticker = driver.find_elements_by_id("textbox")
    if not ticker:
        flag = False
    return flag

... click something to load ...
self.wait = WebDriverWait(driver, timeout)
self.wait.until(conditions)

Whenever you need to wait, you can do it explicitly by checking existance of a certain element (such element may vary from page to page). find_elements_by_id returns list - empty or not, you have just to check.

simno
  • 418
  • 9
  • 14
2

click appears to be blocking? - here's another way to wait if you're using WebDriverJS:

driver.findElement(webdriver.By.name('mybutton')).click().then(function(){
  driver.getPageSource().then(function(source) {
    console.log(source);
  });
});

The code above waits after the button is clicked for the next page to load and then grabs the source of the next page.

Dion
  • 206
  • 1
  • 4
  • 1
    What makes the code wait for the next page to load? Is it just that the first call in the callback is getPageSource? – Isochronous Jul 29 '15 at 20:11
1

Implicitly wait and Thread.sleep Both are used for synchronization only..but the difference is we can use Implicitly wait for entire program but Thread.sleep will works for that single code only..Here my suggestion is use Implicitly wait once in the program when every time your Webpage will get refreshed means use Thread.sleep at that time..it will much Better :)

Here is My Code :

package beckyOwnProjects;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;

public class Flip {

    public static void main(String[] args) throws InterruptedException {
        WebDriver driver=new FirefoxDriver();
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(2, TimeUnit.MINUTES);
        driver.get("https://www.flipkart.com");
    WebElement ele=driver.findElement(By.cssSelector(".menu-text.fk-inline-block"));
    Actions act=new Actions(driver);
    Thread.sleep(5000);
    act.moveToElement(ele).perform();
    }

}
1

Use Actions -

The user-facing API for emulating complex user gestures.

See Actions#pause method.

0

Sometimes implicit wait seems to get overridden and wait time is cut short. [@eugene.polschikov] had good documentation on the whys. I have found in my testing and coding with Selenium 2 that implicit waits are good but occasionally you have to wait explicitly.

It is better to avoid directly calling for a thread to sleep, but sometimes there isn't a good way around it. However, there are other Selenium provided wait options that help. waitForPageToLoad and waitForFrameToLoad have proved especially useful.

BadgerAndK
  • 44
  • 3
0

Sometimes implicit wait fails, saying that an element exists but it really doesn't.

The solution is to avoid using driver.findElement and to replace it with a custom method that uses an Explicit Wait implicitly. For example:

import org.openqa.selenium.NoSuchElementException;


public WebElement element(By locator){
    Integer timeoutLimitSeconds = 20;
    WebDriverWait wait = new WebDriverWait(driver, timeoutLimitSeconds);
    try {
        wait.until(ExpectedConditions.presenceOfElementLocated(locator));
    }
    catch(TimeoutException e){
        throw new NoSuchElementException(locator.toString());
    }
    WebElement element = driver.findElement(locator);
    return element;
}

There are additional reasons to avoid implicit wait other than sporadic, occasional failures (see this link).

You can use this "element" method in the same way as driver.findElement. For Example:

    driver.get("http://yoursite.html");
    element(By.cssSelector("h1.logo")).click();

If you really want to just wait a few seconds for troubleshooting or some other rare occasion, you can create a pause method similar to what selenium IDE offers:

    public void pause(Integer milliseconds){
    try {
        TimeUnit.MILLISECONDS.sleep(milliseconds);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
JohnP2
  • 1,899
  • 19
  • 17
0

Answer : wait for few seconds before element visibility using Selenium WebDriver go through below methods.

implicitlyWait() : WebDriver instance wait until full page load. You muse use 30 to 60 seconds to wait full page load.

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

ExplicitlyWait WebDriverWait() : WebDriver instance wait until full page load.

WebDriverWait wait = new WebDriverWait(driver, 60);

wait.until(ExpectedConditions.visibilityOf(textbox));

driver.findElement(By.id("Year")).sendKeys(allKeys);

Note : Please use ExplicitlyWait WebDriverWait() to handle any particular WebElement.

sandeep shewale
  • 125
  • 1
  • 5
-1

Implicit Wait: During Implicit wait if the Web Driver cannot find it immediately because of its availability, the WebDriver will wait for mentioned time and it will not try to find the element again during the specified time period. Once the specified time is over, it will try to search the element once again the last time before throwing exception. The default setting is zero. Once we set a time, the Web Driver waits for the period of the WebDriver object instance.

Explicit Wait: There can be instance when a particular element takes more than a minute to load. In that case you definitely not like to set a huge time to Implicit wait, as if you do this your browser will going to wait for the same time for every element. To avoid that situation you can simply put a separate time on the required element only. By following this your browser implicit wait time would be short for every element and it would be large for specific element.

-2
Thread.sleep(1000);

is the worse: being a static wait, it will make test script slower.

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

this is a dynamic wait

  • it is valid till webdriver existence or has a scope till driver lifetime
  • we can implicit wait also.

Finally, what I suggest is

WebDriverWait wait = new WebDriverWait(driver,20);
wait.until(ExpectedConditions.<different canned or predefined conditions are there>);

with some predefined conditions:

isAlertPresent();
elementToBeSelected();
visibilityOfElementLocated();
visibilityOfAllElementLocatedBy();
frameToBeAvailableAndSwitchToIt();
  • It is also dynamic wait
  • in this the wait will only be in seconds
  • we have to use explicit wait for a particular web element on which we want to use.
PaoloC
  • 3,817
  • 1
  • 23
  • 27
Shobhit
  • 1
  • 2