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 OpenQA.org, 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).

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}@example.com

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.

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.