Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

file 377 lines (297 sloc) 15.036 kb

PageObjectWrapper

Wraps watir-webdriver with convenient testing interface, based on PageObjects automation testing pattern. Simplifies resulting automated test understanding.
Warning: version 1.0 and higher are not compatible with older versions

Installation

Install Firefox on your system

Add this line to your application's Gemfile:

gem 'page_object_wrapper'

And then execute:

$ bundle

Or install it yourself as:

$ gem install page_object_wrapper

Usage

please look into specs for more detailed usage examples

Basic usecase is following

  1. Define page object with PageObjectWrapper.define_page
  2. Use defined page object inside your tests with usefull page_object #methods

Basic principles of a PageObjectWrapper

  • there are following objects: page_object, elements_set with elements, table, action, pagination
  • a page_object contains elements_sets, tables, actions, paginations
  • an elements_set contains elements
  • every object has a :label
  • a label identifies the object

Here in the structure of PageObjectWrapper: PageObjectWrapper scheme

where required attributes are marked with (*)
optional arguments are enclosed with [ ]

Examples

definition examples

define a page object with url and some elements
PageObjectWrapper.define_page :some_test_page do
  locator 'http://www.cs.tut.fi/~jkorpela/www/testel.html' # url

  text_field(:tf) do # defines a text_field
    locator :id => 'f1' # element locator (can be Hash or String)
    menu :user_defined, 'some food' # input data with type :user_defined for this element
  end

  select(:s1) do # select list
    locator :id => 'f10'
    menu :fresh_food, 'one'
    menu :missing_food, 'three'
  end

  table(:table_with_header) do # table with predifined header
    locator :summary => 'Each row names a Nordic country and specifies its total area and land area, in square kilometers'
    header [:country, :total_area, :land_area] # header will be used later inside #select_from_xxx calls
  end
end
elements can be included into element_sets
PageObjectWrapper.define_page :some_test_page do
  locator 'http://www.cs.tut.fi/~jkorpela/www/testel.html'

  elements_set :test_elements do
    text_field(:tf) do
      locator :id => 'f1'
      menu :user_defined, 'some food'
    end

    textarea :ta do
      locator :id => 'f2'
    end

    select :s1 do
      locator :id => 'f10'
      menu :fresh_food, 'one'
      menu :missing_food, 'three'
    end
  end
end
each element can be marked as required
PageObjectWrapper.define_page :some_test_page do
  locator 'http://www.cs.tut.fi/~jkorpela/www/testel.html'

  text_field :tf do
    locator :id => 'f1'
    menu :user_defined, 'some food'
    required true # will be checked for presence upon page load
  end
end

if all pages are similar through out the web app, it's possible to additionaly set a number of uniq elements
which will be checked for presence as well

PageObjectWrapper.define_page :some_test_page_similar_to_previous do
  locator 'http://www.cs.tut.fi/~jkorpela/www/testel.html'

  uniq_h1 :text => 'Testing display of HTML elements'

  text_field :tf do
    locator :id => 'f1'
    menu :user_defined, 'some food'
    required true # will be checked for presence upon page load
  end
end
it's possible to define action and its aliases inside pages

actions are being executed in browser context

PageObjectWrapper.define_page :some_test_page do
  locator 'http://www.cs.tut.fi/~jkorpela/www/testel.html'
  uniq_h1 :text => 'Testing display of HTML elements'

  action(:press_cool_button, :test_page_with_table) do # this action returns :test_page_with_table object after execution
    button(:name => 'foo').when_present.click
  end

  action :fill_textarea_with_returned_value do |fill_with|  # this action returns 'data' 
    data = (fill_with.nil?)? 'Default data' : fill_with     # (because returned page object is not specified)
    textarea(:id => 'f2').set data
    data
  end 

  action_alias(:fill_textarea_alias, :some_test_page){ action :fill_textarea }
  action_alias(:fill_textarea_with_returned_value_alias){ action :fill_textarea_with_returned_value }

  table(:table_without_header) do
    locator :summary => 'Each row names a Nordic country and specifies its total area and land area, in square kilometers'
  end
end

other definition examples can be found inside 'good_pages', 'bad_pages' folders

PageObjectWrapper.open_page - opens page with specified label

preconditions
There is a directory, where we've defined a page_object inside a *_page.rb file

  1. specify browser to be used by PageObjectWrapper

    @b = Watir::Browser.new
    PageObjectWrapper.use_browser @b

  2. load defined pages

    PageObjectWrapper.load("path/to/pages/directory")

  3. open page in browser

    test_page = PageObjectWrapper.open_page(:some_test_page)

comments

  • it's possible to use any Watir::Browser with any profile
  • it's possible to use any Webdriver, which behaves like Watir::Browser (meaning that Webdriver uses similar methods for locating elements and working with them)
  • .load method validates all pages, defined in specified directory inside any *_page.rb file
  • it's possible to define several page objects in one file
  • .open_page method takes page label, directs browser to that page and returns corresponding page_object
  • PageObjectWrapper.current_page points to the opened page_object
  • it's possible to set page_object locator in 2 different ways: specifying full url (like in example) or specifying PageObjectWrapper.domain and page_object local path (like in specs)
  • it's possible to set dynamic urls for pages, e.g.

    PageObjectWrapper.define_page(:google){ locator 'www.google.com/:some_param' }  
    PageObjectWrapper.open_page(:google, :some_param => 'advanced_search') # => 'http://google.com/advanced_search'  
    

page_object.xxx - returns corresponding Watir element defined inside page_object

parameters
no
returns
Watir::XXX element

Defined elements can be accessed with their labels.

  • element from an element_set is corresponds to real Watir::Element
  • elemets_set corresponds to an Array of Watir::Element

preconditions
tp is a :some_test_page object opened in the browser

  tp.tf # => Watir::TextField
  tp.rb # => Watir::Radio
  tp.test_elements # => Array of Watir elements
  tp.table_with_header # => Watir::Table

feed_xxx - inserts data inside an element, an elements_set or all elements of the page

parameters
menu type, specified inside page_object (optional) returns
current_page

preconditions
tp is a :some_test_page object opened in the browser

  context "menu not specified":
    it "does nothing":
      tp.feed_test_elements
      browser.text_field(:id => 'f1').value.should eq 'Default text.'
      ....

  describe "basic usage": 
    it "FEEDS elements which have provided menu inside defimition":
      tp.feed_test_elements(:loud)
      browser.text_field(:id => 'f1').value.should eq 'tf food'
      ....

    it "feeds ONLY elements which has provided menu":
      tp.feed_test_elements(:quite)
      browser.text_field(:id => 'f1').value.should eq 'Default text.'
      ....

    it "overrides defined menu when passing arguments":
      tp.feed_test_elements(:loud, :tf => 'cheef menu', :rb1 => false, :rb2 => true, :cb2 => true, :s2 => 'three')
      browser.text_field(:id => 'f1').value.should eq 'cheef menu'
      ....

    it "can be used without providing a menu":
      tp.feed_test_elements(:tf => 'cheef menu', :rb2 => true, :cb2 => true, :s2 => 'three')
      browser.text_field(:id => 'f1').value.should eq 'cheef menu'
      ....

xxx_menu - returns corresponding data, defined inside xxx element

parameters
:food_type
returns
food value for this type which is defined in page_object

preconditions
tp is a :some_test_page object opened in the browser

tp.tf_menu(:loud) # => 'tf food' 
tp.rb1_menu(:loud) # => 'true' # pay attention that String is being returned (not true, TrueClass)

fire_xxx - executes action with label xxx

parameters
optional arguments defined inside action
returns
next_page from xxx action

preconditions
tp is a :some_test_page object opened in the browser

it "can be invoked with parameters":
  tp = PageObjectWrapper.current_page
  tp.fire_fill_textarea('User defined data')

context "next_page == nil":
  it "returns action returned value":
    tp = PageObjectWrapper.current_page
    data = tp.fire_fill_textarea_with_returned_value('data to fill with')
    tp.validate_textarea_value(data).should be(true)

context "xxx is alias":
  it "executes corresponding action":
    tp = PageObjectWrapper.open_page(:some_test_page)
    tp.fire_fill_textarea_alias

press_xxx - presses element with label xxx

parameters
no returns
pressed watir element preconditions
tp is a :some_test_page object opened in the browser

  it "returns pressed watir element"
    tp.press_cool_button.should be_a Watir::Button

  it "really presses the element"
    tp.press_standalone_cool_button_with_default_press_action
    PageObjectWrapper.current_page?(:test_page_with_table).should be_true

validate_xxx - executes validator with label xxx

parameters
optional arguments defined inside action
returns
anything block inside xxx validator returns

preconditions
tp is a :some_test_page object opened in the browser

  tp = PageObjectWrapper.open_page(:some_test_page)
  tp.fire_fill_textarea data
  tp.validate_textarea_value.should eq data

select_from_xxx - tries to select data from table with label xxx

parameters
:column_1, :column_2 => search_value, :optional_next_page
returns
Watir::TableCell if next_page not specified
next_page if it is specified

preconditions
tp is a :some_test_page object opened in the browser (url = https://raw.github.com/evgeniy-khatko/page_object_wrapper/master/img/scheme.png)
Method's syntax is close to SQL:
page_object.select_from_xxx( :column1, :column2 => 'string_or_regexp' )
correct arguments are:
:column1 *is a column value from which you want to receive
:column2 *is a column which is used to get specific row

context "where == nil":
  it "returns last row value from provided column":
    tp.select_from_table_without_header(:column_0).text.should eq 'Sweden'
    tp.select_from_table_without_header(:column_1).text.should eq '449,964'
    tp.select_from_table_without_header(:column_2).text.should eq '410,928'

context "where not nil":
  context "found by String":
    it "returns found cells":
      tp.select_from_table_without_header(:column_0, :column_1 => '103,000').text.should eq 'Iceland'
      tp.select_from_table_with_header(:country, :total_area => '337,030').text.should eq 'Finland'
    it "returns nil":
      tp.select_from_table_without_header(:column_0, :column_1 => '123').should eq nil
      tp.select_from_table_with_header(:country, :total_area => '123').should eq nil
  context "found by Regexp":
    it "returns found cells":
      tp.select_from_table_without_header(:column_0, :column_1 => /103/).text.should eq 'Iceland'
      tp.select_from_table_with_header(:country, :total_area => /337/).text.should eq 'Finland'
    it "returns nil":
      tp.select_from_table_without_header(:column_0, :column_1 => /123/).should eq nil
      tp.select_from_table_with_header(:country, :total_area => /123/).should eq nil
    context "found by row number":
      it "returns found cells":
        tp.select_from_table_without_header(:column_0, :row => 2).text.should eq 'Iceland'
        tp.select_from_table_with_header(:country, :row => 3).text.should eq 'Norway'
      it "returns nil":
        tp.select_from_table_with_header(:country, :row => 123).should eq nil

  context "next_page specified":
    context "found by String":
      it "returns found cells":
        tp.select_from_table_without_header(:column_0, {:column_1 => '103,000'}, :some_test_page).should eq PageObjectWrapper.receive_page(:some_test_page)
    context "not found by String":
      it "returns nil":
        tp.select_from_table_without_header(:column_0, {:column_1 => '123'}, :some_test_page).should eq nil
    context "found by row number":
      it "returns found cells":
        tp.select_from_table_without_header(:column_0, {:row => 2}, :some_test_page).should eq PageObjectWrapper.receive_page(:some_test_page)
        tp.select_from_table_with_header(:country, {:row => 3}, :some_test_page).should eq PageObjectWrapper.receive_page(:some_test_page)
      it "returns nil":
        tp.select_from_table_with_header(:country, {:row => 123}, :some_test_page).should eq nil

each_xxx - alternately opens each pagination subpage

  context "correct parameters ( limit = 3 )":
    it "opens browser on subeach page and yields corresponding page_object":
      gp = PageObjectWrapper.open_page(:google_pagination)
      counter = 0
      gp.pagination_each( :limit => 3 ){ |subpage| 
        counter += 1
        subpage.should be_a PageObject 
        subpage.validate_current_number?(counter).should be_true
      }

open_xxx - opens pagination subpage number N

  context "correct parameters":
    it "opens browser on provided subpage returns corresponding page_object":
      n = 10
      yp = PageObjectWrapper.open_page(:yandex_pagination)
      yp.pagination_open(n).should be_a PageObject
      yp.validate_current_number?(n).should be_true
      gp = PageObjectWrapper.open_page(:google_pagination)
      gp.pagination_open(n).should be_a PageObject
      gp.validate_current_number?(n).should be_true

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

page_object_wrapper

Wraps watir-webdriver with convenient testing interface, based on PageObjects automation testing pattern. Simplifies resulting automated test understanding.

Something went wrong with that request. Please try again.