• Jobs
  • About
  • Waiting after web page interactions March 16, 2012

    If you want to build a successful testautomation solution all you really need is make it reliable and make it fast. The single most important factor that affects both of these goals in web automation is how you wait after each page interaction. Whether you click or hover over a web element, execute a javascript function, or simulate a key press, it can cause either a page transition or an ajax operation. You would need to wait for this to complete before you can perform the next operation. If you wait too long, it makes the test execution slower than it needs to be. If you don’t wait or wait too little, it manifests as either consistent or intermittent failures.

    Wait for page transitions

    If you have worked with Selenium 1, you would expect to find a waitForPageToLoad equivalent in WebDriver. You wont find one. WebDriver does a pretty good job waiting for a page transition. In situations that I have run into redirects, WebDriver waited for the page that we were redirected to to load as well. This was something I had to specially handle with Selenium 1.

    When we talk about a “page load” we aren’t talking about Ajax loading though. There can be elements on the page that gets loaded using AJAX after the browser is in a “ready state”. If your next interaction with the page required these elements to be present, you would need to handle it with a wait for a condition.

    By the way, if you find that the page transition wait’s do not work reliably for you, please share the case by adding a comment below. It is worth noting that WebDriver documentation does say:

    “Dependent on several factors, including the OS/Browser combination, WebDriver may or may not wait for the page to load. In some circumstances, WebDriver may return control before the page has finished, or even started, loading. To ensure robustness, you need to wait for the element(s) to exist in the page using Explicit and Implicit Waits.”

    Again, I didn’t run into the situation where WebDriver didn’t detect the page transition correctly yet.

    A simple test that demonstrates this is:

    @Test
    public void simpleTest() {
        WebDriver driver = new FirefoxDriver();
        driver.get("http://referencewebapp.qaautomation.net/");
        driver.findElement(By.linkText("Register")).click();
    
        // Check for body header on new page.<br />
        WebElement bodyHeader = driver.findElement(By.id("body_header"));
        assertEquals("Page body header match failed", "Register", bodyHeader.getText());
        driver.close();
    }
    

    Here you can see I didn’t have to specify a wait between lines 5 and 8.

    Now what if we want to specify how much the max wait time for a page transition should be? To do this in WebDriver you will have to add the following line:

        driver.manage().timeouts().pageLoadTimeout(90, TimeUnit.SECONDS);
    

    We will look into what driver.manage().timeouts() returns a little later, but the key thing to note here is that there is a mechanism to specify the page load timeout. You could set this anywhere you want but I would imagine for most scenarios you may want to specify this right after initializing the driver.

    Wait for a condition

    When we have asynchronous processing either on the web page or even in a different system, before you can do your validation or next browser interaction you will need to wait. If you don’t wait for these process(es) to complete, you will see unreliable results.

    Let us see an example of such an error. Let us write a test that navigates to http://referencewebapp.qaautomation.net/progressbar.php and validates the progress text of "Process completed!".

    Process 4 complete

    @Before
    public void initialize() {
        WebDriver driver = new FirefoxDriver();
        driver.get("http://referencewebapp.qaautomation.net/progressbar.php");
    }
    
    @Test
    public void getProcessTextWithoutWaiting() {
        WebElement progressBar4CommentElement = driver.findElement(By.id("pb4_comment"));
        assertNotNull("Could not find progress bar 4", progressBar4CommentElement);
        assertEquals("Insufficient progress (" + driver.findElement(By.id("pb4_pbText")).getText() + ")",
                "Process completed!", progressBar4CommentElement.getText());
    }
    

    You will notice that we don’t get the expected text of “Process completed!” after the page is loaded. Instead, you will see failures with varying progress bar values. On my machine I see:

    org.junit.ComparisonFailure: Process running (5/100) 
    Expected : Process completed!
    Actual   : Process running...
    

    If you look at the DOM of this page, you will notice that there is an element with id=pb4_status that appears after the progress bar is completely loaded. If you were just to add

    driver.findElement(By.id("pb4_status"));
    

    in the above test, it would fail with an exception

    org.openqa.selenium.NoSuchElementException: Unable to locate element: {"method":"id","selector":"pb4_status"}
    

    So, in this case, the validation of the process completion message can be fixed if we wait for this progress status element. Broadly you have two choices on how you can implement this wait for condition. Let us look at them:

    Implicit Waits

    WebDriver has the ability to poll the DOM for element(s). Use of this capability of WebDriver, as opposed to building your own logic to wait for the element(s), is called an Implicit Wait.

    The way you add this implicit wait is by instantiating an implementation of the WebDriver.Timeouts interface. This implementation allows you to specify how long web driver should keep looking (poll) for an element whenever you use try retrieving an element using findElement or findElements method in the page before failing. The way you would set this implict wait is by calling the implicitlyWait method.

    So using this let us create a new test:

    @Test
    public void implicitWaitForProcessStatus() {
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        WebElement progressBar4CommentElement = driver.findElement(By.id("pb4_comment"));
        assertNotNull("Could not find progress bar 4", progressBar4CommentElement);
    
        driver.findElement(By.id("pb4_status"));
        assertEquals(progressBar4CommentElement.getText(),
                "Process completed!", progressBar4CommentElement.getText());
    }
    

    You will now notice that your test passes! By adding the implicit wait in line 3, WebDriver now does not throw an exception on line 7 and instead polls for the pb4_status element on the page. So once the element exists only then it goes to the next statement where the assertion passes. The maximum time WebDriver polls for this element is 10 seconds, which is specified in the implicitWait call in line 3.

    You can always remove this implict wait by resetting the timeout to zero:

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

    Explicit Waits

    When you build your own logic on how to wait for conditions and you call it between browser interactions, it is called an explicit wait. In this case, since it is your logic, you can build it to do more than just look for an element or elements that match a single criteria. For example you could cater to

    • wait for multiple elements on a page that need a different way to look up i.e. different locators
    • wait for other types of events on the page, like new dialogs (alerts, confirmation), browser windows etc
    • wait for an external system to complete processing etc

    This can be done in different ways. Let us look at some options:

    Fixed delays

    The most common problem that I have seen in tests is when they  have a fixed amount of wait time. An example of how it could be implemented in java is Thread.sleep(milliseconds). If you compare this with waiting for a specific condition, like appearance or disappearance of an element on the page, it is obvious that there could be a lot of wasted time because of all these delays in your tests. I have dedicated a special section at the end of this post with my thoughts on how bad this practice is and why people end up doing this anyways. But for now let’s just move on to options that you would actually want to consider.

    Explicit wait using WebDriver

    Within the WebDriver API you will find WebDriverWait. There are several very good code designs in WebDriver. WebDriverWait is another example. If you understand how it works, you can appreciate how much flexibility it can provide. Let us see an example of how you can use it.

    @Test
    public void explicitWaitUsingWebDriver() {
        WebElement progressBar4CommentElement = driver.findElement(By.id("pb4_comment"));
        assertNotNull("Could not find progress bar 4", progressBar4CommentElement);
    
        Wait<WebDriver> wait = new WebDriverWait(driver, 10);
        // Wait for search to complete
        wait.until(new ExpectedCondition<Boolean>() {
            public Boolean apply(WebDriver webDriver) {
                System.out.println("Searching...");
                return webDriver.findElement(By.id("pb4_status")) != null;
            }
        });
    
        assertEquals(progressBar4CommentElement.getText(),
                "Process completed!", progressBar4CommentElement.getText());
    }
    

    Here we have used WebDriverWait to wait until an ExpectedCondition implementation we created as an anonymous class passes. In this implementation, on line 10, we added our condition – which is to wait for the pb4_status element.

    Another class that WebDriver comes with is ExpectedConditions (note the s at the end of the class name). Using this class you can avoid writing your own implementation of ExpectedCondition (no s at the end of this class name). Using the method presenceOfElementLocated of this class the above test would look like this:

    @Test
    public void explicitWaitUsingExpectedConditions() {
        driver.get(REFERENCE_APP_URL + "progressbar.php");
        WebElement progressBar4CommentElement = driver.findElement(By.id("pb4_comment"));
        assertNotNull("Could not find progress bar 4", progressBar4CommentElement);
    
        Wait<WebDriver> wait = new WebDriverWait(driver, 10);
        // Wait for search to complete
        wait.until(ExpectedConditions.presenceOfElementLocated(By.id("pb4_status")));
    
        assertEquals(progressBar4CommentElement.getText(),
                "Process completed!", progressBar4CommentElement.getText());
    }
    

    I could write an entire post on how to use the WebDriverWait and what type of conditions we could specify. If this is something that interests you, let me know by adding a comment at the bottom of this post. If I see a lot of interest, I will add it soon.

    Let us look at one other option …

    Build your wait logic not using WebDriver

    There may be some situations when you can’t or don’t want to use use WebDriver API. Some such situations are:

    Since Selenium 1 didn’t provide a good way to wait for complex conditions, you might have created your own polling logic … I certainly did. If you think that would still do what you need and you don’t want to take on the risk to porting it to WebDriver’s implementation, you could.

    Let us say you want to poll on external systems to complete some asynchronous processing, you may or may not be able to use WebDriverWait (or its parent FluentWait).

    FluentWait is not thread safe. If you need something thread safe, you will have to build it yourself.

    Some challenges with Waits

    I have witnessed multiple times test frameworks being scrapped because they were slow and/ or unreliable. The biggest factor … improper wait logic implementations. The list of mistakes framework developers make with waits is pretty long, but here are some of the most common reasons and ways to fix it:

    • Most of the times framework developers are volunteering their time to work on this project or they are under a lot of time pressure and take shortcuts. Several people think adding fixed waits requires a lot lesser work than building a wait for a condition logic. Hopefully with this post you can see it doesn’t have to be much work for majority of the cases. There are several ways to work in such high pressure environments including learning how to build incrementally. The trick here is to never loose focus on speed and reliability of what you build even if what you build might be fewer in capabilities at the beginning.
    • There are several conditions you need to wait for which causes some complications in building wait logic … for instance there could be multiple widgets on a page. Couple of the most simplest solutions people should consider are
      • you don’t have to wait for all the dynamic elements on the page but only the one that you need to interact with
      • you don’t have to only wait for an element to appear, you could also wait for an element to disappear. A simple example is the hourglass or spinners that ajax widgets usually have when they are loading. You could just wait for all spinners to stop being visible on the page.
    • It could be that the functionality needs to be wrapped in a more domain specific api/ reusable function and you want to hide the details of what to wait for from the users and it is different for each situation. In some cases waiting for spinners idea mentioned above could solve the problem. The other option is to ask the UI developers to add some hint on the page – for instance a loadcomplete javascript variable on the page which turns to “true” after the dynamic element is loaded.

    This topic is pretty vast so if you think there are some key aspects that this post should cover, please send me your feedback below and I will try to incorporate them.

    Posted by Rahul Poonekar in : Selenium

    27 responses to “Waiting after web page interactions”

    1. Iain Rose says:

      Great post, IMO the handling of waits is one of the most delicate aspects of working on an automation framework.

      I have a few points to raise …

      “In some cases the major reason for the slowness were explicit waits added in the test framework”

      Do you mean static waits? Explicit waits to me mean waiting for a specific condition after an action, these will usually only take the exact amount of time they need. Using an explicit wait should not slow down a test at all.

      Don’t think we need to discuss static waits as the issue with those are clear.

      I started off loving implicit waits until I needed to start checking for the absence of an element. I find that checking for the absence of an element in a test once or twice negates any benefit I get from not creating an explicit wait when I write the test.

      I’m about to remove the implicit wait statement from my frame work and expect a lot of failed tests that need an explicit wait to be added in replacement but going forward I think the effort will pay off.

    2. Iain Rose says:

      Also don’t forget about the built in ExpectedConditions

      http://selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html

      Your explicit wait example of …

      // Wait for search to complete
      wait.until(new ExpectedCondition() {
      public Boolean apply(WebDriver webDriver) {
      System.out.println(“Searching…”);
      return webDriver.findElement(By.id(“pb4_status”)) != null;
      }
      });

      could also be written as

      // Wait for search to complete
      wait.until(ExpectedConditions.presenceOfElementLocated(By.id(“pb4_status”)));

    3. Rahul Poonekar says:

      Thanks for sharing your experience with implicit and explicit waits Iain. Considering that you already have so much of your framework code relying on implicit waits, have you considered switching between implicit and explicit waits?

      When I said “explicit wait” in that sentence I was indeed referring to fixed waits. I have now made what type of explicit wait I was referring to more explicit (pun intended). 🙂

    4. Rahul Poonekar says:

      Thanks Iain! I have added your example in the post.

    5. Iain Rose says:

      Yes, I have definitely considering ripping out my implicit waits, just need to choose a time when I can dedicate the effort to get things working again with specific explicit waits for each action that needs them.

      It’s on my list and I’ll report back when I’m done and let you know if I think the effort was worth it.

    6. Rahul Poonekar says:

      In your first comment I understood you were considering removing implicit waits completely. That’s not what I meant when I said “switching between explicit and implicit waits”. What I meant was that you keep your implicit wait setting as default, and only when you need an explicit wait, turn implicit wait off by calling

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

      You can always turn it back on once you don’t need to do explicit waits anymore. This ofcourse assumes you don’t run into situations where you have to do this (check for absence of an element etc) often.

      Best of luck and let us know how it goes. Thanks

    7. JoshL says:

      Just found your pages on WebDriver and these are fantastic. It’s a mystery to me why the Selenium people can’t have writeups that are this good and this useful. Thanks for your hard work and explicitly clear instructions!

    8. Iain Rose says:

      Hey again,

      I just finished my transition. Took a while but I was working on it passively. I switched them off locally but left them enabled in the repo, as I worked on new tests and maintained old ones I slowly got the page objects to a state where they worked without them.

      I have now dropped all usages of implicit waits from my framework. Run time decreased from 100 mins to 47mins.

    9. Rahul Poonekar says:

      That is a dramatic drop in execution time! I would never have guessed the difference would be this much. This alone makes all your effort worth it 🙂

    10. Radeesh says:

      This post is awesome, please add more details on WebDriverWait, I would like to know more on how to do waits more efficiently.

    11. Preemo says:

      Perfect post – more information about waiting will be cool – mastering Wait art saves time and makes tests stable. BTW all your posts are HQ!

    12. Rahul Poonekar says:

      Thanks. Can you give me some ideas of what types of challenges with waits would you like covered?

    13. Divya says:

      Excellent info. This will be my first source to refer whenever I have questions, doubts or need some info. I am a newbie into Selenium and found this one space THE Best Knowledge Source.

    14. JoshL says:

      When do you think you’ll post the next guide?

    15. JoshL says:

      It’s been a few months and no word. How’s it going?

    16. Gayatri says:

      Thanks a lot for all the explination.
      Could you please explain when is it prefferd to used WaitUntil() and FluentWait()?

    17. chandrasekhar says:

      looking ahead for explanation on Window, frames and Popup dialog handling.

    18. Pet says:

      Hello all.

      I need some more help here. I have some kind of automated tests.
      They worked very well for a long time, but suddenly, they changed this behavior.

      My problem is when the URL I am trying to get with my WebDriver object
      is frozen for some reason. If it has very slow response from server or something else.
      The browser opens, but I get nothing from it (or get just 2 or 3 pages) and the execution stops forever.

      So the program stops in the Webdriver object get exection forever (and the WebDriver’s indicator is staying colored in red),
      untill I see that it stopped and close it by hand.

      The only change is that now I use https instead http. Could it be the reason for frozen WebDriver?

      I need to treat that someway… anyone has done that?

      Thank you very much in advance.

    19. Ayan Modak says:

      Wonderful post. I have learned many things from this site. It is worthy reading.

      Waiting for the next post on Window, frames and Popup dialog handling.

      I highly appreciate your hard work on this.

    20. Faith says:

      Your article is really great!!! I’ve been looking around for something to help me out…I have these tests that fail once in a while, and I wasn’t sure on how to use anything other than thread.sleep! Really liked the ExpectedConditions, hope you write more. 😀

    21. Vishal says:

      Please post the next session.

    22. TargetHwk says:

      Hi ,
      Really useful clear information on Wait. I have a scenario where I do some action on the webpage and get a banner message. I do not know when I get the message sometimes it comes immediately or it takes time. What do you suggest for this scenario. I need to capture the banner message and do assertion on that. Appreciate your help .Thank you

    23. Ritu says:

      Hi,

      We are automating the application thru Selenium IE Web Driver -Java and using selenium ver 2.42 on windows and IE 8.0. After implementing explicity wait the problem do not resolve. The control is not coming out of this statement “driver.switchTo().window(windowId);” the case is “After submitting valid user credentials, user logged into successfully ” and landed home page that have menus for different action. To move on home page, we used “driver.switchTo().window(windowId);” We could see home page with menus but control is not coming out of this statement and even no exception is coming. When we dug up further we came to know that on the menu page, onload is used and due to this the problem is coming. Same problem with Onclick too. Could you pl see. Thank you.

    24. Dharmesh says:

      Why my browser is not invoked by WebDriver driver = new FirefoxDriver(); line .. y do i have to specify binary path and profle.
      Ws Os 7
      Selenium 2.42v
      Firefox 32v

    25. babu says:

      any idea how to handle if the browser keeps spinning and not in ready state?

    26. Putz says:

      Hey, thanks for this post, helped me out, but I have one question: What can I do if the page has a delay when I click for the sorting? I had the solution with an expected condition and a document.readyState, but this doesn’t work with the described delay.
      Another problem is that I can’t wait for a certain Text or item to appear, because the overall structure of the page stays the same and just dynamic created objects are loaded, so what could I do?
      I really don’t want to use a static wait because it would slow down the execution of the tests drastically.
      Thx for any recommendations.

    27. RadioSky says:

      Here is a patch I came up with that you can easily drop in spec/support. It reeovms the need to sleep by retrying. It’s working like a charm!# This patch attempts to fix a race condition in the selenium web driver# Reference: class Capybara::Selenium::Driver def find(selector) browser.find_elements(:xpath, selector).map { |node| Capybara::Selenium::Node.new(self, node) } rescue Selenium::WebDriver::Error::UnhandledError => e e.message =~ /nsIDOMXPathEvaluator.createNSResolver/ ? retry : raise endend

    Leave a Reply

    Your email address will not be published. Required fields are marked *