Writing page based tests with selenium in ruby

This started as an email to someone introducing Selenium. I thought it might have more general use, so I’m posting it here.

If you want to drive a browser, I’d pick Selenium.  It works cross browser and has libraries for most languages, including Ruby.  Selenium isn’t really a test framework though, so you’d combine it with Test::Unit or Rspec/Cukes (but that’s a bit trickier.)  http://seleniumhq.org has decent documentation, but the easiest way to get up to speed is install Selenium IDE (a firefox plugin) and click through record steps and convert it to your favorite language.

The trick comes in organizing test cases in a maintainable manner.  I start by building “page” objects that can identify elements on a page in a readable manner, so instead of steps that looks like this:

@selenium.open “/login”
@selenium.type “username” “aaron”
@selenium.type “password” “secret”
@selenium.click “//input[@type=’submit’]”
@selenium.wait_for_page_to_load "30000"

You abstract your identifiers inside a class

class LoginPage
    @@url = “/login”
    @@username = “username”
    @@password = “password”
    @@loginButton = “//input[@type=’submit’]”

And  makes your tests a bit more readable

@selenium.open loginPage.url
@selenium.type loginPage.username “aaron”
@selenium.type loginPage.password “secret”
@selenium.click loginPage.loginButton

But that doesn’t buy you much, except when you’ve got hairier identifiers (the login button being a fairly easy example) that might be subject to change.

But add a method to your page that passes the selenium object:

class LoginPage
    attr_accessor :selenium
    cattr_accessor :url, :username, :password, :loginButton

    def initialize(selenium)
        @selenium = selenium

    def login(username, password)
        if @url != @selenium.js_eval(‘window.location.href’)
            @selenium.open @@url

        @selenium.type @@username username
        @selenium.type @@password password
        @selenium.click @@loginButton
        @selenium.wait_for_page_to_load TIMEOUT_MAX

        assert_equal(@selenium.getTitle, HomePage.title)

        @page = HomePage.new(@selenium)

And then in your test, all you do is:

@homepage = @loginpage.login(“aaron”, “secret”)

Search for “selenium page objects” or “page based tests” for more info.  It gets more interesting when you can build behaviors with Cukes and do things like make login a dependency of edit profile, etc.  Hope this helps you get started.