AJAX + Selenium: solution for race conditions

There exists a problem with the race conditions testing websites full of AJAX, here is a solution using Selenium.

I’ve been looking for the perfect solution of the pair “AJAX + Web testing tool” and i’ve reached the conclusion that, so far, there isn’t a perfect solution.

Selenium is ready (at least almost ready) to test AJAX websites and apparently, Selenium is the most used tool and has the biggest support community, and therefore, is the better one to deal with AJAX applications.

As probably many of you know, Selenium has methods like “waitForXXX” that can assert most of the AJAX request and if your website renders the code statically or dynamically just some pieces of the site, you won’t have any problems.

But what happens if your website is full of AJAX and all the source code is generated dynamically? I mean, for instance, the JavaScript events.

I’m not an expert in HTML or JavaScript but i’m talking about the onclick, onmouseover, onload, etc. attributes of the HTML tags. Usually, these attributes have JavaScript events that perform a change in the site.

BUT, if these JavaScript events are loaded dynamically and asynchronously using an AJAX request, is Selenium able to perform proper assertions? NO.

With Selenium you can wait for elements in the DOM but this tool doesn’t provide a waitForXXX method to wait for the load of JavaScript code. Therefore, you’ll wait for the element with “waitForElementPresent”, then you’ll click on it and the click won’t work becuase the onclick event is not yet loaded. Here, we have a problem.

My solution?

Using the method “waitForCondition”. I know is not the best solution because you will need to use it in many places of your code, so the best idea will be a more general approach that is explained in the next point.

You can pass as a parameter a JavaScript code and do something like this:

$js = "var target = selenium.browserbot.getCurrentWindow().document.getElementById('idOfTheElement').onclick;";
$js .= "(typeof target = 'function') || (typeof target == 'object')";
$selenium->waitForCondition($js, 5000);

Explanation:

In the first line of the JavaScript code, you need to get the window of the site using “selenium.browserbot.getCurrentWindow()”. Once you have it, you can deal with it as the normal usage of JavaScript, so you can get the document and access the DOM elements like in the example with “document.getElementById(‘idOfTheElement’).onclick;”.

In the second line of the JavaScript code, the result can be two different things: “typeof target = ‘function'” or “typeof target = ‘object'”.

The “waitForCondition” method evaluates the last result of the JavaScript code, so, until the time of its second param expires or the last result  is true, the method is going to be executing the JavaScript code. If the typeof target is a function or an object that means that the AJAX request has finished and the onclick event has loaded, then you can click.

Note: why the typeof is function or object? because in IE, typeof returns “object” and in Firefox returns “function”, the typical problem of JavaScript…

The best solution?

I suggest this idea to whoever really wants to solve this problem:

Keep a container of all the XMLHttpRequest that your site has and improve Selenium with the ability of wait for AJAX request finished asking the state of all these objects. If the state of all this objects is 4 (completed) you will be totally sure that you can perform the next action, you’ll be sure the request that can cause the race condition is fully loaded.

Any voluntary? i can help!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s