Create a page object framework with cucumber watir

1 min


653
1 comment, 653 points
cucumber watir
cucumber watir

Create page object framework using cucumber watir

My first ruby code was with Capybara and cucumber and I’m still coding on it with the help of  site_prism to have a page object structure. Last couple of weeks I’ve spent some time with watir just from curiosity and because it uses Ruby, a full-featured modern scripting language, rather than a proprietary vendorscript. Here I will try to show to you guys how to get started with cucumber watir using page object model.

Cucumber watir setup:
**Install**

 install ruby version manager ([RVM](http://rvm.io/)) before all other
    
    gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
    \curl -sSL https://get.rvm.io | bash -s stable
    
To see all available ruby versions to install
    
    rvm list known    
    
Install appropriate ruby version from .ruby-version file if not installed yet

    rvm install ruby-2.4.0

To see all installed rubies with showing of default and current version
    
    rvm list rubies

Install bundler and app dependencies

    gem install bundler
    bundle install

**Running cucumber tests**

    cucumber

To run a specific feature in a specific file specify the feature file and line number:

    cucumber features/listings.feature:11

Or you can run the feature by name:

    cucumber features --name "I am able to search on google"
Getting started with cucumber watir

Install the gem from rubygems.org:

$ gem install watir-webdriver
Building native extensions.  This could take a while...
Successfully installed json_pure-1.4.6
Successfully installed rubyzip-0.9.4
Successfully installed ffi-0.6.3
Successfully installed childprocess-0.0.7
Successfully installed selenium-webdriver-0.0.29
Successfully installed watir-webdriver-0.1.1
6 gems installed
$ 
Cucumber watir project structure:
cucumber watir
cucumber watir

 

 

 

 

 

 

 

 

Cucumber watir page object model code example:

Lets see what’s inside model >> page_object.rb

class PageObject
  @@mapping = {}

  # Little bit of Meta programming
  def self.container(selector)
    @@mapping[name] ||= {}
    @@mapping[name][:container] = selector
  end

  def self.element(element_name, selector)
    @@mapping[name] ||= {}
    @@mapping[name][:elements] ||= {}
    @@mapping[name][:elements][element_name] = selector
  end

  # Get container selector
  # @return [String]
  def self.container_selector
    mapping[:container]
  end

  # Get element selector
  # @return [String]
  def self.element_selector(element_name)
    mapping[:elements][element_name.downcase]
  end

  # Get mapping hash:
  # full for PageObject class, and self for other
  # @return [Hash]
  def self.mapping
    name == 'PageObject' ? @@mapping : @@mapping[name]
  end
end

Lets create our object inside model >> object.rb

class Object
  # Get component web element representation
  def component(name)
    Component.by_name(name)
  end

  # Get component's web element representation
  def element(element_name, component_name = nil)
    Component.by_element(element_name, component_name)
  end

  # Check if string is kind of xpath selector style
  def xpath_selector?
    is_a?(String) && (start_with?('//') || start_with?('.//'))
  end
end

Lets handle our components :

class Component

  def self.by_name(name)
    component_selector = Object.const_get(name).container_selector
    $b.element(css: component_selector)
  end

  def self.by_element(element_name, component_name = nil)
    # Find correct element selector if component name not specified
    if component_name.nil?
      mapping = PageObject.mapping
                          .find_all { |_k, v| v[:elements][element_name.downcase] }
      raise_exception(element_name) if mapping.empty?
      # ToDo: For now it is used first element found in mapping
      # What to do if found at least two appropriate values???
      component_name = mapping[0][0]
    end

    element_selector = Object.const_get(component_name).element_selector(element_name.downcase)

    # Check selector type: css or xpath
    if element_selector.xpath_selector?
      by_name(component_name).element(xpath: element_selector)
    else
      by_name(component_name).element(css: element_selector)
    end
  end

  private

  def self.raise_exception(element_name, component_name = nil)
    raise "No elements found with name: '#{element_name}' & component: #{component_name}"
  end

end

Your first cucumber watir page inside mapping >> pages >> main_page.rb

class MainPage < PageObject
  container 'body'
    element 'search_button', './/span[contains(text(),"Search")]'
end

Your first cucumber waitr from inside mapping >> forms >> search_form.rb 

class SigninForm < PageObject
  container 'form'

  element 'Search field', 'search'
end

Your first cucumber watir component class inside mapping >> components >> header_menu.rb

class Navigation < PageObject
  container '[role=navigation]'

  element 'sign_in', 'signin'
end
Create your first cucumber watir feature file inside features :
@examples
Feature: This is feature for framework testing purposes & examples

  @ex1
  Scenario: I am able to navigate to google
    Given I navigate to the url google.com
    And I click on the search button
Inside support folder we are going to initialise the project setup , environment variables , selenium driver , and provide the possibility to take screenshots

support >> _init.rb

require 'watir'
require 'fileutils'
require 'rspec/expectations'

# Require model
page_object_dir = File.expand_path('../../../model', __FILE__)
Dir.glob File.join(page_object_dir, 'model', '*.rb'), &method(:require)
# Require mapping classes
Dir.glob File.join(page_object_dir, 'mapping', '**', '*.rb'), &method(:require)

support >> browser.rb

$b = Watir::Browser.new ENV['BROWSER'].to_sym

# close the browser using ruby global hook
at_exit do
  $b.close
end

support >> env.rb

# default browser to run
ENV['BROWSER'] = 'firefox'

ENV['PATH'] = ENV['PATH'] + ':' + File.expand_path('../../../bin', __FILE__)

support >> screenshot_maker.rb

SCREENSHOT_PATH = 'output/screenshots'
FileUtils.mkdir_p SCREENSHOT_PATH

After do |scenario|
  if scenario.failed?
    screenshot_name = "#{Time.now}_#{scenario.name}_#{scenario}".gsub(/\W/, '_') + '.png'
    $b.screenshot.save "#{SCREENSHOT_PATH}/#{screenshot_name}"
    # embed it in html report output
    embed "#{SCREENSHOT_PATH}/#{screenshot_name}", 'image/png'
  end
end

And we are almost done lets create the step definition inside features >> step_definitions for our cucumber watir project

Given /^I navigate to the url (.*)$/ do |url|
  $b.goto url
end

Actions step definitions example :

##### Action steps context #####

Given /^I click on the (.+)$/ do |element_name|
  element(element_name).click
end

Given /^I click on the (.+) for (.+)$/ do |element_name, component_name|
  element(element_name, component_name).click
end

Given /^I enter "(.+)" on the (.+)$/ do |entered_text, element_name|
  element(element_name).send_keys entered_text
end

Given /^I enter "(.+)" on the (.+) for (.+)$/ do |entered_text, element_name, component_name|
  element(element_name, component_name).send_keys entered_text
end

Assertions context example :

##### Assertions context #####

Then /^Fail assert$/ do
  expect(1).to eq 2
end

Then /^Success assert$/ do
  expect(1).to eq 1
end

Here we go , you just managed to setup your first cucumber watir project and your are ready to extend it with as many page objects and components you want.

What I like about this structure is because gives you full reusability of the cucumber steps. I don’t like the fact that complex logic need to be handled separated of the reusable actions .

If you need more informations about setup you can find it here on the official watir page.

How to initialise the cucumber ruby project you can fallow the cucumber documentation .

Happy testing!

 


Like it? Share with your friends!

653
1 comment, 653 points

What's Your Reaction?

cute cute
0
cute
scary scary
1
scary
wtf wtf
0
wtf
geek geek
0
geek
WIN WIN
0
WIN
Love Love
1
Love
OMG OMG
1
OMG
Angry Angry
1
Angry
Lol Lol
1
Lol
Test engineer

One Comment

Your email address will not be published. Required fields are marked *

Choose A Format
Trivia quiz
Story