Pageify

Code Climate Dependency Status Build Status

Simplest way to define page objects. Bonus, tremendously fast tests.

Example

Page definition looks like this

home_page: ".home"
  login: "div.login"
    user_name: "input.user"
    password: "input.password"
    submit: "[name='submit']"
  profile_name: "a.profile"
  settings: "a.settings"
  sign_up: "a.sign_up"

Test steps looks like this

home_page..user_name.f.set "hi"
home_page..password.f.set "bla"
home_page..submit.f.click

home_page.profile_name.f.should match_text "hi"
hoem_page.settings.f.should be_visible

We will be able element whose locators are dynamic

products_page: ".products"
  product: ".product[name='%s']"
    details_row: ".row:nth-of-type(%s)"
      cost: ".cost"
products_page.product("candy").details_row(1).cost.f.should have_text "Rs.10"
products_page.product("tyres").details_row(2).cost.f.should have_text "Rs.20"

Key benefits

Usage

In your project Gemfile add

gem 'pageify'

Cucumber

In env.rb

 require 'pageify'
 require 'pageify/capybara'
 include Pageify

 pageify("features/pages")

Place all the page defenitions under "features/pages"

Methods

Get Element 'f' or 'find'

home_page..user_name.f #=> user_name text box
home_page..user_name.f.set "hi" # set text box value
home_page..user_name.find.should have_value "hi" # assert value
home_page..submit.find.click

Get Element Collection 'find_all'

home_page.product.find_all #=> all products in page
home_page.product.find_all[0] #=> first product in page

Get Selector 'selector'

At times we would need selector of the object

home_page..user_name.selector #=> ".home div.login input.user"

#check element doesn't exist
page.should_not have_selector home_page..user_name.selector

#using capybara actions
fill_in  home_page..user_name.p, :with=> "hi"
click_on home_page..submit.selector

Splitting Long Page Definitions

Sometimes, your page definition may get quite long. In other cases, you may also have the exact same HTML component (say a product listing) that can be repeated in multiple places (e.g. list, search, etc). In these cases, you can use sections to split your page into multiple files that can be reused.

The syntax for this is as follows:

# sections/_product.yml
product: '.product'
  name: '.name'
  price: '.price'

# product_list.yml
product_list: '.product_list'
  :section/product

# search_results.yml
search_results: '.search_results'
  :section/product

Experimental Feature

Making the test more readable is a constant persuite. Currently working on removing use of "find" or "f" in every step

#currently
home_page..user_name.find.set "used"
home_page..user_name.find.click "used"

#with experimaental work under progress the above will look like
home_page..user_name.set "used"
home_page..user_name.click "used"

You can try this in your test suite by

#instead of the adding the below line 
require 'pageify/capybara'

# use this
require 'pageify/capybara_experimental'

Note: There will be a considrable drop in performance, with the use of this experimental feature. Once this performance drop is fixed, this could used in main stream.

How tests gets faster with Pageify

Finding a street in a country, would be much faster when given state -> city -> area -> street, against searching just the street name.

Since we used entire hirerchy of the selector to locate an element, against specific selector, the identification of element gets really faster.
For example,

page.find(".user_name")
page.find(".home_page .login .user_name")
# The later would be much faster, scope for search is reduced to particular container at every level.

The effect gets magnified when the same is done on each and every step of, hundreds and thousand steps, tests.