views:

841

answers:

1

I'm writing WatiN tests to test an Ajax web application and have come across a timing issue with Ajax requests.

After an Ajax request is triggered by an action on the page, I'd like WatiN to wait until the request is complete before validating that the page was updated correctly.

I have a feeling that the solution will involve eval-ing JavaScript to register handlers for $.ajaxStart and $.ajaxComplete to track whether requests are in progress. I'll dig into that shortly, but wanted to see if anybody else has already solved this. Seems like it would be a common problem with Ajax testing.

+4  A: 

I've created a few WatiN Browser extension methods to solve this problem, but am still interested in other solutions.

The InjectAjaxMonitor method creates a javascript global variable that attaches to the ajaxStart and ajaxComplete events to track the number of requests in progress.

Whenever you need to wait for AJAX requests to complete before moving on, you can then call browserInstance.WaitForAjaxRequest();.


public static class BrowserExtensions
{
    public static void WaitForAjaxRequest( this Browser browser )
    {
        int timeWaitedInMilliseconds = 0;
        var maxWaitTimeInMilliseconds = Settings.WaitForCompleteTimeOut*1000;

        while ( browser.IsAjaxRequestInProgress()
                && timeWaitedInMilliseconds < maxWaitTimeInMilliseconds )
        {
            Thread.Sleep( Settings.SleepTime );
            timeWaitedInMilliseconds += Settings.SleepTime;
        }
    }

    public static bool IsAjaxRequestInProgress( this Browser browser )
    {
        var evalResult = browser.Eval( "watinAjaxMonitor.isRequestInProgress()" );
        return evalResult == "true";
    }

    public static void InjectAjaxMonitor( this Browser browser )
    {
        const string monitorScript =
            @"function AjaxMonitor(){"
            + "var ajaxRequestCount = 0;"

            + "$(document).ajaxStart(function(){"
            + "    ajaxRequestCount++;"
            + "});"

            + "$(document).ajaxComplete(function(){"
            + "    ajaxRequestCount--;"
            + "});"

            + "this.isRequestInProgress = function(){"
            + "    return (ajaxRequestCount > 0);"
            + "};"
            + "}"

            + "var watinAjaxMonitor = new AjaxMonitor();";

        browser.Eval( monitorScript );
    }
}
Randy Klingelheber
This solution works well unless one or more ajax requests begin before the monitor javascript is injected (at which point the counter is no longer accurate). I don't know how to inject the monitor earlier in the process from WatiN. It may be that the best bet is to conditionally include the monitor right after jquery is included when running tests.
Randy Klingelheber