Raghubansh
Raghubansh

Reputation: 341

How I can check whether a page is loaded completely or not in web driver?

I am writing some Java Webdriver code to automate my application. How can I correctly check whether the page has been loaded or not? The application has some Ajax calls, too.

I have declared an implicit wait for WebDriver.

Upvotes: 34

Views: 156041

Answers (10)

Kamran
Kamran

Reputation: 749

The solution is using Implicit Wait which will solve your problems of page load.

WebDriverWait waitForElement = new WebDriverWait(driver, 15);
WebElement element = driver.findElement(By.id("myElement"));
element.click(); 
wait.until(ExpectedConditions.visibilityOf(element));

Upvotes: 0

Yoan Kliavkov
Yoan Kliavkov

Reputation: 11

You can get the HTML of the website with driver.getPageSource(). If the html does not change in a given interval of time this means that the page is done loading. One or two seconds should be enough. If you want to speed things up you can just compare the lenght of the two htmls. If their lenght is equal the htmls should be equal and that means the page is fully loaded. The JavaScript solution did not work for me.

Upvotes: 0

Bedirhan
Bedirhan

Reputation: 89

I know this post is old. But after gathering all code from above I made a nice method (solution) to handle ajax running and regular pages. The code is made for C# only (since Selenium is definitely a best fit for C# Visual Studio after a year of messing around).

The method is used as an extension method, which means to put it simple; that you can add more functionality (methods) in this case, to the object IWebDriver. Important is that you have to define: 'this' in the parameters to make use of it.

The timeout variable is the amount of seconds for the webdriver to wait, if the page is not responding. Using 'Selenium' and 'Selenium.Support.UI' namespaces it is possible to execute a piece of javascript that returns a boolean, whether the document is ready (complete) and if jQuery is loaded. If the page does not have jQuery then the method will throw an exception. This exception is 'catched' by error handling. In the catch state the document will only be checked for it's ready state, without checking for jQuery.

public static void WaitUntilDocumentIsReady(this IWebDriver driver, int timeoutInSeconds) {
    var javaScriptExecutor = driver as IJavaScriptExecutor;
    var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));

    try {
        Func<IWebDriver, bool> readyCondition = webDriver => (bool)javaScriptExecutor.ExecuteScript("return (document.readyState == 'complete' && jQuery.active == 0)");
        wait.Until(readyCondition);
    } catch(InvalidOperationException) {
        wait.Until(wd => javaScriptExecutor.ExecuteScript("return document.readyState").ToString() == "complete");
    }
}

Upvotes: 4

Mykola
Mykola

Reputation: 392

Below is some code from my BasePageObject class for waits:

public void waitForPageLoadAndTitleContains(int timeout, String pageTitle) {
    WebDriverWait wait = new WebDriverWait(driver, timeout, 1000);
    wait.until(ExpectedConditions.titleContains(pageTitle));
}

public void waitForElementPresence(By locator, int seconds) {
    WebDriverWait wait = new WebDriverWait(driver, seconds);
    wait.until(ExpectedConditions.presenceOfElementLocated(locator));
}

public void jsWaitForPageToLoad(int timeOutInSeconds) {
    JavascriptExecutor js = (JavascriptExecutor) driver;
    String jsCommand = "return document.readyState";

    // Validate readyState before doing any waits
    if (js.executeScript(jsCommand).toString().equals("complete")) {
        return;
    }

    for (int i = 0; i < timeOutInSeconds; i++) {
        TimeManager.waitInSeconds(3);
        if (js.executeScript(jsCommand).toString().equals("complete")) {
            break;
        }
    }
}

   /**
     * Looks for a visible OR invisible element via the provided locator for up
     * to maxWaitTime. Returns as soon as the element is found.
     *
     * @param byLocator
     * @param maxWaitTime - In seconds
     * @return
     *
     */
    public WebElement findElementThatIsPresent(final By byLocator, int maxWaitTime) {
        if (driver == null) {
            nullDriverNullPointerExeption();
        }
        FluentWait<WebDriver> wait = new FluentWait<>(driver).withTimeout(maxWaitTime, java.util.concurrent.TimeUnit.SECONDS)
                .pollingEvery(200, java.util.concurrent.TimeUnit.MILLISECONDS);

        try {
            return wait.until((WebDriver webDriver) -> {
                List<WebElement> elems = driver.findElements(byLocator);
                if (elems.size() > 0) {
                    return elems.get(0);
                } else {
                    return null;
                }
            });
        } catch (Exception e) {
            return null;
        }
    }

Supporting methods:

     /**
     * Gets locator.
     *
     * @param fieldName
     * @return
     */
    public By getBy(String fieldName) {
        try {
            return new Annotations(this.getClass().getDeclaredField(fieldName)).buildBy();
        } catch (NoSuchFieldException e) {
            return null;
        }
    }

Upvotes: 0

You can take a screenshot and save the rendered page in a location and you can check the screenshot if the page loaded completely without broken images

Upvotes: -4

Narendra Chandratre
Narendra Chandratre

Reputation: 921

Simple ready2use snippet, working perfectly 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);
}

Upvotes: 7

jmathew
jmathew

Reputation: 1556

You can set a JavaScript variable in your WepPage that gets set once it's been loaded. You could put it anywhere, but if you're using jQuery, $(document).onReady isn't a bad place to start. If not, then you can put it in a <script> tag at the bottom of the page.

The advantage of this method as opposed to checking for element visibility is that you know the exact state of the page after the wait statement executes.

MyWebPage.html

... All my page content ...
<script> window.TestReady = true; </script></body></html>

And in your test (C# example):

// The timespan determines how long to wait for any 'condition' to return a value
// If it is exceeded an exception is thrown.
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5.0));

// Set the 'condition' as an anonymous function returning a boolean
wait.Until<Boolean>(delegate(IWebDriver d)
{
    // Check if our global variable is initialized by running a little JS
    return (Boolean)((IJavaScriptExecutor)d).ExecuteScript("return typeof(window.TestReady) !== 'undefined' && window.TestReady === true");
});

Upvotes: 3

Petr Janeček
Petr Janeček

Reputation: 38434

Selenium does it for you. Or at least it tries its best. Sometimes it falls short, and you must help it a little bit. The usual solution is Implicit Wait which solves most of the problems.

If you really know what you're doing, and why you're doing it, you could try to write a generic method which would check whether the page is completely loaded. However, it can't be done for every web and for every situation.


Related question: Selenium WebDriver : Wait for complex page with JavaScript(JS) to load, see my answer there.

Shorter version: You'll never be sure.

The "normal" load is easy - document.readyState. This one is implemented by Selenium, of course. The problematic thing are asynchronous requests, AJAX, because you can never tell whether it's done for good or not. Most of today's webpages have scripts that run forever and poll the server all the time.

The various things you could do are under the link above. Or, like 95% of other people, use Implicit Wait implicity and Explicit Wait + ExpectedConditions where needed.

E.g. after a click, some element on the page should become visible and you need to wait for it:

WebDriverWait wait = new WebDriverWait(driver, 10);  // you can reuse this one

WebElement elem = driver.findElement(By.id("myInvisibleElement"));
elem.click();
wait.until(ExpectedConditions.visibilityOf(elem));

Upvotes: 48

djangofan
djangofan

Reputation: 29669

Here is how I would fix it, using a code snippet to give you a basic idea:

public class IFrame1 extends LoadableComponent<IFrame1> {

    private RemoteWebDriver driver;

    @FindBy(id = "iFrame1TextFieldTestInputControlID" ) public WebElement iFrame1TextFieldInput;
    @FindBy(id = "iFrame1TextFieldTestProcessButtonID" ) public WebElement copyButton;

    public IFrame1( RemoteWebDriver drv ) {
        super();
        this.driver = drv;
        this.driver.switchTo().defaultContent();
        waitTimer(1, 1000);
        this.driver.switchTo().frame("BodyFrame1");
        LOGGER.info("IFrame1 constructor...");
    }

    @Override
    protected void isLoaded() throws Error {        
        LOGGER.info("IFrame1.isLoaded()...");
        PageFactory.initElements( driver, this );
        try {
            assertTrue( "Page visible title is not yet available.", 
                    driver.findElementByCssSelector("body form#webDriverUnitiFrame1TestFormID h1")
                    .getText().equals("iFrame1 Test") );
        } catch ( NoSuchElementException e) {
            LOGGER.info("No such element." );
            assertTrue("No such element.", false);
        }
    }

    /**
     * Method: load
     * Overidden method from the LoadableComponent class.
     * @return  void
     * @throws  null
     */
    @Override
    protected void load() {
        LOGGER.info("IFrame1.load()...");
        Wait<WebDriver> wait = new FluentWait<WebDriver>( driver )
                .withTimeout(30, TimeUnit.SECONDS)
                .pollingEvery(5, TimeUnit.SECONDS)
                .ignoring( NoSuchElementException.class ) 
                .ignoring( StaleElementReferenceException.class ) ;
        wait.until( ExpectedConditions.presenceOfElementLocated( 
                By.cssSelector("body form#webDriverUnitiFrame1TestFormID h1") ) );
    }
....

Upvotes: 0

Manikandan
Manikandan

Reputation: 417

Recently, when I was dealing with an AJAX application/RIA, I was having the same issue! And I used implicit wait, with a time of around 90 seconds. It waits, till the element is available...So, what we can do to make sure, that page gets loaded completely is,

add a boolean statement, checking for whether the condition(a particular part of the element), is present and assign it to a variable, check for the condition and only when it is true, " do the necessary actions!"...In this way, I figured out, both waits could be used...

Ex:

@Before

{ implicit wait statement}

@Test

{

boolean tr1=Driver.findElement(By.xpath("xx")).isEnabled/isDisplayed;

if (tr1==true && ____)//as many conditions, to make sure, the page is loaded

{

//do the necessary set of actions...
driver.findElement(By.xpath("yy")).click();

}

}

Hope this helps!! It is in implementation stage, for me too...

Upvotes: 1

Related Questions