testcentricity 2.4.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +29 -0
  3. data/.rspec +2 -1
  4. data/.rubocop.yml +38 -0
  5. data/.ruby-version +1 -1
  6. data/.simplecov +9 -0
  7. data/.yardopts +3 -0
  8. data/CHANGELOG.md +275 -0
  9. data/CODE_OF_CONDUCT.md +13 -0
  10. data/{LICENSE.txt → LICENSE.md} +3 -4
  11. data/README.md +938 -1378
  12. data/Rakefile +63 -1
  13. data/config/cucumber.yml +145 -0
  14. data/config/locales/en-US.yml +56 -0
  15. data/config/test_data/LOCAL_data.yml +11 -0
  16. data/config/test_data/data.yml +10 -0
  17. data/features/deep_links.feature +26 -0
  18. data/features/login.feature +30 -0
  19. data/features/navigation.feature +31 -0
  20. data/features/step_definitions/generic_steps.rb +72 -0
  21. data/features/support/android/screens/about_screen.rb +11 -0
  22. data/features/support/android/screens/base_app_screen.rb +29 -0
  23. data/features/support/android/screens/checkout_address_screen.rb +17 -0
  24. data/features/support/android/screens/checkout_payment_screen.rb +22 -0
  25. data/features/support/android/screens/login_screen.rb +18 -0
  26. data/features/support/android/screens/products_screen.rb +13 -0
  27. data/features/support/android/screens/saucebot_screen.rb +16 -0
  28. data/features/support/android/screens/webview_screen.rb +13 -0
  29. data/features/support/android/sections/nav_widgets/nav_menu.rb +39 -0
  30. data/features/support/env.rb +61 -0
  31. data/features/support/hooks.rb +135 -0
  32. data/features/support/ios/screens/about_screen.rb +11 -0
  33. data/features/support/ios/screens/base_app_screen.rb +19 -0
  34. data/features/support/ios/screens/checkout_address_screen.rb +17 -0
  35. data/features/support/ios/screens/checkout_payment_screen.rb +22 -0
  36. data/features/support/ios/screens/login_screen.rb +18 -0
  37. data/features/support/ios/screens/products_screen.rb +13 -0
  38. data/features/support/ios/screens/saucebot_screen.rb +16 -0
  39. data/features/support/ios/screens/webview_screen.rb +13 -0
  40. data/features/support/ios/sections/list_items/product_cell_item.rb +13 -0
  41. data/features/support/ios/sections/modals/base_modal.rb +23 -0
  42. data/features/support/ios/sections/modals/logout_modal.rb +6 -0
  43. data/features/support/ios/sections/modals/reset_app_state_modal.rb +6 -0
  44. data/features/support/ios/sections/nav_widgets/nav_bar.rb +31 -0
  45. data/features/support/ios/sections/nav_widgets/nav_menu.rb +41 -0
  46. data/features/support/shared_components/screens/base_app_screen.rb +31 -0
  47. data/features/support/shared_components/screens/checkout_address_screen.rb +17 -0
  48. data/features/support/shared_components/screens/checkout_payment_screen.rb +22 -0
  49. data/features/support/shared_components/screens/login_screen.rb +39 -0
  50. data/features/support/shared_components/screens/saucebot_screen.rb +17 -0
  51. data/features/support/shared_components/screens/webview_screen.rb +12 -0
  52. data/features/support/shared_components/sections/nav_menu.rb +58 -0
  53. data/features/support/world_data.rb +12 -0
  54. data/features/support/world_pages.rb +26 -0
  55. data/lib/testcentricity/app_core/appium_connect_helper.rb +355 -111
  56. data/lib/testcentricity/app_core/screen_object.rb +252 -0
  57. data/lib/testcentricity/app_core/screen_objects_helper.rb +29 -280
  58. data/lib/testcentricity/app_core/screen_section.rb +350 -0
  59. data/lib/testcentricity/app_elements/app_element_helper.rb +17 -8
  60. data/lib/testcentricity/app_elements/checkbox.rb +3 -3
  61. data/lib/testcentricity/data_objects/environment.rb +133 -39
  62. data/lib/testcentricity/version.rb +1 -1
  63. data/lib/testcentricity.rb +4 -129
  64. data/reports/.keep +1 -0
  65. data/spec/fixtures/page_object.rb +22 -0
  66. data/spec/fixtures/page_section_object.rb +21 -0
  67. data/spec/fixtures/screen_object.rb +16 -0
  68. data/spec/fixtures/screen_section_object.rb +16 -0
  69. data/spec/spec_helper.rb +28 -9
  70. data/spec/testcentricity/elements/button_spec.rb +18 -0
  71. data/spec/testcentricity/elements/checkbox_spec.rb +28 -0
  72. data/spec/testcentricity/elements/image_spec.rb +13 -0
  73. data/spec/testcentricity/elements/label_spec.rb +18 -0
  74. data/spec/testcentricity/elements/list_spec.rb +13 -0
  75. data/spec/testcentricity/elements/ui_element_spec.rb +72 -0
  76. data/spec/testcentricity/mobile/appium_connect_spec.rb +117 -0
  77. data/spec/testcentricity/mobile/screen_object_spec.rb +63 -0
  78. data/spec/testcentricity/mobile/screen_section_object_spec.rb +56 -0
  79. data/spec/testcentricity/version_spec.rb +7 -0
  80. data/spec/testcentricity/web/browser_spec.rb +41 -0
  81. data/spec/testcentricity/web/local_webdriver_spec.rb +86 -0
  82. data/spec/testcentricity/web/mobile_webdriver_spec.rb +123 -0
  83. data/spec/testcentricity/web/page_object_spec.rb +85 -0
  84. data/spec/testcentricity/web/page_section_object_spec.rb +72 -0
  85. data/testcentricity.gemspec +28 -27
  86. metadata +196 -127
  87. data/.ruby-gemset +0 -1
  88. data/Gemfile.lock +0 -93
  89. data/bin/console +0 -14
  90. data/bin/setup +0 -8
  91. data/lib/devices/devices.yml +0 -352
  92. data/lib/testcentricity/app_core/appium_server.rb +0 -69
  93. data/lib/testcentricity/app_core/screen_sections_helper.rb +0 -491
  94. data/lib/testcentricity/browser_helper.rb +0 -174
  95. data/lib/testcentricity/data_objects/data_objects_helper.rb +0 -78
  96. data/lib/testcentricity/data_objects/excel_helper.rb +0 -242
  97. data/lib/testcentricity/exception_queue_helper.rb +0 -111
  98. data/lib/testcentricity/utility_helpers.rb +0 -28
  99. data/lib/testcentricity/web_core/drag_drop_helper.rb +0 -15
  100. data/lib/testcentricity/web_core/page_objects_helper.rb +0 -711
  101. data/lib/testcentricity/web_core/page_sections_helper.rb +0 -932
  102. data/lib/testcentricity/web_core/webdriver_helper.rb +0 -588
  103. data/lib/testcentricity/web_elements/button.rb +0 -8
  104. data/lib/testcentricity/web_elements/cell_button.rb +0 -8
  105. data/lib/testcentricity/web_elements/cell_checkbox.rb +0 -38
  106. data/lib/testcentricity/web_elements/cell_element.rb +0 -69
  107. data/lib/testcentricity/web_elements/cell_image.rb +0 -8
  108. data/lib/testcentricity/web_elements/cell_radio.rb +0 -31
  109. data/lib/testcentricity/web_elements/checkbox.rb +0 -100
  110. data/lib/testcentricity/web_elements/file_field.rb +0 -45
  111. data/lib/testcentricity/web_elements/image.rb +0 -34
  112. data/lib/testcentricity/web_elements/label.rb +0 -8
  113. data/lib/testcentricity/web_elements/link.rb +0 -8
  114. data/lib/testcentricity/web_elements/list.rb +0 -100
  115. data/lib/testcentricity/web_elements/list_button.rb +0 -8
  116. data/lib/testcentricity/web_elements/list_checkbox.rb +0 -38
  117. data/lib/testcentricity/web_elements/list_element.rb +0 -61
  118. data/lib/testcentricity/web_elements/list_radio.rb +0 -31
  119. data/lib/testcentricity/web_elements/radio.rb +0 -74
  120. data/lib/testcentricity/web_elements/select_list.rb +0 -208
  121. data/lib/testcentricity/web_elements/siebel_open_ui_helper.rb +0 -15
  122. data/lib/testcentricity/web_elements/table.rb +0 -612
  123. data/lib/testcentricity/web_elements/textfield.rb +0 -114
  124. data/lib/testcentricity/web_elements/ui_elements_helper.rb +0 -532
  125. data/lib/testcentricity/world_extensions.rb +0 -26
  126. data/my_templates/default/method_details/setup.rb +0 -3
  127. data/spec/testcentricity_spec.rb +0 -9
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'capybara/cucumber'
4
+ require 'parallel_tests'
5
+ require 'require_all'
6
+ require 'simplecov'
7
+ require 'testcentricity'
8
+ require 'testcentricity_web'
9
+
10
+ include TestCentricity
11
+
12
+ SimpleCov.command_name("Features-#{ENV['PLATFORM']}-#{Time.now.strftime('%Y%m%d%H%M%S%L')}")
13
+
14
+ require_relative 'world_data'
15
+ require_relative 'world_pages'
16
+
17
+ require_rel 'shared_components'
18
+
19
+ # conditionally require page and section objects based on target platform
20
+ case ENV['PLATFORM'].downcase.to_sym
21
+ when :ios
22
+ require_rel 'ios'
23
+ when :android
24
+ require_rel 'android'
25
+ when :web
26
+ require_rel 'web'
27
+ else
28
+ raise "Platform unknown. Please specify the target test platform using '-p ios', '-p android', or '-p web' in the command line"
29
+ end
30
+
31
+ $LOAD_PATH << './lib'
32
+
33
+ # set the default locale and auto load all translations from config/locales/*.rb,yml.
34
+ ENV['LOCALE'] = 'en-US' unless ENV['LOCALE']
35
+ ENV['LANGUAGE'] = 'en' unless ENV['LANGUAGE']
36
+ I18n.load_path += Dir['config/locales/*.{rb,yml}']
37
+ I18n.default_locale = ENV['LOCALE']
38
+ I18n.locale = ENV['LOCALE']
39
+ Faker::Config.locale = ENV['LOCALE']
40
+
41
+ # instantiate all data objects and target test environment
42
+ include WorldData
43
+ environs.find_environ(ENV['TEST_ENVIRONMENT'], :yaml)
44
+ WorldData.instantiate_data_objects
45
+
46
+ # instantiate all page objects
47
+ include WorldPages
48
+ WorldPages.instantiate_page_objects
49
+
50
+ # connect to appropriate driver (WebDriver or Appium) based on target platform
51
+ case ENV['PLATFORM'].downcase.to_sym
52
+ when :web
53
+ # establish connection to WebDriver and target web browser
54
+ Webdrivers.cache_time = 86_400
55
+ WebDriverConnect.initialize_web_driver
56
+ when :ios, :android
57
+ AppiumConnect.initialize_appium
58
+ end
59
+
60
+ # set TestCentricity's default max wait time to 20 seconds
61
+ Environ.default_max_wait_time = 20
@@ -0,0 +1,135 @@
1
+
2
+ BeforeAll do
3
+ # start Appium Server if command line option was specified and target browser is mobile simulator or device
4
+ if ENV['APPIUM_SERVER'] == 'run' && Environ.driver == :appium
5
+ $server = TestCentricity::AppiumServer.new
6
+ $server.start
7
+ end
8
+ # connect to sim/device and install app
9
+ AppiumConnect.start_driver
10
+ end
11
+
12
+
13
+ AfterAll do
14
+ # quit Appium driver
15
+ TestCentricity::AppiumConnect.quit_driver
16
+ # terminate Appium Server if command line option was specified and target browser is mobile simulator or device
17
+ if ENV['APPIUM_SERVER'] == 'run' && Environ.driver == :appium && $server.running?
18
+ $server.stop
19
+ end
20
+ end
21
+
22
+
23
+ Before do |scenario|
24
+ # if executing tests in parallel concurrent threads, print thread number with scenario name
25
+ message = Environ.parallel ? "Thread ##{Environ.process_num} | Scenario: #{scenario.name}" : "Scenario: #{scenario.name}"
26
+ log message
27
+ $initialized ||= false
28
+ unless $initialized
29
+ $initialized = true
30
+ $test_start_time = Time.now
31
+ # HTML report header information if reporting is enabled
32
+ log Environ.report_header if ENV['REPORTING']
33
+ end
34
+ end
35
+
36
+
37
+ After do |scenario|
38
+ # process and embed any screenshots recorded during execution of scenario
39
+ process_embed_screenshots(scenario)
40
+ # clear out any queued screenshots
41
+ Environ.reset_contexts
42
+ # close app
43
+ TestCentricity::AppiumConnect.close_app
44
+ end
45
+
46
+
47
+ # exclusionary Around hooks to prevent running feature/scenario on unsupported browsers, devices, or
48
+ # cloud remote browser hosting platforms. Use the following tags to block test execution:
49
+ # mobile devices: @!ipad, @!iphone
50
+
51
+
52
+ # block feature/scenario execution if running against iPad mobile browser
53
+ Around('@!ipad') do |scenario, block|
54
+ qualify_device('ipad', scenario, block)
55
+ end
56
+
57
+
58
+ # block feature/scenario execution if running against iPhone mobile browser
59
+ Around('@!iphone') do |scenario, block|
60
+ qualify_device('iphone', scenario, block)
61
+ end
62
+
63
+
64
+ # block feature/scenario execution if running against a physical or emulated mobile device
65
+ Around('@!device') do |scenario, block|
66
+ if Environ.is_device?
67
+ log "Scenario '#{scenario.name}' cannot be executed on physical or emulated devices."
68
+ skip_this_scenario
69
+ else
70
+ block.call
71
+ end
72
+ end
73
+
74
+
75
+ Around('@!ios') do |scenario, block|
76
+ if Environ.device_os == :android
77
+ block.call
78
+ else
79
+ log "Scenario '#{scenario.name}' can not be executed on iOS devices."
80
+ skip_this_scenario
81
+ end
82
+ end
83
+
84
+
85
+ Around('@!android') do |scenario, block|
86
+ if Environ.device_os == :ios
87
+ block.call
88
+ else
89
+ log "Scenario '#{scenario.name}' can not be executed on Android devices."
90
+ skip_this_scenario
91
+ end
92
+ end
93
+
94
+
95
+ # supporting methods
96
+
97
+ def qualify_device(device, scenario, block)
98
+ if Environ.is_device?
99
+ if Environ.device_type.include? device
100
+ log "Scenario '#{scenario.name}' cannot be executed on #{device} devices."
101
+ skip_this_scenario
102
+ else
103
+ block.call
104
+ end
105
+ else
106
+ block.call
107
+ end
108
+ end
109
+
110
+ def screen_shot_and_save_page(scenario)
111
+ timestamp = Time.now.strftime('%Y%m%d%H%M%S%L')
112
+ filename = scenario.nil? ? "Screenshot-#{timestamp}.png" : "Screenshot-#{scenario.__id__}-#{timestamp}.png"
113
+ path = File.join Dir.pwd, 'reports/screenshots/', filename
114
+ if Environ.driver == :appium
115
+ TestCentricity::AppiumConnect.take_screenshot(path)
116
+ else
117
+ save_screenshot path
118
+ end
119
+ log "Screenshot saved at #{path}"
120
+ screen_shot = { path: path, filename: filename }
121
+ Environ.save_screen_shot(screen_shot)
122
+ attach(path, 'image/png') unless scenario.nil?
123
+ end
124
+
125
+ def process_embed_screenshots(scenario)
126
+ screen_shots = Environ.get_screen_shots
127
+ if screen_shots.count > 0
128
+ screen_shots.each do |row|
129
+ path = row[:path]
130
+ attach(path, 'image/png')
131
+ end
132
+ else
133
+ screen_shot_and_save_page(scenario) if scenario.failed?
134
+ end
135
+ end
@@ -0,0 +1,11 @@
1
+ class AboutScreen < BaseAppScreen
2
+ trait(:page_name) { 'About' }
3
+ trait(:page_locator) { { accessibility_id: 'about screen' } }
4
+ trait(:page_url) { 'about' }
5
+ trait(:navigator) { nav_menu.open_about }
6
+
7
+ def verify_page_ui
8
+ super
9
+ verify_ui_states(header_label => { visible: true, caption: 'About' })
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ class BaseAppScreen < TestCentricity::ScreenObject
2
+ include SharedBaseAppScreen
3
+
4
+ trait(:page_name) { 'Base App Screen' }
5
+
6
+ # Base App screen UI elements
7
+ label :header_label, { accessibility_id: 'container header' }
8
+ sections nav_bar: NavBar,
9
+ nav_menu: NavMenu
10
+
11
+ def verify_page_ui
12
+ nav_bar.verify_ui
13
+ end
14
+
15
+ def invoke_nav_menu
16
+ nav_bar.open_menu
17
+ nav_menu.wait_until_visible(3)
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ class CheckoutAddressScreen < BaseAppScreen
2
+ include SharedCheckoutAddressScreen
3
+
4
+ trait(:page_name) { 'Checkout - Address' }
5
+ trait(:page_locator) { { accessibility_id: 'checkout address screen' } }
6
+ trait(:page_url) { 'checkout-address' }
7
+
8
+ # Checkout Address screen UI elements
9
+ textfields fullname_field: { accessibility_id: 'Full Name* input field' },
10
+ address1_field: { accessibility_id: 'Address Line 1* input field' },
11
+ address2_field: { accessibility_id: 'Address Line 2 input field' },
12
+ city_field: { accessibility_id: 'City* input field' },
13
+ state_region_field: { accessibility_id: 'State/Region input field' },
14
+ zip_code_field: { accessibility_id: 'Zip Code* input field' },
15
+ country_field: { accessibility_id: 'Country* input field' }
16
+ button :to_payment_button, { accessibility_id: 'To Payment button' }
17
+ end
@@ -0,0 +1,22 @@
1
+ class CheckoutPaymentScreen < BaseAppScreen
2
+ include SharedCheckoutPaymentScreen
3
+
4
+ trait(:page_name) { 'Checkout - Payment' }
5
+ trait(:page_locator) { { accessibility_id: 'checkout payment screen' } }
6
+ trait(:page_url) { 'checkout-payment' }
7
+
8
+ # Checkout Payment screen UI elements
9
+ textfields payee_name_field: { xpath: '(//XCUIElementTypeTextField[@name="Full Name* input field"])[1]' },
10
+ card_number_field: { accessibility_id: 'Card Number* input field' },
11
+ expiration_field: { accessibility_id: 'Expiration Date* input field' },
12
+ security_code_field: { accessibility_id: 'Security Code* input field' },
13
+ recipient_name_field: { xpath: '(//XCUIElementTypeTextField[@name="Full Name* input field"])[2]' },
14
+ address1_field: { accessibility_id: 'Address Line 1* input field' },
15
+ address2_field: { accessibility_id: 'Address Line 2 input field' },
16
+ city_field: { accessibility_id: 'City* input field' },
17
+ state_region_field: { accessibility_id: 'State/Region input field' },
18
+ zip_code_field: { accessibility_id: 'Zip Code* input field' },
19
+ country_field: { accessibility_id: 'Country* input field' }
20
+ checkbox :bill_address_check, { xpath: '//XCUIElementTypeOther[contains(@name, "checkbox")]'}
21
+ button :review_order_button, { accessibility_id: 'Review Order button' }
22
+ end
@@ -0,0 +1,18 @@
1
+ class LoginScreen < BaseAppScreen
2
+ include SharedLoginScreen
3
+
4
+ trait(:page_name) { 'Login' }
5
+ trait(:page_locator) { { accessibility_id: 'login screen' } }
6
+ trait(:page_url) { 'login' }
7
+ trait(:navigator) { nav_menu.open_log_in }
8
+
9
+ # Login screen UI elements
10
+ labels username_label: { accessibility_id: 'Username'},
11
+ password_label: { xpath: '(//XCUIElementTypeStaticText[@name="Password"])[1]'},
12
+ username_error: { accessibility_id: 'Username-error-message' },
13
+ password_error: { accessibility_id: 'Password-error-message' },
14
+ generic_error: { accessibility_id: 'generic-error-message' }
15
+ textfields username_field: { accessibility_id: 'Username input field' },
16
+ password_field: { accessibility_id: 'Password input field' }
17
+ button :login_button, { accessibility_id: 'Login button' }
18
+ end
@@ -0,0 +1,13 @@
1
+ class ProductsScreen < BaseAppScreen
2
+ trait(:page_name) { 'Products' }
3
+ trait(:page_locator) { { accessibility_id: 'products screen' } }
4
+ trait(:page_url) { 'store-overview' }
5
+
6
+ def verify_page_ui
7
+ super
8
+ ui = {
9
+ header_label => { visible: true, caption: 'Products' }
10
+ }
11
+ verify_ui_states(ui)
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ class SauceBotScreen < BaseAppScreen
2
+ include SharedSauceBotScreen
3
+
4
+ trait(:page_name) { 'SauceBot Video' }
5
+ trait(:page_locator) { { accessibility_id: 'SauceBot screen' } }
6
+ trait(:navigator) { nav_menu.open_saucebot_video }
7
+
8
+ # SauceBot Video screen UI elements
9
+ element :video_player, { accessibility_id: 'YouTube Video Player' }
10
+ buttons video_back: { accessibility_id: 'video icon backward' },
11
+ video_play: { accessibility_id: 'video icon play' },
12
+ video_pause: { accessibility_id: 'video icon stop' },
13
+ video_forward: { accessibility_id: 'video icon forward' },
14
+ video_volume: { accessibility_id: 'video icon volume-up' },
15
+ video_mute: { accessibility_id: 'video icon volume-mute' }
16
+ end
@@ -0,0 +1,13 @@
1
+ class WebViewScreen < BaseAppScreen
2
+ include SharedWebViewScreen
3
+
4
+ trait(:page_name) { 'Webview' }
5
+ trait(:page_locator) { { accessibility_id: 'webview selection screen' } }
6
+ trait(:page_url) { 'webview' }
7
+ trait(:navigator) { nav_menu.open_webview }
8
+
9
+ # Webview screen UI elements
10
+ label :url_label, { accessibility_id: 'URL' }
11
+ textfield :url_field, { accessibility_id: 'URL input field' }
12
+ button :go_to_site_button, { accessibility_id: 'Go To Site button' }
13
+ end
@@ -0,0 +1,13 @@
1
+ class ProductCellItem < TestCentricity::ScreenSection
2
+ trait(:section_name) { 'Product Cell Item' }
3
+ trait(:section_locator) { { xpath: "//XCUIElementTypeOther[@name='store item']" } }
4
+
5
+ # Product Cell Item UI elements
6
+ labels product_name: { xpath: '(//XCUIElementTypeOther)[1]' },
7
+ product_price: { xpath: "//XCUIElementTypeStaticText[@name='store item price']" }
8
+ buttons review_star_1: { xpath: "//XCUIElementTypeOther[@name='review star 1']" },
9
+ review_star_2: { xpath: "//XCUIElementTypeOther[@name='review star 2']" },
10
+ review_star_3: { xpath: "//XCUIElementTypeOther[@name='review star 3']" },
11
+ review_star_4: { xpath: "//XCUIElementTypeOther[@name='review star 4']" },
12
+ review_star_5: { xpath: "//XCUIElementTypeOther[@name='review star 5']" }
13
+ end
@@ -0,0 +1,23 @@
1
+ class BaseIOSModal < TestCentricity::ScreenSection
2
+ trait(:section_name) { 'Base iOS Modal' }
3
+ trait(:section_locator) { { class: 'XCUIElementTypeAlert' } }
4
+
5
+ # Base Modal UI elements
6
+ alert :alert_modal, { class: 'XCUIElementTypeAlert' }
7
+
8
+ def await_and_respond(action, timeout)
9
+ if alert_modal.await(timeout)
10
+ case action
11
+ when :allow, :accept
12
+ alert_modal.accept
13
+ when :dont_allow, :dismiss
14
+ alert_modal.dismiss
15
+ else
16
+ raise "#{action} is not a valid selector"
17
+ end
18
+ true
19
+ else
20
+ false
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,6 @@
1
+ class LogOutModal < BaseIOSModal
2
+ trait(:section_name) { 'Log Out Modal' }
3
+
4
+ # Log Out Modal UI elements
5
+ alert :alert_modal, { xpath: "//XCUIElementTypeAlert[@name='Log Out']" }
6
+ end
@@ -0,0 +1,6 @@
1
+ class ResetAppStateModal < BaseIOSModal
2
+ trait(:section_name) { 'Reset App State Modal' }
3
+
4
+ # Reset App State Modal UI elements
5
+ alert :alert_modal, { xpath: "//XCUIElementTypeAlert[@name='Reset App State']" }
6
+ end
@@ -0,0 +1,31 @@
1
+ class NavBar < TestCentricity::ScreenSection
2
+ trait(:section_name) { 'Nav Bar' }
3
+ trait(:section_locator) { { xpath: '(//XCUIElementTypeOther[@name="Catalog, tab, 1 of 3 0 Menu, tab, 3 of 3"])[1]' } }
4
+
5
+ # Nav Bar UI elements
6
+ buttons catalog_tab: { accessibility_id: 'tab bar option catalog' },
7
+ cart_tab: { accessibility_id: 'tab bar option cart' },
8
+ menu_tab: { accessibility_id: 'tab bar option menu' }
9
+ label :cart_quantity, {}
10
+
11
+ def verify_ui
12
+ ui = {
13
+ catalog_tab => { visible: true, enabled: true, caption: 'Catalog, tab, 1 of 3' },
14
+ cart_tab => { visible: true, enabled: true },
15
+ menu_tab => { visible: true, enabled: true, caption: 'Menu, tab, 3 of 3' }
16
+ }
17
+ verify_ui_states(ui)
18
+ end
19
+
20
+ def open_catalog
21
+ catalog_tab.click
22
+ end
23
+
24
+ def open_cart
25
+ cart_tab.click
26
+ end
27
+
28
+ def open_menu
29
+ menu_tab.click
30
+ end
31
+ end
@@ -0,0 +1,41 @@
1
+ class NavMenu < TestCentricity::ScreenSection
2
+ include SharedNavMenu
3
+
4
+ trait(:section_name) { 'Nav Menu' }
5
+ trait(:section_locator) { { xpath: '//XCUIElementTypeScrollView' } }
6
+
7
+ # Nav Menu UI elements
8
+ buttons close_button: { accessibility_id: 'close menu' },
9
+ webview_button: { accessibility_id: 'menu item webview' },
10
+ qr_code_button: { accessibility_id: 'menu item qr code scanner' },
11
+ geo_location_button: { accessibility_id: 'menu item geo location' },
12
+ drawing_button: { accessibility_id: 'menu item drawing' },
13
+ report_a_bug_button: { accessibility_id: 'menu item report a bug' },
14
+ about_button: { accessibility_id: 'menu item about' },
15
+ reset_app_button: { accessibility_id: 'menu item reset app' },
16
+ biometrics_button: { accessibility_id: 'menu item biometrics' },
17
+ log_in_button: { accessibility_id: 'menu item log in' },
18
+ log_out_button: { accessibility_id: 'menu item log out' },
19
+ api_calls_button: { accessibility_id: 'menu item api calls' },
20
+ sauce_video_button: { accessibility_id: 'menu item sauce bot video' }
21
+
22
+ def verify_ui
23
+ ui = {
24
+ self => { visible: true },
25
+ close_button => { visible: true, enabled: true },
26
+ webview_button => { visible: true, enabled: true, caption: 'Webview' },
27
+ qr_code_button => { visible: true, enabled: true, caption: 'QR Code Scanner' },
28
+ geo_location_button => { visible: true, enabled: true, caption: 'Geo Location' },
29
+ drawing_button => { visible: true, enabled: true, caption: 'Drawing' },
30
+ report_a_bug_button => { visible: true, enabled: true, caption: 'Report A Bug' },
31
+ about_button => { visible: true, enabled: true, caption: 'About' },
32
+ reset_app_button => { visible: true, enabled: true, caption: 'Reset App State' },
33
+ biometrics_button => { visible: true, enabled: true, caption: 'FaceID' },
34
+ log_in_button => { visible: true, enabled: true, caption: 'Log In' },
35
+ log_out_button => { visible: true, enabled: true, caption: 'Log Out' },
36
+ api_calls_button => { visible: true, enabled: true, caption: 'Api Calls' },
37
+ sauce_video_button => { visible: true, enabled: true, caption: 'Sauce Bot Video' }
38
+ }
39
+ verify_ui_states(ui)
40
+ end
41
+ end
@@ -0,0 +1,31 @@
1
+ module SharedBaseAppScreen
2
+ include WorldData
3
+ include WorldPages
4
+
5
+ def nav_menu_action(action)
6
+ case action.downcase.to_sym
7
+ when :open
8
+ invoke_nav_menu
9
+ when :close
10
+ nav_menu.close if nav_menu.visible?
11
+ else
12
+ raise "#{action} is not a valid selector"
13
+ end
14
+ end
15
+
16
+ def navigate_to
17
+ invoke_nav_menu
18
+ navigator
19
+ end
20
+
21
+ def verify_nav_menu(state)
22
+ case state.downcase.to_sym
23
+ when :closed
24
+ nav_menu.verify_closed
25
+ when :displayed
26
+ nav_menu.verify_ui
27
+ else
28
+ raise "#{action} is not a valid selector"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,17 @@
1
+ module SharedCheckoutAddressScreen
2
+ def verify_page_ui
3
+ super
4
+ ui = {
5
+ header_label => { visible: true, caption: 'Checkout' },
6
+ fullname_field => { visible: true, enabled: true, placeholder: 'Rebecca Winter' },
7
+ address1_field => { visible: true, enabled: true, placeholder: 'Mandorley 112' },
8
+ address2_field => { visible: true, enabled: true, placeholder: 'Entrance 1' },
9
+ city_field => { visible: true, enabled: true, placeholder: 'Truro' },
10
+ state_region_field => { visible: true, enabled: true, placeholder: 'Cornwall' },
11
+ zip_code_field => { visible: true, enabled: true, placeholder: '89750' },
12
+ country_field => { visible: true, enabled: true, placeholder: 'United Kingdom' },
13
+ to_payment_button => { visible: true, enabled: true, caption: 'To Payment' }
14
+ }
15
+ verify_ui_states(ui)
16
+ end
17
+ end
@@ -0,0 +1,22 @@
1
+ module SharedCheckoutPaymentScreen
2
+ def verify_page_ui
3
+ super
4
+ ui = {
5
+ header_label => { visible: true, caption: 'Checkout' },
6
+ payee_name_field => { visible: true, enabled: true, placeholder: 'Rebecca Winter' },
7
+ card_number_field => { visible: true, enabled: true, placeholder: '3258 1265 7568 789' },
8
+ expiration_field => { visible: true, enabled: true, placeholder: '03/25' },
9
+ security_code_field => { visible: true, enabled: true, placeholder: '123' },
10
+ bill_address_check => { visible: true, enabled: true },
11
+ recipient_name_field => { visible: false },
12
+ address1_field => { visible: false },
13
+ address2_field => { visible: false },
14
+ city_field => { visible: false },
15
+ state_region_field => { visible: false },
16
+ zip_code_field => { visible: false },
17
+ country_field => { visible: false },
18
+ review_order_button => { visible: true, enabled: true, caption: 'Review Order' }
19
+ }
20
+ verify_ui_states(ui)
21
+ end
22
+ end
@@ -0,0 +1,39 @@
1
+ module SharedLoginScreen
2
+ def verify_page_ui
3
+ super
4
+ ui = {
5
+ header_label => { visible: true, caption: 'Login' },
6
+ username_label => { visible: true, caption: 'Username' },
7
+ username_field => { visible: true, enabled: true },
8
+ password_label => { visible: true, caption: 'Password' },
9
+ password_field => { visible: true, enabled: true },
10
+ login_button => { visible: true, enabled: true, caption: 'Login' }
11
+ }
12
+ verify_ui_states(ui)
13
+ end
14
+
15
+ def login(username, password)
16
+ fields = {
17
+ username_field => username,
18
+ password_field => password
19
+ }
20
+ populate_data_fields(fields)
21
+ login_button.tap
22
+ end
23
+
24
+ def verify_entry_error(reason)
25
+ ui = case reason.gsub(/\s+/, '_').downcase.to_sym
26
+ when :invalid_password, :invalid_user
27
+ { generic_error => { visible: true, caption: 'Provided credentials do not match any user in this service.' } }
28
+ when :locked_account
29
+ { generic_error => { visible: true, caption: 'Sorry, this user has been locked out.' } }
30
+ when :no_username
31
+ { username_error => { visible: true, caption: 'Username is required' } }
32
+ when :no_password
33
+ { password_error => { visible: true, caption: 'Password is required' } }
34
+ else
35
+ raise "#{reason} is not a valid selector"
36
+ end
37
+ verify_ui_states(ui)
38
+ end
39
+ end
@@ -0,0 +1,17 @@
1
+ module SharedSauceBotScreen
2
+ def verify_page_ui
3
+ super
4
+ video_player.wait_until_visible(10)
5
+ ui = {
6
+ header_label => { visible: true, caption: 'SauceBot - The Beginning' },
7
+ video_player => { visible: true, enabled: true },
8
+ video_back => { visible: true, enabled: true },
9
+ video_pause => { visible: true, enabled: true },
10
+ video_play => { visible: false },
11
+ video_forward => { visible: true, enabled: true },
12
+ video_volume => { visible: true, enabled: true },
13
+ video_mute => { visible: false }
14
+ }
15
+ verify_ui_states(ui)
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ module SharedWebViewScreen
2
+ def verify_page_ui
3
+ super
4
+ ui = {
5
+ header_label => { visible: true, caption: 'Webview' },
6
+ url_label => { visible: true, caption: 'URL' },
7
+ url_field => { visible: true, enabled: true, placeholder: 'https://www.website.com' },
8
+ go_to_site_button => { visible: true, enabled: true, caption: 'Go To Site' }
9
+ }
10
+ verify_ui_states(ui)
11
+ end
12
+ end
@@ -0,0 +1,58 @@
1
+ module SharedNavMenu
2
+ def close
3
+ close_button.click
4
+ self.wait_until_hidden(3)
5
+ end
6
+
7
+ def verify_closed
8
+ verify_ui_states(close_button => { visible: false })
9
+ end
10
+
11
+ def open_webview
12
+ webview_button.click
13
+ end
14
+
15
+ def open_qr_code_scanner
16
+ qr_code_button.click
17
+ end
18
+
19
+ def open_geo_location
20
+ geo_location_button.click
21
+ end
22
+
23
+ def open_drawing
24
+ drawing_button.click
25
+ end
26
+
27
+ def open_report_a_bug
28
+ report_a_bug_button.click
29
+ end
30
+
31
+ def open_about
32
+ about_button.click
33
+ end
34
+
35
+ def open_reset_app
36
+ reset_app_button.click
37
+ end
38
+
39
+ def open_biometrics
40
+ biometrics_button.click
41
+ end
42
+
43
+ def open_log_in
44
+ log_in_button.click
45
+ end
46
+
47
+ def open_log_out
48
+ log_out_button.click
49
+ end
50
+
51
+ def open_api_calls
52
+ api_calls_button.click
53
+ end
54
+
55
+ def open_saucebot_video
56
+ sauce_video_button.click
57
+ end
58
+ end