21

Some of the sites I deal with have heavy ajax requests. I plan to wait for Ajax request completion before clicking for asserting for element. Currently I use

try {
    if (driver instanceof JavascriptExecutor) {
        JavascriptExecutor jsDriver = (JavascriptExecutor)driver;

        for (int i = 0; i< timeoutInSeconds; i++) 
        {
            Object numberOfAjaxConnections = jsDriver.executeScript("return jQuery.active");
            // return should be a number
            if (numberOfAjaxConnections instanceof Long) {
                Long n = (Long)numberOfAjaxConnections;
                System.out.println("Number of active jquery ajax calls: " + n);
                if (n.longValue() == 0L)  break;
            }
            Thread.sleep(1000);
        }
    }
    else {
       System.out.println("Web driver: " + driver + " cannot execute javascript");
    }
}
catch (InterruptedException e) {
    System.out.println(e);
}

But it works well for Ajax requests but not for any similar requests with variants of jQuery libraries.

Note:

document.readyState == 'complete'

It doesn't work for Ajax requests or any other similar alternatives.

Neither tests are written by me or belong to single webapp. So I can't edit the webapp.

9
  • Do you mean you in other sites ajax calls are made without jquery? What's the purpose of injecting jquery? Commented Jun 19, 2014 at 4:55
  • Question is why you need that Commented Jun 19, 2014 at 5:31
  • If asynchronous requests are sent using other libraries like vanilla, does jquery.active still work? If not then I am asking wrong question. Commented Jun 19, 2014 at 8:09
  • If your application does not use jquery, you don't have any point of injecting it to the application. Commented Jun 19, 2014 at 8:11
  • 2
    Have you checked this SO question : How to check if HTTP requests are open in browser? Commented Jun 23, 2014 at 12:12

4 Answers 4

13

I found the answer and it worked for few Ajax and non-ajax sites I checked. After this patch I no longer need to do implicit waits even for ajax heavy pages, LeGac pointed out the following code in one of his comments to the question.

public static void checkPendingRequests(FirefoxDriver driver) {
    int timeoutInSeconds = 5;
    try {
        if (driver instanceof JavascriptExecutor) {
            JavascriptExecutor jsDriver = (JavascriptExecutor)driver;

            for (int i = 0; i< timeoutInSeconds; i++) 
            {
                Object numberOfAjaxConnections = jsDriver.executeScript("return window.openHTTPs");
                // return should be a number
                if (numberOfAjaxConnections instanceof Long) {
                    Long n = (Long)numberOfAjaxConnections;
                    System.out.println("Number of active calls: " + n);
                    if (n.longValue() == 0L)  break;
                } else{
                    // If it's not a number, the page might have been freshly loaded indicating the monkey
                    // patch is replaced or we haven't yet done the patch.
                    monkeyPatchXMLHttpRequest(driver);
                }
                Thread.sleep(1000);
            }
        }
        else {
           System.out.println("Web driver: " + driver + " cannot execute javascript");
        }
    }
    catch (InterruptedException e) {
        System.out.println(e);
    }    
}



public static void monkeyPatchXMLHttpRequest(FirefoxDriver driver) {
    try {
        if (driver instanceof JavascriptExecutor) {
            JavascriptExecutor jsDriver = (JavascriptExecutor)driver;
            Object numberOfAjaxConnections = jsDriver.executeScript("return window.openHTTPs");
            if (numberOfAjaxConnections instanceof Long) {
                return;
            }
            String script = "  (function() {" +
                "var oldOpen = XMLHttpRequest.prototype.open;" +
                "window.openHTTPs = 0;" +
                "XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {" +
                "window.openHTTPs++;" +
                "this.addEventListener('readystatechange', function() {" +
                "if(this.readyState == 4) {" +
                "window.openHTTPs--;" +
                "}" +
                "}, false);" +
                "oldOpen.call(this, method, url, async, user, pass);" +
                "}" +
                "})();";
            jsDriver.executeScript(script);
        }
        else {
           System.out.println("Web driver: " + driver + " cannot execute javascript");
        }
    }
    catch (Exception e) {
        System.out.println(e);
    }
}

After every step you would need to call

checkPendingRequests(driver);
Sign up to request clarification or add additional context in comments.

3 Comments

Are you sure that it's javascript? It looks like java
in the angular app, this script is giving below warning in browser console and my service calls are failing too. [Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check xhr.spec.whatwg.org.
This is racy. You will get times when the page has already fired off ajax before your script runs. The best way to do this is with a browser extension. But that doesn't work for Chrome Headless mode.
2

This doesn't work? http://api.jquery.com/ajaxstop/

$(document).ajaxStop(function() {
    // Do stuff here...    
});

1 Comment

No it works only for ajax but the requests can be of any type.
1

If you are using JSONP requests, you need to enable the active handling:

jQuery.ajaxPrefilter(function( options ) {
    options.global = true;
});

I think that the use of active is correct, but possibly the way you have used might return false in the instanceof conditions.

Optionally, see another way to wait for jQuery ajax calls using active in Selenium tests:

browser.wait_for_condition("selenium.browserbot.getCurrentWindow().jQuery.active === 0;", '30000')

Comments

-3

Based on our discussion over the comments, this might work for you.

With prototype.js:

var ACTIVE_REQUESTS = 0; // GLOBAL

ACTIVE_REQUESTS++
new Ajax.Request('/your/url', {
  onSuccess: function(response) {
    ACTIVE_REQUESTS--;
    // Handle the response content...
  }
}));

console.log("there are " + ACTIVE_REQUESTS + " open AJAX requests pending");

With plain script:

interValRef = 0;

interValRef = setInterval("checkState();",100)

function checkState(){
    if(document.readyState == 'complete'){
        clearInterval(interValRef);
        myFunc();
    }
}

Source: Check Pending AJAX requests or HTTP GET/POST request

1 Comment

Doesnt work for me. I have checked with a pending ajax request. document.readyState is always 'complete'. checkout this tinypic.com/r/mr4qis/8. even with pending ajax requests, document.readyState is 'complete'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.