Selenium: Execute arbitrary javascript (even jQuery)

We're very happy with our new-ish Selenium + Saucelabs setup for web site automation testing. But as easy as Selenium makes it to compose tests, you will inevitably be frustrated trying to do some of the more complicated test scenarios.

For example, the Selenium IDE has not been sufficient for us to automatically generate code to look inside a javascript based rich text editor control. Similarly, we could not figure out how to uncheck ALL checkboxes in a certain form when you don't know their IDs/names up front.

As a web developer, when I run into issues like this with Selenium, I find myself wishing that I could just use jQuery. It's such a familiar tool, that I often think of how I would implement something with jQuery, and then attempt to translate that into the Selenium API.

Maybe in the future, Selenium will let you just code in javascript. What could be more natural? For now, you can use a work-around like the following python helper.

# adapted from
def javascript(sel, script):
    return sel.get_eval("""
    (function() {
            with(this) {
    """ % locals())

There is a tricky bit here. When you call get_eval(), your javascript is executed in the context of the test runner, not the actual test window. Hence wrapping your javascript in an anonymous function, and executing it in the context of the browserbot window via the call() method.

Another subtly is using getUserWindow() instead of getCurrentWindow(). This is so you can use the jQuery library already loaded by your app. Due to SEL-558, getCurrentWindow() no longer gives you access to dynamically defined document properties, like "jQuery" or "$". Thanks to Christopher Schmidt.

Assuming you already have jQuery loaded in your application, un-checking all the checkboxes on the page is as simple as:

class MyTest(SeleniumTestCase):
   def runTest(self):
      javascript(self.selenium, "$('input[type=checkbox]').attr('checked', false);")

You can also use a jQuery selector to find a particular element and then return it. Any string returned from javascript() will get passed back to the python test runner code.