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
# 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 }



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

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



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

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_apps/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_apps/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_apps/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_apps/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_apps/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_apps/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 }



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

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



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

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_apps/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_apps/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_apps/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_apps/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

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



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

def self.menubar(section_name, obj, locator = 0)
  define_screen_element(section_name, obj, locator)
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_apps/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_apps/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



306
307
308
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 306

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



317
318
319
320
321
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 317

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 }



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

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



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

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 }



102
103
104
# File 'lib/testcentricity_apps/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_apps/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_apps/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_apps/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)


329
330
331
332
333
334
335
336
337
338
339
340
341
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 329

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

#identifierObject



357
358
359
360
361
362
363
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 357

def identifier
  if Environ.is_macos?
    find_element(@locator.keys[0], @locator.values[0]).identifier
  else
    raise 'identifier is not a supported attribute'
  end
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


429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 429

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


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

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:



349
350
351
352
353
354
355
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 349

def title
  if Environ.is_macos?
    find_element(@locator.keys[0], @locator.values[0]).title
  else
    raise 'title is not a supported attribute'
  end
end

#verify_screen_existsObject

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



410
411
412
413
414
415
416
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 410

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



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

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



372
373
374
375
376
377
378
379
380
381
382
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 372

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



391
392
393
394
395
396
397
398
399
400
401
# File 'lib/testcentricity_apps/app_core/screen_object.rb', line 391

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