How to make Selenium WebDriver wait for the page load when a new page is loaded via JS event

I am working on automating a site with multiple links that load new pages via a JS event. Basically, there are items that can be clicked, clicking one at a time triggers JavaScript to run, and this causes the form to be submitted and routed to a new page.

Now if these were just standard HTML links there would be no problem as Selenium is smart enough to say there is a new page and wait to do something. But it's so good that Selenium can't tell that clicks on that instance are causing new pages to load, so they don't wait and just keep going. So it doesn't wait for a new page, tries to find elements that aren't there, and my tests don't work. Bummer.

As a workaround, I simply pause the program for three seconds:

oldPageDriver.clickThatButton();

try {
  Thread.sleep(3000);
} catch(InterruptedException ex) {
  Thread.currentThread().interrupt();
}

newPageDriver = new NewPageDriver(driver);
newPageDriver.doStuffOnNewPage();

      

And it works like. I don't like this because it is "hacked" and just interrupts the program and doesn't make something smarter. Since the delay is hardcoded after three seconds, I get crashes if the link works but is just slow. I've looked into something like implicit wait, but it does the same thing, and I haven't found a reliable, workable Java answer anywhere after considerable searching.

So, can anyone suggest a way to get around this? Specifically, how do you make Selenium know that a new page is expected and wait until it appears?

+3


source to share


3 answers


Explicit expectations are what you need;

http://docs.seleniumhq.org/docs/04_webdriver_advanced.jsp



You can add this directly to your test, or you might want to dry it out, especially if there is a general expectation of expectation such as the pictogram disappearing.

You can extend the click method to always wait after being clicked, or if the following page objects are present, add the wait_until_loaded method to the base class of the page. There are many other valid approaches out there, but depends on how the AUT is implemented.

+3


source


Waiting for the document.ready event is not a complete fix for this problem, because this code is still in a race condition: sometimes this code runs before the click event is handled, so this is returned directly as the browser hasn I started loading a new one page.

After some searching I found a post on Obay the test goat which has a solution for this problem. The C # code for this solution looks something like this:



 IWebElement page = null;
 ...
 public void WaitForPageLoad()
 {
    if (page != null)
    {
       var waitForCurrentPageToStale = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
       waitForCurrentPageToStale.Until(ExpectedConditions.StalenessOf(page));
    }

    var waitForDocumentReady = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
    waitForDocumentReady.Until((wdriver) => (driver as IJavaScriptExecutor).ExecuteScript("return document.readyState").Equals("complete"));

    page = driver.FindElement(By.TagName("html"));

}

      

`I run this method directly after driver.navigate.gotourl so that it gets the link to the page as soon as possible. Have fun with it!

+6


source


A simple ready2use snippet working fine for me

static void waitForPageLoad(WebDriver wdriver) {
    WebDriverWait wait = new WebDriverWait(wdriver, 60);

    Predicate<WebDriver> pageLoaded = new Predicate<WebDriver>() {

        @Override
        public boolean apply(WebDriver input) {
            return ((JavascriptExecutor) input).executeScript("return document.readyState").equals("complete");
        }

    };
    wait.until(pageLoaded);
}

      

+3


source







All Articles