Class: TestCentricity::ScreenObject

Inherits:
BaseScreenSectionObject show all
Includes:
Test::Unit::Assertions
Defined in:
lib/testcentricity_mobile/app_core/screen_object.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from BaseScreenSectionObject

#populate_data_fields, #swipe_gesture, trait, #verify_ui_states

Constructor Details

#initializeScreenObject

Returns a new instance of ScreenObject.



9
10
11
12
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 9

def initialize
  raise "Screen object #{self.class.name} does not have a screen_name trait defined" unless defined?(screen_name)
  @locator = screen_locator if defined?(screen_locator)
end

Instance Attribute Details

#locatorObject (readonly)

Returns the value of attribute locator.



7
8
9
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 7

def locator
  @locator
end

Class Method Details

.alert(element_name, locator) ⇒ Object

Declare and instantiate a single alert UI Element for this screen object.

Examples:

alert :generic_alert_modal, { id: 'android:id/parentPanel' }
alert :generic_alert_modal, { class: 'XCUIElementTypeAlert' }

Parameters:

  • element_name (Symbol)

    name of alert object (as a symbol)

  • locator (Hash)

    { locator_strategy: locator_identifier }



247
248
249
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 247

def self.alert(element_name, locator)
  define_screen_element(element_name, TestCentricity::AppElements::AppAlert, locator)
end

.alerts(element_hash) ⇒ Object

Declare and instantiate a collection of alerts for this screen object.

Examples:

alerts grant_modal: { id: 'com.android.permissioncontroller:id/grant_dialog' },
       alert_modal: { id: 'android:id/parentPanel' }

Parameters:

  • element_hash (Hash)

    names of alerts (as symbol) and locator Hash



258
259
260
261
262
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 258

def self.alerts(element_hash)
  element_hash.each do |element_name, locator|
    alert(element_name, locator)
  end
end

.button(element_name, locator) ⇒ Object

Declare and instantiate a single button UI Element for this screen object.

Examples:

button :video_play,  { accessibility_id: 'video icon play' }

Parameters:

  • element_name (Symbol)

    name of button object (as a symbol)

  • locator (Hash)

    { locator_strategy: locator_identifier }



51
52
53
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 51

def self.button(element_name, locator)
  define_screen_element(element_name, TestCentricity::AppElements::AppButton, locator)
end

.buttons(element_hash) ⇒ Object

Declare and instantiate a collection of buttons for this screen object.

Examples:

buttons video_back:    { accessibility_id: 'video icon backward' },
        video_play:    { accessibility_id: 'video icon play' },
        video_pause:   { accessibility_id: 'video icon stop' },
        video_forward: { accessibility_id: 'video icon forward' }

Parameters:

  • element_hash (Hash)

    names of buttons (as symbol) and locator Hash



64
65
66
67
68
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 64

def self.buttons(element_hash)
  element_hash.each do |element_name, locator|
    button(element_name, locator)
  end
end

.checkbox(element_name, locator) ⇒ Object

Declare and instantiate a single checkbox UI Element for this screen object.

Examples:

checkbox :bill_address_check, { xpath: '//XCUIElementTypeOther[contains(@name, "billing checkbox")]'}

Parameters:

  • element_name (Symbol)

    name of checkbox object (as a symbol)

  • locator (Hash)

    { locator_strategy: locator_identifier }



126
127
128
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 126

def self.checkbox(element_name, locator)
  define_screen_element(element_name, TestCentricity::AppElements::AppCheckBox, locator)
end

.checkboxes(element_hash) ⇒ Object

Declare and instantiate a collection of checkboxes for this screen object.

Examples:

checkboxes bill_address_check: { xpath: '//XCUIElementTypeOther[contains(@name, "billing checkbox")]'},
           is_gift_check: { accessibility_id: 'is a gift' }

Parameters:

  • element_hash (Hash)

    names of checkboxes (as symbol) and locator Hash



137
138
139
140
141
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 137

def self.checkboxes(element_hash)
  element_hash.each do |element_name, locator|
    checkbox(element_name, locator)
  end
end

.element(element_name, locator) ⇒ Object

Declare and instantiate a single generic UI Element for this screen object.

  • The locator_identifier (a String) is the value or attribute that uniquely and unambiguously identifies the UI element.

Examples:

element :video_player, { accessibility_id: 'YouTube Video Player' }

Parameters:

  • element_name (Symbol)

    name of UI object (as a symbol)

  • locator (Hash)

    { locator_strategy: locator_identifier } The locator_strategy (a Symbol) specifies the selector strategy that Appium will use to find the UI element. Valid selectors are accessibility_id:, id:, name:, class:, xpath:, predicate: (iOS only), class_chain: (iOS only), and css: (WebViews in hybrid apps only).



26
27
28
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 26

def self.element(element_name, locator)
  define_screen_element(element_name, TestCentricity::AppElements::AppUIElement, locator)
end

.elements(element_hash) ⇒ Object

Declare and instantiate a collection of generic UI Elements for this screen object.

Examples:

elements drop_down_field: { accessibility_id: 'drop_trigger' },
         settings_item: { accessibility_id: 'settings' },
         video_player: { accessibility_id: 'YouTube Video Player' }

Parameters:

  • element_hash (Hash)

    names of UI objects (as a Symbol) and locator Hash



38
39
40
41
42
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 38

def self.elements(element_hash)
  element_hash.each do |element_name, locator|
    element(element_name, locator)
  end
end

.image(element_name, locator) ⇒ Object

Declare and instantiate a single image UI Element for this screen object.

Examples:

image :product_image, { xpath: '//XCUIElementTypeImage' }

Parameters:

  • element_name (Symbol)

    name of image object (as a symbol)

  • locator (Hash)

    { locator_strategy: locator_identifier }



222
223
224
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 222

def self.image(element_name, locator)
  define_screen_element(element_name, TestCentricity::AppElements::AppImage, locator)
end

.images(element_hash) ⇒ Object

Declare and instantiate a collection of images for this screen object.

Examples:

images empty_cart_image: { accessibility_id: 'empty_cart' },
       logo_image: { accessibility_id: 'WebdriverIO logo' }

Parameters:

  • element_hash (Hash)

    names of images (as symbol) and locator Hash



233
234
235
236
237
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 233

def self.images(element_hash)
  element_hash.each do |element_name, locator|
    image(element_name, locator)
  end
end

.label(element_name, locator) ⇒ Object

Declare and instantiate a single label UI Element for this screen object.

Examples:

label :header_label, { accessibility_id: 'container header' }

Parameters:

  • element_name (Symbol)

    name of label object (as a symbol)

  • locator (Hash)

    { locator_strategy: locator_identifier }



174
175
176
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 174

def self.label(element_name, locator)
  define_screen_element(element_name, TestCentricity::AppElements::AppLabel, locator)
end

.labels(element_hash) ⇒ Object

Declare and instantiate a collection of labels for this screen object.

Examples:

labels total_qty_value:   { accessibility_id: 'total number' },
       total_price_value: { accessibility_id: 'total price' }

Parameters:

  • element_hash (Hash)

    names of labels (as symbol) and locator Hash



185
186
187
188
189
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 185

def self.labels(element_hash)
  element_hash.each do |element_name, locator|
    label(element_name, locator)
  end
end

.list(element_name, locator) ⇒ Object

Declare and instantiate a single list UI Element for this screen object.

Examples:

list :carousel_list, { accessibility_id: 'Carousel' }

Parameters:

  • element_name (Symbol)

    name of list object (as a symbol)

  • locator (Hash)

    { locator_strategy: locator_identifier }



198
199
200
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 198

def self.list(element_name, locator)
  define_screen_element(element_name, TestCentricity::AppElements::AppList, locator)
end

.lists(element_hash) ⇒ Object

Declare and instantiate a collection of lists for this screen object.

Examples:

lists product_grid: { xpath: '//android.widget.ScrollView/android.view.ViewGroup' },
      cart_list: { xpath: '//android.widget.ScrollView[@content-desc="cart screen"]' }

Parameters:

  • element_hash (Hash)

    names of lists (as symbol) and locator Hash



209
210
211
212
213
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 209

def self.lists(element_hash)
  element_hash.each do |element_name, locator|
    list(element_name, locator)
  end
end

.radio(element_name, locator) ⇒ Object

Declare and instantiate a single radio button UI Element for this screen object.

Examples:

radio :unicode_radio, { xpath: '//XCUIElementTypeRadioButton[@label="Unicode"]'}

Parameters:

  • element_name (Symbol)

    name of radio button object (as a symbol)

  • locator (Hash)

    { locator_strategy: locator_identifier }



150
151
152
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 150

def self.radio(element_name, locator)
  define_screen_element(element_name, TestCentricity::AppElements::AppRadio, locator)
end

.radios(element_hash) ⇒ Object

Declare and instantiate a collection of radio buttons for this screen object.

Examples:

radios unicode_radio: { xpath: '//XCUIElementTypeRadioButton[@label="Unicode"]'},
       ascii_radio:   { xpath: '//XCUIElementTypeRadioButton[@label="ASCII"] }

Parameters:

  • element_hash (Hash)

    names of radio buttons (as symbol) and locator Hash



161
162
163
164
165
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 161

def self.radios(element_hash)
  element_hash.each do |element_name, locator|
    radio(element_name, locator)
  end
end

.section(section_name, obj, locator = 0) ⇒ Object

Instantiate a single ScreenSection object within this ScreenObject.

Examples:

section :nav_menu, NavMenu

Parameters:

  • section_name (Symbol)

    name of ScreenSection object (as a symbol)

  • class_name (Class)

    Class name of ScreenSection object



271
272
273
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 271

def self.section(section_name, obj, locator = 0)
  define_screen_element(section_name, obj, locator)
end

.sections(section_hash) ⇒ Object

Declare and instantiate a collection of ScreenSection objects for this screen object.

Examples:

sections nav_bar:  NavBar,
         nav_menu: NavMenu

Parameters:

  • element_hash (Hash)

    names of ScreenSections (as symbol) and class name



282
283
284
285
286
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 282

def self.sections(section_hash)
  section_hash.each do |section_name, class_name|
    section(section_name, class_name)
  end
end

.switch(element_name, locator) ⇒ Object

Declare and instantiate a single switch UI Element for this screen object.

Examples:

switch :debug_mode_switch, { accessibility_id: 'debug mode' }

Parameters:

  • element_name (Symbol)

    name of switch object (as a symbol)

  • locator (Hash)

    { locator_strategy: locator_identifier }



102
103
104
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 102

def self.switch(element_name, locator)
  define_screen_element(element_name, TestCentricity::AppElements::AppSwitch, locator)
end

.switches(element_hash) ⇒ Object

Declare and instantiate a collection of switches for this screen object.

Examples:

switches debug_mode_switch: { accessibility_id: 'debug mode' },
         metrics_switch: { accessibility_id: 'metrics' }

Parameters:

  • element_hash (Hash)

    names of switches (as symbol) and locator Hash



113
114
115
116
117
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 113

def self.switches(element_hash)
  element_hash.each do |element_name, locator|
    switch(element_name, locator)
  end
end

.textfield(element_name, locator) ⇒ Object

Declare and instantiate a single textfield UI Element for this screen object.

Examples:

textfield :payee_name_field, { xpath: '//android.widget.EditText[@content-desc="Full Name* input field"]' }
textfield :payee_name_field, { xpath: '//XCUIElementTypeTextField[@name="Full Name* input field"]' }

Parameters:

  • element_name (Symbol)

    name of textfield object (as a symbol)

  • locator (Hash)

    { locator_strategy: locator_identifier }



78
79
80
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 78

def self.textfield(element_name, locator)
  define_screen_element(element_name, TestCentricity::AppElements::AppTextField, locator)
end

.textfields(element_hash) ⇒ Object

Declare and instantiate a collection of textfields for this screen object.

Examples:

textfields username_field: { accessibility_id: 'Username input field' },
           password_field: { accessibility_id: 'Password input field' }

Parameters:

  • element_hash (Hash)

    names of textfields (as symbol) and locator Hash



89
90
91
92
93
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 89

def self.textfields(element_hash)
  element_hash.each do |element_name, locator|
    textfield(element_name, locator)
  end
end

Instance Method Details

#exists?Boolean

Does Screen object exists?

Examples:

home_screen.exists?

Returns:

  • (Boolean)


294
295
296
297
298
299
300
301
302
303
304
305
306
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 294

def exists?
  @locator.is_a?(Array) ? tries ||= 2 : tries ||= 1
  if @locator.is_a?(Array)
    loc = @locator[tries - 1]
    find_element(loc.keys[0], loc.values[0])
  else
    find_element(@locator.keys[0], @locator.values[0])
  end
  true
rescue
  retry if (tries -= 1) > 0
  false
end

#load_screenObject

Load the screen using its defined deep_link trait. When testing on physical iOS devices running iOS/iPadOS versions earlier than version 16.4, deep links can only be opened by sending the deeplink URL to the mobile Safari web browser, and then accepting the confirmation modal that pops up. This method handles invoking deeplinks on Android and iOS/iPadOS simulators and physical devices.

This method verifies that the target screen is loaded and displayed, and sets ScreenManager.current_screen to reference the target screen instance.

Examples:

cart_screen.load_screen


372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 372

def load_screen
  # return if target screen is already loaded
  if exists?
    ScreenManager.current_screen = self
    return
  end

  url = if deep_link.include?("://")
          deep_link
        elsif !Environ.current.deep_link_prefix.blank?
          "#{Environ.current.deep_link_prefix}://#{deep_link}"
        end

  if Environ.is_android?
    Environ.appium_driver.execute_script('mobile:deepLink', { url: url, package: Environ.current.android_app_id })
  elsif Environ.is_ios?
    if Environ.is_device? && Environ.device_os_version.to_f < 16.4
      # launch Safari browser on iOS real device if iOS version is below 16.4
      Environ.appium_driver.execute_script('mobile: launchApp', { bundleId: 'com.apple.mobilesafari' })
      unless Environ.appium_driver.is_keyboard_shown
        begin
          # attempt to find and click URL button on iOS 15 Safari browser
          find_element(:accessibility_id, 'TabBarItemTitle').click
        rescue
          # fall back to URL button on iOS 14 Safari browser
          find_element(:xpath, '//XCUIElementTypeButton[@name="URL"]').click
        end
      end
      # enter deep-link URL
      wait_for_object(:xpath, '//XCUIElementTypeTextField[@name="URL"]', 5).send_keys("#{url}\uE007")
      # wait for and accept the popup modal
      wait_for_object(:xpath, '//XCUIElementTypeButton[@name="Open"]', 10).click
    else
      # iOS version is >= 16.4 so directly load screen via deepLink
      Environ.appium_driver.get(url)
    end
  else
    raise "#{Environ.device_os} is not supported"
  end
  verify_screen_exists
end


346
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 346

def navigate_to; end

#verify_screen_existsObject

Verifies that the target screen is displayed, and sets ScreenManager.current_screen to reference the target screen instance.



353
354
355
356
357
358
359
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 353

def verify_screen_exists
  wait = Selenium::WebDriver::Wait.new(timeout: Environ.default_max_wait_time)
  wait.until { exists? }
  ScreenManager.current_screen = self
rescue
  raise "Could not find screen_locator for screen object '#{self.class.name}' (#{@locator}) after #{Environ.default_max_wait_time} seconds"
end

#verify_screen_uiObject



348
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 348

def verify_screen_ui; end

#wait_until_exists(seconds = nil, post_exception = true) ⇒ Object

Wait until the Screen object exists, or until the specified wait time has expired. If the wait time is nil, then the wait time will be Environ.default_max_wait_time.

Examples:

cart_screen.wait_until_exists(15)

Parameters:

  • seconds (Integer or Float) (defaults to: nil)

    wait time in seconds



315
316
317
318
319
320
321
322
323
324
325
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 315

def wait_until_exists(seconds = nil, post_exception = true)
  timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
  wait = Selenium::WebDriver::Wait.new(timeout: timeout)
  wait.until { exists? }
rescue
  if post_exception
    raise "Screen object #{self.class.name} not found after #{timeout} seconds" unless exists?
  else
    exists?
  end
end

#wait_until_gone(seconds = nil, post_exception = true) ⇒ Object

Wait until the Screen object is gone, or until the specified wait time has expired. If the wait time is nil, then the wait time will be Environ.default_max_wait_time.

Examples:

.wait_until_gone(15)

Parameters:

  • seconds (Integer or Float) (defaults to: nil)

    wait time in seconds



334
335
336
337
338
339
340
341
342
343
344
# File 'lib/testcentricity_mobile/app_core/screen_object.rb', line 334

def wait_until_gone(seconds = nil, post_exception = true)
  timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
  wait = Selenium::WebDriver::Wait.new(timeout: timeout)
  wait.until { !exists? }
rescue
  if post_exception
    raise "Screen object #{self.class.name} remained visible after #{timeout} seconds" if exists?
  else
    exists?
  end
end