Test::Page helps you to write easily maintainable integration tests by implementing Page Objects pattern.

  • It is framework agnostic - you can use it with any library you want - Watir, Selenium, Capybara etc.
  • It has really easy API - you can start testing right away instead of spending much time to learn new framework.
  • It has really small codebase - even if you can't remember that easy API you can dig right into the code - it's less than 100 lines!

Despite of its name you can use it with RSpec, Test::Unit or any other testing library.


Add this line to your application's Gemfile:

gem 'test-page'

And then execute:

$ bundle

Or install it yourself as:

$ gem install test-page


The following example uses Watir with RSpec, but you can use whichever library you like.

This is the spec we are trying to run:

# spec/search_spec.rb

require "test/page"
require "watir"
require File.expand_path("support/page/search_page", File.dirname(__FILE__))

describe "Bing" do

  let(:browser)     { Watir::Browser.new }
  let(:search_page) { SearchPage.new }

  before { Test::Page.browser = browser }
  after  { browser.close }

  it "finds Google" do
    results_page = search_page.search "google"
    results_page.should have(10).results
    results_page.results[0].text.should =~ /google/i

  it "finds Bing itself" do
    results_page = search_page.search "bing"
    results_page.results.should include("Bing")


Let's create the SearchPage object:

# spec/support/page/search_page.rb

require File.expand_path("results_page", File.dirname(__FILE__))

class SearchPage < Test::Page
  # Specifying the container element.
  element { browser.div(:id => "sbox") }

  # #setup is an optional method which any page might have
  # to set the state up properly after initialization.
  def setup
    browser.goto "http://bing.com"

  # #search will perform the search operation and return
  # a ResultsPage object after it's done.
  def search(term)
    text_field(:id => "sb_form_q").set term
    button(:id => "sb_form_go").click
    redirect_to ResultsPage, browser.ul(:id => "wg0")

Let's create the ResultsPage object:

# spec/support/page/results_page.rb

class ResultsPage < Test::Page
  # #results return the LiCollection which has #include? as its additional
  # helper method. This is done with the help of Test::Page#modify.
  def results
    modify lis(:class => "sa_wr").map(&:text),
      :include? => proc do |term|
        regexp = Regexp.new Regexp.escape(term)
        results.any? { |result| result =~ regexp }

There you have it, a fully functional spec using two page objects. Reference to the API documentation for more usage information.


Copyright (c) Jarmo Pertman. See LICENSE for details.