TestCentricity / testcentricity_web

TestCentricity™ For Web core POM test automation framework gem
https://rubygems.org/gems/testcentricity_web
BSD 3-Clause "New" or "Revised" License
0 stars 0 forks source link
automation cucumber page-object-model ruby-gem selenium test-automation web webdriver

TestCentricity™ For Web

Gem Version License (3-Clause BSD) Gem Downloads Maintained Docs

The TestCentricity™ For Web core framework for desktop and mobile web browser-based app testing implements a Page Object Model DSL for use with Cucumber (version 7.x or greater) or RSpec, and Selenium-Webdriver. It also facilitates the configuration of the appropriate Selenium-Webdriver capabilities required to establish connections with one or more local or cloud hosted desktop or mobile web browsers.

The TestCentricity™ For Web gem supports connecting to, and running automated tests against the following target web browsers:

What's New

A complete history of bug fixes and new features can be found in the {file:CHANGELOG.md CHANGELOG} file.

The RubyDocs for this gem can be found here.

An example project that demonstrates the implementation of a page object model framework using TestCentricity™ For Web and Cucumber can be found here.

Which gem should I use?

Tested platforms TestCentricity For Web TestCentricity For Mobile TestCentricity For Apps
Desktop/mobile web browsers only Yes No No
Native mobile iOS and/or Android apps only No Yes Yes
MacOS desktop apps No No Yes

Installation

TestCentricity For Web version 4.4 and above requires Ruby version 3.0.0 or later. To install the TestCentricity For Web gem, add this line to your automation project's Gemfile:

gem 'testcentricity_web'

And then execute:

$ bundle

Or install it yourself using:

$ gem install testcentricity_web

Setup

Using Cucumber

If you are using Cucumber, you need to require the following in your env.rb file:

    require 'capybara/cucumber'
    require 'testcentricity_web'

Using RSpec

If you are using RSpec instead, you need to require the following in your spec_helper.rb file:

    require 'capybara/rspec'
    require 'testcentricity_web'

PageObjects

The Page Object Model is a test automation pattern that aims to create an abstraction of your web app's User Interface that can be used in tests. A Page Object represents a single page in your AUT (Application Under Test). Page Objects encapsulate the implementation details of a web page and expose an API that supports interaction with, and validation of the UI elements on the page.

Page Objects makes it easier to maintain automated tests because changes to page UI elements are updated in only one location - in the Page Object class definition. By adopting a Page Object Model, Cucumber Feature files and step definitions are no longer required to hold specific information about a page's UI objects, thus minimizing maintenance requirements. If any element on, or property of a page changes (URL path, text field attributes, button captions, etc.), maintenance is performed in the PageObject class definition only, typically with no need to update the affected feature files, scenarios, or step definitions.

Defining a PageObject

Your PageObject class definitions should be contained within individual .rb files in the features/support/pages folder of your test automation project. You define new PageObjects as shown below:

    class LoginPage < TestCentricity::PageObject
    end

    class HomePage < TestCentricity::PageObject
    end

    class RegistrationPage < TestCentricity::PageObject
    end

    class UserAccountPage < TestCentricity::PageObject
    end

Adding Traits to a PageObject

Web pages typically have names and URLs associated with them. Web pages also typically have a unique object or attribute that, when present, indicates that the page's contents have fully loaded.

The page_name trait is registered with the PageManager object, which includes a find_page method that takes a page name as a parameter and returns an instance of the associated PageObject. If you intend to use the PageManager, you must define a page_name trait for each PageObject to be registered. Refer to section 7 (Instantiating Your PageObjects).

The page_name trait is usually a String value that represents the name of the page that will be matched by the PageManager.findpage method. page_name traits are case and white-space sensitive. For pages that may be referenced with multiple names, the page_name trait may also be an Array of String values representing those page names.

A page_locator trait is defined if a page has a unique object or attribute that exists once the page's contents have fully loaded. The page_locator trait is a CSS or Xpath expression that uniquely identifies the object or attribute. The verify_page_exists method waits for the page_locator trait to exist.

An optional page_url trait should be defined if a page can be directly loaded using a URL. If you set Capybara's app_host, or specify a base URL when calling the WebDriverConnect.initialize_web_driver method, then your page_url trait can be the relative URL slug that will be appended to the base URL specified in app_host. Specifying a page_url trait is optional, as not all web pages can be directly loaded via a URL.

You define your page's Traits as shown below:

    class LoginPage < TestCentricity::PageObject
      trait(:page_name)    { 'Login' }
      trait(:page_url)     { '/sign_in' }
      trait(:page_locator) { 'body.login-body' }
    end

    class HomePage < TestCentricity::PageObject
      # this page may be referred to as 'Home' or 'Dashboard' page so page_name trait is an Array of Strings
      trait(:page_name)    { ['Home', 'Dashboard'] }
      trait(:page_url)     { '/dashboard' }
      trait(:page_locator) { 'body.dashboard' }
    end

    class RegistrationPage < TestCentricity::PageObject
      trait(:page_name)    { 'Registration' }
      trait(:page_url)     { '/register' }
      trait(:page_locator) { 'body.registration' }
    end

    class UserAccountPage < TestCentricity::PageObject
      trait(:page_name)    { 'User Account' }
      trait(:page_url)     { "/user_account/#{User.current.id}" }
      trait(:page_locator) { 'body.useraccount' }
    end

Adding UI Elements to a PageObject

Web pages are made up of UI elements like text fields, check boxes, combo boxes, radio buttons, tables, lists, buttons, etc. UI Elements are added to your PageObject class definition as shown below:

    class LoginPage < TestCentricity::PageObject
      trait(:page_name)    { 'Login' }
      trait(:page_url)     { '/sign_in' }
      trait(:page_locator) { 'body.login-body' }

      # Login page UI elements
      textfield :user_id_field,       'input#userName'
      textfield :password_field,      'input#password'
      button    :login_button,        'button#login'
      checkbox  :remember_checkbox,   'input#rememberUser'
      label     :error_message_label, 'div#statusBar.login-error'
    end

    class RegistrationPage < TestCentricity::PageObject
      trait(:page_name)    { 'Registration' }
      trait(:page_url)     { '/register' }
      trait(:page_locator) { 'body.registration' }

      # Registration page UI elements
      textfields  first_name_field:    'input#firstName',
                  last_name_field:     'input#lastName',
                  email_field:         'input#email',
                  phone_number_field:  'input#phone',
                  address_field:       'input#streetAddress',
                  city_field:          'input#city',
                  post_code_field:     'input#postalCode',
                  password_field:      'input#password',
                  pword_confirm_field: 'input#passwordConfirmation'
      selectlists title_select:        'select#title',
                  gender_select:       'select#gender',
                  state_select:        'select#stateProvince'
      checkbox    :email_opt_in_check, 'input#marketingEmailsOptIn'
      button      :sign_up_button,     'button#registrationSignUp'
    end

Adding Methods to a PageObject

It is good practice for your Cucumber step definitions to call high level methods in your your PageObject instead of directly accessing and interacting with a page object's UI elements. You can add high level methods to your PageObject class definition for interacting with the UI to hide implementation details, as shown below:

    class LoginPage < TestCentricity::PageObject
      trait(:page_name)    { 'Login' }
      trait(:page_url)     { '/sign_in' }
      trait(:page_locator) { 'body.login-body' }

      # Login page UI elements
      textfield :user_id_field,        'input#userName'
      textfield :password_field,       'input#password'
      button    :login_button,         'button#login'
      checkbox  :remember_checkbox,    'input#rememberUser'
      label     :error_message_label,  'div#statusBar.login-error'
      link      :forgot_password_link, 'a.forgotPassword'

      # log in to web app
      def login(user_id, password)
        user_id_field.set(user_id)
        password_field.set(password)
        login_button.click
      end

      # set the state of the Remember Me checkbox
      def remember_me(state)
        remember_checkbox.set_checkbox_state(state)
      end

      # verify Login page default UI state
      def verify_page_ui
        ui = {
          self => { title: 'Login' },
          login_button => {
            visible: true,
            caption: 'LOGIN'
          },
          user_id_field => {
            visible: true,
            enabled: true,
            value: '',
            placeholder: 'User name'
          },
          password_field => {
            visible: true,
            enabled: true,
            value: '',
            placeholder: 'Password'
          },
          remember_checkbox => {
            exists: true,
            enabled: true,
            checked: false
          },
          forgot_password_link => {
            visible: true,
            caption: 'Forgot your password?'
          },
          error_message_label => { visible: false }
        }
        verify_ui_states(ui)
      end
    end

    class RegistrationPage < TestCentricity::PageObject
      trait(:page_name)    { 'Registration' }
      trait(:page_url)     { '/register' }
      trait(:page_locator) { 'body.registration' }

      # Registration page UI elements
      textfields  first_name_field:    'input#firstName',
                  last_name_field:     'input#lastName',
                  email_field:         'input#email',
                  phone_number_field:  'input#phone',
                  address_field:       'input#streetAddress',
                  city_field:          'input#city',
                  post_code_field:     'input#postalCode',
                  password_field:      'input#password',
                  pword_confirm_field: 'input#passwordConfirmation'
      selectlists title_select:        'select#title',
                  gender_select:       'select#gender',
                  state_select:        'select#stateProvince'
      checkbox    :email_opt_in_check, 'input#marketingEmailsOptIn'
      buttons     sign_up_button:      'button#registrationSignUp',
                  cancel_button:       'button#registrationCancel'

      # populate Registration page fields with profile data
      def enter_profile_data(profile)
        fields = { title_select        => profile.title,
                   first_name_field    => profile.first_name,
                   last_name_field     => profile.last_name,
                   gender_select       => profile.gender,
                   phone_number_field  => profile.phone,
                   email_field         => profile.email,
                   address_field       => profile.address,
                   city_field          => profile.city,
                   state_select        => profile.state,
                   post_code_field     => profile.postal_code,
                   password_field      => profile.password,
                   pword_confirm_field => profile.confirm_password,
                   email_opt_in_check  => profile.email_opt_in
        }
        populate_data_fields(fields)
        sign_up_button.click
      end
    end

Once your PageObjects have been instantiated, you can call your methods as shown below:

    login_page.remember_me(true)
    login_page.login(user_id = 'snicklefritz', password = 'Pa55w0rd')

PageSections

A PageSection is a collection of UI Elements that may appear in multiple locations on a page, or on multiple pages in a web app. It is a collection of UI Elements that represent a conceptual area of functionality, like a navigation bar, a search capability, a menu, or a pop-up panel. UI Elements and functional behavior are confined to the scope of a PageSection object.

Below is an example of a header navigation bar feature that is common to multiple pages -

Navigation Header

-

Navigation Header

Below is an example of a popup Shopping Bag panel associated with a header navigation bar -

Shopping Bag Popup

A PageSection may contain other PageSection objects.

Defining a PageSection

Your PageSection class definitions should be contained within individual .rb files in the features/support/sections folder of your test automation project. You define new PageSection as shown below:

    class BagViewPopup < TestCentricity::PageSection
    end

Adding Traits to a PageSection

A PageSection typically has a root node object that encapsulates a collection of UIElements. The section_locator trait specifies the CSS or Xpath expression that uniquely identifies that root node object.

You define your section's Traits as shown below:

    class BagViewPopup < TestCentricity::PageSection
      trait(:section_locator) { 'aside.ac-gn-bagview' }
      trait(:section_name)    { 'Shopping Bag Popup' }
    end

Adding UI Elements to a PageSection

PageSections are typically made up of UI elements like text fields, check boxes, combo boxes, radio buttons, tables, lists, buttons, etc. UI Elements are added to your PageSection class definition as shown below:

    class BagViewPopup < TestCentricity::PageSection
      trait(:section_locator) { 'aside.ac-gn-bagview' }
      trait(:section_name)    { 'Shopping Bag Popup' }

      # Shopping Bag Popup UI elements
      label  :bag_message,     'p[class*="ac-gn-bagview-message"]'
      lists  bag_items_list:   'ul[class*="ac-gn-bagview-bag"]',
             bag_nav_list:     'ul.ac-gn-bagview-nav-list '
      button :checkout_button, 'a[class*="ac-gn-bagview-button-checkout"]'
    end

Adding Methods to a PageSection

You can add high level methods to your PageSection class definition, as shown below:

    class BagViewPopup < TestCentricity::PageSection
      trait(:section_locator) { 'aside.ac-gn-bagview' }
      trait(:section_name)    { 'Shopping Bag Popup' }

      # Shopping Bag Popup UI elements
      label  :bag_message,     'p[class*="ac-gn-bagview-message"]'
      lists  bag_items_list:   'ul[class*="ac-gn-bagview-bag"]',
             bag_nav_list:     'ul.ac-gn-bagview-nav-list '
      button :checkout_button, 'a[class*="ac-gn-bagview-button-checkout"]'

      def item_count
        bag_items_list.visible? ? bag_items_list.item_count : 0
      end

      def perform_action(action)
        case action.gsub(/\s+/, '_').downcase.to_sym
        when :check_out
          checkout_button.click
        when :view_bag
          bag_nav_list.choose_item(1)
        when :saved_items
          bag_nav_list.choose_item(2)
        when :orders
          bag_nav_list.choose_item(3)
        when :account
          bag_nav_list.choose_item(4)
        when :sign_in, :sign_out
          bag_nav_list.choose_item(5)
        else
          raise "#{action} is not a valid selector"
        end
      end
    end

Adding PageSections to your PageObject

You add a PageSection to its associated PageObject as shown below:

    class HomePage < TestCentricity::PageObject
      trait(:page_name)    { 'Home' }
      trait(:page_url)     { '/dashboard' }
      trait(:page_locator) { 'body.dashboard' }

      # Home page Section Objects
      section :search_form, SearchForm
    end

Once your PageObject has been instantiated, you can call its PageSection methods as shown below:

    home_page.search_form.search_for('ocarina')

UIElements

PageObjects and PageSections are typically made up of UI elements like text fields, check boxes, select lists (combo boxes), radio buttons, tables, ordered and unordered lists, buttons, images, HTML5 video or audio player objects, etc. UI elements are declared and instantiated within the class definition of the PageObject or PageSection in which they are contained. With TestCentricity For Web, all UI elements are based on the UIElement class.

Declaring and Instantiating UIElements

Single UIElement declarations have the following format:

elementType :elementName, locator

Multiple UIElement declarations for a collection of elements of the same type can be performed by passing a hash table containing the names and locators of each individual element.

Example UIElement Declarations

Supported UIElement elementTypes and their declarations have the following format:

Single element declarations:

    class SamplePage < TestCentricity::PageObject

      button     :button_name, locator
      textfield  :field_name, locator
      checkbox   :checkbox_name, locator
      radio      :radio_button_name, locator
      label      :label_name, locator
      link       :link_name, locator
      selectlist :select_name, locator
      list       :list_name, locator
      table      :table_name, locator
      range      :range_name, locator
      image      :image_name, locator
      video      :video_name, locator
      audio      :audio_name, locator
      filefield  :filefield_name, locator

    end

Multiple element declarations:

    class SamplePage < TestCentricity::PageObject

      buttons     button_1_name: locator,
                  button_2_name: locator,
                  button_X_name: locator
      textfields  field_1_name: locator,
                  field_2_name: locator,
                  field_X_name: locator
      checkboxes  check_1_name: locator,
                  check_2_name: locator,
                  check_X_name: locator
      radios      radio_1_name: locator,
                  radio_X_name: locator
      labels      label_1_name: locator,
                  label_X_name: locator
      links       link_1_name: locator,
                  link_X_name: locator
      selectlists selectlist_1_name: locator,
                  selectlist_X_name: locator
      lists       list_1_name: locator,
                  list_X_name: locator
      tables      table_1_name: locator,
                  table_X_name: locator
      ranges      range_1_name: locator,
                  range_X_name: locator
      images      image_1_name: locator,
                  image_X_name: locator
      videos      video_1_name: locator,
                  video_X_name: locator
      audios      audio_1_name: locator,
                  audio_X_name: locator
      filefields  filefield_1_name: locator,
                  filefield_X_name: locator

    end

Refer to the Class List documentation for the PageObject and PageSection classes for details on the class methods used for declaring and instantiating UIElements. Examples of UI element declarations can be found in the section 4.3 (Adding UI Elements to your PageObject) and section 5.3 (Adding UI Elements to your PageSection) sections above.

UIElement Inherited Methods

With TestCentricity, all UI elements are based on the UIElement class, and inherit the following methods:

Action methods:

element.click
element.double_click
element.right_click
element.click_at(x, y)
element.hover
element.hover_at(x, y)
element.scroll_to(position)
element.drag_by(right_offset, down_offset)
element.drag_and_drop(target, right_offset, down_offset)

Object state methods:

element.exists?
element.visible?
element.hidden?
element.enabled?
element.disabled?
element.displayed?
element.obscured?
element.focused?
element.required?
element.content_editable?
element.crossorigin
element.get_value
element.count
element.style
element.title
element.width
element.height
element.x
element.y
element.get_attribute(attrib)
element.get_native_attribute(attrib)

Waiting methods:

element.wait_until_exists(seconds)
element.wait_until_gone(seconds)
element.wait_until_visible(seconds)
element.wait_until_hidden(seconds)
element.wait_until_enabled(seconds)
element.wait_until_value_is(value, seconds)
element.wait_until_value_changes(seconds)
element.wait_while_busy(seconds)

WAI-ARIA Object Accessibility (A11y) methods:

element.role
element.tabindex
element.aria_disabled?
element.aria_hidden?
element.aria_expanded?
element.aria_required?
element.aria_invalid?
element.aria_checked?
element.aria_readonly?
element.aria_haspopup?
element.aria_selected?
element.aria_pressed?
element.aria_label
element.aria_labelledby
element.aria_describedby
element.aria_live
element.aria_sort
element.aria_rowcount
element.aria_colcount
element.aria_valuemax
element.aria_valuemin
element.aria_valuenow
element.aria_valuetext
element.aria_orientation
element.aria_roledescription
element.aria_autocomplete
element.aria_controls
element.aria_modal?
element.aria_keyshortcuts
element.aria_multiline?
element.aria_multiselectable?
element.aria_busy?

Populating a PageObject or PageSection With Data

A typical automated test may be required to perform the entry of test data by interacting with various UIElements on your PageObject or PageSection. This data entry can be performed using the various object action methods (listed above) for each UIElement that needs to be interacted with.

The PageObject.populate_data_fields and PageSection.populate_data_fields methods support the entry of test data into a collection of UIElements. The populate_data_fields method accepts a hash containing key/hash pairs of UIElements and their associated data to be entered. Data values must be in the form of a String for textfield, selectlist, and filefield controls. For checkbox and radio controls, data must either be a Boolean or a String that evaluates to a Boolean value (Yes, No, 1, 0, true, false). For range controls, data must be an Integer. For input(type='color') color picker controls, which are specified as a textfield, data must be in the form of a hex color String. For section objects, data values must be a String, and the section object must have a set method defined.

The populate_data_fields method verifies that data attributes associated with each UIElement is not nil or empty before attempting to enter data into the UIElement.

The optional wait_time parameter is used to specify the time (in seconds) to wait for each UIElement to become viable for data entry (the UIElement must be visible and enabled) before entering the associated data value. This option is useful in situations where entering data, or setting the state of a UIElement might cause other UIElements to become visible or active. Specifying a wait_time value ensures that the subsequent UIElements will be ready to be interacted with as states are changed. If the wait time is nil, then the wait time will be 5 seconds.

    def enter_data(user_data)
      fields = {
        first_name_field    => user_data.first_name,
        last_name_field     => user_data.last_name,
        email_field         => user_data.email,
        country_code_select => user_data.country_code,
        phone_number_field  => user_data.phone_number,
        time_zone_select    => user_data.time_zone,
        language_select     => user_data.language
      }
      populate_data_fields(fields, wait_time = 2)
    end

Verifying UIElements on a PageObject or PageSection

A typical automated test executes one or more interactions with the user interface, and then performs a validation to verify whether the expected state of the UI has been achieved. This verification can be performed using the various object state methods (listed above) for each UIElement that requires verification. Depending on the complexity and number of UIElements to be verified, the code required to verify the presence of UIElements and their correct states can become cumbersome.

The PageObject.verify_ui_states and PageSection.verify_ui_states methods support the verification of multiple properties of multiple UI elements on a PageObject or PageSection. The verify_ui_states method accepts a hash containing key/hash pairs of UI elements and their properties or attributes to be verified.

     ui = {
       object1 => { property: state },
       object2 => { property: state, property: state },
       object3 => { property: state }
     }
     verify_ui_states(ui)

The verify_ui_states method queues up any exceptions that occur while verifying each object's properties until all UIElements and their properties have been checked, and then posts any exceptions encountered upon completion. Posted exceptions include a screenshot with a red dashed highlight around the UI element that did not match the expected results.

The verify_ui_states method supports the following property/state pairs:

All Objects:

:exists            Boolean
:enabled           Boolean
:disabled          Boolean
:visible           Boolean
:hidden            Boolean
:displayed         Boolean
:obscured          Boolean
:width             Integer
:height            Integer
:x                 Integer
:y                 Integer
:class             String
:value or :caption String
:attribute         Hash
:style             String
:tabindex          Integer
:required          Boolean
:crossorigin       String

Pages:

:secure Boolean
:title  String

Text Fields:

:readonly    Boolean
:placeholder String
:maxlength   Integer
:min         Integer
:max         Integer
:step        Integer

Text Field Constraint Validation

:validation_message String
:badInput           Boolean
:customError        Boolean
:patternMismatch    Boolean
:rangeOverflow      Boolean
:rangeUnderflow     Boolean
:stepMismatch       Boolean
:tooLong            Boolean
:tooShort           Boolean
:typeMismatch       Boolean
:valid              Boolean
:valueMissing       Boolean

Checkboxes:

:checked       Boolean
:indeterminate Boolean

Radio Buttons:

:selected Boolean

Links:

:href String

Images

:loaded Boolean
:broken Boolean
:src    String
:alt    String

Lists

:items     Array of Strings
:itemcount Integer
:item      Hash
:selected  String

Select Lists (ComboBoxes):

:items or :options         Array of Strings
:itemcount or :optioncount Integer
:selected                  String
:groupcount                Integer
:group_headings            Array of Strings

Tables

:rowcount      Integer
:columncount   Integer
:columnheaders Array of String
:cell          Hash
:row           Hash
:column        Hash

Audio/Video Media Objects

:autoplay              Boolean
:ended                 Boolean
:controls              Boolean
:loop                  Boolean
:muted                 Boolean
:default_muted         Boolean
:paused                Boolean
:seeking               Boolean
:src                   String
:current_time          Float
:default_playback_rate Float
:duration              Float
:playback_rate         Float
:ready_state           Integer
:volume                Float
:preload               String
:poster                String
:track_count           Integer
:active_track          Integer
:active_track_data     Hash
:all_tracks_data       Array of Hash
:track_data            Hash
:active_track_source   String
:track_source          String

ARIA Accessibility Property/State Pairs

The verify_ui_states method supports the following ARIA accessibility property/state pairs:

:aria_label           String
:aria_disabled        Boolean
:aria_labelledby      String
:aria_describedby     String
:aria_live            Boolean
:aria_selected        Boolean
:aria_hidden          Boolean
:aria_expanded        Boolean
:aria_required        Boolean
:aria_invalid         Boolean
:aria_checked         Boolean
:aria_readonly        Boolean
:aria_pressed         Boolean
:aria_busy            Boolean
:aria_haspopup        Boolean
:aria_sort            String
:aria_rowcount        String
:aria_colcount        String
:aria_valuemax        String
:aria_valuemin        String
:aria_valuenow        String
:aria_valuetext       String
:aria_orientation     String
:aria_keyshortcuts    String
:aria_roledescription String
:aria_autocomplete    String
:aria_controls        String
:aria_modal           String
:aria_multiline       Boolean
:aria_multiselectable Boolean
:content_editable     Boolean
:role                 String

Comparison States

The verify_ui_states method supports comparison states using property/comparison state pairs:

    object => { property: { comparison_state: value } }

Comparison States:

:lt or :less_than                  Integer or String
:lt_eq or :less_than_or_equal      Integer or String
:gt or :greater_than               Integer or String
:gt_eq or :greater_than_or_equal   Integer or String
:starts_with                       String
:ends_with                         String
:contains                          String
:not_contains or :does_not_contain Integer or String
:not_equal                         Integer, String, or Boolean

The example below depicts a verify_changes_saved method that uses the verify_ui_states method to verify that all expected values appear in the associated text fields after entering data and performing a save operation.

    def verify_changes_saved
      # verify saved user data is correctly displayed
      ui = {
        first_name_field => {
          visible: true,
          aria_invalid: false,
          value: User.current.first_name
        },
        last_name_field => {
          visible: true,
          aria_invalid: false,
          value: User.current.last_name
        },
        email_field => {
          visible: true,
          aria_invalid: false,
          value: User.current.email
        },
        phone_number_field => {
          visible: true,
          aria_invalid: false,
          value: User.current.phone_number
        },
        time_zone_select => {
          visible: true,
          aria_invalid: false,
          value: User.current.time_zone
        },
        language_select => {
          visible: true,
          aria_invalid: false,
          value: User.current.language
        },
        avatar_container => { visible: true },
        avatar_image => {
          visible: true,
          broken: false,
          src: { ends_with: User.current.avatar_file_name },
          alt: "#{User.current.first_name} #{User.current.last_name}",
          style: { contains: 'border-radius: 50%;'}
        },
        error_message_label => { visible: false }
      }
      verify_ui_states(ui)

      # verify avatar src url does not contain /null/ institution id
      verify_ui_states(avatar_image => { src: { does_not_contain: "/null/" } })
    end

I18n Translation Validation

The verify_ui_states method also supports I18n string translations using property/I18n key name pairs:

    object => { property: { translate_key: 'name of key in I18n compatible .yml file' } }

I18n Translation Keys:

:translate            String
:translate_upcase     String
:translate_downcase   String
:translate_capitalize String
:translate_titlecase  String

The example below depicts the usage of the verify_ui_states method to verify that the captions for a popup Shopping Bag panel are correctly translated.

Localized UI

    class BagViewPopup < TestCentricity::PageSection
      trait(:section_locator) { 'aside.ac-gn-bagview' }
      trait(:section_name)    { 'Shopping Bag Popup' }

      # Shopping Bag Popup UI elements
      label  :bag_message,     'p[class*="ac-gn-bagview-message"]'
      lists  bag_items_list:   'ul[class*="ac-gn-bagview-bag"]',
             bag_nav_list:     'ul.ac-gn-bagview-nav-list '
      button :checkout_button, 'a[class*="ac-gn-bagview-button-checkout"]'

      def verify_empty_bag_ui
        nav_items = %w[
          BagViewPopup.bag
          BagViewPopup.saved_items
          BagViewPopup.orders
          BagViewPopup.account
          BagViewPopup.sign_in
        ]
        ui = {
          bag_message => {
            visible: true,
            caption: { translate: 'BagViewPopup.bag_is_empty' }
          },
          bag_nav_list => {
            visible: true,
            itemcount: 5,
            items: { translate: nav_items }
          },
          bag_items_list => { visible: false },
          checkout_button => { visible: false }
        }
        verify_ui_states(ui)
      end
    end

I18n .yml files contain key/value pairs representing the name of a translated string (key) and the string value. For the popup Shopping Bag panel example above, the translated strings for English, Spanish, and French are represented in below:

English - en.yml

    en:
      BagViewPopup:
        bag_is_empty: 'Your Bag is empty.'
        bag: 'Bag'
        saved_items: 'Saved Items'
        orders: 'Orders'
        account: 'Account'
        sign_in: 'Sign in'
        sign_out: 'Sign out'

Spanish - es.yml

    es:
      BagViewPopup:
        bag_is_empty: 'Tu bolsa está vacía.'
        bag: 'Bolsa'
        saved_items: 'Artículos guardados'
        orders: 'Pedidos'
        account: 'Cuenta'
        sign_in: 'Iniciar sesión'
        sign_out: 'Cerrar sesión'

French - fr.yml

    fr:
      BagViewPopup:
        bag_is_empty: 'Votre sac est vide.'
        bag: 'Sac'
        saved_items: 'Articles enregistrés'
        orders: 'Commandes'
        account: 'Compte'
        sign_in: 'Ouvrir une session'
        sign_out: 'Fermer la session'

Each supported language/locale combination has a corresponding .yml file. I18n .yml file naming convention uses ISO-639 language codes and ISO-3166 country codes. For example:

Language (Country) File name
English en.yml
English (Canada) en-CA.yml
French (Canada) fr-CA.yml
French fr.yml
Spanish es.yml
German de.yml
Portuguese (Brazil) pt-BR.yml
Portuguese (Portugal) pt-PT.yml

Baseline translation strings are stored in .yml files in the config/locales/ folder.

   📁 my_automation_project/
    ├── 📁 config/
    │   ├── 📁 locales/
    │   │   ├── 📄 en.yml
    │   │   ├── 📄 en-AU.yml
    │   │   ├── 📄 es.yml
    │   │   ├── 📄 de.yml
    │   │   ├── 📄 fr.yml
    │   │   ├── 📄 fr-CA.yml
    │   │   ├── 📄 pt-BR.yml
    │   │   └── 📄 pt-PT.yml
    │   ├── 📁 test_data/
    │   └── 📄 cucumber.yml
    ├── 📁 downloads/
    ├── 📁 features/
    ├── 📄 Gemfile
    └── 📄 README.md

Working With Custom UIElements

Many responsive and touch-enabled web based user interfaces are implemented using front-end JavaScript libraries for building user interfaces based on multiple composite UI components. Popular JS libraries include React, Angular, and Ember.js. These stylized and adorned controls can present a challenge when attempting to interact with them using Capybara and Selenium based automated tests.

Radio and Checkbox UIElements

Sometimes, radio buttons and checkboxes implemented using JS component libraries cannot be interacted with due to other UI elements being overlaid on top of them, causing the base input(type='radio') or input(type='checkbox') element to not receive click actions.

In the screenshot below of an airline flight search and booking page, the Round-trip, One-way, and Multi-city radio buttons are overlaid with div elements that also acts as proxies for their associated input(type='radio') elements, and that intercept the click actions that would normally be handled by the input(type='radio') elements.

Custom Radio buttons

The checkbox controls on the airline flight search and booking page are also overlaid with div elements that intercept the click actions that would normally be handled by the input(type='checkbox') elements.

Custom Checkbox controls

The Radio.define_custom_elements and CheckBox.define_custom_elements methods provide a way to specify the input, proxy, and/or label elements associated with the input(type='radio') and input(type='checkbox') elements. The define_custom_elements method should be called from an initialize method for the PageObject or PageSection where the radio or checkbox elements are instantiated.

The code snippet below demonstrates the use of the Radio.define_custom_elements and CheckBox.define_custom_elements methods to define the multiple UI elements that comprise each radio button and checkbox.

    class FlightBookingPage < TestCentricity::PageObject
      trait(:page_name)    { 'Flight Booking Home' }
      trait(:page_locator) { 'div[class*="bookerContainer"]' }

      # Flight Booking page UI elements
      radios     roundtrip_radio:  'div[role="radiogroup"] > div.ftRadio:nth-of-type(1)',
                 one_way_radio:    'div[role="radiogroup"] > div.ftRadio:nth-of-type(2)',
                 multi_city_radio: 'div[role="radiogroup"] > div.ftRadio:nth-of-type(3)'
      checkboxes use_miles_check:  'div#divAwardReservation',
                 flex_dates_check: 'div#divLowFareCalendar > div.left',
                 near_from_check:  'div#divIncludeNearbyDepartureAirports',
                 near_to_check:    'div#divIncludeNearbyArrivalAirports'

      def initialize
        # define the custom element components for the Round Trip, One Way, and Multi-City radio buttons
        radio_spec = {
          input: 'input[type="radio"]',
          label: 'label.normal'
        }
        roundtrip_radio.define_custom_elements(radio_spec)
        one_way_radio.define_custom_elements(radio_spec)
        multi_city_radio.define_custom_elements(radio_spec)

        # define the custom element components for the checkboxes
        check_spec = {
          input: 'input[type="checkbox"]',
          label: 'label.normal'
        }
        use_miles_check.define_custom_elements(check_spec)
        flex_dates_check.define_custom_elements(check_spec)
        near_from_check.define_custom_elements(check_spec)
        near_to_check.define_custom_elements(check_spec)
      end
    end

List UIElements

The basic HTML list element is typically composed of the parent ul or ol object, and one or more li elements representing the items in the list. However, list controls implemented using JS component libraries can be composed of multiple elements representing the components of a list implementation.

In the screenshots below, an inspection of the Menu Groups horizontal scrolling list on a Restaurant Detail page reveals that it is a div element that contains multiple button elements with data-testid attributes of menu-group that represent the list items that can be selected.

Custom List

The List.define_list_elements method provides a means of specifying the elements that make up the key components of a list control. The method accepts a hash of element designators (key) and a CSS or Xpath expression (value) that expression that uniquely identifies the element. Valid element designators are :list_itemand :selected_item.

The RestaurantPage page object's initialize method in the code snippet below demonstrates the use of the List.define_list_elements method to define the common components that make up the Menu Groups horizontal scrolling list.

    class RestaurantPage < TestCentricity::PageObject
      trait(:page_name)    { 'Restaurant Detail' }
      trait(:page_locator) { 'div.restaurant-menus-container' }

      # Restaurant Detail page UI elements
      list :menu_groups_list, 'div[class*="menus-and-groups-selector__SliderItems"]'

      def initialize
        super
        # define the custom list element components for the Menu Groupslists
        list_spec = { list_item: 'button[data-testid="menu-group"]' }
        menu_groups_list.define_list_elements(list_spec)
      end
    end

SelectList UIElements

The basic HTML select element is typically composed of the parent select object, and one or more option elements representing the selectable items in the drop-down list. However, select type controls implemented using JS component libraries (React.js, Chosen, GWT, etc.) can be composed of multiple elements representing the various components of a drop-down style selectlist implementation.

Custom SelectList

In the screenshots below, an inspection of the Football Teams selector reveals that it is a div element that contains a textfield element (outlined in purple) for inputting a selection by typing, a ul element (outlined in blue) that contains the drop-down list, and multiple li elements with the active-result snippet in their class names (outlined in orange) that represent the list items or options that can be selected. The currently selected item or option can be identified by an li with the result-selected snippet in its class name. Group headings and items in the drop-down list are represented by li elements with a class name of group-result (outlined in green).

Custom SelectList

The SelectList.define_list_elements method provides a means of specifying the various elements that make up the key components of a selectlist control. The method accepts a hash of element designators (key) and a CSS or Xpath expression (value) that uniquely identifies the element. Valid element designators are :list_item, :options_list, :list_trigger, :selected_item, :text_field, :group_heading, and :group_item.

The CustomControlsPage page object's initialize method in the code snippet below demonstrates the use of the SelectList.define_list_elements method to define the common components that make up the Teams drop-down style selector.

    class CustomControlsPage < TestCentricity::PageObject
      trait(:page_name)    { 'Custom Controls' }
      trait(:page_locator) { 'div.custom-controls-page-body' }

      # Custom Controls page UI elements
      selectlists country_select: 'div#country_chosen',
                  team_select:    'div#team_chosen'

      def initialize
        super
        # define the custom list element components for the Team Chosen selectlists
        list_spec = {
          selected_item: 'li[class*="result-selected"]',
          list_item:     'li[class*="active-result"]',
          text_field:    'input.chosen-search-input',
          options_list:  'ul.chosen-results',
          group_item:    'li.group-result',
          group_heading: 'li.group-result'
        }
        country_select.define_list_elements(list_spec)
        team_select.define_list_elements(list_spec)
      end
    end

Table UIElements

The basic HTML table element is typically composed of the parent table object, a body (tbody) containing one or more rows (tr), with each row containing one or more columns (td). Tables can also include an optional header (thead) with a header row (tr) containing one or more header columns (th).

However, custom tables can be implemented using elements other than the standard table components described above. In the screenshot below, an inspection of the table reveals that it is comprised of div elements representing the table, body, rows, columns, header, header row, and header columns.

Custom Table

The Table.define_table_elements method provides a means of specifying the various elements that make up the key components of a table. The method accepts a hash of element designators (key) and a CSS or Xpath expression (value) that uniquely identifies the element. Valid element designators are :table_header, :header_row, :header_column, :table_body, :table_row, and :table_column.

The CustomControlsPage page object's initialize method in the code snippet below demonstrates the use of the Table.define_table_elements method to define the components that make up the responsive table.

    class CustomControlsPage < TestCentricity::PageObject
      trait(:page_name)    { 'Custom Controls' }
      trait(:page_locator) { 'div.custom-controls-page-body' }

      # Custom Controls page UI elements
      table :custom_table, 'div#resp-table'

      def initialize
        super
        # define the custom element components for the table
        table_spec = {
          table_header:  'div.resp-table-header',
          header_row:    'div.resp-table-row',
          header_column: 'div.table-header-cell',
          table_body:    'div.resp-table-body',
          table_row:     'div.resp-table-row',
          table_column:  'div.table-body-cell'
        }
        custom_table.define_table_elements(table_spec)
      end
    end

Instantiating Your PageObjects

Before you can call the methods in your PageObjects and PageSections, you must instantiate the PageObjects of your web application, as well as create instance variables which can be used when calling a PageObject's methods from your step definitions. There are several ways to instantiate your PageObjects.

One common implementation is shown below:

    module WorldPages
      def login_page
        @login_page ||= LoginPage.new
      end

      def home_page
        @home_page ||= HomePage.new
      end

      def registration_page
        @registration_page ||= RegistrationPage.new
      end

      def search_results_page
        @search_results_page ||= SearchResultsPage.new
      end
    end

    World(WorldPages)

The WorldPages module above can be defined in your env.rb file, or you can define it in a separate world_pages.rb file in the features/support folder.

While this approach is effective for small web applications with only a few pages (and hence few PageObjects), it quickly becomes cumbersome to manage if your web application has dozens of PageObjects that need to be instantiated and managed.

Using the PageManager

The PageManager class provides methods for supporting the instantiation and management of PageObjects. In the code example below, the page_objects method contains a hash table of your PageObject instances and their associated PageObject classes to be instantiated by PageManager:

    module WorldPages
      def page_objects
        {
          login_page:                LoginPage,
          home_page:                 HomePage,
          registration_page:         RegistrationPage,
          search_results_page:       SearchResultsPage,
          products_grid_page:        ProductsCollectionPage,
          product_detail_page:       ProductDetailPage,
          shopping_basket_page:      ShoppingBasketPage,
          payment_method_page:       PaymentMethodPage,
          confirm_purchase_page:     PurchaseConfirmationPage,
          my_account_page:           MyAccountPage,
          my_order_history_page:     MyOrderHistoryPage,
          my_ship_to_addresses_page: MyShipToAddressesPage,
          terms_conditions_page:     TermsConditionsPage,
          privacy_policy_page:       PrivacyPolicyPage,
          faqs_page:                 FAQsPage,
          contact_us_page:           ContactUsPage
        }
      end
    end

    World(WorldPages)

The WorldPages module above should be defined in the world_pages.rb file in the features/support folder.

Include the code below in your env.rb file to ensure that your PageObjects are instantiated before your Cucumber scenarios are executed:

    include WorldPages
    WorldPages.instantiate_page_objects

NOTE: If you intend to use the PageManager, you must define a page_name trait for each of the PageObjects to be registered.

Leveraging the PageManager in Your Cucumber Tests

Many Cucumber based automated tests suites include scenarios that verify that web pages are correctly loaded, displayed, or can be navigated to by clicking associated links. One such Cucumber navigation scenario is displayed below:

    Scenario Outline:  Verify Home page navigation links
      Given I am on the Home page
      When I click the <page name> navigation link
      Then I expect the <page name> page to be correctly displayed

      Examples:
        |page name          |
        |Registration       |
        |My Account         |
        |Terms & Conditions |
        |Privacy Policy     |
        |FAQs               |
        |Contact Us         |

In the above example, the step definitions associated with the 3 steps might be implemented using a page_dispatcher method using a case statement to parse the page parameter as in the example below:

    Given(/^I am on the (.*) page$/) do |page_name|
      target_page = page_dispatcher(page_name)
      target_page.load_page
    end

    When(/^I click the (.*) navigation link$/) do |link_name|
      target_page = page_dispatcher(link_name)
      target_page.navigate_to
    end

    Then(/^I expect the (.*) page to be correctly displayed$/) do |page_name|
      target_page = page_dispatcher(page_name)
      target_page.verify_page_exists
      target_page.verify_page_ui
    end

    # this method takes a page name as a parameter and returns an instance of the associated Page Object
      def page_dispatcher(page_name)
        page = case page_name
               when 'Registration'
                 registration_page
               when 'My Account'
                 my_account_page
               when 'Terms & Conditions'
                 terms_conditions_page
               when 'Privacy Policy'
                 privacy_policy_page
               when 'Contact Us'
                 contact_us_page
               when 'FAQs'
                 faqs_page
               end
        raise "No page object defined for page named '#{page_name}'" unless page
        page
      end

While this approach may be effective for small web applications with only a few pages (and hence few PageObjects), it quickly becomes cumbersome to manage if your web application has dozens of PageObjects that need to be managed.

The PageManager class provides a find_page method that replaces the cumbersome and difficult to maintain case statement used in the above example. The PageManager.current_page method allows you to set or get an instance of the currently active Page Object.

To use these PageManager methods, include the step definitions and code below in a page_steps.rb or generic_steps.rb file in the features/step_definitions folder:

    include TestCentricity

    Given(/^I am on the (.*) page$/) do |page_name|
      target_page = PageManager.find_page(page_name)
      target_page.load_page
    end

    When(/^I click the (.*) navigation link$/) do |page_name|
      target_page = PageManager.find_page(page_name)
      target_page.navigate_to
    end

    Then(/^I expect to see the (.*) page$/) do |page_name|
      target_page = PageManager.find_page(page_name)
      target_page.verify_page_exists
    end

    Then(/^I expect the (.*) page to be correctly displayed$/) do |page_name|
      target_page = PageManager.find_page(page_name)
      target_page.verify_page_exists
      target_page.verify_page_ui
    end

Connecting to Web Browsers

Since its inception, TestCentricity has provided support for establishing a single connection to a target desktop or mobile web browser by instantiating a WebDriver object. Environment Variables are used to specify the local, grid, or remote cloud hosted target web browser, and the various WebDriver capability parameters required to configure the driver object. The appropriate Environment Variables are typically specified in the command line at runtime through the use of profiles set in a cucumber.yml file (Refer to section 8.9 (Using Browser Specific Profiles in cucumber.yml) below).

However, for those use cases requiring the instantiation of multiple WebDriver objects within a test case or test scenario, Environment Variables are a less effective means of specifying multiple driver capabilities. And even in those use cases where only a single WebDriver object is required, there are a growing number of optional Selenium and Appium capabilities that are being offered by cloud hosted browser service providers (like BrowserStack, Sauce Labs, TestingBot, or LambdaTest) that Environment Variables may not effectively address.

Beginning with TestCentricity version 4.4.0, the TestCentricity::WebDriverConnect.initialize_web_driver method accepts an optional options hash for specifying desired capabilities (using the W3C protocol), driver type, driver name, endpoint URL, device type, and desktop web browser window size information. TestCentricity also now supports the instantiation of multiple WebDriver objects to establish connections with, and coordinate test execution between multiple desktop and/or mobile web browser instances.

Some use cases for the verification of real-time multiple user interactions across multiple concurrent browsers or devices are:

If the optional options hash is not provided when calling the TestCentricity::WebDriverConnect.initialize_web_driver method, then Environment Variables must be used to specify the target local or remote web browser, and the various webdriver capability parameters required to establish a connection with a single target web browser.

Specifying Options and Capabilities in the options Hash

For those test scenarios requiring the instantiation of multiple WebDriver objects, or where cumbersome Environment Variables are less than ideal, call the TestCentricity::WebDriverConnect.initialize_web_driver method with an options hash that specifies the WebDriver desired capabilities and the driver type, as depicted in the example below:

    options = {
      capabilities: { browserName: :firefox },
      driver: :webdriver
    }
    WebDriverConnect.initialize_web_driver(options)

Additional options that can be specified in an options hash include the following:

Option Purpose
browser_size: optional desktop web browser window size (width and height)
driver_name: optional driver name
endpoint: optional endpoint URL for remote grid or cloud hosted browser service providers
device_type: only used for locally or cloud hosted mobile device browser - set to :phone or :tablet

Details on specifying desired capabilities, driver type, endpoint URL, and default driver names are provided in each of the browser hosting sections below.

Specifying the Driver Type

The driver: type is a required entry in the options hash when instantiating a WebDriver object using the initialize_web_driver method. Valid driver: type values are listed in the table below:

driver: Driver Type
:webdriver locally hosted desktop or emulated mobile browser
:grid Selenium Grid 4 hosted browser
:appium locally hosted native iOS/Android mobile browser using device simulator or physical device
:browserstack remote browser hosted on BrowserStack
:saucelabs remote browser hosted on Sauce Labs
:testingbot remote browser hosted on TestingBot
:lambdatest remote browser hosted on LambdaTest
:custom remote browser hosted on unsupported cloud based browser hosting services

Specifying a Driver Name

An optional user defined driver_name: can be specified in the options hash when instantiating a WebDriver object using the TestCentricity::WebDriverConnect.initialize_web_driver method. If a driver name is not specified, the initialize_web_driver method will assign a default driver name comprised of the specified driver type (driver:) and the browserName: specified in the capabilities: hash. Details on default driver names are provided in each of the browser hosting sections below.

For those test scenarios requiring the instantiation of multiple WebDriver objects, each driver object should be assigned a unique driver name, which is used when switching between driver contexts. For instance, when performing end-to-end testing of a Food Delivery Service which consists of separate web portals for the Customer Experience (find, order, and pay for food), the Restaurant Experience (menu management, order fulfillment, and order delivery dispatch), and the Delivery Driver Experience (customer location and tracking), 3 driver objects must be instantiated.

Assigning meaningful unique driver names for the 3 driver objects (:customer_portal, :merchant_portal, :delivery_portal) in the options hash when calling TestCentricity::WebDriverConnect.initialize_web_driver method reduces confusion when switching between the driver objects using the TestCentricity:WebDriverConnect.activate_driver(driver_name) method, which expects a driver name, specified as a Symbol.

Setting Desktop Browser Window Size

Using :browser_size in the options Hash

The size (width and height) of a desktop browser window can be specified in the options hash for browsers that are hosted locally, in a Selenium Grid, or by a cloud hosted browser service provider. You cannot set the size of a mobile device web browser, which is determined by the mobile device's screen size.

To set the size of a desktop browser window in the options hash, you specify a :browser_size with the desired width and height in pixels as shown below:

    options = {
      browser_size: [1100, 900],
      capabilities: { browserName: :edge },
      driver: :webdriver
    }
    WebDriverConnect.initialize_web_driver(options)

To maximize a desktop browser window, you specify a :browser_size of 'max' as shown below:

    options = {
      browser_size: 'max',
      capabilities: { browserName: :chrome },
      driver: :webdriver
    }
    WebDriverConnect.initialize_web_driver(options)

If a :browser_size is not specified, then the default size of a desktop browser window will be set to the size specified in the BROWSER_SIZE Environment Variable (if it has been specified) or to a default width and height of 1650 by 1000 pixels.

Using the BROWSER_SIZE Environment Variable

To set the size of a desktop browser window without using an options hash, you set the BROWSER_SIZE Environment Variable to the desired width and height in pixels as shown below:

BROWSER_SIZE=1600,1000

To maximize a desktop browser window, you set the BROWSER_SIZE Environment Variable to 'max' as shown below:

BROWSER_SIZE=max

If the BROWSER_SIZE Environment Variable is not specified, then the default size of a desktop browser window will be set to a width and height of 1650 by 1000 pixels.

Locally Hosted Desktop Web Browsers

For locally hosted desktop web browsers running on macOS, Windows, or Linux platforms, the browser type and driver type must be specified when calling the TestCentricity::WebDriverConnect.initialize_web_driver method. The table below contains the values that can be used to specify the locally hosted desktop web browser to be instantiated when calling the initialize_web_driver method:

browserName: or WEB_BROWSER Desktop Platform
chrome macOS, Windows, or Linux
chrome_headless macOS, Windows, or Linux (headless - no visible UI)
firefox macOS, Windows, or Linux
firefox_headless macOS, Windows, or Linux (headless - no visible UI)
edge macOS or Windows
edge_headless macOS or Windows (headless - no visible UI)
safari macOS only

Local Desktop Browser using Environment Variables

If the options hash is not provided when calling the TestCentricity::WebDriverConnect.initialize_web_driver method, then the following Environment Variables must be set as described in the table below:

Environment Variable Description
WEB_BROWSER Must be set to one of the values from the table above
DRIVER Must be set to webdriver
BROWSER_SIZE [Optional] Set to 'width in pixels, heigh in pixels' or 'max'

Refer to section 8.9 (Using Browser Specific Profiles in cucumber.yml) below.

Local Desktop Browser in the options Hash

When using the options hash, the following options and capabilities must be specified:

    options = {
      capabilities: { browserName: value_from_table_above },
      driver: :webdriver
    }
    WebDriverConnect.initialize_web_driver(options)

ℹ️ If an optional user defined driver_name: is not specified in the options hash, the default driver name will be set to :local_<browserName> - e.g. :local_chrome or :local_edge_headless.

Below is an example of an options hash for specifying a connection to a locally hosted Firefox desktop web browser. The options hash includes options for specifying the driver name and setting the browser window size.

    options = {
      driver: :webdriver,
      driver_name: :customer_context,
      browser_size: [1400, 1100],
      capabilities: { browserName: :firefox }
    }
    WebDriverConnect.initialize_web_driver(options)

Testing File Downloads With Desktop Browsers

File download functionality can be tested with locally hosted instances of Chrome, Edge, or Firefox desktop browsers. Your automation project must set the DOWNLOADS Environment Variable to true, which will result in a /downloads folder being created, which will be used as the destination for files that are downloaded by your automated tests. The /downloads folder will be at the same level as the /config and /features folders, as depicted below:

    📁 my_automation_project/
    ├── 📁 config/
    ├── 📁 downloads/
    ├── 📁 features/
    ├── 📄 Gemfile
    └── 📄 README.md

When running tests in multiple concurrent threads using the parallel_tests gem, a new folder will be created within the /downloads folder for each test thread. This is to ensure that files downloaded in each test thread are isolated from tests running in other parallel threads. An example of the/downloads folder structure for 4 parallel threads is depicted below:

    📁 my_automation_project/
    ├── 📁 config/
    ├── 📁 downloads/
    │   ├── 📁 1/
    │   ├── 📁 2/
    │   ├── 📁 3/
    │   └── 📁 4/
    ├── 📁 features/
    ├── 📄 Gemfile
    └── 📄 README.md

When testing file downloads using a local instance of Firefox, you will need to specify the MIME types of the various file types that your tests will be downloading. This is accomplished by setting the MIME_TYPES Environment Variable to a comma-delimited string containing the list of MIME types to be accepted. The MIME_TYPES Environment Variable should be set before initializing the Firefox web driver. This list of file types is required as it will prevent Firefox from displaying the File Download modal dialog, which will halt your automated tests. An example of a list of MIME types is depicted below:

    # set list of all supported MIME types for testing file downloads with Firefox
    mime_types = [
      'application/pdf',
      'image/png',
      'image/jpeg',
      'image/gif',
      'text/csv',
      'text/plain'
    ]
    ENV['MIME_TYPES'] = mime_types.join(',')

A detailed list of file MIME types can be found here.

Locally Hosted Emulated Mobile Web Browsers

You can run your tests against mobile device browsers that are emulated within a locally hosted instance of a Chrome desktop browser on macOS or Windows. The specified mobile browser's user agent, CSS screen dimensions, and default screen orientation will be automatically set within the local Chrome browser instance. You may also specify the emulated device's screen orientation.

⚠️ For best results when testing against mobile web browsers, you should run your tests against iOS and Android simulators or physical devices, either hosted locally or via a remotely cloud hosted service.

For locally hosted emulated mobile web browsers, the WEB_BROWSER Environment Variable must be set to one of the values from the table below:

browserName: or WEB_BROWSER CSS Screen Dimensions Default Orientation OS Version
iphone_11 414 x 896 portrait iOS 15.5
iphone_11_pro 375 x 812 portrait iOS 15.5
iphone_11_pro_max 414 x 896 portrait iOS 15.5
iphone_12_mini 375 x 812 portrait iOS 15.5
iphone_12 390 x 844 portrait iOS 15.5
iphone_12_pro 390 x 844 portrait iOS 15.5
iphone_12_pro_max 428 x 926 portrait iOS 15.5
iphone_13_mini 375 x 812 portrait iOS 15.5
iphone_13 390 x 844 portrait iOS 15.5
iphone_13_pro 390 x 844 portrait iOS 15.5
iphone_13_pro_max 428 x 926 portrait iOS 15.5
iphone_se 375 x 667 portrait iOS 15.5
iphone_14 390 x 844 portrait iOS 16.2
iphone_14_plus 428 x 926 portrait iOS 16.2
iphone_14_pro 393 x 852 portrait iOS 16.2
iphone_14_pro_max 430 x 932 portrait iOS 16.2
ipad 1080 x 810 landscape iOS 15.5
ipad_mini 1133 x 744 landscape iOS 15.5
ipad_air 1180 x 820 landscape iOS 15.5
ipad_pro_11 1194 x 834 landscape iOS 15.5
ipad_pro_12_9 1366 x 1024 landscape iOS 15.5
pixel_5 393 x 851 portrait Android 12
pixel_6 412 x 915 portrait Android 12
pixel_xl 412 x 732 portrait Android 12
nexus_10 1280 x 800 landscape Android 12
pixel_c 1280 x 900 landscape Android 12
kindle_fire 1024 x 600 landscape
kindle_firehd7 800 x 480 landscape Fire OS 3
kindle_firehd8 1280 x 800 landscape Fire OS 5
kindle_firehd10 1920 x 1200 landscape Fire OS 5
surface 1366 x 768 landscape
blackberry_playbook 1024 x 600 landscape BlackBerry Tablet OS
windows_phone7 320 x 480 portrait Windows Phone OS 7.5
windows_phone8 320 x 480 portrait Windows Phone OS 8.0
lumia_950_xl 360 x 640 portrait Windows Phone OS 10
blackberry_z10 384 x 640 portrait BlackBerry 10 OS
blackberry_z30 360 x 640 portrait BlackBerry 10 OS
blackberry_leap 360 x 640 portrait BlackBerry 10 OS
blackberry_passport 504 x 504 square BlackBerry 10 OS

Local Emulated Mobile Browser using Environment Variables

If the options hash is not provided when calling the TestCentricity::WebDriverConnect.initialize_web_driver method, then the following Environment Variables must be set as described in the table below:

Environment Variable Description
WEB_BROWSER Must be set to one of the values from the table above
DRIVER Must be set to webdriver
ORIENTATION [Optional] Set to portrait or landscape

Refer to section 8.9 (Using Browser Specific Profiles in cucumber.yml) below.

Local Emulated Mobile Browser in the options Hash

When using the options hash, the following options and capabilities must be specified:

    options = {
      capabilities: { browserName: value_from_table_above },
      driver: :webdriver
    }
    WebDriverConnect.initialize_web_driver(options)

To change the emulated device's screen orientation from the default setting, set the optional orientation: to either :portrait or :landscape in the capabilities: hash as shown in the example below:

    options = {
      capabilities: {
        browserName: :ipad_pro_12_9,
        orientation: :portrait
      },
      driver: :webdriver
    }
    WebDriverConnect.initialize_web_driver(options)

ℹ️ If an optional user defined driver_name: is not specified in the options hash, the default driver name will be set to :local_<browserName> - e.g. :local_ipad_pro_12_9 or :local_pixel_6.

Below is an example of an options hash for specifying a connection to a locally hosted emulated mobile Safari web browser running on an iPhone. Theoptions hash includes options for specifying the driver name and setting the browser orientation to landscape mode.

    options = {
      driver: :webdriver,
      driver_name: :user1,
      capabilities: {
        browserName: :iphone_13_pro_max,
        orientation: :landscape
      }
    }
    WebDriverConnect.initialize_web_driver(options)

User Defined Emulated Mobile Browser Profiles

User defined mobile browser profiles can be specified in a device.yml file for testing locally hosted emulated mobile web browsers running in an instance of the Chrome desktop browser. The user specified browser profiles must be located at config/data/devices/devices.yml as depicted below:

    📁 my_automation_project/
    ├── 📁 config/
    │   ├── 📁 data/
    │   │   └── 📁 devices/
    │   │       └── 📄devices.yml
    │   ├── 📁 locales/
    │   ├── 📁 test_data/
    │   └── 📄 cucumber.yml
    ├── 📁 downloads/
    ├── 📁 features/
    ├── 📄 Gemfile
    └── 📄 README.md

The format for a new mobile browser profile is:

    :my_device_profile:
      :name: "My New Device Name"
      :os: (ios, android, kindle, or blackberry)
      :type: (phone or tablet)
      :css_width: css width in pixels
      :css_height: css height in pixels
      :default_orientation: (portrait or landscape)
      :user_agent: "user agent string"

To specify a user defined emulated mobile browser, set browserName: or the WEB_BROWSER Environment Variable to the device's profile name.

Selenium Grid Hosted Desktop and Emulated Mobile Web Browsers

For remotely hosted desktop web browsers running on a Selenium 4 Grid, the browser type and driver type must be specified when calling the TestCentricity::WebDriverConnect.initialize_web_driver method. The table below contains the values that can be used to specify the grid hosted desktop web browser to be instantiated when calling theinitialize_web_driver method:

browserName: or WEB_BROWSER
chrome
chrome_headless
firefox
firefox_headless
edge
edge_headless

Grid Browsers using Environment Variables

If the options hash is not provided when calling the TestCentricity::WebDriverConnect.initialize_web_driver method, then the following Environment Variables must be set as described in the table below:

Environment Variable Description
WEB_BROWSER Must be set to one of the values from the table above, or any of the emulated mobile web browsers described above in section 8.4.
DRIVER Must be set to grid
REMOTE_ENDPOINT [Optional] Set to the URL of the Grid hub. Set to http://localhost:4444/wd/hub if not specified
BROWSER_SIZE [Optional] Set to 'width in pixels, heigh in pixels' or 'max'

Refer to section 8.9 (Using Browser Specific Profiles in cucumber.yml) below.

Grid Browser in the options Hash

When using the options hash, the following options and capabilities must be specified:

    options = {
      capabilities: { browserName: value_from_table_above },
      driver: :grid,
      endpoint: 'http://localhost:4444/wd/hub'
    }
    WebDriverConnect.initialize_web_driver(options)

ℹ️ If an optional user defined driver_name: is not specified in the options hash, the default driver name will be set to :remote_<browserName> - e.g. :remote_chrome or :remote_edge_headless.

ℹ️ If an endpoint: is not specified in the optionshash, then the default remote endpoint URL of http://localhost:4444/wd/hub will be used.

Below is an example of an options hash for specifying a connection to a grid hosted Chrome desktop web browser. The options hash includes options for specifying the driver name and setting the browser window size.

    options = {
      driver: :grid,
      driver_name: :admin_user,
      browser_size: [1400, 1100],
      capabilities: { browserName: :chrome }
    }
    WebDriverConnect.initialize_web_driver(options)

Locally Hosted Mobile Browsers on Simulators or Physical Devices

Refer to this page for information regarding specifying Appium capabilities.

⚠️ If you are running locally hosted mobile web tests on iOS or Android simulators or devices using version 1.x of the Appium server, the APPIUM_SERVER_VERSION environment variable must be set to 1 in order to ensure that the correct Appium server endpoint is used.

Mobile Safari Browser on iOS Simulators or iOS Physical Devices

You can run your mobile web tests against the mobile Safari browser on iOS device simulators or physically connected iOS devices using Appium and XCode on macOS. You must install Appium, XCode, and the iOS version-specific device simulators for XCode. Information about Appium setup and configuration requirements with the XCUITest driver for testing on physically connected iOS devices can be found on this page. Refer to this page for information regarding specifying Appium capabilities that are specific to the XCUITest driver.

The Appium server must be running prior to invoking Cucumber to run your features/scenarios. Refer to section 8.6.3 (Starting and Stopping Appium Server) below.

Local Mobile Safari Browser using Environment Variables

If the options hash is not provided when calling the TestCentricity::WebDriverConnect.initialize_web_driver method, the following Environment Variables must be set as described in the table below.

Environment Variable Description
DRIVER Must be set to appium
AUTOMATION_ENGINE Must be set to xcuitest
APP_PLATFORM_NAME Must be set to iOS
APP_BROWSER Must be set to Safari
APP_VERSION Must be set to which ever iOS version you wish to run within the XCode Simulator
APP_DEVICE Set to iOS device name supported by the iOS Simulator (iPhone 13 Pro Max, iPad Pro (12.9-inch) (5th generation), etc.) or name of physically connected iOS device
DEVICE_TYPE Must be set to phone or tablet
UDID UDID of physically connected iOS device (not used for simulators)
TEAM_ID unique 10-character Apple developer team identifier string (not used for simulators)
TEAM_NAME String representing a signing certificate (not used for simulators)
APP_ALLOW_POPUPS [Optional] Allow javascript to open new windows in Safari. Set to true or false
APP_IGNORE_FRAUD_WARNING [Optional] Prevent Safari from showing a fraudulent website warning. Set to true or false
APP_NO_RESET [Optional] Don't reset app state after each test. Set to true or false
APP_FULL_RESET [Optional] Perform a complete reset. Set to true or false
APP_INITIAL_URL [Optional] Initial URL, default is a local welcome page. e.g. http://www.apple.com
WDA_LOCAL_PORT [Optional] Used to forward traffic from Mac host to real iOS devices over USB. Default value is same as port number used by WDA on device.
ORIENTATION [Optional] Set to portrait or landscape (only for iOS simulators)
NEW_COMMAND_TIMEOUT [Optional] Time (in Seconds) that Appium will wait for a new command from the client
SHOW_SIM_KEYBOARD [Optional] Show the simulator keyboard during text entry. Set to true or false
SHUTDOWN_OTHER_SIMS [Optional] Close any other running simulators. Set to true or false. See note below.

The SHUTDOWN_OTHER_SIMS environment variable can only be set if you are running Appium Server with the --relaxed-security or --allow-insecure=shutdown_other_sims arguments passed when starting it from the command line, or when running the server from the Appium Server GUI app. A security violation error will occur without relaxed security enabled.

Refer to section 8.9 (Using Browser Specific Profiles in cucumber.yml) below.

Local Mobile Safari Browser in the options Hash

When using the options hash, the following options and capabilities must be specified:

    options = {
      driver: :appium,
      device_type: phone_or_tablet,
      capabilities: {
        platformName: 'ios',
        browserName: 'Safari',
        'appium:automationName': 'xcuitest',
        'appium:platformVersion': ios_version,
        'appium:deviceName': device_or_simulator_name
      },
      endpoint: 'http://localhost:4723'
    }
    WebDriverConnect.initialize_web_driver(options)

ℹ️ If an optional user defined driver_name: is not specified in the options hash, the default driver name will be set to appium_safari.

ℹ️ If an endpoint: is not specified in the options hash, then the default remote endpoint URL of http://localhost:4723 will be used.

Below is an example of an options hash for specifying a connection to a locally hosted mobile Safari web browser running on an iPad simulator. The options hash includes options for specifying the driver name and setting the simulated device orientation to portrait mode.

      options = {
        driver: :appium,
        device_type: :tablet,
        driver_name: :student_ipad,
        capabilities: {
          platformName: 'ios',
          browserName: 'Safari',
          'appium:platformVersion': '15.4',
          'appium:deviceName': 'iPad Pro (12.9-inch) (5th generation)',
          'appium:automationName': 'xcuitest',
          'appium:orientation': 'PORTRAIT'
        }
      }
      WebDriverConnect.initialize_web_driver(options)

Mobile Chrome or Android Browsers on Android Studio Virtual Device Emulators

You can run your mobile web tests against the mobile Chrome or Android browser on emulated Android devices using Appium and Android Studio on macOS. You must install Android Studio, the desired Android version-specific virtual device emulators, and Appium. Refer to this page for information on configuring Appium to work with the Android SDK. Refer to this page for information regarding specifying Appium capabilities that are specific to the UiAutomator2 driver.

The Appium server must be running prior to invoking Cucumber to run your features/scenarios. Refer to section 8.6.3 (Starting and Stopping Appium Server) below.

Local Mobile Android Browsers using Environment Variables

If the options hash is not provided when calling the TestCentricity::WebDriverConnect.initialize_web_driver method, the following Environment Variables must be set as described in the table below.

Environment Variable Description
DRIVER Must be set to appium
AUTOMATION_ENGINE Must be set to UiAutomator2
APP_PLATFORM_NAME Must be set to Android
APP_BROWSER Must be set to Chrome or Browser
APP_VERSION Must be set to which ever Android OS version you wish to run with the Android Virtual Device
APP_DEVICE Set to Android Virtual Device ID (Pixel_2_XL_API_26, Nexus_6_API_23, etc.) found in Advanced Settings of AVD Configuration
DEVICE_TYPE Must be set to phone or tablet
ORIENTATION [Optional] Set to portrait or landscape
APP_INITIAL_URL [Optional] Initial URL, default is a local welcome page. e.g. http://www.apple.com
APP_NO_RESET [Optional] Don't reset app state after each test. Set to true or false
APP_FULL_RESET [Optional] Perform a complete reset. Set to true or false
NEW_COMMAND_TIMEOUT [Optional] Time (in Seconds) that Appium will wait for a new command from the client
CHROMEDRIVER_EXECUTABLE [Optional] Absolute local path to ChromeDriver executable

Refer to section 8.9 (Using Browser Specific Profiles in cucumber.yml) below.

Local Mobile Android Browser in the options Hash

When using the options hash, the following options and capabilities must be specified:

    options = {
      driver: :appium,
      device_type: phone_or_tablet,
      capabilities: {
        platformName: 'Android',
        browserName: 'Chrome',
        'appium:automationName': 'UiAutomator2',
        'appium:platformVersion': android_version,
        'appium:deviceName': simulator_name,
        'appium:avd': simulator_name
      },
      endpoint: 'http://localhost:4723'
    }
    WebDriverConnect.initialize_web_driver(options)

ℹ️ If an optional user defined driver_name: is not specified in the options hash, the default driver name will be set to appium_chrome.

ℹ️ If an endpoint: is not specified in the options hash, then the default remote endpoint URL of http://localhost:4723 will be used.

Below is an example of an options hash for specifying a connection to a locally hosted mobile Chrome web browser running on an Android phone simulator. The options hash includes options for specifying the driver name, setting the simulated device orientation to landscape mode, and specifying the path to the ChromeDriver executable.

      options = {
        driver: :appium,
        device_type: :phone,
        driver_name: :student_phone,
        capabilities: {
          platformName: 'Android',
          browserName: 'Chrome',
          'appium:platformVersion': '12.0',
          'appium:deviceName': 'Pixel_5_API_31',
          'appium:avd': 'Pixel_5_API_31',
          'appium:automationName': 'UiAutomator2',
          'appium:orientation': 'LANDSCAPE',
          'appium:chromedriverExecutable': '/Users/Shared/config/webdrivers/chromedriver'
        }
      }
      WebDriverConnect.initialize_web_driver(options)

Starting and Stopping Appium Server

Using Appium Server with Cucumber

The Appium server must be running prior to invoking Cucumber to run your features/scenarios on locally hosted mobile simulators or physical devices. To programmatically control the starting and stopping of Appium server with the execution of your automated tests, place the code shown below in your hooks.rb file.

    BeforeAll do
      # start Appium Server if APPIUM_SERVER = 'run' and target browser is a mobile simulator or device
      if ENV['APPIUM_SERVER'] == 'run' && Environ.driver == :appium
        $server = TestCentricity::AppiumServer.new
        $server.start
      end
    end

    AfterAll do
      # terminate all driver instances
      WebDriverConnect.close_all_drivers
      # terminate Appium Server if APPIUM_SERVER = 'run' and target browser is a mobile simulator or device
      $server.stop if ENV['APPIUM_SERVER'] == 'run' && Environ.driver == :appium && $server.running?
    end

The APPIUM_SERVER environment variable must be set to run in order to programmatically start and stop the Appium server. This can be set by adding the following to your cucumber.yml file and including -p run_appium in your command line when starting your Cucumber test suite(s):

run_appium: APPIUM_SERVER=run

If you are running locally hosted mobile web tests on iOS or Android simulators or devices using version 1.x of the Appium server, the APPIUM_SERVER_VERSION environment variable must be set to 1 in order to ensure that the correct Appium server endpoint is used. This can be set by adding the following to your cucumber.yml file and including -p appium_1x in your command line when starting your Cucumber test suite(s):

appium_1x: APPIUM_SERVER_VERSION=1

Refer to section 8.9 (Using Browser Specific Profiles in cucumber.yml) below.

Using Appium Server with RSpec

The Appium server must be running prior to executing test specs on locally hosted mobile simulators or physical device. To control the starting and stopping of the Appium server with the execution of your specs, place the code shown below in the body of an example group:

    before(:context) do
      # start Appium server before all of the examples in this group
      $server = TestCentricity::AppiumServer.new
      $server.start
    end

    after(:context) do
      # terminate Appium Server after all of the examples in this group
      $server.stop if Environ.driver == :appium && $server.running?
    end

If you are running locally hosted mobile web tests on iOS or Android simulators or devices using version 1.x of the Appium server, the APPIUM_SERVER_VERSION environment variable must be set to 1 in order to ensure that the correct Appium server endpoint is used.

Remote Cloud Hosted Desktop and Mobile Web Browsers

You can run your automated tests against remote cloud hosted desktop and mobile web browsers using the BrowserStack, SauceLabs, TestingBot, or LambdaTest services. If your tests are running against a web site hosted on your local computer (localhost), or on a staging server inside your LAN, you must set the TUNNELING Environment Variable to true.

If the BrowserStack Local instance is running (TUNNELING Environment Variable is true), call theTestCentricity::WebDriverConnect.close_tunnel method upon completion of your test suite to stop the Local instance. Place the code shown below in your env.rb or hooks.rb file:

    # code to stop BrowserStack Local instance after end of test (if tunneling is enabled)
    at_exit do
      TestCentricity::WebDriverConnect.close_tunnel if Environ.tunneling
    end

Remote Desktop Browsers on the BrowserStack Service

For remotely hosted desktop web browsers on the BrowserStack service, refer to the Browserstack-specific capabilities chart page for information regarding the options and capabilities available for the various supported desktop operating systems and web browsers. Select the Legacy Integration method tab and the W3C Protocol tab on the capabilities page.

BrowserStack Desktop Browser using Environment Variables

If the options hash is not provided when calling the TestCentricity::WebDriverConnect.initialize_web_driver method, the following Environment Variables must be set as described in the table below.

Environment Variable Description
DRIVER Must be set to browserstack
BS_USERNAME Must be set to your BrowserStack account user name
BS_AUTHKEY Must be set to your BrowserStack account access key
BS_OS Must be set to OS X or Windows
BS_OS_VERSION Refer to os_version capability in chart
BS_BROWSER Refer to browserName capability in chart
BS_VERSION [Optional] Refer to browser_version capability in chart. If not specified, latest stable version of browser will be used.
TUNNELING [Optional] Must be true if you are testing against internal/local servers (true or false). If true, the BrowserStack Local instance will be automatically started.
RESOLUTION [Optional] Refer to supported screen resolution capability in chart
RECORD_VIDEO [Optional] Enable screen video recording during test execution (true or false)
TIME_ZONE [Optional] Specify custom time zone. Refer to browserstack.timezone capability in chart
IP_GEOLOCATION [Optional] Specify IP Geolocation. Refer to IP Geolocation to select a country code.
ALLOW_POPUPS [Optional] Allow popups (true or false) - for Safari, IE, and Edge browsers only
ALLOW_COOKIES [Optional] Allow all cookies (true or false) - for Safari browsers only
SCREENSHOTS [Optional] Generate screenshots for debugging (true or false)
NETWORK_LOGS [Optional] Capture network logs (true or false)
BrowserStack Desktop Browser in the options Hash

When using the options hash, the following options and capabilities must be specified:

    options = {
      driver: :browserstack,
      capabilities: {
        browserName: browser_name_from_chart,
        browserVersion: browser_version_from_chart,
        'bstack:options': {
          userName: bs_account_user_name,
          accessKey: bs_account_access_key,
          os: os_name_from_chart,
          osVersion: os_version_from_chart
        }
      }
    }
    WebDriverConnect.initialize_web_driver(options)

ℹ️ If an optional user defined driver_name: is not specified in the options hash, the default driver name will be set to :browserstack_<browserName> - e.g. :browserstack_chrome or :browserstack_safari.

ℹ️ If an endpoint: is not specified in the options hash, then the default remote endpoint URL will be set to the following:

https://#{ENV['BS_USERNAME']}:#{ENV['BS_AUTHKEY']}@hub-cloud.browserstack.com/wd/hub

This default endpoint requires that the BS_USERNAME Environment Variable is set to your BrowserStack account user name and the BS_AUTHKEY Environment Variable is set to your BrowserStack access key.

Below is an example of an options hash for specifying a connection to the latest version of an Edge desktop web browser running on macOS Sonoma hosted on BrowserStack. The options hash includes options for specifying the driver name, setting the browser window size, and capabilities for setting screen resolution, geoLocation, time zone, Selenium version, and various test configuration options.

    options = {
      driver: :browserstack,
      driver_name: :admin_user,
      browser_size: [1400, 1100],
      capabilities: {
        browserName: 'Edge',
        browserVersion: 'latest',
        'bstack:options': {
          userName: ENV['BS_USERNAME'],
          accessKey: ENV['BS_AUTHKEY'],
          projectName: 'ALP AP',
          buildName: "Test Build #{ENV['BUILD_NUM']}",
          sessionName: 'AU Regression Suite',
          os: 'OS X',
          osVersion: 'Sonoma',
          resolution: '3840x2160',
          local: 'false',
          seleniumVersion: '4.15.0',
          networkLogs: 'true',
          geoLocation: 'AU',
          timezone: 'Perth'
        }
      }
    }
    WebDriverConnect.initialize_web_driver(options)

Remote Mobile Browsers on the BrowserStack Service

For remotely hosted mobile web browsers on the BrowserStack service, refer to the Browserstack-specific capabilities chart page for information regarding the options and capabilities available for the various supported mobile operating systems, devices, and web browsers. Select the Legacy Integration method tab and the W3C Protocol tab on the capabilities page.

BrowserStack Mobile Browser using Environment Variables

If the options hash is not provided when calling the TestCentricity::WebDriverConnect.initialize_web_driver method, the following Environment Variables must be set as described in the table below.

Environment Variable Description
DRIVER Must be set to browserstack
BS_USERNAME Must be set to your BrowserStack account user name
BS_AUTHKEY Must be set to your BrowserStack account access key
BS_OS Must be set to ios or android
BS_OS_VERSION Refer to osVersion capability in chart
BS_BROWSER Must be set to Safari (for iOS) or Chrome (for Android)
BS_DEVICE Refer to deviceName capability in chart
BS_REAL_MOBILE Set to true if running against a real device
DEVICE_TYPE Must be set to phone or tablet
TUNNELING [Optional] Must be true if you are testing against internal/local servers (true or false). If true, the BrowserStack Local instance will be automatically started.
ORIENTATION [Optional] Set to portrait or landscape
RECORD_VIDEO [Optional] Enable screen video recording during test execution (true or false)
TIME_ZONE [Optional] Specify custom time zone. Refer to browserstack.timezone capability in chart
IP_GEOLOCATION [Optional] Specify IP Geolocation. Refer to IP Geolocation to select a country code.
SCREENSHOTS [Optional] Generate screenshots for debugging (true or false)
NETWORK_LOGS [Optional] Capture network logs (true or false)
APPIUM_LOGS [Optional] Generate Appium logs (true or false)
BrowserStack Mobile Browser in the options Hash

When using the options hash, the following options and capabilities must be specified:

    options = {
      driver: :browserstack,
      device_type: phone_or_tablet,
      capabilities: {
        browserName: browser_name_from_chart,
        'bstack:options': {
          userName: bs_account_user_name,
          accessKey: bs_account_access_key,
          osVersion: os_version_from_chart,
          deviceName: device_name_from_chart
        }
      }
    }
    WebDriverConnect.initialize_web_driver(options)

ℹ️ If an optional user defined driver_name: is not specified in the options hash, the default driver name will be set to :browserstack_<browserName> - e.g. :browserstack_chrome or :browserstack_safari.

ℹ️ If an endpoint: is not specified in the options hash, then the default remote endpoint URL will be set to the following:

https://#{ENV['BS_USERNAME']}:#{ENV['BS_AUTHKEY']}@hub-cloud.browserstack.com/wd/hub

This default endpoint requires that the BS_USERNAME Environment Variable is set to your BrowserStack account user name and the BS_AUTHKEY Environment Variable is set to your BrowserStack access key.

Below is an example of an options hash for specifying a connection to a mobile Samsung web browser running on an Android tablet hosted on BrowserStack. The options hash includes options for specifying the driver name, and capabilities for setting geoLocation, time zone, Appium version, and various test configuration options.

    options = {
      driver: :browserstack,
      driver_name: :admin_tablet,
      capabilities: {
        browserName: 'samsung',
        device_type: :tablet,
        'bstack:options': {
          userName: ENV['BS_USERNAME'],
          accessKey: ENV['BS_AUTHKEY'],
          projectName: 'ALP AP',
          buildName: "Test Build #{ENV['BUILD_NUM']}",
          sessionName: 'AU Regression Suite',
          os: 'android',
          osVersion: '13.0',
          deviceName: 'Samsung Galaxy Tab S9',
          deviceOrientation: 'portrait',
          appiumVersion: '1.22.0',
          realMobile: 'true',
          local: 'false',
          networkLogs: 'true',
          geoLocation: 'AU',
          timezone: 'Perth'
        }
      }
    }
    WebDriverConnect.initialize_web_driver(options)

Remote Desktop Browsers on the Sauce Labs Service

For remotely hosted desktop web browsers on the Sauce Labs service, refer to the Platform Configurator page for information regarding the options and capabilities available for the various supported desktop operating systems and web browsers. Use the Selenium 4 selection in the Config Script section of the Configurator page.

Sauce Labs Desktop Browser using Environment Variables

If the options hash is not provided when calling the TestCentricity::WebDriverConnect.initialize_web_driver method, the following Environment Variables must be set as described in the table below.

Environment Variable Description
DRIVER Must be set to saucelabs
SL_USERNAME Must be set to your Sauce Labs account user name or email address
SL_AUTHKEY Must be set to your Sauce Labs account access key
SL_DATA_CENTER Must be set to your Sauce Labs account Data Center assignment (us-west-1, eu-central-1, apac-southeast-1)
SL_OS Refer to platformName capability in the Config Script section of the Platform Configurator page
SL_BROWSER Must be set to chrome, firefox, safari, internetExplorer, or MicrosoftEdge
SL_VERSION Refer to browserVersion capability in the Config Script section of the Platform Configurator page
RESOLUTION [Optional] Refer to supported screenResolution capability in the Config Script section of the Platform Configurator page
BROWSER_SIZE [Optional] Specify width, height of browser window
RECORD_VIDEO [Optional] Enable screen video recording during test execution (true or false)
Sauce Labs Desktop Browser in the options Hash

When using the options hash, the following options and capabilities must be specified:

    options = {
      driver: :saucelabs,
      capabilities: {
        browserName: browser_name_from_chart,
        browser_version: browser_version_from_chart,
        platform_name: platform_name_from_chart,
        'sauce:options': {
          username: sl_account_user_name,
          access_key: bs_account_access_key
        }
      }
    }
    WebDriverConnect.initialize_web_driver(options)

ℹ️ If an optional user defined driver_name: is not specified in the options hash, the default driver name will be set to :saucelabs_<browserName> - e.g. :saucelabs_chrome or :saucelabs_safari.

ℹ️ If an endpoint: is not specified in the options hash, then the default remote endpoint URL will be set to the following:

https://#{ENV['SL_USERNAME']}:#{ENV['SL_AUTHKEY']}@ondemand.#{ENV['SL_DATA_CENTER']}.saucelabs.com:443/wd/hub

This default endpoint requires that the SL_USERNAME Environment Variable is set to your Sauce Labs account user name, the SL_AUTHKEY Environment Variable is set to your Sauce Labs access key, and the SL_DATA_CENTER Environment Variable is set to your Sauce Labs account Data Center assignment (us-west-1, eu-central-1, apac-southeast-1).

Below is an example of an options hash for specifying a connection to the latest version of an Edge desktop web browser running on macOS Ventura hosted on Sauce Labs. The options hash includes options for specifying the driver name, setting the browser window size, and capabilities for setting screen resolution, time zone, and various test configuration options.

    options = {
      driver: :saucelabs,
      driver_name: :admin_user,
      browser_size: [1400, 1100],
      capabilities: {
        browserName: 'MicrosoftEdge',
        browser_version: 'latest',
        platform_name: 'macOS 13',
        'sauce:options': {
          username: ENV['SL_USERNAME'],
          access_key: ENV['SL_AUTHKEY'],
          name: 'ALP AP',
          build: "Test Build #{ENV['BUILD_NUM']}",
          screenResolution: '2048x1536',
          timeZone: 'Perth',
          maxDuration: 2400,
          idleTimeout: 60
        }
      }
    }
    WebDriverConnect.initialize_web_driver(options)

Remote Mobile Browsers on the Sauce Labs Service

For remotely hosted mobile web browsers on the Sauce Labs service, refer to the Platform Configurator page for information regarding the options and capabilities available for the various supported mobile operating systems, devices, and web browsers.

Sauce Labs Mobile Browser using Environment Variables

If the options hash is not provided when calling the TestCentricity::WebDriverConnect.initialize_web_driver method, the following Environment Variables must be set as described in the table below.

Environment Variable Description
DRIVER Must be set to saucelabs
AUTOMATION_ENGINE Must be set to XCUITest or UiAutomator2
SL_PLATFORM Must be set to iOS or Android
SL_BROWSER Must be set to Safari or Chrome
SL_VERSION Refer to platformVersion capability in the Config Script section of the Platform Configurator page
SL_DEVICE Refer to deviceName capability in chart
DEVICE_TYPE Must be set to phone or tablet
SL_USERNAME Must be set to your Sauce Labs account user name or email address
SL_AUTHKEY Must be set to your Sauce Labs account access key
SL_DATA_CENTER Must be set to your Sauce Labs account Data Center assignment (us-west-1, eu-central-1, apac-southeast-1)
ORIENTATION [Optional] Set to PORTRAIT or LANDSCAPE
Sauce Labs Mobile Browser in the options Hash

When using the options hash, the following options and capabilities must be specified:

    options = {
      driver: :saucelabs,
      device_type: phone_or_tablet,
      capabilities: {
        browserName: browser_name_from_chart,
        platform_name: platform_name_from_chart,
        'appium:automationName': automationName_from_chart,
        'appium:platformVersion': os_version_from_chart,
        'appium:deviceName': device_name_from_chart,
        'sauce:options': {
          userName: bs_account_user_name,
          accessKey: bs_account_access_key
        }
      }
    }
    WebDriverConnect.initialize_web_driver(options)

ℹ️ If an optional user defined driver_name: is not specified in the options hash, the default driver name will be set to :saucelabs_<browserName> - e.g. :saucelabs_chrome or :saucelabs_safari.

ℹ️ If an endpoint: is not specified in the options hash, then the default remote endpoint URL will be set to the following:

https://#{ENV['SL_USERNAME']}:#{ENV['SL_AUTHKEY']}@ondemand.#{ENV['SL_DATA_CENTER']}.saucelabs.com:443/wd/hub

This default endpoint requires that the SL_USERNAME Environment Variable is set to your Sauce Labs account user name, the SL_AUTHKEY Environment Variable is set to your Sauce Labs access key, and the SL_DATA_CENTER Environment Variable is set to your Sauce Labs account Data Center assignment (us-west-1, eu-central-1, apac-southeast-1).

Below is an example of an options hash for specifying a connection to a mobile Safari web browser running on an iPad tablet hosted on Sauce Labs. The options hash includes options for specifying the driver name, and capabilities for setting device orientation, Appium version, and various test configuration options.

    options = {
      driver: :saucelabs,
      device_type: :tablet,
      driver_name: :admin_tablet,
      capabilities: {
        browserName: 'Safari',
        platform_name: 'iOS',
        'appium:automationName': 'XCUITest',
        'appium:platformVersion': '15.4',
        'appium:deviceName': 'iPad Pro (12.9 inch) (5th generation) Simulator',
        'sauce:options': {
          username: ENV['SL_USERNAME'],
          access_key: ENV['SL_AUTHKEY'],
          name: 'ALP AP',
          build: "Test Build #{ENV['BUILD_NUM']}",
          deviceOrientation: 'PORTRAIT',
          appiumVersion: '1.22.3'
        }
      }
    }
    WebDriverConnect.initialize_web_driver(options)

Remote Desktop Browsers on the TestingBot Service

For remotely hosted desktop web browsers on the TestingBot service, refer to the TestingBot List of Available Browsers page and the TestingBot Automated Test Options page for information regarding the options and capabilities available for the various supported desktop operating systems and web browsers.

TestingBot Desktop Browser using Environment Variables

If the options hash is not provided when calling the TestCentricity::WebDriverConnect.initialize_web_driver method, the following Environment Variables must be set as described in the table below.

Environment Variable Description
DRIVER Must be set to testingbot
TB_USERNAME Must be set to your TestingBot account user name
TB_AUTHKEY Must be set to your TestingBot account access key
TB_OS Refer to platform capability in chart
TB_BROWSER Refer to browserName capability in chart
TB_VERSION Refer to version capability in chart
TUNNELING [Optional] Must be true if you are testing against internal/local servers (true or false)
RESOLUTION [Optional] Refer to Change Screen Resolution
BROWSER_SIZE [Optional] Specify width, height of browser window
TestingBot Desktop Browser in the options Hash

When using the options hash, the following options and capabilities must be specified:

    options = {
      driver: :testingbot,
      capabilities: {
        browserName: browser_name_from_chart,
        browser_version: browser_version_from_chart,
        platform_name: platform_name_from_chart
      }
    }
    WebDriverConnect.initialize_web_driver(options)

ℹ️ If an optional user defined driver_name: is not specified in the options hash, the default driver name will be set to :testingbot_<browserName> - e.g. :testingbot_chrome or :testingbot_microsoftedge.

ℹ️ If an endpoint: is not specified in the options hash, then the default remote endpoint URL will be set to the following:

https://#{ENV['TB_USERNAME']}:#{ENV['TB_AUTHKEY']}@hub.testingbot.com/wd/hub

This default endpoint requires that the TB_USERNAME Environment Variable is set to your TestingBot account user name and the TB_AUTHKEY Environment Variable is set to your TestingBot access key.

Below is an example of an options hash for specifying a connection to the latest version of an Edge desktop web browser running on macOS Sonoma hosted on TestingBot. The options hash includes options for specifying the driver name, setting the browser window size, and capabilities for setting screen resolution, time zone, and various test configuration options.

    options = {
      driver: :testingbot,
      driver_name: :admin_user,
      browser_size: [1400, 1100],
      capabilities: {
        browserName: 'microsoftedge',
        browser_version: 'latest',
        platform_name: 'SONOMA',
        'tb:options': {
          name: 'ALP AP',
          build: "Test Build #{ENV['BUILD_NUM']}",
          timeZone: 'Australia/Adelaide',
          'testingbot.geoCountryCode': 'AU',
          'screen-resolution': '2048x1536',
          'selenium-version': '4.14.1'
        }
      }
    }
    WebDriverConnect.initialize_web_driver(options)

Remote Mobile Browsers on the TestingBot Service

For remotely hosted mobile web browsers on the TestingBot service, refer to the TestingBot List of Available Browsers page and the TestingBot Automated Test Options page for information regarding the options and capabilities available for the various supported mobile operating systems, devices, and web browsers.

TestingBot Mobile Browser using Environment Variables

If the options hash is not provided when calling the TestCentricity::WebDriverConnect.initialize_web_driver method, the following Environment Variables must be set as described in the table below.

Environment Variable Description
DRIVER Must be set to testingbot
TB_USERNAME Must be set to your TestingBot account user name
TB_AUTHKEY Must be set to your TestingBot account access key
TB_PLATFORM Must be set to iOS or ANDROID
TB_OS Must be set to iOS or ANDROID
TB_BROWSER Must be set to safari (for iOS) or chrome (for Android)
TB_VERSION Refer to version capability in chart
TB_DEVICE Refer to deviceName capability in chart
DEVICE_TYPE Must be set to phone or tablet
TUNNELING [Optional] Must be true if you are testing against internal/local servers (true or false)
ORIENTATION [Optional] Set to portrait or landscape
TestingBot Mobile Browser in the options Hash

When using the options hash, the following options and capabilities must be specified:

    options = {
      driver: :testingbot,
      device_type: phone_or_tablet,
      capabilities: {
        browserName: browser_name_from_chart,
        platform_name: platform_name_from_chart,
        browserVersion: os_version_from_chart,
        'tb:options': {
          deviceName: device_name_from_chart
        }
      }
    }
    WebDriverConnect.initialize_web_driver(options)

ℹ️ If an optional user defined driver_name: is not specified in the options hash, the default driver name will be set to :testingbot_<browserName> - e.g. :testingbot_chrome or :testingbot_safari.

ℹ️ If an endpoint: is not specified in the options hash, then the default remote endpoint URL will be set to the following:

https://#{ENV['TB_USERNAME']}:#{ENV['TB_AUTHKEY']}@hub.testingbot.com/wd/hub

This default endpoint requires that the TB_USERNAME Environment Variable is set to your TestingBot account user name and the TB_AUTHKEY Environment Variable is set to your TestingBot access key.

Below is an example of an options hash for specifying a connection to a mobile Safari web browser running on an iPad tablet hosted on TestingBot. The options hash includes options for specifying the driver name, and capabilities for setting device orientation, Appium version, and various test configuration options.

    options = {
      driver: :testingbot,
      device_type: :tablet,
      driver_name: :admin_tablet,
      capabilities: {
        browserName: 'safari',
        browserVersion: '15.4',
        platformName: 'iOS',
        'tb:options': {
          deviceName: 'iPad Pro (12.9-inch) (5th generation)',
          name: 'ALP AP',
          build: "Test Build #{ENV['BUILD_NUM']}",
          orientation: 'LANDSCAPE'
        }
      }
    }
    WebDriverConnect.initialize_web_driver(options)

Remote Desktop Browsers on the LambdaTest Service

For remotely hosted desktop web browsers on the LambdaTest service, refer to the Selenium 4 Configuration Wizard on the Selenium Desired Capabilities Generator for information regarding the options and capabilities available for the various supported desktop operating systems and web browsers.

LambdaTest Desktop Browser using Environment Variables

If the options hash is not provided when calling the TestCentricity::WebDriverConnect.initialize_web_driver method, the following Environment Variables must be set as described in the table below.

Environment Variable Description
DRIVER Must be set to lambdatest
LT_USERNAME Must be set to your LambdaTest account user name or email address
LT_AUTHKEY Must be set to your LambdaTest account access key
LT_OS Refer to platformName capability in the sample script of the Wizard
LT_BROWSER Refer to browserName capability in the sample script of the Wizard
LT_VERSION Refer to browserVersion capability in chart
RESOLUTION [Optional] Refer to supported resolution capability in the sample script of the Wizard
BROWSER_SIZE [Optional] Specify width, height of browser window
RECORD_VIDEO [Optional] Enable screen video recording during test execution (true or false)
ALLOW_POPUPS [Optional] Allow popups (true or false) - for Safari, IE, and Edge browsers only
ALLOW_COOKIES [Optional] Allow all cookies (true or false) - for Safari browsers only
CONSOLE_LOGS [Optional] Used to capture browser console logs.
LambdaTest Desktop Browser in the options Hash

When using the options hash, the following options and capabilities must be specified:

    options = {
      driver: :lambdatest,
      capabilities: {
        browserName: browser_name_from_chart,
        browserVersion: browser_version_from_chart,
        'LT:Options': {
          username: lt_account_user_name,
          accessKey: lt_account_access_key,
          platformName: platformName_from_chart
        }
      }
    }
    WebDriverConnect.initialize_web_driver(options)

ℹ️ If an optional user defined driver_name: is not specified in the options hash, the default driver name will be set to :lambdatest_<browserName> - e.g. :lambdatest_chrome or :lambdatest_safari.

ℹ️ If an endpoint: is not specified in the options hash, then the default remote endpoint URL will be set to the following:

https://#{ENV['LT_USERNAME']}:#{ENV['LT_AUTHKEY']}@hub.lambdatest.com/wd/hub

This default endpoint requires that the LT_USERNAME Environment Variable is set to your LambdaTest account user name and the LT_AUTHKEY Environment Variable is set to your LambdaTest access key.

Below is an example of an options hash for specifying a connection to the latest version of an Edge desktop web browser running on macOS Sonoma hosted on LambdaTest. The options hash includes options for specifying the driver name, setting the browser window size, and capabilities for setting screen resolution, geoLocation, time zone, Selenium version, and various test configuration options.

    options = {
      driver: :lambdatest,
      driver_name: :admin_user,
      browser_size: [1400, 1100],
      capabilities: {
        browserName: 'MicrosoftEdge',
        browserVersion: '119.0',
        'LT:Options': {
          platformName: 'macOS Sonoma',
          username: ENV['LT_USERNAME'],
          accessKey: ENV['LT_AUTHKEY'],
          project: 'ALP AP',
          build: "Test Build #{ENV['BUILD_NUM']}",
          resolution: '2560x1440',
          selenium_version: '4.13.0',
          networkLogs: 'true',
          geoLocation: 'AU',
          timezone: 'Adelaide',
          console: 'info',
          network: true
        }
      }
    }
    WebDriverConnect.initialize_web_driver(options)

Remote Browsers on Unsupported Cloud Hosting Services

Limited support is provided for executing automated tests against remotely hosted desktop and mobile web browsers on currently unsupported cloud hosting services. You must call the TestCentricity::WebDriverConnect.initialize_web_driver method with an options hash - Environment Variables cannot be used to specify a user-defined custom WebDriver instance.

The following options and capabilities must be specified:

All other required capabilities specified by the hosting service configuration documentation should be included in the capabilities: hash.

    options = {
      driver: :custom,
      endpoint: endpoint_url,
      capabilities: { browserName: browser_name_from_chart }
    }
    WebDriverConnect.initialize_web_driver(options)

ℹ️ If an optional user defined driver_name: is not specified in the options hash, the default driver name will be set to :custom_<browserName> - e.g. :custom_chrome or :custom_safari.

Prior to calling the TestCentricity::WebDriverConnect.initialize_web_driver method, you must set Environ.platform to either :desktop or :mobile, and Environ.device to either :web or :device dependent on whether the target browser is a desktop browser or a mobile browser running on a mobile device or simulator.

Below is an example for specifying a connection to a Firefox desktop web browser on an unsupported hosting service:

      # specify desktop platform
      Environ.platform = :desktop
      Environ.device = :web
      # instantiate a cloud hosted desktop web browser on an unsupported hosting service
      options = {
        driver: :custom,
        driver_name: :user_defined,
        browser_size: [1400, 1100],
        endpoint: endpoint_url,
        capabilities: {
          browserName: 'Firefox',
          browser_version: browser_version_from_chart
          #  other capabilities go here
        }
      }
      WebDriverConnect.initialize_web_driver(options)

Below is an example for specifying a connection to a mobile Safari web browser running on an iPad on an unsupported hosting service:

      # specify mobile platform, device type, and device name
      Environ.platform = :mobile
      Environ.device = :device
      Environ.device_name = device_name_from_chart
      # instantiate a cloud hosted mobile browser on a device on an unsupported hosting service
      options = {
        driver: :custom,
        driver_name: :user_defined,
        device_type: :tablet,
        endpoint: endpoint_url,
        capabilities: {
          browserName: 'Safari',
          #  other capabilities go here
        }
      }
      WebDriverConnect.initialize_web_driver(options)

Closing Browser and Driver Instances

Closing Instances Using Cucumber

To close all browser and driver instances upon completion of your automated Cucumber features, place the code shown below in your hooks.rb file:

    AfterAll do
      # terminate all driver instances
      WebDriverConnect.close_all_drivers
    end

Closing Instances Using RSpec

To close all browser and driver instances upon completion of an automated spec, place the code shown below in the body of an example group:

    after(:each) do
      # terminate all driver instances
      WebDriverConnect.close_all_drivers
    end

Using Browser Specific Profiles in cucumber.yml

While you can set Environment Variables in the command line when invoking Cucumber, a preferred method of specifying and managing target web browsers is to create browser specific Profiles that set the appropriate Environment Variables for each target browser in your cucumber.yml file.

Below is a list of Cucumber Profiles for supported locally and remotely hosted desktop and mobile web browsers (put these in in yourcucumber.yml file). Before you can use the BrowserStack, SauceLabs, TestingBot or LambdaTest services, you will need to replace the INSERT USER NAME HERE and INSERT PASSWORD HERE placeholder text with your user account and authorization code for the cloud service(s) that you intend to connect with.

⚠️ Cloud service credentials should not be stored as text in your cucumber.yml file where it can be exposed by anyone with access to your version control system.

<% desktop = "--tags @desktop --require features BROWSER_TILE=true BROWSER_SIZE=1500,1000" %>
<% tablet  = "--tags @desktop --require features BROWSER_TILE=true" %>
<% mobile  = "--tags @mobile  --require features BROWSER_TILE=true" %>

#==============
# profiles for locally hosted desktop web browsers
#==============

firefox: WEB_BROWSER=firefox <%= desktop %>
chrome:  WEB_BROWSER=chrome <%= desktop %>
edge:    WEB_BROWSER=edge <%= desktop %>
safari:  WEB_BROWSER=safari <%= desktop %>

firefox_headless: WEB_BROWSER=firefox_headless <%= desktop %>
chrome_headless:  WEB_BROWSER=chrome_headless <%= desktop %>
edge_headless:    WEB_BROWSER=edge_headless <%= desktop %>

#==============
# profiles for locally hosted mobile web browsers (emulated locally in Chrome browser)
#==============

iphone_11:           WEB_BROWSER=iphone_11           <%= mobile %>
iphone_11_pro:       WEB_BROWSER=iphone_11_pro       <%= mobile %>
iphone_11_pro_max:   WEB_BROWSER=iphone_11_pro_max   <%= mobile %>
iphone_12_mini:      WEB_BROWSER=iphone_12_mini      <%= mobile %>
iphone_12:           WEB_BROWSER=iphone_12           <%= mobile %>
iphone_12_pro:       WEB_BROWSER=iphone_12_pro       <%= mobile %>
iphone_12_pro_max:   WEB_BROWSER=iphone_12_pro_max   <%= mobile %>
iphone_13_mini:      WEB_BROWSER=iphone_13_mini      <%= mobile %>
iphone_13:           WEB_BROWSER=iphone_13           <%= mobile %>
iphone_13_pro:       WEB_BROWSER=iphone_13_pro       <%= mobile %>
iphone_13_pro_max:   WEB_BROWSER=iphone_13_pro_max   <%= mobile %>
iphone_se:           WEB_BROWSER=iphone_se           <%= mobile %>
iphone_14:           WEB_BROWSER=iphone_14           <%= mobile %>
iphone_14_plus:      WEB_BROWSER=iphone_14_plus      <%= mobile %>
iphone_14_pro:       WEB_BROWSER=iphone_14_pro       <%= mobile %>
iphone_14_pro_max:   WEB_BROWSER=iphone_14_pro_max   <%= mobile %>
ipad:                WEB_BROWSER=ipad                <%= tablet %>
ipad_mini:           WEB_BROWSER=ipad_mini           <%= tablet %>
ipad_air:            WEB_BROWSER=ipad_air            <%= tablet %>
ipad_pro_11:         WEB_BROWSER=ipad_pro_11         <%= tablet %>
ipad_pro_12_9:       WEB_BROWSER=ipad_pro_12_9       <%= tablet %>
pixel_5:             WEB_BROWSER=pixel_5             <%= mobile %>
pixel_6:             WEB_BROWSER=pixel_6             <%= mobile %>
pixel_xl:            WEB_BROWSER=pixel_xl            <%= mobile %>
windows_phone7:      WEB_BROWSER=windows_phone7      <%= mobile %>
windows_phone8:      WEB_BROWSER=windows_phone8      <%= mobile %>
lumia_950_xl:        WEB_BROWSER=lumia_950_xl        <%= mobile %>
blackberry_z10:      WEB_BROWSER=blackberry_z10      <%= mobile %>
blackberry_z30:      WEB_BROWSER=blackberry_z30      <%= mobile %>
blackberry_leap:     WEB_BROWSER=blackberry_leap     <%= mobile %>
blackberry_passport: WEB_BROWSER=blackberry_passport <%= mobile %>
pixel_c:             WEB_BROWSER=pixel_c             <%= tablet %>
nexus_10:            WEB_BROWSER=nexus_10            <%= tablet %>
kindle_fire:         WEB_BROWSER=kindle_fire         <%= tablet %>
kindle_firehd7:      WEB_BROWSER=kindle_firehd7      <%= tablet %>
kindle_firehd8:      WEB_BROWSER=kindle_firehd8      <%= tablet %>
kindle_firehd10:     WEB_BROWSER=kindle_firehd10     <%= tablet %>
surface:             WEB_BROWSER=surface             <%= tablet %>
blackberry_playbook: WEB_BROWSER=blackberry_playbook <%= tablet %>

#==============
# profiles for mobile device screen orientation
#==============

portrait:  ORIENTATION=portrait
landscape: ORIENTATION=landscape

#==============
# profile to start Appium Server prior to running mobile browser tests on iOS or Android simulators or physical devices
#==============

run_appium: APPIUM_SERVER=run
appium_1x: APPIUM_SERVER_VERSION=1

#==============
# profiles for mobile Safari web browsers hosted within XCode iOS simulator
# NOTE: Requires installation of XCode, iOS version specific target simulators, and Appium
#==============

appium_ios: DRIVER=appium AUTOMATION_ENGINE=XCUITest APP_PLATFORM_NAME="ios" APP_BROWSER="Safari" NEW_COMMAND_TIMEOUT=30 SHOW_SIM_KEYBOARD=false
app_ios_15: --profile appium_ios APP_VERSION="15.4"
ipad_pro_12_15_sim: --profile app_ios_15 DEVICE_TYPE=tablet APP_DEVICE="iPad Pro (12.9-inch) (5th generation)"
ipad_air_15_sim:    --profile app_ios_15 DEVICE_TYPE=tablet APP_DEVICE="iPad Air (5th generation)" <%= desktop %>
ipad_15_sim:        --profile app_ios_15 DEVICE_TYPE=tablet APP_DEVICE="iPad (9th generation)"

#==============
# profiles for mobile Safari web browsers running on physically connected iOS devices
# NOTE: Requires installation of XCode and Appium
#==============

my_ios_15_iphone: --profile app_ios_15 DEVICE_TYPE=phone APP_DEVICE="My Test iPhoneX" UDID="INSERT YOUR DEVICE UDID"
my_ios_15_ipad:   --profile app_ios_15 DEVICE_TYPE=tablet APP_DEVICE="My Test iPad Pro" UDID="INSERT YOUR DEVICE UDID"

#==============
# profiles for Android mobile web browsers hosted within Android Studio Android Virtual Device emulators
# NOTE: Requires installation of Android Studio, Android version specific virtual device simulators, and Appium
#==============

appium_android:    DRIVER=appium APP_PLATFORM_NAME="Android" <%= mobile %>
app_android_12:    --profile appium_android APP_BROWSER="Chrome" APP_VERSION="12.0"
pixel_c_api31_sim: --profile app_android_12 DEVICE_TYPE=tablet APP_DEVICE="Pixel_C_API_31"

#==============
# profiles for remotely hosted web browsers on the BrowserStack service
# WARNING: Credentials should not be stored as text in your cucumber.yml file where it can be exposed by anyone with
#          access to your version control system
#==============

browserstack: DRIVER=browserstack BS_USERNAME="<INSERT USER NAME HERE>" BS_AUTHKEY="<INSERT PASSWORD HERE>"
bs_desktop: --profile browserstack <%= desktop %> RESOLUTION="1920x1080"
bs_mobile:  --profile browserstack <%= mobile %>

# BrowserStack macOS desktop browser profiles
bs_macos_sonoma:  --profile bs_desktop BS_OS="OS X" BS_OS_VERSION="Sonoma"
bs_chrome_sonoma: --profile bs_macos_sonoma BS_BROWSER="Chrome" BS_VERSION="latest"
bs_edge_sonoma:   --profile bs_macos_sonoma BS_BROWSER="Edge" BS_VERSION="latest"
bs_safari_sonoma: --profile bs_macos_sonoma BS_BROWSER="Safari" BS_VERSION="latest"

# BrowserStack Windows desktop browser profiles
bs_win11:        --profile bs_desktop BS_OS="Windows" BS_OS_VERSION="11"
bs_chrome_win11: --profile bs_win11 BS_BROWSER="Chrome" BS_VERSION="latest"
bs_edge_win11:   --profile bs_win11 BS_BROWSER="Edge" BS_VERSION="latest"
bs_win10:        --profile bs_desktop BS_OS="Windows" BS_OS_VERSION="10"
bs_ie_win10:     --profile bs_win10 BS_BROWSER="IE" BS_VERSION="11.0"

# BrowserStack iOS mobile browser profiles
bs_ipad:        --profile bs_mobile BS_OS=ios BS_BROWSER=Safari DEVICE_TYPE=tablet BS_REAL_MOBILE="true"
bs_ipad_pro_12: --profile bs_ipad BS_DEVICE="iPad Pro 12.9 2018" BS_OS_VERSION="15"

# BrowserStack Android mobile browser profiles
bs_android:        --profile bs_mobile BS_OS=android BS_BROWSER=Chrome DEVICE_TYPE=tablet BS_REAL_MOBILE="true"
bs_android_tablet: --profile bs_android BS_DEVICE="Samsung Galaxy Tab S7" BS_OS_VERSION="10.0"

#==============
# profiles for remotely hosted web browsers on the SauceLabs service
# WARNING: Credentials should not be stored as text in your cucumber.yml file where it can be exposed by anyone with
#          access to your version control system
#==============

saucelabs:  DRIVER=saucelabs SL_USERNAME="<INSERT USER NAME HERE>" SL_AUTHKEY="<INSERT PASSWORD HERE>" SL_DATA_CENTER="<INSERT DATA CENTER HERE"
sl_desktop: --profile saucelabs <%= desktop %>
sl_mobile:  --profile saucelabs <%= mobile %>

# SauceLabs macOS desktop browser profiles
sl_macos_ventura:  --profile sl_desktop SL_OS="macOS 13" RESOLUTION="1920x1440"
sl_chrome_ventura: --profile sl_macos_ventura SL_BROWSER="chrome" SL_VERSION="latest"
sl_edge_ventura:   --profile sl_macos_ventura SL_BROWSER="MicrosoftEdge" SL_VERSION="latest"
sl_firefox_ventura: --profile sl_macos_ventura SL_BROWSER="Firefox" SL_VERSION="latest"

# SauceLabs Windows desktop browser profiles
sl_windows:    --profile sl_desktop RESOLUTION="1920x1200"
sl_edge_win11: --profile sl_windows SL_OS="Windows 11" SL_BROWSER="MicrosoftEdge" SL_VERSION="latest"
sl_ie_win10:   --profile sl_windows SL_OS="Windows 10" SL_BROWSER="internet explorer" SL_VERSION="11"

# SauceLabs iOS mobile browser profiles
sl_ipad:        --profile sl_mobile DEVICE_TYPE=tablet SL_PLATFORM=iOS SL_BROWSER=Safari
sl_ipad_pro_12: --profile sl_ipad SL_DEVICE="iPad Pro (12.9 inch) (5th generation) Simulator" SL_VERSION="15.0"

#==============
# profiles for remotely hosted web browsers on the TestingBot service
# WARNING: Credentials should not be stored as text in your cucumber.yml file where it can be exposed by anyone with
#          access to your version control system
#==============

testingbot: DRIVER=testingbot TB_USERNAME="<INSERT USER NAME HERE>" TB_AUTHKEY="<INSERT PASSWORD HERE>"
tb_desktop: --profile testingbot <%= desktop %> RESOLUTION="1920x1200"

# TestingBot macOS desktop browser profiles
tb_macos_sonoma:  --profile tb_desktop TB_OS="SONOMA"
tb_chrome_sonoma: --profile tb_macos_sonoma TB_BROWSER="chrome" TB_VERSION="latest"
tb_edge_sonoma:   --profile tb_macos_sonoma TB_BROWSER="microsoftedge" TB_VERSION="latest"

# TestingBot Windows desktop browser profiles
tb_win11:      --profile tb_desktop TB_OS="WIN11"
tb_edge_win11: --profile tb_win11 TB_BROWSER="microsoftedge" TB_VERSION="latest"
tb_win10:      --profile tb_desktop TB_OS="WIN10"
tb_ie_win10:   --profile tb_win10 TB_BROWSER="internet explorer" TB_VERSION="11"

#==============
# profiles for remotely hosted web browsers on the LambdaTest service
# WARNING: Credentials should not be stored as text in your cucumber.yml file where it can be exposed by anyone with
#          access to your version control system
#==============

lambdatest: DRIVER=lambdatest LT_USERNAME=<INSERT USER NAME HERE> LT_AUTHKEY=<INSERT PASSWORD HERE>
lt_desktop: --profile lambdatest <%= desktop %> RESOLUTION="2560x1440"

# LambdaTest macOS desktop browser profiles
lt_macos_monterey:  --profile lt_desktop LT_OS="MacOS Monterey"
lt_chrome_monterey: --profile lt_macos_monterey LT_BROWSER="Chrome" LT_VERSION="98.0"
lt_edge_monterey:   --profile lt_macos_monterey LT_BROWSER="MicrosoftEdge" LT_VERSION="97.0"

# LambdaTest Windows desktop browser profiles
lt_win11:      --profile lt_desktop LT_OS="Windows 11"
lt_edge_win11: --profile lt_win11 LT_BROWSER="MicrosoftEdge" LT_VERSION="98.0"
lt_win10:      --profile lt_desktop LT_OS="Windows 10"
lt_i0_win11:   --profile lt_win10 LT_BROWSER="Internet Explorer" LT_VERSION="11.0"

To specify a locally hosted target browser using a profile at runtime, you use the flag --profile or -p followed by the profile name when invoking Cucumber in the command line. For instance, the following command invokes Cucumber and specifies that a local instance of Firefox will be used as the target web browser:

cucumber -p firefox

The following command specifies that Cucumber will run tests against an instance of Chrome hosted within a Dockerized Selenium Grid 4 environment:

cucumber -p chrome -p grid

The following command specifies that Cucumber will run tests against a local instance of Chrome, which will be used to emulate an iPad Pro in landscape orientation:

cucumber -p ipad_pro -p landscape

The following command specifies that Cucumber will run tests against an iPad Pro (12.9-inch) (5th generation) with iOS version 15.4 in an XCode Simulator in landscape orientation:

cucumber -p ipad_pro_12_15_sim -p landscape

⚠️ Appium must be running prior to executing this command

You can ensure that Appium Server is running by including -p run_appium in your command line:

cucumber -p ipad_pro_12_15_sim -p landscape -p run_appium

If you are running locally hosted mobile web tests using version 1.x of Appium server, you must include -p appium_1x in your command line:

cucumber -p ipad_pro_12_15_sim -p landscape -p run_appium -p appium_1x

The following command specifies that Cucumber will run tests against a remotely hosted Safari web browser running on a macOS Sonoma virtual machine on the BrowserStack service:

cucumber -p bs_safari_sonoma

Recommended Project Organization and Structure

Below is an example of the project structure of a typical Cucumber based test automation framework with a Page Object Model architecture. PageObject class definitions should be stored in the /features/support/pages folder, organized in functional area sub-folders as needed. Likewise, PageSection class definitions should be stored in the /features/support/sections folder.

    📁 my_automation_project/
    ├── 📁 config/
    │   ├── 📁 locales/
    │   ├── 📁 test_data/
    │   └── 📄 cucumber.yml
    ├── 📁 downloads/
    ├── 📁 features/
    │   ├── 📁 step_definitions/
    │   └── 📁 support/
    │       ├── 📁 pages/
    │       ├── 📁 sections/
    │       ├── 📄 env.rb
    │       ├── 📄 hooks.rb
    │       └── 📄 world_pages.rb
    ├── 📄 Gemfile
    └── 📄 README.md

Web Test Automation Framework Implementation

TestCentricity For Web Framework Overview


Copyright and License

TestCentricity™ Framework is Copyright (c) 2014-2024, Tony Mrozinski. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.