Question

There is this rather interesting problem. I will provide some context because a lot of people might ask why somebody would need something like this.

Background info

Have to make unit (integration) tests for large and complicated .net web forms app. Currently using visual studio 2010, nunit, watin 2.1, ie9. There already are a few hudred rather complicated unit tests but they are slow, not very reliable mainly because of timing issues. So have to get execution time down from many many hours to something more reasonable and keep them reliable.

Current problem

I have some problems with waiting for async requests to be completed. (This needs to be done to get updated page from screen for testing.) The current situation looks something like this:

//Function is called after making an async request to wait for DOM to be updated
    public static void WaitForAsyncPostBackToComplete(this Browser browser)
    {
        int waited = 0;
        bool isInPostback = true;
        while (isInPostback)
        {
            if (waited > AjaxWaitTime)
            {
                throw new Exception(string.Format(
                    "Looks like Ajax reqest timed out. Test waited {0} milliseconds.",
                    waited));
            }
            isInPostback = IsInPostback(browser);
            if (isInPostback)
            {
                // Request is not completed, wait a bit for next polling.
                Thread.Sleep(AjaxSleepTime);
                waited += AjaxSleepTime;
            }
        }
        // IMPORTANT: Wait for DOM to be actually updated???
        Thread.Sleep(300);
    }

    // Check if something is in postback now.
    private static bool IsInPostback(Browser browser)
    {
        string function =
            "(  typeof(Sys) === undefined " +
            "|| Sys == undefined || Sys == 'undefined' || Sys==null " +
            "|| typeof(Sys.WebForms) === undefined " +
            "|| Sys.WebForms==null || Sys.WebForms==undefined|| Sys.WebForms=='undefined'" +
            "|| typeof(Sys.WebForms.PageRequestManager) === undefined) " +
            "|| Sys.WebForms.PageRequestManager==null || Sys.WebForms.PageRequestManager==undefined|| Sys.WebForms.PageRequestManager=='undefined'" +
            "? true " +
            ": Sys.WebForms.PageRequestManager.getInstance().get_isInAsyncPostBack();";

        string result = browser.EvalSafely(function);
        return Convert.ToBoolean(result);
    }

So I am pooling very often to check if ajax request is completed with IsInPostback() function. This seems to work pretty fast and reliably.

However I think that IsInPostback() says that everything is done before it is actually inserted in DOM. That means we got the answer, but we need some time to insert it here. Because of this I need that ugly Thread.Sleep(300) line to wait for DOM to be updated. I would like to make that line go away by somehow determining when DOM is updated more precisely and reliably.

The real question

Is there any good way to determine that DOM is loaded in IE9 with async madness going on? I have been thinking about simply getting entire DOM in variable (how could it even work if DOM is changing) and polling to check for changes in it. If no changes are made for like last 50ms, I could stop waiting. Is there any good way to do something like this?

Any thoughts are welcome ....

Was it helpful?

Solution 2

This question is very old, but it still gets some views, so I thought about adding some afterthoughts about this problem.

After reading some documentation (that is not very detailed for such a specific case) and doing some experiments I came to the conclusion that Sys.WebForms.PageRequestManager.getInstance().get_isInAsyncPostBack(); method should exit (return true) only after DOM update is completely finished.

However it turned out to be pretty hard to use this kind of approach with high precision because in ASP.NET Web Forms and we did not have complete control of the JS that was generated. So if there are multiple requests after one user action because of nested update panels, or there are some delayed updates or some inconsistencies in execution of JavaScript this kind of approach is not 100% stable.

In the end there probably are two possible partial solutions:

  1. Accept that this kind of approach does not work accurately in 100% of the cases and deal with it higher levels of abstraction.
  2. Add other layers on top of this function (for better dealing with multiple AJAX requests in a row or delayed requests) and combine it with smaller waiting times.

Either way there seems to be no clear cut answer that works in 100% of the cases with no explicit waiting in the thread.

This question is very specific and probably cannot get any answers that could be accepted in the future, but I think it contains some interesting points, so I will leave the question open here and accept these afterthoughts.

OTHER TIPS

You can set the 'Ajax Requests Completed Flag' from javascript and check it in C#.
HTML:

<input type='hidden' id='hdnRequestCompletedFlag' value='0' />

Javascript:

var NoOfCompletedRequests = 0;
var NoOfRequests = 10; // Your number of requests.
$.ajax({
    ...,
    success: function( data ) { // This function same for all the ajax requests.
        NoOfCompletedRequests++;
        if(NoOfCompletedRequests == NoOfRequests)
            $('#hdnRequestCompletedFlag').val('1');
    }
});

C#:

private static bool IsInPostback(Browser browser)
{
    string function =
        "(  typeof(Sys) === undefined " +
        "|| Sys == undefined || Sys == 'undefined' || Sys==null " +
        "|| typeof(Sys.WebForms) === undefined " +
        "|| Sys.WebForms==null || Sys.WebForms==undefined|| Sys.WebForms=='undefined'" +
        "|| typeof(Sys.WebForms.PageRequestManager) === undefined) " +
        "|| Sys.WebForms.PageRequestManager==null || Sys.WebForms.PageRequestManager==undefined|| Sys.WebForms.PageRequestManager=='undefined'" +
        "? true " +
        ": Sys.WebForms.PageRequestManager.getInstance().get_isInAsyncPostBack();";

    string result = browser.EvalSafely(function);
    return Convert.ToBoolean(result) && (hdnRequestCompletedFlag.Value == '1');
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top