Rafael's Blog

Because manual testing is boring.

Selenium and the Page Object Design Pattern

Selenium is the most popular testing framework for web applications. It’s free, open-source and very useful when trying to verify how your application will behave on a specific browser. As the official website states, “Selenium automates browsers”. Pretty simple. There are a couple different versions of the framework, but I highly recommend using Selenium WebDriver (or Selenium 2), which in my opinion is a lot more robust than the old Selenium IDE. Selenium WebDriver runs in many browsers and operating systems and can be controlled by many programming languages. For the purpose of this short tutorial, I’m doing this on a Mac and using Ruby and Rspec to write the tests.

Why Page Objects?

A few years back when I started doing test automation, I wanted to automate as much as I could to save time, so I started writing a lot of code for the tests. I quickly realized that once the application changed (e.g. Element id changed), I had to go back and update all my tests that were now broken trying to identify a changed element on a page. By using the Page Object Design Pattern you basically abstract your application from your tests. That way if you have 50 tests for one page and some element changes, all you need to do is update the one page file, and all tests will continue to pass.

How does it work?

You could do this with any language supported by Selenium. Write code that builds a class that represents the page being tested with all identifiers and actions your tests need and then write your tests using that class. Fortunately, in Ruby you don’t have to. Thanks to Jeff Morgan, Ruby has an awesome gem that does most of the work for you when building page objects. Here’s what your page object file should look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
require 'page-object'

class LoginPage
  include PageObject

  page_url('https://vimeo.com/log_in')
  text_field(:email, :id => 'email')
  text_field(:password, :id => 'password')
  button(:login_button, :css => 'input.btn')

  def login(username, password)
    self.email = username
    self.password = password
    self.login_button
  end

end

I’m using the Vimeo login page here, but as long as you change the attributes of the page, it should work for any website that has login functionality. You’ll find different opinions on this, but I believe asserts should not be part of page objects, as discussed on this stackoverflow thread. Once you created the page, you are now ready to write one or more tests:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
require 'rspec'
require './login_page'
require 'selenium-webdriver'

describe 'User Login' do

  before(:each) do
    @browser = Selenium::WebDriver.for :firefox
  end

  it 'should login a valid user' do
    login_page = LoginPage.new(@browser)
    login_page.goto
    login_page.login('my_email_address', 'my_password')
    login_page.text.should include('Welcome home')
  end

  after(:each) do
    @browser.quit
  end

end

By default, Selenium includes a driver for Firefox only (on the Mac). If you want to test using Chrome, you need to download ChromeDriver and modify the line inside the before block:

1
@browser = Selenium::WebDriver.for :chrome

Replace the strings inside the login method with your Vimeo username and password and run the test using rspec:

1
2
3
4
5
rspec login_spec.rb
.

Finished in 9.7 seconds
1 example, 0 failures

If you need to interact with other elements on your page, make sure to checkout the wiki pages here. On the next post, I’ll show you how to test virtually on any browser and operating system, using a cloud service.

Comments