Class: TestCentricity::ScreenObject

Inherits:
BaseScreenSectionObject show all
Includes:
Test::Unit::Assertions
Defined in:
lib/testcentricity_apps/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
13
# File 'lib/testcentricity_apps/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_apps/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 }



296
297
298
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 296

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



307
308
309
310
311
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 307

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 }



52
53
54
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 52

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



65
66
67
68
69
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 65

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 }



127
128
129
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 127

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



138
139
140
141
142
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 138

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

.define_screen_element(element_name, obj, locator) ⇒ Object



520
521
522
523
524
525
526
527
528
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 520

def self.define_screen_element(element_name, obj, locator)
  define_method(element_name) do
    ivar_name = "@#{element_name}"
    ivar = instance_variable_get(ivar_name)
    return ivar if ivar

    instance_variable_set(ivar_name, obj.new(element_name, self, locator, :screen))
  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).



27
28
29
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 27

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



39
40
41
42
43
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 39

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 }



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

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



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

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 }



175
176
177
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 175

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



186
187
188
189
190
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 186

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 }



199
200
201
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 199

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



210
211
212
213
214
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 210

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

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

Examples:

menu :convert_menu, { xpath: '//XCUIElementTypeMenuBarItem[6]' }

Parameters:

  • element_name (Symbol)

    name of menu object (as a symbol)

  • locator (Hash)

    { locator_strategy: locator_identifier }



320
321
322
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 320

def self.menu(element_name, locator)
  define_screen_element(element_name, TestCentricity::AppElements::AppMenu, locator)
end

Declare and instantiate a single MenuBar object for this screen object.

Examples:

menubar :menu_bar, CalculatorMenuBar

Parameters:

  • element_name (Symbol)

    name of MenuBar object (as a symbol)

  • class_name (Class)

    Class name of MenuBar object



344
345
346
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 344

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

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

Examples:

menus convert_menu: { xpath: '//XCUIElementTypeMenuBarItem[6]' },
      view_menu:    { xpath: '//XCUIElementTypeMenuBarItem[5]' }

Parameters:

  • element_hash (Hash)

    names of menus (as symbol) and locator Hash



331
332
333
334
335
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 331

def self.menus(element_hash)
  element_hash.each do |element_name, locator|
    menu(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 }



151
152
153
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 151

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



162
163
164
165
166
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 162

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



355
356
357
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 355

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



366
367
368
369
370
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 366

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

.selectlist(element_name, locator) ⇒ Object

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

Examples:

selectlist :convert_list, { xpath: '//XCUIElementTypePopUpButton[@label="convert"]' }

Parameters:

  • element_name (Symbol)

    name of selectlist object (as a symbol)

  • locator (Hash)

    { locator_strategy: locator_identifier }



223
224
225
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 223

def self.selectlist(element_name, locator)
  define_screen_element(element_name, TestCentricity::AppElements::AppSelectList, locator)
end

.selectlists(element_hash) ⇒ Object

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

Examples:

selectlists convert_list: { xpath: '//XCUIElementTypePopUpButton[@label="convert"]' },
            from_list:    { xpath: '//XCUIElementTypePopUpButton[@label="convert_from"]' }

Parameters:

  • element_hash (Hash)

    names of selectlists (as symbol) and locator Hash



234
235
236
237
238
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 234

def self.selectlists(element_hash)
  element_hash.each do |element_name, locator|
    selectlist(element_name, locator)
  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 }



103
104
105
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 103

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



114
115
116
117
118
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 114

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

.table(element_name, locator) ⇒ Object

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

Examples:

table :sidebar_table, { predicate: 'identifier == "library.sidebar"' }

Parameters:

  • element_name (Symbol)

    name of table object (as a symbol)

  • locator (Hash)

    { locator_strategy: locator_identifier }



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

def self.table(element_name, locator)
  define_screen_element(element_name, TestCentricity::AppElements::AppTable, locator)
end

.tables(element_hash) ⇒ Object

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

Examples:

tables sidebar_table: { predicate: 'identifier == "library.sidebar"' },
       view_table:    { predicate: 'identifier == "view.library.table"' }

Parameters:

  • element_hash (Hash)

    names of tables (as symbol) and locator Hash



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

def self.tables(element_hash)
  element_hash.each do |element_name, locator|
    table(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 }



79
80
81
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 79

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



90
91
92
93
94
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 90

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)


378
379
380
381
382
383
384
385
386
387
388
389
390
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 378

def exists?
  tries ||= @locator.is_a?(Array) ? 2 : 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).positive?
  false
end

#identifierObject



404
405
406
407
408
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 404

def identifier
  raise 'identifier is not a supported attribute' unless Environ.is_macos?

  find_element(@locator.keys[0], @locator.values[0]).identifier
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


474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 474

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_macos?
    Environ.appium_driver.execute_script('macos: 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


448
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 448

def navigate_to; end

#titleString

Return window title. For MacOS app testing only. Raises exception if called while testing iOS or Android

Examples:

calculator_screen.title

Returns:



398
399
400
401
402
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 398

def title
  raise 'title is not a supported attribute' unless Environ.is_macos?

  find_element(@locator.keys[0], @locator.values[0]).title
end

#verify_screen_existsObject

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



455
456
457
458
459
460
461
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 455

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



450
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 450

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



417
418
419
420
421
422
423
424
425
426
427
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 417

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



436
437
438
439
440
441
442
443
444
445
446
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 436

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