testcentricity 3.0.1 → 3.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/README.md +1 -0
  4. data/Rakefile +2 -2
  5. data/config/cucumber.yml +1 -0
  6. data/config/test_data/data.yml +66 -0
  7. data/features/deep_links.feature +12 -0
  8. data/features/navigation.feature +12 -0
  9. data/features/step_definitions/generic_steps.rb +14 -19
  10. data/features/support/android/screens/base_app_screen.rb +2 -0
  11. data/features/support/android/screens/biometrics_screen.rb +17 -0
  12. data/features/support/android/screens/geo_location_screen.rb +28 -0
  13. data/features/support/android/screens/product_item_screen.rb +39 -0
  14. data/features/support/android/screens/products_screen.rb +15 -1
  15. data/features/support/android/screens/qr_code_scanner_screen.rb +15 -0
  16. data/features/support/android/sections/list_items/product_list_item.rb +13 -0
  17. data/features/support/data/product_data.rb +27 -0
  18. data/features/support/data/user_data.rb +17 -0
  19. data/features/support/env.rb +2 -1
  20. data/features/support/ios/screens/base_app_screen.rb +1 -0
  21. data/features/support/ios/screens/biometrics_screen.rb +17 -0
  22. data/features/support/ios/screens/geo_location_screen.rb +32 -0
  23. data/features/support/ios/screens/product_item_screen.rb +39 -0
  24. data/features/support/ios/screens/products_screen.rb +15 -1
  25. data/features/support/ios/screens/qr_code_scanner_screen.rb +11 -0
  26. data/features/support/ios/sections/list_items/product_list_item.rb +13 -0
  27. data/features/support/shared_components/screens/base_app_screen.rb +4 -0
  28. data/features/support/world_data.rb +4 -1
  29. data/features/support/world_pages.rb +4 -0
  30. data/lib/testcentricity/app_elements/alert.rb +64 -0
  31. data/lib/testcentricity/app_elements/app_element_helper.rb +55 -12
  32. data/lib/testcentricity/version.rb +1 -1
  33. data/testcentricity.gemspec +4 -4
  34. metadata +58 -43
  35. data/config/test_data/LOCAL_data.yml +0 -11
  36. data/features/support/ios/sections/list_items/product_cell_item.rb +0 -13
  37. data/features/support/ios/sections/modals/base_modal.rb +0 -23
  38. data/features/support/ios/sections/modals/logout_modal.rb +0 -6
  39. data/features/support/ios/sections/modals/reset_app_state_modal.rb +0 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31f94846b0235fd3b3507025052c4bc2672fc06d3646dd6e51f30a746522ceb8
4
- data.tar.gz: 399961e0864716031576c8e12cd244b379ac2a67e2319d730c64cc1a431af49e
3
+ metadata.gz: e4c7b4120e8589701d29a850600108df295c1c199fa8c19e9f6f92bd76b49a47
4
+ data.tar.gz: 956e90ac6395ed32e69c2fd7558977398b8c42c075577d858090ce194da8c668
5
5
  SHA512:
6
- metadata.gz: 76f54f2ca7d2338a17a112907b8d084c84e458f9f8b5f6e0bf82405734d252acd6042daaef739d76f60675f8167a25c297f8cf996413f099e9e528b194903d47
7
- data.tar.gz: a5ac5ff41bfef9124b088492824c2583f5465fa855e42f6574a06498ac863503b9a280a88b58ff2bd3eb879fa75fb3176b914ad87da0a18586395c4f90309199
6
+ metadata.gz: b389a6ce9b701bb380ae02d34b7dc2880617aa315738a59082dfabf3c00fc2411d4f7ab99b3102f048918c9cc77e2e02b3b475fae3836986bfcc2237d7495112
7
+ data.tar.gz: b8d6b8ce2cb4cf7f98d66b8fe7ea7a9e4a1db0a07d3410660d5e6c06d962dc0bb48ce761d8998b4ac1475165ae042f8116109f049b8241e6eda7f64eb7147430
data/CHANGELOG.md CHANGED
@@ -2,6 +2,29 @@
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
4
 
5
+ ## [3.0.4] - 02-JUNE-2022
6
+
7
+ ### Added
8
+ * Added `AppUIElement.wait_until_enabled` method.
9
+
10
+ ### Updated
11
+ * Incorporated all changes from the [TestCentricity™ Web gem](https://rubygems.org/gems/testcentricity_web) version 4.2.4, which is
12
+ bundled with this gem.
13
+
14
+
15
+ ## [3.0.3] - 30-MAY-2022
16
+
17
+ ### Added
18
+ * Added `AppAlert.await_and_respond` method.
19
+
20
+
21
+ ## [3.0.2] - 26-MAY-2022
22
+
23
+ ### Fixed
24
+ * Added runtime dependencies `curb` and `json` to gemspec.
25
+ * Fixed CHANGELOG url in gemspec.
26
+
27
+
5
28
  ## [3.0.1] - 26-MAY-2022
6
29
 
7
30
  ### Added
data/README.md CHANGED
@@ -536,6 +536,7 @@ With TestCentricity, all native app UI elements are based on the `AppUIElement`
536
536
  element.wait_until_gone(seconds)
537
537
  element.wait_until_visible(seconds)
538
538
  element.wait_until_hidden(seconds)
539
+ element.wait_until_enabled(seconds)
539
540
  element.wait_until_value_is(value, seconds)
540
541
  element.wait_until_value_changes(seconds)
541
542
 
data/Rakefile CHANGED
@@ -35,7 +35,7 @@ desc 'Run required specs and Cucumber features'
35
35
  task required: [:required_specs, :android_sim, :ios_sim]
36
36
 
37
37
 
38
- desc 'Run all specs and Cucumber features'
38
+ desc 'Run all specs'
39
39
  task all_specs: [:required_specs, :web_specs]
40
40
 
41
41
 
@@ -52,7 +52,7 @@ end
52
52
  desc 'Build and release new version'
53
53
  task :release do
54
54
  version = TestCentricity::VERSION
55
- puts "Releasing #{version}, y/n?"
55
+ puts "Releasing version #{version} of TestCentricity gem, y/n?"
56
56
  exit(1) unless $stdin.gets.chomp == 'y'
57
57
  sh 'gem build testcentricity.gemspec && ' \
58
58
  "gem push testcentricity-#{version}.gem"
data/config/cucumber.yml CHANGED
@@ -21,6 +21,7 @@ bvt: <%= acceptance %>
21
21
  #==============
22
22
 
23
23
  report: <%= reports %> REPORTING=true
24
+ parallel: PARALLEL=true REPORTING=true --require features --format pretty --format html --out reports/test_results<%= ENV['TEST_ENV_NUMBER'] %>.html --format junit --out reports --format json --out reports/test_results<%= ENV['TEST_ENV_NUMBER'] %>.json
24
25
 
25
26
 
26
27
  #==============
@@ -8,3 +8,69 @@ Environments:
8
8
  IOS_IPA_PATH: '/Users/Shared/Test_Apps/iOS/iOS-Real-Device-MyRNDemoApp.1.3.0-162.ipa'
9
9
  ANDROID_APK_PATH: '/Users/Shared/Test_Apps/Android/Android-MyDemoAppRN.1.2.0.build-231.apk'
10
10
 
11
+ # This section is populated with user credential data required to test the Login screen features
12
+ User_creds:
13
+ valid_data:
14
+ username: 'bob@example.com'
15
+ password: '10203040'
16
+ invalid_user:
17
+ username: 'iggy.snicklefritz@example.com'
18
+ password: '10203040'
19
+ locked_account:
20
+ username: 'alice@example.com'
21
+ password: '10203040'
22
+ no_username:
23
+ password: '10203040'
24
+ no_password:
25
+ username: 'bob@example.com'
26
+
27
+ # This section is populated with Product data required for testing the Shopping features
28
+ Products:
29
+ 1:
30
+ id: 1
31
+ name: 'Sauce Labs Backpack'
32
+ description: 'carry.allTheThings() with the sleek, streamlined Sly Pack that melds uncompromising style with unequaled laptop and tablet protection.'
33
+ price: '$29.99'
34
+ review: 4
35
+ colors: ['BLACK', 'BLUE', 'GRAY', 'RED']
36
+ defaultColor: 'BLACK'
37
+ 2:
38
+ id: 2
39
+ name: 'Sauce Labs Bike Light'
40
+ description: "A red light isn't the desired state in testing but it sure helps when riding your bike at night. Water-resistant with 3 lighting modes, 1 AAA battery included."
41
+ price: '$9.99'
42
+ review: 4
43
+ colors: ['BLACK']
44
+ defaultColor: 'BLACK'
45
+ 3:
46
+ id: 3
47
+ name: 'Sauce Labs Bolt T-Shirt'
48
+ description: 'Get your testing superhero on with the Sauce Labs bolt T-shirt. From American Apparel, 100% ringspun combed cotton, heather gray with red bolt.'
49
+ price: '$15.99'
50
+ review: 4
51
+ colors: ['BLACK']
52
+ defaultColor: 'BLACK'
53
+ 4:
54
+ id: 4
55
+ name: 'Sauce Labs Fleece Jacket'
56
+ description: "It's not every day that you come across a midweight quarter-zip fleece jacket capable of handling everything from a relaxing day outdoors to a busy day at the office."
57
+ price: '$49.99'
58
+ review: 4
59
+ colors: ['GRAY']
60
+ defaultColor: 'GRAY'
61
+ 5:
62
+ id: 5
63
+ name: 'Sauce Labs Onesie'
64
+ description: "Rib snap infant onesie for the junior automation engineer in development. Reinforced 3-snap bottom closure, two-needle hemmed sleeved and bottom won't unravel."
65
+ price: '$7.99'
66
+ review: 4
67
+ colors: ['BLACK', 'GRAY', 'RED']
68
+ defaultColor: 'RED'
69
+ 6:
70
+ id: 6
71
+ name: 'Test.allTheThings() T-Shirt'
72
+ description: 'This classic Sauce Labs t-shirt is perfect to wear when cozying up to your keyboard to automate a few tests. Super-soft and comfy ringspun combed cotton.'
73
+ price: '$15.99'
74
+ review: 4
75
+ colors: ['BLACK', 'GRAY', 'RED']
76
+ defaultColor: 'RED'
@@ -24,3 +24,15 @@ Feature: App screen deep links
24
24
  |Products |Checkout - Address |
25
25
  |Products |Checkout - Payment |
26
26
  |About |Products |
27
+
28
+
29
+ Scenario Outline: Verify Product Item screen can be directly accessed via deep links
30
+ Given I am on the Products screen
31
+ And I access the data for product id <product_id>
32
+ When I load the Product Item screen
33
+ Then I expect the Product Item screen to be correctly displayed
34
+
35
+ Examples:
36
+ |product_id |
37
+ |1 |
38
+ |5 |
@@ -29,3 +29,15 @@ Feature: Screen Navigation
29
29
  |Login |
30
30
  |Webview |
31
31
  |SauceBot Video |
32
+
33
+
34
+ Scenario Outline: Verify screen navigation features with popup modals
35
+ When I tap the <screen_name> navigation menu item
36
+ And I accept the popup request modal
37
+ Then I expect the <screen_name> screen to be correctly displayed
38
+
39
+ Examples:
40
+ |screen_name |
41
+ |QR Code Scanner |
42
+ |Geo Location |
43
+ |Biometrics |
@@ -18,6 +18,7 @@ When(/^I (?:click|tap) the ([^\"]*) navigation menu item$/) do |screen_name|
18
18
  # find and navigate to the specified target page/screen
19
19
  target_page = PageManager.find_page(screen_name)
20
20
  target_page.navigate_to
21
+ PageManager.current_page = target_page
21
22
  end
22
23
 
23
24
 
@@ -30,25 +31,9 @@ Then(/^I expect the (.*) (?:page|screen) to be correctly displayed$/) do |screen
30
31
  end
31
32
 
32
33
 
33
- When(/^I enter user credentials with (.*)$/) do |reason|
34
- case reason.gsub(/\s+/, '_').downcase.to_sym
35
- when :valid_data
36
- username = 'bob@example.com'
37
- password = '10203040'
38
- when :invalid_user
39
- username = 'iggy.snicklefritz@example.com'
40
- password = '10203040'
41
- when :locked_account
42
- username = 'alice@example.com'
43
- password = '10203040'
44
- when :no_username
45
- password = '10203040'
46
- when :no_password
47
- username = 'bob@example.com'
48
- else
49
- raise "#{reason} is not a valid selector"
50
- end
51
- login_screen.login(username, password)
34
+ When(/^I enter user credentials with (.*)$/) do |creds|
35
+ cred_data = user_data_source.find_user_creds(creds.gsub(/\s+/, '_').downcase)
36
+ login_screen.login(cred_data.username, cred_data.password)
52
37
  end
53
38
 
54
39
 
@@ -70,3 +55,13 @@ end
70
55
  Then(/^I expect the navigation menu to be hidden$/) do
71
56
  PageManager.current_page.verify_nav_menu(state = :closed)
72
57
  end
58
+
59
+
60
+ When(/^I (.*) the popup request modal$/) do |action|
61
+ PageManager.current_page.modal_action(action)
62
+ end
63
+
64
+
65
+ When(/^I access the data for product id (.*)$/) do |product_id|
66
+ product_data_source.find_product(product_id)
67
+ end
@@ -8,6 +8,8 @@ class BaseAppScreen < TestCentricity::ScreenObject
8
8
  cart_button: { accessibility_id: 'cart badge' }
9
9
  labels header_label: { xpath: '//android.view.ViewGroup[@content-desc="container header"]/android.widget.TextView' },
10
10
  cart_quantity: { xpath: '//android.view.ViewGroup[@content-desc="cart badge"]/android.widget.TextView' }
11
+ alerts grant_modal: { id: 'com.android.permissioncontroller:id/grant_dialog' },
12
+ alert_modal: { id: 'android:id/parentPanel' }
11
13
  section :nav_menu, NavMenu
12
14
 
13
15
  def verify_page_ui
@@ -0,0 +1,17 @@
1
+ class BiometricsScreen < BaseAppScreen
2
+ trait(:page_name) { 'Biometrics' }
3
+ trait(:page_locator) { { accessibility_id: 'biometrics screen' } }
4
+ trait(:navigator) { nav_menu.open_biometrics }
5
+
6
+ # Biometrics screen UI elements
7
+ switch :fingerprint_switch, { accessibility_id: 'biometrics switch'}
8
+
9
+ def verify_page_ui
10
+ super
11
+ ui = {
12
+ header_label => { visible: true, caption: 'FingerPrint' },
13
+ fingerprint_switch => { visible: true, enabled: false }
14
+ }
15
+ verify_ui_states(ui)
16
+ end
17
+ end
@@ -0,0 +1,28 @@
1
+ class GeoLocationScreen < BaseAppScreen
2
+ trait(:page_name) { 'Geo Location' }
3
+ trait(:page_locator) { { accessibility_id: 'geo location screen' } }
4
+ trait(:page_url) { 'geo-locations' }
5
+ trait(:navigator) { nav_menu.open_geo_location }
6
+
7
+ # Geo Location screen UI elements
8
+ buttons start_observing_button: { accessibility_id: 'Start Observing button'},
9
+ stop_observing_button: { accessibility_id: 'Stop Observing button'}
10
+ labels latitude_data: { accessibility_id: 'latitude data' },
11
+ longitude_data: { accessibility_id: 'longitude data' }
12
+
13
+ def verify_page_ui
14
+ super
15
+ ui = {
16
+ header_label => { visible: true, caption: 'Geo Location' },
17
+ start_observing_button => { visible: true, enabled: false, caption: 'Start Observing' },
18
+ stop_observing_button => { visible: true, enabled: true, caption: 'Stop Observing' },
19
+ latitude_data => { visible: true, caption: { not_equal: '0' } },
20
+ longitude_data => { visible: true, caption: { not_equal: '0' } }
21
+ }
22
+ verify_ui_states(ui)
23
+ end
24
+
25
+ def modal_action(action)
26
+ grant_modal.await_and_respond(action.downcase.to_sym, timeout = 1, button_name = 'Only this time')
27
+ end
28
+ end
@@ -0,0 +1,39 @@
1
+ class ProductItemScreen < BaseAppScreen
2
+ trait(:page_name) { 'Product Item' }
3
+ trait(:page_locator) { { accessibility_id: 'product screen' } }
4
+ trait(:page_url) { "product-details/#{ProductData.current.id.to_s}" }
5
+
6
+ # Product Item screen UI elements
7
+ labels price_value: { accessibility_id: 'product price' },
8
+ description_value: { accessibility_id: 'product description' },
9
+ quantity_value: { accessibility_id: 'counter amount' },
10
+ highlights_label: { xpath: '//android.view.ViewGroup/android.widget.TextView[2]' }
11
+ image :product_image, { xpath: '//android.view.ViewGroup/android.widget.ImageView' }
12
+ buttons add_to_cart_button: { accessibility_id: 'Add To Cart button' },
13
+ minus_qty_button: { accessibility_id: 'counter minus button' },
14
+ plus_qty_button: { accessibility_id: 'counter plus button' },
15
+ black_color_button: { accessibility_id: 'black circle' },
16
+ blue_color_button: { accessibility_id: 'blue circle' },
17
+ gray_color_button: { accessibility_id: 'gray circle' },
18
+ red_color_button: { accessibility_id: 'red circle' }
19
+
20
+ def verify_page_ui
21
+ super
22
+ ui = {
23
+ header_label => { visible: true, caption: ProductData.current.name },
24
+ price_value => { visible: true, caption: ProductData.current.price },
25
+ highlights_label => { visible: true, caption: 'Product Highlights' },
26
+ description_value => { visible: true, caption: ProductData.current.description },
27
+ product_image => { visible: true, enabled: true },
28
+ black_color_button => { visible: ProductData.current.colors.include?('BLACK') },
29
+ blue_color_button => { visible: ProductData.current.colors.include?('BLUE') },
30
+ gray_color_button => { visible: ProductData.current.colors.include?('GRAY') },
31
+ red_color_button => { visible: ProductData.current.colors.include?('RED') },
32
+ minus_qty_button => { visible: true, enabled: true },
33
+ quantity_value => { visible: true, enabled: true, caption: '1' },
34
+ plus_qty_button => { visible: true, enabled: true },
35
+ add_to_cart_button => { visible: true, enabled: true, caption: 'Add To Cart' }
36
+ }
37
+ verify_ui_states(ui)
38
+ end
39
+ end
@@ -3,10 +3,24 @@ class ProductsScreen < BaseAppScreen
3
3
  trait(:page_locator) { { accessibility_id: 'products screen' } }
4
4
  trait(:page_url) { 'store-overview' }
5
5
 
6
+ # Products screen UI elements
7
+ list :product_list, { xpath: '//android.widget.ScrollView' }
8
+ section :product_list_item, ProductListItem
9
+
10
+ def initialize
11
+ super
12
+ # define the list item element for the Product list object
13
+ list_elements = { list_item: { xpath: '//android.view.ViewGroup[@content-desc="store item"]' } }
14
+ product_list.define_list_elements(list_elements)
15
+ # associate the Product List Item indexed section object with the Product list object
16
+ product_list_item.set_list_index(product_list)
17
+ end
18
+
6
19
  def verify_page_ui
7
20
  super
8
21
  ui = {
9
- header_label => { visible: true, caption: 'Products' }
22
+ header_label => { visible: true, caption: 'Products' },
23
+ product_list => { visible: true, itemcount: 6 }
10
24
  }
11
25
  verify_ui_states(ui)
12
26
  end
@@ -0,0 +1,15 @@
1
+ class QRCodeScannerScreen < BaseAppScreen
2
+ trait(:page_name) { 'QR Code Scanner' }
3
+ trait(:page_locator) { { accessibility_id: 'qr code screen' } }
4
+ trait(:page_url) { 'qr-code-scanner' }
5
+ trait(:navigator) { nav_menu.open_qr_code_scanner }
6
+
7
+ def verify_page_ui
8
+ super
9
+ verify_ui_states(header_label => { visible: true, caption: 'QR Code Scanner' })
10
+ end
11
+
12
+ def modal_action(action)
13
+ grant_modal.await_and_respond(action.downcase.to_sym, timeout = 1, button_name = 'Only this time')
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ class ProductListItem < TestCentricity::ScreenSection
2
+ trait(:section_name) { 'Product List Item' }
3
+ trait(:section_locator) { { xpath: '//android.view.ViewGroup[@content-desc="store item"]' } }
4
+
5
+ # Product Cell Item UI elements
6
+ labels product_name: { xpath: '//android.widget.TextView[@content-desc="store item text"]' },
7
+ product_price: { xpath: '//android.widget.TextView[@content-desc="store item price"]' }
8
+ buttons review_star_1: { xpath: '//android.view.ViewGroup[@content-desc="review star 1"]' },
9
+ review_star_2: { xpath: '//android.view.ViewGroup[@content-desc="review star 2"]' },
10
+ review_star_3: { xpath: '//android.view.ViewGroup[@content-desc="review star 3"]' },
11
+ review_star_4: { xpath: '//android.view.ViewGroup[@content-desc="review star 4"]' },
12
+ review_star_5: { xpath: '//android.view.ViewGroup[@content-desc="review star 5"]' }
13
+ end
@@ -0,0 +1,27 @@
1
+ class ProductDataSource < TestCentricity::DataSource
2
+ def find_product(product_id)
3
+ ProductData.current = ProductData.new(environs.read('Products', product_id.to_i))
4
+ end
5
+ end
6
+
7
+
8
+ class ProductData < TestCentricity::DataPresenter
9
+ attribute :id, Integer
10
+ attribute :name, String
11
+ attribute :description, String
12
+ attribute :price, String
13
+ attribute :review, Integer
14
+ attribute :colors, Array
15
+ attribute :default_color, String
16
+
17
+ def initialize(data)
18
+ @id = data[:id]
19
+ @name = data[:name]
20
+ @description = data[:description]
21
+ @price = data[:price]
22
+ @review = data[:review]
23
+ @colors = data[:colors]
24
+ @default_color = data[:defaultColor]
25
+ super
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ class UserDataSource < TestCentricity::DataSource
2
+ def find_user_creds(node_name)
3
+ UserData.current = UserData.new(environs.read('User_creds', node_name))
4
+ end
5
+ end
6
+
7
+
8
+ class UserData < TestCentricity::DataPresenter
9
+ attribute :username, String
10
+ attribute :password, String
11
+
12
+ def initialize(data)
13
+ @username = data[:username]
14
+ @password = data[:password]
15
+ super
16
+ end
17
+ end
@@ -4,8 +4,8 @@ require 'capybara/cucumber'
4
4
  require 'parallel_tests'
5
5
  require 'require_all'
6
6
  require 'simplecov'
7
- require 'testcentricity'
8
7
  require 'testcentricity_web'
8
+ require 'testcentricity'
9
9
 
10
10
  include TestCentricity
11
11
 
@@ -14,6 +14,7 @@ SimpleCov.command_name("Features-#{ENV['PLATFORM']}-#{Time.now.strftime('%Y%m%d%
14
14
  require_relative 'world_data'
15
15
  require_relative 'world_pages'
16
16
 
17
+ require_rel 'data'
17
18
  require_rel 'shared_components'
18
19
 
19
20
  # conditionally require page and section objects based on target platform
@@ -5,6 +5,7 @@ class BaseAppScreen < TestCentricity::ScreenObject
5
5
 
6
6
  # Base App screen UI elements
7
7
  label :header_label, { accessibility_id: 'container header' }
8
+ alert :alert_modal, { class: 'XCUIElementTypeAlert' }
8
9
  sections nav_bar: NavBar,
9
10
  nav_menu: NavMenu
10
11
 
@@ -0,0 +1,17 @@
1
+ class BiometricsScreen < BaseAppScreen
2
+ trait(:page_name) { 'Biometrics' }
3
+ trait(:page_locator) { { accessibility_id: 'biometrics screen' } }
4
+ trait(:navigator) { nav_menu.open_biometrics }
5
+
6
+ # Biometrics screen UI elements
7
+ switch :face_id_switch, { accessibility_id: 'biometrics switch'}
8
+
9
+ def verify_page_ui
10
+ super
11
+ ui = {
12
+ header_label => { visible: true, caption: 'FaceID' },
13
+ face_id_switch => { visible: true, enabled: false, value: '0' }
14
+ }
15
+ verify_ui_states(ui)
16
+ end
17
+ end
@@ -0,0 +1,32 @@
1
+ class GeoLocationScreen < BaseAppScreen
2
+ trait(:page_name) { 'Geo Location' }
3
+ trait(:page_locator) { { accessibility_id: 'geo location screen' } }
4
+ trait(:page_url) { 'geo-locations' }
5
+ trait(:navigator) { nav_menu.open_geo_location }
6
+
7
+ # Geo Location screen UI elements
8
+ buttons start_observing_button: { accessibility_id: 'Start Observing button'},
9
+ stop_observing_button: { accessibility_id: 'Stop Observing button'}
10
+ labels latitude_label: { accessibility_id: 'Latitude:' },
11
+ latitude_data: { accessibility_id: 'latitude data' },
12
+ longitude_label: { accessibility_id: 'Longitude:' },
13
+ longitude_data: { accessibility_id: 'longitude data' }
14
+
15
+ def verify_page_ui
16
+ super
17
+ ui = {
18
+ header_label => { visible: true, caption: 'Geo Location' },
19
+ start_observing_button => { visible: true, enabled: false, caption: 'Start Observing' },
20
+ stop_observing_button => { visible: true, enabled: true, caption: 'Stop Observing' },
21
+ latitude_label => { visible: true, caption: 'Latitude:' },
22
+ latitude_data => { visible: true, caption: { not_equal: '0' } },
23
+ longitude_label => { visible: true, caption: 'Longitude:' },
24
+ longitude_data => { visible: true, caption: { not_equal: '0' } }
25
+ }
26
+ verify_ui_states(ui)
27
+ end
28
+
29
+ def modal_action(action)
30
+ alert_modal.await_and_respond(action.downcase.to_sym, timeout = 1, button_name = 'Allow Once')
31
+ end
32
+ end
@@ -0,0 +1,39 @@
1
+ class ProductItemScreen < BaseAppScreen
2
+ trait(:page_name) { 'Product Item' }
3
+ trait(:page_locator) { { accessibility_id: 'product screen' } }
4
+ trait(:page_url) { "product-details/#{ProductData.current.id.to_s}" }
5
+
6
+ # Product Item screen UI elements
7
+ labels price_value: { accessibility_id: 'product price' },
8
+ description_value: { accessibility_id: 'product description' },
9
+ quantity_value: { accessibility_id: 'counter amount' },
10
+ highlights_label: { accessibility_id: 'Product Highlights' }
11
+ image :product_image, { xpath: '//XCUIElementTypeImage' }
12
+ buttons add_to_cart_button: { accessibility_id: 'Add To Cart button' },
13
+ minus_qty_button: { accessibility_id: 'counter minus button' },
14
+ plus_qty_button: { accessibility_id: 'counter plus button' },
15
+ black_color_button: { accessibility_id: 'black circle' },
16
+ blue_color_button: { accessibility_id: 'blue circle' },
17
+ gray_color_button: { accessibility_id: 'gray circle' },
18
+ red_color_button: { accessibility_id: 'red circle' }
19
+
20
+ def verify_page_ui
21
+ super
22
+ ui = {
23
+ header_label => { visible: true, caption: ProductData.current.name },
24
+ price_value => { visible: true, caption: ProductData.current.price },
25
+ highlights_label => { visible: true, caption: 'Product Highlights' },
26
+ description_value => { visible: true, caption: ProductData.current.description },
27
+ product_image => { visible: true, enabled: true },
28
+ black_color_button => { visible: ProductData.current.colors.include?('BLACK') },
29
+ blue_color_button => { visible: ProductData.current.colors.include?('BLUE') },
30
+ gray_color_button => { visible: ProductData.current.colors.include?('GRAY') },
31
+ red_color_button => { visible: ProductData.current.colors.include?('RED') },
32
+ minus_qty_button => { visible: true, enabled: true },
33
+ quantity_value => { visible: true, enabled: true, caption: '1' },
34
+ plus_qty_button => { visible: true, enabled: true },
35
+ add_to_cart_button => { visible: true, enabled: true, caption: 'Add To Cart' }
36
+ }
37
+ verify_ui_states(ui)
38
+ end
39
+ end
@@ -3,10 +3,24 @@ class ProductsScreen < BaseAppScreen
3
3
  trait(:page_locator) { { accessibility_id: 'products screen' } }
4
4
  trait(:page_url) { 'store-overview' }
5
5
 
6
+ # Products screen UI elements
7
+ list :product_list, { xpath: '//XCUIElementTypeScrollView/XCUIElementTypeOther[1]' }
8
+ section :product_list_item, ProductListItem
9
+
10
+ def initialize
11
+ super
12
+ # define the list item element for the Product list object
13
+ list_elements = { list_item: { xpath: '//XCUIElementTypeOther[@name="store item"]' } }
14
+ product_list.define_list_elements(list_elements)
15
+ # associate the Product List Item indexed section object with the Product list object
16
+ product_list_item.set_list_index(product_list)
17
+ end
18
+
6
19
  def verify_page_ui
7
20
  super
8
21
  ui = {
9
- header_label => { visible: true, caption: 'Products' }
22
+ header_label => { visible: true, caption: 'Products' },
23
+ # product_list => { visible: true, itemcount: 6 }
10
24
  }
11
25
  verify_ui_states(ui)
12
26
  end
@@ -0,0 +1,11 @@
1
+ class QRCodeScannerScreen < BaseAppScreen
2
+ trait(:page_name) { 'QR Code Scanner' }
3
+ trait(:page_locator) { { accessibility_id: 'qr code screen' } }
4
+ trait(:page_url) { 'qr-code-scanner' }
5
+ trait(:navigator) { nav_menu.open_qr_code_scanner }
6
+
7
+ def verify_page_ui
8
+ super
9
+ verify_ui_states(header_label => { visible: true, caption: 'QR Code Scanner' })
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ class ProductListItem < TestCentricity::ScreenSection
2
+ trait(:section_name) { 'Product List Item' }
3
+ trait(:section_locator) { { xpath: '//XCUIElementTypeOther[@name="store item"]' } }
4
+
5
+ # Product Cell Item UI elements
6
+ labels product_name: { xpath: '//XCUIElementTypeStaticText[@name="store item text"]' },
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
@@ -28,4 +28,8 @@ module SharedBaseAppScreen
28
28
  raise "#{action} is not a valid selector"
29
29
  end
30
30
  end
31
+
32
+ def modal_action(action)
33
+ alert_modal.await_and_respond(action.downcase.to_sym, timeout = 1)
34
+ end
31
35
  end
@@ -4,7 +4,10 @@ module WorldData
4
4
  # by the TestCentricity™ DataManager. Data Object class definitions are contained in the features/support/data folder.
5
5
  #
6
6
  def data_objects
7
- {}
7
+ {
8
+ user_data_source: UserDataSource,
9
+ product_data_source: ProductDataSource
10
+ }
8
11
  end
9
12
  end
10
13
 
@@ -15,8 +15,12 @@ module WorldPages
15
15
  login_screen: LoginScreen,
16
16
  webview_screen: WebViewScreen,
17
17
  products_screen: ProductsScreen,
18
+ product_item_screen: ProductItemScreen,
18
19
  checkout_address_screen: CheckoutAddressScreen,
19
20
  checkout_payment_screen: CheckoutPaymentScreen,
21
+ qr_code_scanner_screen: QRCodeScannerScreen,
22
+ geo_location_screen: GeoLocationScreen,
23
+ biometrics_screen: BiometricsScreen,
20
24
  saucebot_video_screen: SauceBotScreen
21
25
  }
22
26
  end
@@ -5,6 +5,16 @@ module TestCentricity
5
5
  @type = :alert
6
6
  end
7
7
 
8
+ # Wait until the alert modal is visible, or until the specified wait time has expired. If the wait time is nil, then the
9
+ # wait time will be Environ.default_max_wait_time. Unlike wait_until_visible or wait_until_exists, this method does not
10
+ # raise an exception if the alert modal does not appear within the specified wait time.
11
+ # Returns true if the alert modal is visible.
12
+ #
13
+ # @return [Integer]
14
+ # @param seconds [Integer or Float] wait time in seconds
15
+ # @example
16
+ # permissions_modal.await(2)
17
+ #
8
18
  def await(seconds)
9
19
  timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
10
20
  wait = Selenium::WebDriver::Wait.new(timeout: timeout)
@@ -14,14 +24,68 @@ module TestCentricity
14
24
  false
15
25
  end
16
26
 
27
+ # Performs the action required accept the currently visible alert modal. If the alert modal is still visible after
28
+ # 5 seconds, an exception is raised.
29
+ #
30
+ # @example
31
+ # alert_modal.accept
32
+ #
17
33
  def accept
18
34
  alert_accept
19
35
  wait_until_gone(5)
20
36
  end
21
37
 
38
+ # Performs the action required dismiss the currently visible alert modal. If the alert modal is still visible after
39
+ # 5 seconds, an exception is raised.
40
+ #
41
+ # @example
42
+ # alert_modal.dismiss
43
+ #
22
44
  def dismiss
23
45
  alert_dismiss
24
46
  wait_until_gone(5)
25
47
  end
48
+
49
+ #
50
+ # @return [Integer]
51
+ # @param action [Symbol] action to perform if alert modal is visible. Acceptable values are :allow, :accept, :dont_allow, or :dismiss
52
+ # @param timeout [Integer or Float] wait time in seconds. Defaults to 2 if not specified
53
+ # @param button_name [String] optional caption of button to tap associated with the specified action
54
+ # @example
55
+ # alert_modal.await_and_respond(:dismiss)
56
+ # OR
57
+ # permissions_modal.await_and_respond(:accept, timeout = 1, button_name = 'Allow Once')
58
+ #
59
+ def await_and_respond(action, timeout = 2, button_name = nil)
60
+ if await(timeout)
61
+ case action
62
+ when :allow, :accept
63
+ if button_name.nil?
64
+ accept
65
+ elsif Environ.is_ios?
66
+ $driver.execute_script('mobile: alert', { action: 'accept', buttonLabel: button_name })
67
+ else
68
+ $driver.execute_script('mobile: acceptAlert', { buttonLabel: button_name })
69
+ end
70
+ when :dont_allow, :dismiss
71
+ if button_name.nil?
72
+ dismiss
73
+ elsif Environ.is_ios?
74
+ $driver.execute_script('mobile: alert', { action: 'dismiss', buttonLabel: button_name })
75
+ else
76
+ $driver.execute_script('mobile: dismissAlert', { buttonLabel: button_name })
77
+ end
78
+ else
79
+ raise "#{action} is not a valid selector"
80
+ end
81
+ if Environ.is_ios? && await(1)
82
+ buttons = $driver.execute_script('mobile: alert', { action: 'getButtons' })
83
+ raise "Could not perform #{action} action on active modal. Available modal buttons are #{buttons}"
84
+ end
85
+ true
86
+ else
87
+ false
88
+ end
89
+ end
26
90
  end
27
91
  end
@@ -174,12 +174,16 @@ module TestCentricity
174
174
  # @example
175
175
  # run_button.wait_until_exists(0.5)
176
176
  #
177
- def wait_until_exists(seconds = nil)
177
+ def wait_until_exists(seconds = nil, post_exception = true)
178
178
  timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
179
179
  wait = Selenium::WebDriver::Wait.new(timeout: timeout)
180
180
  wait.until { exists? }
181
181
  rescue
182
- raise "Could not find UI #{object_ref_message} after #{timeout} seconds" unless exists?
182
+ if post_exception
183
+ raise "Could not find UI #{object_ref_message} after #{timeout} seconds" unless exists?
184
+ else
185
+ exists?
186
+ end
183
187
  end
184
188
 
185
189
  # Wait until the object no longer exists, or until the specified wait time has expired. If the wait time is nil, then
@@ -189,12 +193,16 @@ module TestCentricity
189
193
  # @example
190
194
  # logout_button.wait_until_gone(5)
191
195
  #
192
- def wait_until_gone(seconds = nil)
196
+ def wait_until_gone(seconds = nil, post_exception = true)
193
197
  timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
194
198
  wait = Selenium::WebDriver::Wait.new(timeout: timeout)
195
199
  wait.until { !exists? }
196
200
  rescue
197
- raise "UI #{object_ref_message} remained visible after #{timeout} seconds" if exists?
201
+ if post_exception
202
+ raise "UI #{object_ref_message} remained visible after #{timeout} seconds" if exists?
203
+ else
204
+ exists?
205
+ end
198
206
  end
199
207
 
200
208
  # Wait until the object is visible, or until the specified wait time has expired. If the wait time is nil, then the
@@ -204,12 +212,16 @@ module TestCentricity
204
212
  # @example
205
213
  # run_button.wait_until_visible(0.5)
206
214
  #
207
- def wait_until_visible(seconds = nil)
215
+ def wait_until_visible(seconds = nil, post_exception = true)
208
216
  timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
209
217
  wait = Selenium::WebDriver::Wait.new(timeout: timeout)
210
218
  wait.until { visible? }
211
219
  rescue
212
- raise "Could not find UI #{object_ref_message} after #{timeout} seconds" unless visible?
220
+ if post_exception
221
+ raise "Could not find UI #{object_ref_message} after #{timeout} seconds" unless visible?
222
+ else
223
+ visible?
224
+ end
213
225
  end
214
226
 
215
227
  # Wait until the object is hidden, or until the specified wait time has expired. If the wait time is nil, then the
@@ -219,12 +231,35 @@ module TestCentricity
219
231
  # @example
220
232
  # run_button.wait_until_hidden(10)
221
233
  #
222
- def wait_until_hidden(seconds = nil)
234
+ def wait_until_hidden(seconds = nil, post_exception = true)
223
235
  timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
224
236
  wait = Selenium::WebDriver::Wait.new(timeout: timeout)
225
237
  wait.until { hidden? }
226
238
  rescue
227
- raise "UI #{object_ref_message} remained visible after #{timeout} seconds" if visible?
239
+ if post_exception
240
+ raise "UI #{object_ref_message} remained visible after #{timeout} seconds" if visible?
241
+ else
242
+ hidden?
243
+ end
244
+ end
245
+
246
+ # Wait until the object is enabled, or until the specified wait time has expired. If the wait time is nil, then the
247
+ # wait time will be Environ.default_max_wait_time.
248
+ #
249
+ # @param seconds [Integer or Float] wait time in seconds
250
+ # @example
251
+ # run_button.wait_until_enabled(10)
252
+ #
253
+ def wait_until_enabled(seconds = nil, post_exception = true)
254
+ timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
255
+ wait = Selenium::WebDriver::Wait.new(timeout: timeout)
256
+ wait.until { enabled? }
257
+ rescue
258
+ if post_exception
259
+ raise "UI #{object_ref_message} remained disabled after #{timeout} seconds" unless enabled?
260
+ else
261
+ enabled?
262
+ end
228
263
  end
229
264
 
230
265
  # Wait until the object's value equals the specified value, or until the specified wait time has expired. If the wait
@@ -237,12 +272,16 @@ module TestCentricity
237
272
  # or
238
273
  # total_weight_field.wait_until_value_is({ :greater_than => '250' }, 5)
239
274
  #
240
- def wait_until_value_is(value, seconds = nil)
275
+ def wait_until_value_is(value, seconds = nil, post_exception = true)
241
276
  timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
242
277
  wait = Selenium::WebDriver::Wait.new(timeout: timeout)
243
278
  wait.until { compare(value, get_value) }
244
279
  rescue
245
- raise "Value of UI #{object_ref_message} failed to equal '#{value}' after #{timeout} seconds" unless get_value == value
280
+ if post_exception
281
+ raise "Value of UI #{object_ref_message} failed to equal '#{value}' after #{timeout} seconds" unless get_value == value
282
+ else
283
+ get_value == value
284
+ end
246
285
  end
247
286
 
248
287
  # Wait until the object's value changes to a different value, or until the specified wait time has expired. If the
@@ -252,13 +291,17 @@ module TestCentricity
252
291
  # @example
253
292
  # basket_grand_total_label.wait_until_value_changes(5)
254
293
  #
255
- def wait_until_value_changes(seconds = nil)
294
+ def wait_until_value_changes(seconds = nil, post_exception = true)
256
295
  value = get_value
257
296
  timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
258
297
  wait = Selenium::WebDriver::Wait.new(timeout: timeout)
259
298
  wait.until { get_value != value }
260
299
  rescue
261
- raise "Value of UI #{object_ref_message} failed to change from '#{value}' after #{timeout} seconds" if get_value == value
300
+ if post_exception
301
+ raise "Value of UI #{object_ref_message} failed to change from '#{value}' after #{timeout} seconds" if get_value == value
302
+ else
303
+ get_value == value
304
+ end
262
305
  end
263
306
 
264
307
  def width
@@ -1,3 +1,3 @@
1
1
  module TestCentricity
2
- VERSION = '3.0.1'
2
+ VERSION = '3.0.4'
3
3
  end
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.required_ruby_version = '>= 2.7.5'
11
11
  spec.authors = ['A.J. Mrozinski']
12
12
  spec.email = ['testcentricity@gmail.com']
13
- spec.summary = %q{A Page Object Model Framework for desktop/mobile web and native mobile app testing}
13
+ spec.summary = %q{A Page Object Model Framework for native mobile app and desktop/mobile web portal testing}
14
14
  spec.description = '
15
15
  The TestCentricity™ core framework for native mobile iOS and Android apps and desktop/mobile web testing implements a Page Object
16
16
  Model DSL for use with Cucumber, Appium, Capybara, and Selenium-Webdriver v4.x. The gem also facilitates the configuration of the
@@ -33,8 +33,6 @@ Gem::Specification.new do |spec|
33
33
  spec.add_development_dependency 'bundler'
34
34
  spec.add_development_dependency 'cucumber'
35
35
  spec.add_development_dependency 'cuke_modeler', '~> 3.0'
36
- spec.add_development_dependency 'curb'
37
- spec.add_development_dependency 'json'
38
36
  spec.add_development_dependency 'parallel_tests'
39
37
  spec.add_development_dependency 'rake'
40
38
  spec.add_development_dependency 'require_all', '=1.5.0'
@@ -43,6 +41,8 @@ Gem::Specification.new do |spec|
43
41
  spec.add_development_dependency 'yard', ['>= 0.9.0']
44
42
 
45
43
  spec.add_runtime_dependency 'appium_lib'
46
- spec.add_runtime_dependency 'testcentricity_web', '>= 4.2.2'
44
+ spec.add_runtime_dependency 'curb'
45
+ spec.add_runtime_dependency 'json'
46
+ spec.add_runtime_dependency 'testcentricity_web', '>= 4.2.4'
47
47
  spec.add_runtime_dependency 'test-unit'
48
48
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: testcentricity
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - A.J. Mrozinski
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-26 00:00:00.000000000 Z
11
+ date: 2022-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,34 +52,6 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
- - !ruby/object:Gem::Dependency
56
- name: curb
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: json
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
55
  - !ruby/object:Gem::Dependency
84
56
  name: parallel_tests
85
57
  requirement: !ruby/object:Gem::Requirement
@@ -178,20 +150,48 @@ dependencies:
178
150
  - - ">="
179
151
  - !ruby/object:Gem::Version
180
152
  version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: curb
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: json
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
181
  - !ruby/object:Gem::Dependency
182
182
  name: testcentricity_web
183
183
  requirement: !ruby/object:Gem::Requirement
184
184
  requirements:
185
185
  - - ">="
186
186
  - !ruby/object:Gem::Version
187
- version: 4.2.2
187
+ version: 4.2.4
188
188
  type: :runtime
189
189
  prerelease: false
190
190
  version_requirements: !ruby/object:Gem::Requirement
191
191
  requirements:
192
192
  - - ">="
193
193
  - !ruby/object:Gem::Version
194
- version: 4.2.2
194
+ version: 4.2.4
195
195
  - !ruby/object:Gem::Dependency
196
196
  name: test-unit
197
197
  requirement: !ruby/object:Gem::Requirement
@@ -233,7 +233,6 @@ files:
233
233
  - Rakefile
234
234
  - config/cucumber.yml
235
235
  - config/locales/en-US.yml
236
- - config/test_data/LOCAL_data.yml
237
236
  - config/test_data/data.yml
238
237
  - features/deep_links.feature
239
238
  - features/login.feature
@@ -241,27 +240,35 @@ files:
241
240
  - features/step_definitions/generic_steps.rb
242
241
  - features/support/android/screens/about_screen.rb
243
242
  - features/support/android/screens/base_app_screen.rb
243
+ - features/support/android/screens/biometrics_screen.rb
244
244
  - features/support/android/screens/checkout_address_screen.rb
245
245
  - features/support/android/screens/checkout_payment_screen.rb
246
+ - features/support/android/screens/geo_location_screen.rb
246
247
  - features/support/android/screens/login_screen.rb
248
+ - features/support/android/screens/product_item_screen.rb
247
249
  - features/support/android/screens/products_screen.rb
250
+ - features/support/android/screens/qr_code_scanner_screen.rb
248
251
  - features/support/android/screens/saucebot_screen.rb
249
252
  - features/support/android/screens/webview_screen.rb
253
+ - features/support/android/sections/list_items/product_list_item.rb
250
254
  - features/support/android/sections/nav_widgets/nav_menu.rb
255
+ - features/support/data/product_data.rb
256
+ - features/support/data/user_data.rb
251
257
  - features/support/env.rb
252
258
  - features/support/hooks.rb
253
259
  - features/support/ios/screens/about_screen.rb
254
260
  - features/support/ios/screens/base_app_screen.rb
261
+ - features/support/ios/screens/biometrics_screen.rb
255
262
  - features/support/ios/screens/checkout_address_screen.rb
256
263
  - features/support/ios/screens/checkout_payment_screen.rb
264
+ - features/support/ios/screens/geo_location_screen.rb
257
265
  - features/support/ios/screens/login_screen.rb
266
+ - features/support/ios/screens/product_item_screen.rb
258
267
  - features/support/ios/screens/products_screen.rb
268
+ - features/support/ios/screens/qr_code_scanner_screen.rb
259
269
  - features/support/ios/screens/saucebot_screen.rb
260
270
  - features/support/ios/screens/webview_screen.rb
261
- - features/support/ios/sections/list_items/product_cell_item.rb
262
- - features/support/ios/sections/modals/base_modal.rb
263
- - features/support/ios/sections/modals/logout_modal.rb
264
- - features/support/ios/sections/modals/reset_app_state_modal.rb
271
+ - features/support/ios/sections/list_items/product_list_item.rb
265
272
  - features/support/ios/sections/nav_widgets/nav_bar.rb
266
273
  - features/support/ios/sections/nav_widgets/nav_menu.rb
267
274
  - features/support/shared_components/screens/base_app_screen.rb
@@ -337,8 +344,8 @@ requirements:
337
344
  rubygems_version: 3.1.6
338
345
  signing_key:
339
346
  specification_version: 4
340
- summary: A Page Object Model Framework for desktop/mobile web and native mobile app
341
- testing
347
+ summary: A Page Object Model Framework for native mobile app and desktop/mobile web
348
+ portal testing
342
349
  test_files:
343
350
  - features/deep_links.feature
344
351
  - features/login.feature
@@ -346,27 +353,35 @@ test_files:
346
353
  - features/step_definitions/generic_steps.rb
347
354
  - features/support/android/screens/about_screen.rb
348
355
  - features/support/android/screens/base_app_screen.rb
356
+ - features/support/android/screens/biometrics_screen.rb
349
357
  - features/support/android/screens/checkout_address_screen.rb
350
358
  - features/support/android/screens/checkout_payment_screen.rb
359
+ - features/support/android/screens/geo_location_screen.rb
351
360
  - features/support/android/screens/login_screen.rb
361
+ - features/support/android/screens/product_item_screen.rb
352
362
  - features/support/android/screens/products_screen.rb
363
+ - features/support/android/screens/qr_code_scanner_screen.rb
353
364
  - features/support/android/screens/saucebot_screen.rb
354
365
  - features/support/android/screens/webview_screen.rb
366
+ - features/support/android/sections/list_items/product_list_item.rb
355
367
  - features/support/android/sections/nav_widgets/nav_menu.rb
368
+ - features/support/data/product_data.rb
369
+ - features/support/data/user_data.rb
356
370
  - features/support/env.rb
357
371
  - features/support/hooks.rb
358
372
  - features/support/ios/screens/about_screen.rb
359
373
  - features/support/ios/screens/base_app_screen.rb
374
+ - features/support/ios/screens/biometrics_screen.rb
360
375
  - features/support/ios/screens/checkout_address_screen.rb
361
376
  - features/support/ios/screens/checkout_payment_screen.rb
377
+ - features/support/ios/screens/geo_location_screen.rb
362
378
  - features/support/ios/screens/login_screen.rb
379
+ - features/support/ios/screens/product_item_screen.rb
363
380
  - features/support/ios/screens/products_screen.rb
381
+ - features/support/ios/screens/qr_code_scanner_screen.rb
364
382
  - features/support/ios/screens/saucebot_screen.rb
365
383
  - features/support/ios/screens/webview_screen.rb
366
- - features/support/ios/sections/list_items/product_cell_item.rb
367
- - features/support/ios/sections/modals/base_modal.rb
368
- - features/support/ios/sections/modals/logout_modal.rb
369
- - features/support/ios/sections/modals/reset_app_state_modal.rb
384
+ - features/support/ios/sections/list_items/product_list_item.rb
370
385
  - features/support/ios/sections/nav_widgets/nav_bar.rb
371
386
  - features/support/ios/sections/nav_widgets/nav_menu.rb
372
387
  - features/support/shared_components/screens/base_app_screen.rb
@@ -1,11 +0,0 @@
1
- Form_data:
2
- primary:
3
- username: "Ignatius von Snicklefritz"
4
- password: "T0p_Sekrit"
5
- image_filename: "Wilder.jpg"
6
- multi_select: "Selection Item 2"
7
- drop_down_item: "Drop Down Item 5"
8
- check1: true
9
- check2: true
10
- check3: false
11
- radio_select: 2
@@ -1,13 +0,0 @@
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
@@ -1,23 +0,0 @@
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
@@ -1,6 +0,0 @@
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
@@ -1,6 +0,0 @@
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