23

Is there a universal approach for Selenium to wait till all ajax content has loaded? (not tied to a specific website - so it works for every ajax website)

Fabian Lurz
  • 2,029
  • 6
  • 26
  • 52

4 Answers4

31

You need to wait for Javascript and jQuery to finish loading. Execute Javascript to check if jQuery.active is 0 and document.readyState is complete, which means the JS and jQuery load is complete.

public boolean waitForJSandJQueryToLoad() {

    WebDriverWait wait = new WebDriverWait(driver, 30);

    // wait for jQuery to load
    ExpectedCondition<Boolean> jQueryLoad = new ExpectedCondition<Boolean>() {
      @Override
      public Boolean apply(WebDriver driver) {
        try {
          return ((Long)((JavascriptExecutor)getDriver()).executeScript("return jQuery.active") == 0);
        }
        catch (Exception e) {
          // no jQuery present
          return true;
        }
      }
    };

    // wait for Javascript to load
    ExpectedCondition<Boolean> jsLoad = new ExpectedCondition<Boolean>() {
      @Override
      public Boolean apply(WebDriver driver) {
        return ((JavascriptExecutor)getDriver()).executeScript("return document.readyState")
        .toString().equals("complete");
      }
    };

  return wait.until(jQueryLoad) && wait.until(jsLoad);
}
LINGS
  • 3,560
  • 5
  • 34
  • 47
  • 1
    Thanks :) Will this work with every website or only with the websites using jQuery? – Fabian Lurz Oct 26 '15 at 15:15
  • Will work on any website, it handles presence and absence of Jquery and JS – LINGS Oct 26 '15 at 15:16
  • Thanks - i'll give it a try now – Fabian Lurz Oct 26 '15 at 15:16
  • Great. It seems to work - does this also work with angularjs? Also - i'm not 100 aware of document.readyState - does this include if a webpage loads content via ajax? (e.g. Pinterest?) – Fabian Lurz Oct 26 '15 at 15:33
  • @FabianLurz Yes I have been using it on pages with angularJs, it works well. AJAX page load will also fall under jQuery/JS and hence it should handle it as well. – LINGS Oct 26 '15 at 15:42
  • @FabianLurz remember to make a call to this method every time your action on the webpage could potentially trigger an AJAX call or JS/Jquery load. Sometimes, the load may be complete but the element you want to interact with may not be accessible, in that case you have to wait for the element. – LINGS Oct 26 '15 at 15:45
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/93383/discussion-between-lings-and-fabian-lurz). – LINGS Oct 26 '15 at 15:45
  • This is great! Thanks for sharing. – JeffC Oct 26 '15 at 16:53
  • @LINGS What is a correct method to call this with waiting? – Ishita Shah Apr 09 '18 at 05:33
  • Quick question guys, I'm just starting with a Cucumber Java framework and still don't know where all parts go. I tried creating a "public bool waitForJSandJQueryToLoad" method under "src/test/java/pages/helpers", but IntelliJ IDE fails to recognising it saying => "class or interface expected". Do you know where or how I should integrate this with my framework? – mickael Jul 07 '18 at 19:09
4

As Mark Collin described in his book "Mastering Selenium Webdriver", use JavascriptExecutor let you figure out whether a website using jQuery has finished making AJAX calls

public class AdditionalConditions {

  public static ExpectedCondition<Boolean> jQueryAJAXCallsHaveCompleted() {
    return new ExpectedCondition<Boolean>() {

        @Override
        public Boolean apply(WebDriver driver) {
            return (Boolean) ((JavascriptExecutor) driver).executeScript("return (window.jQuery != null) && (jQuery.active === 0);");
        }
    };
  }
}
T J
  • 42,762
  • 13
  • 83
  • 138
Slav Kurochkin
  • 444
  • 3
  • 9
  • Thanks for your hint. But what if a side doesn't use jQuery? – Fabian Lurz Oct 26 '15 at 15:03
  • Well if you have other javascript library you would need to rely on it. In the same book he has example for AngularJS, otherwise I would agree with another answer you have to be domain specific, and use [Explicit and Implicit Waits](http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp#explicit-and-implicit-waits) – Slav Kurochkin Oct 26 '15 at 15:15
2

I have been using this simple do while to iterate until an AJAX is finished. It consistently works for me.

public void waitForAjax() throws InterruptedException{
    while (true)
    {
        Boolean ajaxIsComplete = (Boolean) ((JavascriptExecutor)driver).executeScript("return jQuery.active == 0");
        if (ajaxIsComplete){
            info("Ajax Call completed. ");
            break;
        }
        Thread.sleep(150);
    }
}
0

I don't believe that there is a universal approach out of the box. I typically make a method that does a .waituntilrowcount(2) or waituntilvisible() that polls an element.

T J
  • 42,762
  • 13
  • 83
  • 138
eagle12
  • 1,658
  • 11
  • 14
  • Hm - dammn. Is there any other library that is capable of crawling ajax websites? Tried selenium, htmlunit and crawljax. Problem htmlunit: Very sensitive against error and u can't turn it off. Crawljax: Probably capable of crawling ajax but you can't get the html of a webpage - ouch selenium: see question ;) – Fabian Lurz Oct 26 '15 at 15:05