Guest Post: Designing a Ruby-based Sauce Test Automation Framework Pt. 2

Designing a Ruby-based Sauce Test Automation Framework – Implementing it on Ruby using Page Object Pattern
 

In the first part of this blog series, we defined Page Object Pattern and also familiarized ourselves with the various building blocks of the Ruby-based test automation framework. Now that, we have realized the benefits of using such a framework, let us try implementing a Simple Test Framework on Ruby using Page Object Pattern. Implementing a Simple Test Framework on Ruby using Page Object Pattern
In the following section, we will implement a simple Selenium test framework using Page object pattern. Our framework contains Base classes for Test, Action, Page and Page element objects. Next, we will write a few very simple test cases for:

  1. Verifying the page title on a web page
  2. b. Test a form by filling the data elements in the form and testing a successful submit.

Test Base Class

First, let’s do a walkthrough of the Test Base class.

  1. Include the Selenium-webdriver Rubygem which is used to connect the testing framework with Selenium web driver.
  2. The start_browser() function invokes the Firefox browser with required options such as OS type, browser version, etc.

>Please Note: For testing purposes we have set the default browser as Firefox on Linux, but we can make this dynamic by passing the corresponding parameters.

  1. This class also has other utility functions such as
    1. get_data() - to make Database connections and retrieve data
    2. launch_url() - to launch a new URL on the browser
    3. switch_to_frame() - to switch between active frames / windows.
require 'rubygems'
require 'selenium-webdriver'

class SeleniumTestBase

  def initialize (webDriver)
    @driver = webDriver
  end

  #this function starts the selenium webDriver on Firefox browser type
  #we can make it dynamic by using the params

  def start_browser(browser_type,platform,version)

    caps = Selenium::WebDriver::Remote::Capabilities.firefox
    caps.version = "5"
    caps.platform = :LINUX
    caps[:name] = "Testing Selenium 2 with Ruby on SauceLabs Environment"

    @driver = Selenium::WebDriver.for(
      :remote,
      :url => "<Use SauceLabs URL with appropriate key>",
      :desired_capabilities => caps
    )
  end

  def switch_to_window(handle)
    @driver.switch_to.window handle
  end

  def switch_to_frame (handle)
    @driver.switch.frame handle
  end

  def launch_url ( url)
    @driver.navigate.to url
  end

  def get_data(conn_string,sql1 )
    #some sql statements
  end

  def refresh
    @driver.get @driver.url
  end

  def teardown
    @driver.quit
  end
end

Please note one of the advantages of writing a separate Test Base class is that it uses the underlying driver implementation from the Test cases. Therefore, if we want to experiment with a new Driver version or even a completely new Driver, then the TestBase is the only class that will change leaving other parts of the framework untouched. In a later section, we will show how one can create a project specific TestBase class which extends the main TestBase class. This will allow individual project teams to make project specific changes to the base class.

Action Base Class

>Actions Base classes are responsible for the following:

  1. Executing steps required to run the test
  2. Inserting / Updating data elements and changing the state of the application while executing the test
  3. Reverting the changes made during the tests (for eg., rolling back the changes made on the database)
  4. Page operations such as navigating to a page, refreshing, switching across different frames and windows, etc.
class SeleniumActionBase

  def initialize (webDriver)
    @driver =  webDriver
  end

  def get_data(conn_string,sql1 )
    #connect to db
    #execute sql to retrieve data
  end

  def start_browser(browser_type)
    #override
  end

  def switch_to_window(handle)
    #override
  end

  def switch_to_frame (handle)\
    #override
  end

  def launch_url (url)
    #override
  end

  def refresh
    #override
  end
end

The Page Class refers to actual web pages on the application that we want to test and essentially consists of a group of Page Elements. This class also defines a variable called BrowserIndex. Different browsers implement the locator start indexes differently and this variable can be used to handle the different implementations based on the browser type.

class SeleniumPageBase

  attr_reader :browserIndex

  def initialize ( webDriver)
    @driver = webDriver
    @browserIndex  = 1
  end

end

Page Element Base Class

The Page Element class is responsible for the following:

  1. Handle the actual interactions between the tests and the web pages.
  2. Wait for a particular page element to load (especially in case of Ajax)
  3. Provide specific error messages to describe why a particular page interaction failed.
class SeleniumPageElement

  def initialize(webDriver)
    @driver = webDriver
  end

  def waiting_get(seconds = 5, errorMessage = "")
    wait = Selenium::WebDriver::Wait.new(:timeout => seconds)
    wait.until { @myDriver.find_element(:id, @myBy) }
  end

  def click(seconds = 5, errorMessage = "")
    waiting_get(seconds, errorMessage).click();
  end

  def load_element(locator,val,errorMessage ='')
    @myBy = locator
    @element = find_element_id
    @element.send_keys val
  end

  def submit
    @element.submit
  end

  def get_response
    @driver.find_element(:id, 'your_comments')
  end

  protected

  def find_element_id
    begin
      return  @driver.find_element(:id, @myBy)
    rescue  Exception=>e
      raise e
    end
  end
end

This guest blog post was written by Vinodh Balaji Sridharan and Ganesh Kaliannan, Neev Technologies

Written by

Bill McGee

Topics

FrameworksAutomated testing