testcentricity 2.4.1 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +29 -0
- data/.rspec +2 -1
- data/.rubocop.yml +38 -0
- data/.ruby-version +1 -1
- data/.simplecov +9 -0
- data/.yardopts +3 -0
- data/CHANGELOG.md +275 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/{LICENSE.txt → LICENSE.md} +3 -4
- data/README.md +938 -1378
- data/Rakefile +63 -1
- data/config/cucumber.yml +145 -0
- data/config/locales/en-US.yml +56 -0
- data/config/test_data/LOCAL_data.yml +11 -0
- data/config/test_data/data.yml +10 -0
- data/features/deep_links.feature +26 -0
- data/features/login.feature +30 -0
- data/features/navigation.feature +31 -0
- data/features/step_definitions/generic_steps.rb +72 -0
- data/features/support/android/screens/about_screen.rb +11 -0
- data/features/support/android/screens/base_app_screen.rb +29 -0
- data/features/support/android/screens/checkout_address_screen.rb +17 -0
- data/features/support/android/screens/checkout_payment_screen.rb +22 -0
- data/features/support/android/screens/login_screen.rb +18 -0
- data/features/support/android/screens/products_screen.rb +13 -0
- data/features/support/android/screens/saucebot_screen.rb +16 -0
- data/features/support/android/screens/webview_screen.rb +13 -0
- data/features/support/android/sections/nav_widgets/nav_menu.rb +39 -0
- data/features/support/env.rb +61 -0
- data/features/support/hooks.rb +135 -0
- data/features/support/ios/screens/about_screen.rb +11 -0
- data/features/support/ios/screens/base_app_screen.rb +19 -0
- data/features/support/ios/screens/checkout_address_screen.rb +17 -0
- data/features/support/ios/screens/checkout_payment_screen.rb +22 -0
- data/features/support/ios/screens/login_screen.rb +18 -0
- data/features/support/ios/screens/products_screen.rb +13 -0
- data/features/support/ios/screens/saucebot_screen.rb +16 -0
- data/features/support/ios/screens/webview_screen.rb +13 -0
- data/features/support/ios/sections/list_items/product_cell_item.rb +13 -0
- data/features/support/ios/sections/modals/base_modal.rb +23 -0
- data/features/support/ios/sections/modals/logout_modal.rb +6 -0
- data/features/support/ios/sections/modals/reset_app_state_modal.rb +6 -0
- data/features/support/ios/sections/nav_widgets/nav_bar.rb +31 -0
- data/features/support/ios/sections/nav_widgets/nav_menu.rb +41 -0
- data/features/support/shared_components/screens/base_app_screen.rb +31 -0
- data/features/support/shared_components/screens/checkout_address_screen.rb +17 -0
- data/features/support/shared_components/screens/checkout_payment_screen.rb +22 -0
- data/features/support/shared_components/screens/login_screen.rb +39 -0
- data/features/support/shared_components/screens/saucebot_screen.rb +17 -0
- data/features/support/shared_components/screens/webview_screen.rb +12 -0
- data/features/support/shared_components/sections/nav_menu.rb +58 -0
- data/features/support/world_data.rb +12 -0
- data/features/support/world_pages.rb +26 -0
- data/lib/testcentricity/app_core/appium_connect_helper.rb +355 -111
- data/lib/testcentricity/app_core/screen_object.rb +252 -0
- data/lib/testcentricity/app_core/screen_objects_helper.rb +29 -280
- data/lib/testcentricity/app_core/screen_section.rb +350 -0
- data/lib/testcentricity/app_elements/app_element_helper.rb +17 -8
- data/lib/testcentricity/app_elements/checkbox.rb +3 -3
- data/lib/testcentricity/data_objects/environment.rb +133 -39
- data/lib/testcentricity/version.rb +1 -1
- data/lib/testcentricity.rb +4 -129
- data/reports/.keep +1 -0
- data/spec/fixtures/page_object.rb +22 -0
- data/spec/fixtures/page_section_object.rb +21 -0
- data/spec/fixtures/screen_object.rb +16 -0
- data/spec/fixtures/screen_section_object.rb +16 -0
- data/spec/spec_helper.rb +28 -9
- data/spec/testcentricity/elements/button_spec.rb +18 -0
- data/spec/testcentricity/elements/checkbox_spec.rb +28 -0
- data/spec/testcentricity/elements/image_spec.rb +13 -0
- data/spec/testcentricity/elements/label_spec.rb +18 -0
- data/spec/testcentricity/elements/list_spec.rb +13 -0
- data/spec/testcentricity/elements/ui_element_spec.rb +72 -0
- data/spec/testcentricity/mobile/appium_connect_spec.rb +117 -0
- data/spec/testcentricity/mobile/screen_object_spec.rb +63 -0
- data/spec/testcentricity/mobile/screen_section_object_spec.rb +56 -0
- data/spec/testcentricity/version_spec.rb +7 -0
- data/spec/testcentricity/web/browser_spec.rb +41 -0
- data/spec/testcentricity/web/local_webdriver_spec.rb +86 -0
- data/spec/testcentricity/web/mobile_webdriver_spec.rb +123 -0
- data/spec/testcentricity/web/page_object_spec.rb +85 -0
- data/spec/testcentricity/web/page_section_object_spec.rb +72 -0
- data/testcentricity.gemspec +28 -27
- metadata +196 -127
- data/.ruby-gemset +0 -1
- data/Gemfile.lock +0 -93
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/lib/devices/devices.yml +0 -352
- data/lib/testcentricity/app_core/appium_server.rb +0 -69
- data/lib/testcentricity/app_core/screen_sections_helper.rb +0 -491
- data/lib/testcentricity/browser_helper.rb +0 -174
- data/lib/testcentricity/data_objects/data_objects_helper.rb +0 -78
- data/lib/testcentricity/data_objects/excel_helper.rb +0 -242
- data/lib/testcentricity/exception_queue_helper.rb +0 -111
- data/lib/testcentricity/utility_helpers.rb +0 -28
- data/lib/testcentricity/web_core/drag_drop_helper.rb +0 -15
- data/lib/testcentricity/web_core/page_objects_helper.rb +0 -711
- data/lib/testcentricity/web_core/page_sections_helper.rb +0 -932
- data/lib/testcentricity/web_core/webdriver_helper.rb +0 -588
- data/lib/testcentricity/web_elements/button.rb +0 -8
- data/lib/testcentricity/web_elements/cell_button.rb +0 -8
- data/lib/testcentricity/web_elements/cell_checkbox.rb +0 -38
- data/lib/testcentricity/web_elements/cell_element.rb +0 -69
- data/lib/testcentricity/web_elements/cell_image.rb +0 -8
- data/lib/testcentricity/web_elements/cell_radio.rb +0 -31
- data/lib/testcentricity/web_elements/checkbox.rb +0 -100
- data/lib/testcentricity/web_elements/file_field.rb +0 -45
- data/lib/testcentricity/web_elements/image.rb +0 -34
- data/lib/testcentricity/web_elements/label.rb +0 -8
- data/lib/testcentricity/web_elements/link.rb +0 -8
- data/lib/testcentricity/web_elements/list.rb +0 -100
- data/lib/testcentricity/web_elements/list_button.rb +0 -8
- data/lib/testcentricity/web_elements/list_checkbox.rb +0 -38
- data/lib/testcentricity/web_elements/list_element.rb +0 -61
- data/lib/testcentricity/web_elements/list_radio.rb +0 -31
- data/lib/testcentricity/web_elements/radio.rb +0 -74
- data/lib/testcentricity/web_elements/select_list.rb +0 -208
- data/lib/testcentricity/web_elements/siebel_open_ui_helper.rb +0 -15
- data/lib/testcentricity/web_elements/table.rb +0 -612
- data/lib/testcentricity/web_elements/textfield.rb +0 -114
- data/lib/testcentricity/web_elements/ui_elements_helper.rb +0 -532
- data/lib/testcentricity/world_extensions.rb +0 -26
- data/my_templates/default/method_details/setup.rb +0 -3
- 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,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
|