Wednesday, January 18, 2006

Testing Commentary (and thus Ajax) with Selenium

I've been working on adding Selenium tests to the application that Titus and I will be presenting at our PyCon tutorial in February. Titus included Ian Bicking's Commentary functionality into our app, and of course the challenge was how to test this stuff. If you visit the live Commentary page and double-click anywhere on the page, a form magically pops up (Ajax stuff, of course) and allows you to enter and save a comment. The challenge of course was how to fire the mouse doubleclick event in Selenium. After a lot of pain, mostly involving searching through the messages posted to the selenium-dev and selenium-users lists at, I came up with a solution. It's not pretty, but it does the job well enough.

I can't show you a live demo yet, but here's what I did to get it to work.

I extended the selenium-api.js and selenium-browserbot.js files and added functions dealing with mouse doubleclick events. This basically added a new dblclick command to the "Selenese" API. Here, a huge help was the "Key and Mouse events" post on the OpenQA JIRA issue tracker, and its associated code (kudos to FJH for writing it).

I added the following lines to selenium-api.js:

Selenium.prototype.doDblclick = function(locator) {
var element =;;
I added the following lines to selenium-browserbot.js (if you need to support IE, you need to add a corresponding IEPageBot function):
MozillaPageBot.prototype.dblclickElement = function(element) {

triggerEvent(element, 'focus', false);

// Trigger the mouse event.
triggerMouseEvent(element, 'dblclick', true);

if (this.windowClosed()) {

triggerEvent(element, 'blur', false);

At this point, I was able to put together a Selenium test table in order to test the functionality of opening a commentary form via double-clicking, filling the username, email and commentary fields, clicking the Save button, and finally verifying that the text of the commentary appears on the page. I chose //blockquote as the element locator to fire the doubleclick on, but I could just as easily have chosen any element on the page under test via its XPath location (speaking about XPath, here's a good tutorial).

Here are the relevant rows of the test table:

dblclick //blockquote
pause 2000
store javascript{Math.round(1000*Math.random())} var
type username user${var}
type email user${var}
type comment hello there from user${var}
click //form//button[1]
pause 2000
assertTextPresent hello there from user${var}

The "pause" commands were necessary to wait for the page to be updated via the Commentary Ajax calls. I could have used the waitForCondition user extension contributed by Dan Fabulich, but I took the easy way out for now. I do intend to rewrite the test so that it uses waitForCondition, because the pause command is not reliable enough. On some slower machines, it took much longer for the Commentary form to be saved.

Bottom line: Selenium passed the test of testing an Ajax application with flying colors! If you have Ajax code that depends on other key or mouse events, take a look at the code and the corresponding Selenium table test posted by FJH.


Anonymous said...

Is there any way to get this functionality in Selenium IDE?
I have started using it recently and need the dbl click recording but can't figure out how to! :(

cainlevy said...

I recently jumped into Selenium, and this article helped me get started. Thanks! After trying pauses and waitForConditions, I actually am now trying a more direct approach to waiting for Ajax requests.

Anonymous said...

Most helpful (love the Javascript Math 100 call)

Many thx for sharing.

Cheers - JR

Anonymous said...

can we parameterize the user name by giving the value from excel sheet or CSV file..If so how

Anonymous said...

Sounds like you Selenium overall - which version (RC,IDE?). I am in the process of evaluating this tool, hoping it recognizes web objects easily and has a simple framework to run all tests.

Mona said...


I'm testing a GWT application that has a grid. double clicking a record in the grid will launch an update form for the clicked record.

I added the lines to selenium-browserbot.js and to selenium-api.js, but it did not work.. do I need to do anything else?

Modifying EC2 security groups via AWS Lambda functions

One task that comes up again and again is adding, removing or updating source CIDR blocks in various security groups in an EC2 infrastructur...