testcentricity 2.4.3 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) 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 -1384
  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 +343 -111
  56. data/lib/testcentricity/app_core/screen_object.rb +252 -0
  57. data/lib/testcentricity/app_core/screen_objects_helper.rb +29 -201
  58. data/lib/testcentricity/app_core/{screen_sections_helper.rb → screen_section.rb} +40 -105
  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/browser_helper.rb +0 -174
  94. data/lib/testcentricity/data_objects/data_objects_helper.rb +0 -78
  95. data/lib/testcentricity/data_objects/excel_helper.rb +0 -242
  96. data/lib/testcentricity/exception_queue_helper.rb +0 -111
  97. data/lib/testcentricity/utility_helpers.rb +0 -32
  98. data/lib/testcentricity/web_core/drag_drop_helper.rb +0 -15
  99. data/lib/testcentricity/web_core/page_objects_helper.rb +0 -677
  100. data/lib/testcentricity/web_core/page_sections_helper.rb +0 -895
  101. data/lib/testcentricity/web_core/webdriver_helper.rb +0 -588
  102. data/lib/testcentricity/web_elements/button.rb +0 -8
  103. data/lib/testcentricity/web_elements/cell_button.rb +0 -8
  104. data/lib/testcentricity/web_elements/cell_checkbox.rb +0 -38
  105. data/lib/testcentricity/web_elements/cell_element.rb +0 -69
  106. data/lib/testcentricity/web_elements/cell_image.rb +0 -8
  107. data/lib/testcentricity/web_elements/cell_radio.rb +0 -31
  108. data/lib/testcentricity/web_elements/checkbox.rb +0 -100
  109. data/lib/testcentricity/web_elements/file_field.rb +0 -45
  110. data/lib/testcentricity/web_elements/image.rb +0 -34
  111. data/lib/testcentricity/web_elements/label.rb +0 -8
  112. data/lib/testcentricity/web_elements/link.rb +0 -8
  113. data/lib/testcentricity/web_elements/list.rb +0 -100
  114. data/lib/testcentricity/web_elements/list_button.rb +0 -8
  115. data/lib/testcentricity/web_elements/list_checkbox.rb +0 -38
  116. data/lib/testcentricity/web_elements/list_element.rb +0 -61
  117. data/lib/testcentricity/web_elements/list_radio.rb +0 -31
  118. data/lib/testcentricity/web_elements/radio.rb +0 -74
  119. data/lib/testcentricity/web_elements/select_list.rb +0 -208
  120. data/lib/testcentricity/web_elements/siebel_open_ui_helper.rb +0 -15
  121. data/lib/testcentricity/web_elements/table.rb +0 -612
  122. data/lib/testcentricity/web_elements/textfield.rb +0 -114
  123. data/lib/testcentricity/web_elements/ui_elements_helper.rb +0 -532
  124. data/lib/testcentricity/world_extensions.rb +0 -26
  125. data/my_templates/default/method_details/setup.rb +0 -3
  126. data/spec/testcentricity_spec.rb +0 -9
data/README.md CHANGED
@@ -1,236 +1,66 @@
1
- # TestCentricity™ Web
1
+ # TestCentricity™
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/testcentricity.svg)](https://badge.fury.io/rb/testcentricity) [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](http://opensource.org/licenses/BSD-3-Clause)
4
-
5
-
6
- The TestCentricity™ Web core generic framework for desktop and mobile web site testing implements a Page Object and Data Object Model DSL for
7
- use with Cucumber, Capybara, and Selenium-Webdriver.
8
-
9
- The TestCentricity™ Web gem supports running automated tests against the following web test targets:
10
- * locally hosted desktop browsers (Firefox*, Chrome, Safari, or IE)
11
- * locally hosted emulated iOS Mobile Safari, Android, Windows Phone, or Blackberry mobile browsers (running within a local instance of Chrome)
12
- * a "headless" browser (using Poltergeist and PhantomJS)
13
- * mobile Safari browsers on iOS device simulators or physical iOS devices (using Appium and XCode on OS X)
14
- * mobile Chrome or Android browsers on Android Studio virtual device emulators (using Appium and Android Studio on OS X)
15
- * cloud hosted desktop (Firefox, Chrome, Safari, IE, or Edge) or mobile (iOS Mobile Safari or Android) web browsers using the [Browserstack](https://www.browserstack.com/list-of-browsers-and-platforms?product=automate),
16
- [Sauce Labs](https://saucelabs.com/open-source#automated-testing-platform), [CrossBrowserTesting](https://crossbrowsertesting.com/selenium-testing), or
17
- [TestingBot](https://testingbot.com/features) services.
4
+ ![Gem Downloads](https://img.shields.io/gem/dt/testcentricity) ![Maintained](https://img.shields.io/maintenance/yes/2022)
5
+
6
+
7
+ The TestCentricity™ core framework for native mobile iOS and Android apps and desktop/mobile web testing implements a Screen
8
+ and Page Object Model DSL for use with Cucumber (version 7.x or greater), Appium, Capybara, and Selenium-Webdriver (version 4.x). It also facilitates
9
+ the configuration of the appropriate Appium capabilities and driver required to establish a connection with locally hosted or
10
+ cloud hosted (using BrowserStack, Sauce Labs, or TestingBot services) iOS and Android real devices or simulators. For more
11
+ information on desktop/mobile web testing with this gem, refer to docs for the [TestCentricity™ Web gem](https://www.rubydoc.info/gems/testcentricity_web)
12
+
13
+ The TestCentricity™ gem supports automated testing of native iOS and Android apps running on the following mobile test targets:
14
+ * locally hosted iOS device simulators or physical iOS devices (using Appium and XCode on macOS)
15
+ * locally hosted Android devices or Android Studio virtual device emulators (using Appium and Android Studio on macOS)
16
+ * cloud hosted physical devices and simulators from the following service:
17
+ * [Browserstack](https://www.browserstack.com/list-of-browsers-and-platforms/app_automate)
18
+ * [Sauce Labs](https://saucelabs.com/platform/mobile-testing)
19
+ * [TestingBot](https://testingbot.com/mobile/realdevicetesting)
20
+
21
+ The TestCentricity™ gem also incorporates all of the features and capabilities of the TestCentricity™ Web framework gem, which
22
+ supports running automated tests against the following web test targets:
23
+ * locally hosted desktop browsers (Chrome, Edge, Firefox, Safari, or IE)
24
+ * locally hosted "headless" Chrome, Firefox, or Edge browsers
25
+ * remote desktop and emulated mobile web browsers hosted on Selenium Grid 4 and Dockerized Selenium Grid 4 environments
26
+ * mobile Safari browsers on iOS device simulators or physical iOS devices (using Appium and XCode on macOS)
27
+ * mobile Chrome or Android browsers on Android Studio virtual device emulators (using Appium and Android Studio on macOS)
28
+ * cloud hosted desktop (Firefox, Chrome, Safari, IE, or Edge) or mobile (iOS Mobile Safari or Android) web browsers using the following service:
29
+ * [Browserstack](https://www.browserstack.com/list-of-browsers-and-platforms?product=automate)
30
+ * [Sauce Labs](https://saucelabs.com/open-source#automated-testing-platform)
31
+ * [TestingBot](https://testingbot.com/features)
32
+ * [LambdaTest](https://www.lambdatest.com/selenium-automation)
18
33
  * web portals utilizing JavaScript front end application frameworks like Ember, React, Angular, and GWT
19
- * enterprise web portals build using Siebel Open UI
20
-
21
-
22
- **Note:** Test execution against local instances of Firefox version 48 or greater is currently not supported by the TestCentricity™ Web gem. Testing with
23
- locally hosted instances of Firefox 48 or greater requires Marionette (aka geckodriver) and selenium-webdriver version 3.x, both of which are currently
24
- feature incomplete and potentially unstable. More information can be found [here](https://github.com/teamcapybara/capybara/issues/1710).
25
-
26
- TestCentricity™ will be updated to support testing with Selenium-WebDriver version 3.x as soon as a stable version is available that **fully** supports locally
27
- hosted instances of Chrome, Firefox, Safari, and IE web browsers.
34
+ * web pages containing HTML5 Video and Audio objects
28
35
 
29
36
 
30
37
  ## What's New
31
- ###Version 2.4.3
32
-
33
- * Updated device profiles for iPhone 7 (iOS 11) with Mobile Firefox browser and iPad (iOS 10) with Mobile Firefox browser.
34
-
35
- ###Version 2.4.1
36
-
37
- * Added device profiles for iPad (iOS 10) with MS Edge browser.
38
-
39
- ###Version 2.4.0
40
-
41
- * Updated `TestCentricity::WebDriverConnect.initialize_web_driver` method to read the `APP_FULL_RESET`, `APP_NO_RESET`, and `NEW_COMMAND_TIMEOUT` Environment
42
- Variables and set the corresponding `fullReset`, `noReset`, and `newCommandTimeout` Appium capabilities for iOS and Android physical devices and simulators.
43
- Also reads the `WDA_LOCAL_PORT` Environment Variable and sets the `wdaLocalPort` Appium capability for iOS physical devices only.
44
-
45
- ###Version 2.3.18
46
-
47
- * Updated `SelectList.define_list_elements` method to accept value for `:list_trigger` element.
48
- * Updated `SelectList.choose_option` to respect `:list_item` value and to click on `:list_trigger` element, if one is specified.
49
- * Updated `PageSection` and `PageObject` UI element object declaration methods to no longer use `class_eval` pattern.
50
- * Updated device profiles for iPhone 7 (iOS 10) with Chrome browser and iPad (iOS 10) with Chrome browser.
51
-
52
- ###Version 2.3.17
53
-
54
- * Added `List.wait_until_item_count_is` and `List.wait_until_item_count_changes` methods.
55
- * `UIElement.wait_until_value_is` and `List.wait_until_item_count_is` methods now accept comparison hash.
56
-
57
- ###Version 2.3.16
58
-
59
- * Added `PageSection.double_click`, `PageObject.right_click`, and `PageObject.send_keys` methods.
60
-
61
- ###Version 2.3.15
62
-
63
- * Added `PageObject.wait_until_exists` and `PageObject.wait_until_gone` methods.
64
-
65
- ###Version 2.3.14
66
-
67
- * Updated device profiles for iPhone 7 (iOS 10) with MS Edge browser.
68
-
69
- ###Version 2.3.13
70
-
71
- * Added `AppiumServer.start`, `AppiumServer.running?`, and `AppiumServer.stop` methods for starting and stopping the Appium Server prior to executing tests on
72
- iOS physical devices or simulators, or Android virtual device emulators.
73
-
74
- ###Version 2.3.12
75
-
76
- * Added `Environ.is_simulator?` and `Environ.is_web?` methods.
77
-
78
- ###Version 2.3.11
79
-
80
- * Added support for running tests in Mobile Safari browser on physical iOS devices.
81
- * Updated device profiles for iPhone 7 (iOS 10) with Mobile Firefox browser and iPad (iOS 10) with Mobile Firefox browser.
82
-
83
- ###Version 2.3.10
84
-
85
- * Added support for running tests in mobile Chrome or Android browsers on Android Studio virtual device emulators.
86
- * Added `displayed?`, `get_all_items_count`, and `get_all_list_items` methods to `PageSection` class.
87
- * Added `get_all_items_count`, and `get_all_list_items` methods to `List` class.
88
-
89
- ###Version 2.3.9
90
-
91
- * Updated `PageObject.populate_data_fields` and `PageSection.populate_data_fields` methods to accept optional `wait_time` parameter.
92
- * Updated device profiles for iPhone 7 (iOS 10) with MS Edge browser, iPhone 7 (iOS 10) with Chrome browser, and iPhone 7 (iOS 10) with Firefox browser.
93
- * Updated device profiles for iPad (iOS 10) with Chrome browser and iPad (iOS 10) with Firefox browser.
94
-
95
- ###Version 2.3.7
96
-
97
- * Added `width`, `height`, `x`, `y`, and `displayed?` methods to `UIElement` class.
98
-
99
- ###Version 2.3.6
100
-
101
- * Added `TextField.clear` method for deleting the contents of text fields. This method should trigger the `onchange` event for the associated text field.
102
-
103
- ###Version 2.3.5
104
-
105
- * Updated `PageObject.populate_data_fields` and `PageSection.populate_data_fields` methods to be compatible with Redactor editor fields.
106
- * Updated device profiles for iPhone 7 (iOS 10) with MS Edge browser, iPhone 7 (iOS 10) with Chrome browser, and iPhone 7 (iOS 10) with Firefox browser.
107
-
108
- ###Version 2.3.3
109
-
110
- * Added device profile for iPhone 7 (iOS 10) with MS Edge browser.
111
-
112
- ###Version 2.3.1
113
-
114
- * When testing using remotely hosted browsers on the BrowserStack service, the BrowserStack Local instance is automatically started if the `TUNNELING`
115
- Environment Variable is set to `true`. `Environ.tunneling` will be set to true if the BrowserStack Local instance is succesfully started.
116
- * Added `TestCentricity::WebDriverConnect.close_tunnel` method to close BrowserStack Local instance when Local testing is enabled. Refer to the
117
- **Remotely hosted desktop and mobile web browsers** section for information on usage.
118
-
119
- ###Version 2.2.0
120
-
121
- * CSS selectors or XPath expressions may be used as locators for all types of **UI Elements**, including tables.
122
-
123
- ###Version 2.1.10
124
-
125
- * Added device profiles for iPhone 7 (iOS 10) with Mobile Firefox browser and iPad (iOS 10) with Mobile Firefox browser.
126
-
127
- ###Version 2.1.8
128
-
129
- * Added `PageSection.verify_list_items` method for **Indexed PageSection Objects**.
130
-
131
- ###Version 2.1.7
132
-
133
- * Updated `PageObject.populate_data_fields` and `PageSection.populate_data_fields` methods to use backspace characters to delete contents of a textfield
134
- instead of using `clear`, which was preventing `onchange` JavaScript events from being triggered in some browsers.
135
-
136
- ###Version 2.1.5
137
-
138
- * Added `get_min`, `get_max`, and `get_step` methods to `TextField` class.
139
-
140
- * Updated `PageObject.verify_ui_states` and `PageSection.verify_ui_states` methods to support verification of `min`, `max`, and `step` attributes
141
- for textfields.
142
-
143
- ###Version 2.1.4
144
-
145
- * Added suppression of the Info Bar that displays "Chrome is being controlled by automated test software" on locally hosted instances of the Chrome browser.
146
-
147
-
148
- ###Version 2.1.3
149
-
150
- * Added support for "tiling" or cascading multiple browser windows when the `BROWSER_TILE` and `PARALLEL` Environment Variables are set to true. For each
151
- concurrent parallel thread being executed, the position of each browser will be offset by 100 pixels right and 100 pixels down. For parallel test execution,
152
- use the [parallel_tests gem](https://rubygems.org/gems/parallel_tests) to decrease overall test execution time.
153
-
154
- ###Version 2.1.2
155
-
156
- * Added device profiles for Microsoft Lumia 950, Blackberry Leap, Blackberry Passport, and Kindle Fire HD 10
157
- * Added ability to set browser language support via the `LOCALE` Environment Variable for local instances of Chrome browsers
158
-
159
- ###Version 2.1.0
160
-
161
- * Added device profiles for iPhone 8, iPhone 8 Plus, iPhone X devices running iOS 11
162
- * Added device profile for iPad Pro 10.5" with iOS 11
163
- * Updated iPhone 7 and iPhone 7 Plus profiles to iOS 10
164
- * Updated Google Pixel and Google Pixel XL profiles to Android 8
165
- * Added device profiles for iPhone 7 (iOS 10) with Mobile Chrome browser and iPad (iOS 10) with Mobile Chrome browser
166
-
167
-
168
- ## What's Fixed
169
- ###Version 2.3.19
170
-
171
- * Fixed device profile for `android_phone` - Generic Android Phone
172
-
173
- ###Version 2.3.18
174
-
175
- * Fixed `SelectList.choose_option` to also accept `:text`, `:value`, and `:index` option hashes across all types of select list objects.
176
-
177
-
178
- ###Version 2.3.15
179
-
180
- * Fixed bug in `UIElement.get_object_type` method that could result in a `NoMethodError obj not defined` error.
181
- * Fixed bug in `PageObject.verify_ui_states` and `PageSection.verify_ui_states` methods that failed to enqueue errors when UI elements could not be found.
182
-
183
- ###Version 2.3.8
184
-
185
- * Fixed locator resolution for **Indexed PageSection Objects**.
186
-
187
- ###Version 2.3.6.1
188
-
189
- * `TextField.clear` method now works with most `number` type fields.
190
38
 
191
- ###Version 2.3.4
39
+ A complete history of bug fixes and new features can be found in the {file:CHANGELOG.md CHANGELOG} file.
192
40
 
193
- * Fixed bug in `PageObject.populate_data_fields` and `PageSection.populate_data_fields` methods that prevented deletion of data in number type textfields
194
- and textarea controls.
41
+ The RubyDocs for this gem can be found [here](https://www.rubydoc.info/gems/testcentricity/).
195
42
 
196
- ###Version 2.3.3
197
43
 
198
- * Corrected device profiles for iPad (iOS 10) with Mobile Chrome browser and iPad (iOS 10) with Mobile Firefox browser.
44
+ ## Which gem should I use?
199
45
 
200
- ###Version 2.2.1
46
+ | Tested platforms | TestCentricity | TestCentricity Web |
47
+ |--------------------------------------------------|----------------|--------------------|
48
+ | Native mobile apps only | Yes | No |
49
+ | Hybrid apps with WebViews only | Yes | No |
50
+ | Native mobile apps and desktop/mobile web | Yes | No |
51
+ | Hybrid apps with WebViews and desktop/mobile web | Yes | No |
52
+ | Desktop/mobile web only | No | Yes |
201
53
 
202
- * `SelectList.choose_option` method now accepts index values for Chosen list objects.
203
-
204
- ###Version 2.1.9
205
-
206
- * Fixed bug in `SelectList.choose_option`, `SelectList.get_options`, `SelectList.get_option_count`, and `SelectList.get_selected_option` methods which
207
- did not recognize grouped option in Chosen list objects.
208
-
209
- ###Version 2.1.6
210
-
211
- * Fixed bug in `TestCentricity::WebDriverConnect.set_webdriver_path` method that was failing to set the path to the appropriate chromedriver file for OS X
212
- and Windows.
213
-
214
- ###Version 2.1.5
215
-
216
- * Fixed Chrome and Firefox support for setting browser language via the `LOCALE` Environment Variable. This capability now works for emulated mobile
217
- browsers hosted in a local instance of Chrome or Firefox.
218
-
219
- ###Version 2.1.0
220
-
221
- * The `TestCentricity::WebDriverConnect.initialize_web_driver` method now sets the `Environ` object to the correct device connection states for local and
222
- cloud hosted browsers.
223
- * The `TestCentricity::WebDriverConnect.initialize_web_driver` method no longer calls `initialize_browser_size` when running tests against cloud hosted
224
- mobile web browser, which was resulting in Appium throwing exceptions for unsupported method calls.
225
- * The `TestCentricity::WebDriverConnect.set_webdriver_path` method now correctly sets the path for Chrome webDrivers when the `HOST_BROWSER` Environment
226
- Variable is set to `chrome`. Tests against locally hosted emulated mobile web browser running on a local instance of Chrome will now work correctly.
54
+ The TestCentricity gem is designed to support testing of native and hybrid mobile apps and/or web interfaces via desktop and
55
+ mobile web browsers. The TestCentricity Web gem only supports testing of web interfaces via desktop and mobile web browsers.
227
56
 
228
57
 
229
58
  ## Installation
230
59
 
231
- Add this line to your automation project's Gemfile:
60
+ TestCentricity version 3.0 and above requires Ruby 2.7.5 or later. To install the TestCentricity gem, add this line to your automation
61
+ project's Gemfile:
232
62
 
233
- gem 'testcentricity_web'
63
+ gem 'testcentricity'
234
64
 
235
65
  And then execute:
236
66
 
@@ -238,443 +68,452 @@ And then execute:
238
68
 
239
69
  Or install it yourself as:
240
70
 
241
- $ gem install testcentricity_web
71
+ $ gem install testcentricity
242
72
 
243
73
 
244
74
  ## Setup
245
- ###Using Cucumber
75
+ ### Using Cucumber
246
76
 
247
- If you are using Cucumber, you need to require the following in your *env.rb* file:
77
+ If you are using Cucumber, you need to require the following in your `env.rb` file:
248
78
 
249
- require 'capybara'
250
79
  require 'capybara/cucumber'
251
- require 'testcentricity_web'
80
+ require 'testcentricity'
252
81
 
253
82
 
254
- ###Using RSpec
83
+ ### Using RSpec
255
84
 
256
- If you are using RSpec instead, you need to require the following in your *env.rb* file:
85
+ If you are using RSpec instead, you need to require the following in your `spec_helper.rb` file:
257
86
 
258
- require 'capybara'
259
87
  require 'capybara/rspec'
260
- require 'testcentricity_web'
88
+ require 'testcentricity'
261
89
 
262
90
 
263
- ### Using Poltergeist
91
+ ## ScreenObjects
264
92
 
265
- If you will be running your tests on a "headless" web browser using Poltergeist and PhantomJS, you must add this line to your automation
266
- project's Gemfile:
93
+ The **Screen Object Model** is a test automation pattern that aims to create an abstraction of your native mobile app's User
94
+ Interface that can be used in tests. The **Screen** Object Model in native mobile test automation is equivalent to the **Page**
95
+ Object Model in web interface test automation.
267
96
 
268
- gem 'poltergeist'
97
+ A **Screen Object** is an object that represents a single screen in your AUT (Application Under Test). **Screen Objects**
98
+ encapsulate the implementation details of a mobile app screen and expose an API that supports interaction with, and validation
99
+ of the UI elements on the screen.
269
100
 
270
-
271
- ### Using Appium
272
-
273
- If you will be running your tests on mobile Safari browsers on simulated iOS devices using Appium and XCode Simulators, you need to require
274
- the following in your *env.rb* file:
275
-
276
- require 'appium_capybara'
277
-
278
- You also need to add this line to your automation project's Gemfile:
279
-
280
- gem 'appium_capybara'
281
-
282
- And then execute:
283
-
284
- $ bundle
101
+ **Screen Objects** makes it easier to maintain automated tests because changes to screen UI elements are updated in only one
102
+ location - in the `ScreenObject` class definition. By adopting a **Screen Object Model**, Cucumber feature files and step
103
+ definitions are no longer required to hold specific information about a screen's UI objects, thus minimizing maintenance
104
+ requirements. If any element on, or property of a screen changes (text field attributes, button captions, element states,
105
+ etc.), maintenance is performed in the `ScreenObject` class definition only, typically with no need to update the affected
106
+ feature file, scenarios, or step definitions.
285
107
 
286
108
 
109
+ ### Defining a ScreenObject
287
110
 
288
- ## Page Objects
111
+ Your `ScreenObject` class definitions should be contained within individual `.rb` files in the `features/support/<platform>/screens`
112
+ folder of your test automation project, where `<platform>` is typically `ios` or `android`. For each screen in your app, you will
113
+ typically have to define two `ScreenObjects` - one for iOS and the other for Android.
289
114
 
290
- The **Page Object Model** is a test automation pattern that aims to create an abstraction of your web app's User Interface that can be used
291
- in tests. A **Page Object** is an object that represents a single page in your AUT (Application Under Test). **Page Objects** encapsulate the
292
- implementation details of a web page and expose an API that supports interaction with, and validation of the UI elements on the page.
115
+ my_automation_project
116
+ ├── config
117
+ ├── features
118
+ │ ├── step_definitions
119
+ │ ├── support
120
+ │ │ ├── android
121
+ | | | └── screens
122
+ │ │ ├── ios
123
+ | | | └── screens
124
+ │ │ ├── env.rb
125
+ │ │ └── hooks.rb
126
+ ├── Gemfile
127
+ └── README.md
293
128
 
294
- **Page Objects** makes it easier to maintain automated tests because changes to page UI elements are updated in only one location - in the
295
- **Page Object** class definition. By adopting a **Page Object Model**, Cucumber Feature files and step definitions are no longer required to
296
- hold specific information about a page's UI objects, thus minimizing maintenance requirements. If any element on a page changes (URL path,
297
- text field attributes, button captions, etc.), maintenance is performed in the **Page Object** class definition only, typically with no need
298
- to update the affected feature file, scenarios, or step definitions.
299
129
 
130
+ You define a new `ScreenObject` as shown below:
300
131
 
301
- ### Defining a Page Object
302
-
303
- Your **Page Object** class definitions should be contained within individual `.rb` files in the `features/support/pages` folder of your
304
- test automation project. You define new **Page Objects** as shown below:
305
-
306
- class LoginPage < TestCentricity::PageObject
132
+ class LoginScreen < TestCentricity::ScreenObject
307
133
  end
308
134
 
309
135
 
310
- class HomePage < TestCentricity::PageObject
136
+ class ProductsScreen < TestCentricity::ScreenObject
311
137
  end
312
138
 
313
139
 
314
- class RegistrationPage < TestCentricity::PageObject
140
+ class CheckoutAddressScreen < TestCentricity::ScreenObject
315
141
  end
316
142
 
317
143
 
318
- ### Adding Traits to your Page Object
144
+ ### Adding Traits to your ScreenObject
319
145
 
320
- Web pages typically have names and URLs associated with them. Web pages also typically have a unique object or attribute that, when present,
321
- indicates that the page's contents have fully loaded.
146
+ Native app screens typically have names associated with them. Screens also typically have a unique object or attribute that, when
147
+ present, indicates that the screen's contents have fully loaded.
322
148
 
323
- The `page_name` trait is registered with the **PageManager** object, which includes a `find_page` method that takes a page name as a
324
- parameter and returns an instance of the associated **Page Object**. If you intend to use the **PageManager**, you must define a `page_name`
325
- trait for each of the **Page Objects** to be registered.
149
+ The `page_name` trait is registered with the `PageManager` object, which includes a `find_page` method that takes a page name as
150
+ a parameter and returns an instance of the associated `ScreenObject`. If you intend to use the `PageManager`, you must define a
151
+ `page_name` trait for each `ScreenObject` to be registered.
326
152
 
327
- The `page_name` trait is usually a `String` value that represents the name of the page that will be matched by the `PageManager.findpage` method.
328
- `page_name` traits are case and white-space sensitive. For pages that may be referenced with multiple names, the `page_name` trait may also be
329
- an `Array` of `String` values representing those page names.
153
+ The `page_name` trait is usually a `String` value that represents the name of the screen that will be matched by the
154
+ `PageManager.findpage` method. `page_name` traits are case and white-space sensitive. For screens that may be referenced with
155
+ multiple names, the `page_name` trait may also be an `Array` of `String` values representing those screen names.
330
156
 
331
- A `page_url` trait should be defined if a page can be directly loaded using a URL. If you set Capybara's `app_host`, or specify a base URL
332
- when calling the `WebDriverConnect.initialize_web_driver` method, then your `page_url` trait can be the relative URL slug that will
333
- be appended to the base URL specified in `app_host`. Specifying a `page_url` trait is optional, as not all web pages can be directly loaded
334
- via a URL.
157
+ The `page_locator` trait specifies a locator for unique object that exists once the screen's contents have been fully rendered. The
158
+ `page_locator` trait is a locator strategy that uniquely identifies the object. The `ScreenObject.verify_page_exists` method
159
+ waits for the `page_locator` trait to exist, and raises an exception if the wait time exceeds the `default_max_wait_time`.
335
160
 
336
- A `page_locator` trait is defined if a page has a unique object or attribute that exists once the page's contents have fully loaded. The
337
- `page_locator` trait is a CSS or Xpath expression that uniquely identifies the object or attribute. The `verify_page_exists` method waits
338
- for the `page_locator` trait to exist.
161
+ A `page_url` trait should be defined if a screen can be directly loaded using a deep link. Specifying a `page_url` trait is optional,
162
+ as not all screens can be directly accessed via a deep link.
339
163
 
340
- You define your page's **Traits** as shown below:
164
+ You define your screen's **Traits** as shown below:
341
165
 
342
- class LoginPage < TestCentricity::PageObject
343
- trait(:page_name) { 'Login' }
344
- trait(:page_url) { '/sign_in' }
345
- trait(:page_locator) { 'body.login-body' }
166
+ class LoginScreen < TestCentricity::ScreenObject
167
+ trait(:page_name) { 'Login' }
168
+ trait(:page_locator) { { accessibility_id: 'login screen' } }
169
+ trait(:page_url) { 'login' }
346
170
  end
347
171
 
348
172
 
349
- class HomePage < TestCentricity::PageObject
350
- # this page may be referred to as 'Home' or 'Dashboard' page so page_name trait is an Array of Strings
351
- trait(:page_name) { ['Home', 'Dashboard'] }
352
- trait(:page_url) { '/dashboard' }
353
- trait(:page_locator) { 'body.dashboard' }
173
+ class ProductsScreen < TestCentricity::ScreenObject
174
+ trait(:page_name) { 'Products' }
175
+ trait(:page_locator) { { accessibility_id: 'products screen' } }
176
+ trait(:page_url) { 'store-overview' }
354
177
  end
355
178
 
356
179
 
357
- class RegistrationPage < TestCentricity::PageObject
358
- trait(:page_name) { 'Registration' }
359
- trait(:page_url) { '/register' }
360
- trait(:page_locator) { 'body.registration' }
180
+ class CheckoutAddressScreen < TestCentricity::ScreenObject
181
+ trait(:page_name) { 'Checkout - Address' }
182
+ trait(:page_locator) { { accessibility_id: 'checkout address screen' } }
183
+ trait(:page_url) { 'checkout-address' }
361
184
  end
362
185
 
363
186
 
364
- ### Adding UI Elements to your Page Object
187
+ ### Adding UI Elements to your ScreenObject
365
188
 
366
- Web pages are made up of UI elements like text fields, check boxes, combo boxes, radio buttons, tables, lists, buttons, etc.
367
- **UI Elements** are added to your **Page Object** class definition as shown below:
189
+ Native app screens are made up of UI elements like text fields, check boxes, switches, lists, buttons, etc. **UI Elements** are
190
+ added to your `ScreenObject` class definition as shown below:
368
191
 
369
- class LoginPage < TestCentricity::PageObject
370
- trait(:page_name) { 'Login' }
371
- trait(:page_url) { '/sign_in' }
372
- trait(:page_locator) { 'body.login-body' }
373
-
374
- # Login page UI elements
375
- textfield :user_id_field, 'input#userName'
376
- textfield :password_field, 'input#password'
377
- button :login_button, 'button#login'
378
- checkbox :remember_checkbox, 'input#rememberUser'
379
- label :error_message_label, 'div#statusBar.login-error'
192
+ class LoginScreen < TestCentricity::ScreenObject
193
+ trait(:page_name) { 'Login' }
194
+ trait(:page_locator) { { accessibility_id: 'login screen' } }
195
+ trait(:page_url) { 'login' }
196
+
197
+ # Login screen UI elements
198
+ labels username_label: { accessibility_id: 'Username'},
199
+ password_label: { xpath: '(//XCUIElementTypeStaticText[@name="Password"])[1]'},
200
+ username_error: { accessibility_id: 'Username-error-message' },
201
+ password_error: { accessibility_id: 'Password-error-message' },
202
+ generic_error: { accessibility_id: 'generic-error-message' }
203
+ textfields username_field: { accessibility_id: 'Username input field' },
204
+ password_field: { accessibility_id: 'Password input field' }
205
+ button :login_button, { accessibility_id: 'Login button' }
380
206
  end
381
-
382
207
 
383
- class RegistrationPage < TestCentricity::PageObject
384
- trait(:page_name) { 'Registration' }
385
- trait(:page_url) { '/register' }
386
- trait(:page_locator) { 'body.registration' }
387
-
388
- # Registration page UI elements
389
- textfields first_name_field: 'input#firstName',
390
- last_name_field: 'input#lastName',
391
- email_field: 'input#email',
392
- phone_number_field: 'input#phone',
393
- address_field: 'input#streetAddress',
394
- city_field: 'input#city',
395
- post_code_field: 'input#postalCode',
396
- password_field: 'input#password',
397
- pword_confirm_field: 'input#passwordConfirmation'
398
- selectlists title_select: 'select#title',
399
- gender_select: 'select#gender',
400
- state_select: 'select#stateProvince'
401
- checkbox :email_opt_in_check, 'input#marketingEmailsOptIn'
402
- button :sign_up_button, 'button#registrationSignUp'
403
- end
404
208
 
209
+ class CheckoutAddressScreen < TestCentricity::ScreenObject
210
+ trait(:page_name) { 'Checkout - Address' }
211
+ trait(:page_locator) { { accessibility_id: 'checkout address screen' } }
212
+ trait(:page_url) { 'checkout-address' }
213
+
214
+ # Checkout Address screen UI elements
215
+ textfields fullname_field: { accessibility_id: 'Full Name* input field' },
216
+ address1_field: { accessibility_id: 'Address Line 1* input field' },
217
+ address2_field: { accessibility_id: 'Address Line 2 input field' },
218
+ city_field: { accessibility_id: 'City* input field' },
219
+ state_region_field: { accessibility_id: 'State/Region input field' },
220
+ zip_code_field: { accessibility_id: 'Zip Code* input field' },
221
+ country_field: { accessibility_id: 'Country* input field' }
222
+ button :to_payment_button, { accessibility_id: 'To Payment button' }
223
+ end
405
224
 
406
- ### Adding Methods to your Page Object
407
225
 
408
- It is good practice for your Cucumber step definitions to call high level methods in your your **Page Object** instead of directly accessing
409
- and interacting with a page object's UI elements. You can add high level methods to your **Page Object** class definition for interacting with
410
- the UI to hide implementation details, as shown below:
226
+ ### Adding Methods to your ScreenObject
411
227
 
412
- class LoginPage < TestCentricity::PageObject
413
- trait(:page_name) { 'Login' }
414
- trait(:page_url) { '/sign_in' }
415
- trait(:page_locator) { 'body.login-body' }
416
-
417
- # Login page UI elements
418
- textfield :user_id_field, 'input#userName'
419
- textfield :password_field, 'input#password'
420
- button :login_button, 'button#login'
421
- checkbox :remember_checkbox, 'input#rememberUser'
422
- label :error_message_label, 'div#statusBar.login-error'
423
- link :forgot_password_link, 'a.forgotPassword'
424
-
425
- # log in to web app
426
- def login(user_id, password)
427
- user_id_field.set(user_id)
428
- password_field.set(password)
429
- login_button.click
430
- end
228
+ It is good practice for your Cucumber step definitions to call high level methods in your your `ScreenObject` instead of
229
+ directly accessing and interacting with a screen object's UI elements. You can add high level methods to your `ScreenObject`
230
+ class definition for interacting with the UI to hide implementation details, as shown below:
431
231
 
432
- def remember_me(state)
433
- remember_checkbox.set_checkbox_state(state)
434
- end
232
+ class LoginScreen < TestCentricity::ScreenObject
233
+ trait(:page_name) { 'Login' }
234
+ trait(:page_locator) { { accessibility_id: 'login screen' } }
235
+ trait(:page_url) { 'login' }
236
+
237
+ # Login screen UI elements
238
+ labels username_label: { accessibility_id: 'Username'},
239
+ password_label: { xpath: '(//XCUIElementTypeStaticText[@name="Password"])[1]'},
240
+ username_error: { accessibility_id: 'Username-error-message' },
241
+ password_error: { accessibility_id: 'Password-error-message' },
242
+ generic_error: { accessibility_id: 'generic-error-message' }
243
+ textfields username_field: { accessibility_id: 'Username input field' },
244
+ password_field: { accessibility_id: 'Password input field' }
245
+ button :login_button, { accessibility_id: 'Login button' }
435
246
 
436
- # verify Login page default UI state
437
247
  def verify_page_ui
248
+ super
438
249
  ui = {
439
- login_button => { :visible => true, :caption => 'LOGIN' },
440
- user_id_field => { :visible => true, :enabled => true },
441
- password_field => { :visible => true, :enabled => true, :value => '', :placeholder => 'Password' },
442
- remember_checkbox => { :exists => true, :enabled => true, :checked => false },
443
- forgot_password_link => { :visible => true, :caption => 'Forgot your password?' },
444
- error_message_label => { :visible => false }
445
- }
250
+ header_label => { visible: true, caption: 'Login' },
251
+ username_label => { visible: true, caption: 'Username' },
252
+ username_field => { visible: true, enabled: true },
253
+ password_label => { visible: true, caption: 'Password' },
254
+ password_field => { visible: true, enabled: true },
255
+ login_button => { visible: true, enabled: true, caption: 'Login' }
256
+ }
446
257
  verify_ui_states(ui)
447
- super
448
258
  end
449
- end
450
-
451
-
452
- class RegistrationPage < TestCentricity::PageObject
453
- trait(:page_name) { 'Registration' }
454
- trait(:page_url) { '/register' }
455
- trait(:page_locator) { 'body.registration' }
456
-
457
- # Registration page UI elements
458
- textfields first_name_field: 'input#firstName',
459
- last_name_field: 'input#lastName',
460
- email_field: 'input#email',
461
- phone_number_field: 'input#phone',
462
- address_field: 'input#streetAddress',
463
- city_field: 'input#city',
464
- post_code_field: 'input#postalCode',
465
- password_field: 'input#password',
466
- pword_confirm_field: 'input#passwordConfirmation'
467
- selectlists title_select: 'select#title',
468
- gender_select: 'select#gender',
469
- state_select: 'select#stateProvince'
470
- checkbox :email_opt_in_check, 'input#marketingEmailsOptIn'
471
- button :sign_up_button, 'button#registrationSignUp'
472
259
 
473
- # populate Registration page fields with profile data
474
- def enter_profile_data(profile)
475
- fields = { title_select => profile.title,
476
- first_name_field => profile.first_name,
477
- last_name_field => profile.last_name,
478
- gender_select => profile.gender,
479
- phone_number_field => profile.phone,
480
- email_field => profile.email,
481
- address_field => profile.address,
482
- city_field => profile.city,
483
- state_select => profile.state,
484
- post_code_field => profile.postal_code,
485
- password_field => profile.password,
486
- pword_confirm_field => profile.confirm_password
487
- }
260
+ def login(username, password)
261
+ fields = {
262
+ username_field => username,
263
+ password_field => password
264
+ }
488
265
  populate_data_fields(fields)
489
- sign_up_button.click
266
+ login_button.tap
267
+ end
268
+
269
+ def verify_entry_error(reason)
270
+ ui = case reason.gsub(/\s+/, '_').downcase.to_sym
271
+ when :invalid_password, :invalid_user
272
+ { generic_error => { visible: true, caption: 'Provided credentials do not match any user in this service.' } }
273
+ when :locked_account
274
+ { generic_error => { visible: true, caption: 'Sorry, this user has been locked out.' } }
275
+ when :no_username
276
+ { username_error => { visible: true, caption: 'Username is required' } }
277
+ when :no_password
278
+ { password_error => { visible: true, caption: 'Password is required' } }
279
+ else
280
+ raise "#{reason} is not a valid selector"
281
+ end
282
+ verify_ui_states(ui)
490
283
  end
491
284
  end
492
285
 
493
286
 
494
287
 
495
- Once your **Page Objects** have been instantiated, you can call your methods as shown below:
288
+ Once your `ScreenObject` has been instantiated, you can call your methods as shown below:
289
+
290
+ login_screen.login('snicklefritz', 'Pa55w0rd')
291
+ login_screen.verify_entry_error('invalid user')
496
292
 
497
- login_page.remember_me(true)
498
- login_page.user_id_field.set('snicklefritz', 'Pa55w0rd')
499
-
500
293
 
294
+ ## ScreenSections
501
295
 
502
- ## PageSection Objects
296
+ A `ScreenSection` is a collection of **UI Elements** that may appear in multiple locations on a screen, or on multiple screens
297
+ in an app. It is a collection of **UI Elements** that represent a conceptual area of functionality, like a navigation bar, a
298
+ search capability, or a menu. **UI Elements** and functional behavior are confined to the scope of a `ScreenSection` object.
503
299
 
504
- A **PageSection Object** is a collection of **UI Elements** that may appear in multiple locations on a page, or on multiple pages in a web
505
- app. It is a collection of **UI Elements** that represent a conceptual area of functionality, like a navigation bar, a search capability,
506
- or a menu. **UI Elements** and functional behavior are confined to the scope of a **PageSection Object**.
300
+ A `ScreenSection` may contain other `ScreenSection` objects.
507
301
 
508
- A **PageSection Object** may contain other **PageSection Objects**.
509
302
 
303
+ ### Defining a ScreenSection
510
304
 
511
- ### Defining a PageSection Object
305
+ Your `ScreenSection` class definitions should be contained within individual `.rb` files in the `features/support/<platform>/sections`
306
+ folder of your test automation project, where `<platform>` is typically `ios` or `android`. For each screen section in your app,
307
+ you will typically have to define two `ScreenSections` - one for iOS and the other for Android.
512
308
 
513
- Your **PageSection** class definitions should be contained within individual `.rb` files in the `features/support/sections` folder of
514
- your test automation project. You define new **PageSection Objects** as shown below:
309
+ my_automation_project
310
+ ├── config
311
+ ├── features
312
+ │ ├── step_definitions
313
+ │ ├── support
314
+ │ │ ├── android
315
+ | | | ├── screens
316
+ | | | └── sections
317
+ │ │ ├── ios
318
+ | | | ├── screens
319
+ | | | └── sections
320
+ │ │ ├── env.rb
321
+ │ │ └── hooks.rb
322
+ ├── Gemfile
323
+ └── README.md
515
324
 
516
- class SearchForm < TestCentricity::PageSection
325
+
326
+ You define a new `ScreenSection` as shown below:
327
+
328
+ class NavMenu < TestCentricity::ScreenSection
517
329
  end
518
330
 
519
331
 
520
- ### Adding Traits to a PageSection Object
332
+ ### Adding Traits to a ScreenSection
521
333
 
522
- A **PageSection Object** typically has a root node object that encapsulates a collection of **UI Elements**. The `section_locator` trait
334
+ A `ScreenSection` typically has a root node object that encapsulates a collection of `UIElements`. The `section_locator` trait
523
335
  specifies the CSS or Xpath expression that uniquely identifies that root node object.
524
336
 
525
- You define your page section's **Traits** as shown below:
337
+ You define your section's **Traits** as shown below:
526
338
 
527
- class SearchForm < TestCentricity::PageSection
528
- trait(:section_locator) { 'form#gnav-search' }
529
- trait(:section_name) { 'Search widget' }
339
+ class NavMenu < TestCentricity::ScreenSection
340
+ trait(:section_name) { 'Nav Menu' }
341
+ trait(:section_locator) { { xpath: '//XCUIElementTypeScrollView' } }
530
342
  end
531
343
 
532
344
 
533
- ### Adding UI Elements to your PageSection Object
345
+ ### Adding UI Elements to your ScreenSection
346
+
347
+ A `ScreenSection` is typically made up of UI elements like text fields, check boxes, switches, lists, buttons, etc. **UI Elements**
348
+ are added to your `ScreenSection` class definition as shown below:
349
+
350
+ class NavMenu < TestCentricity::ScreenSection
351
+ trait(:section_name) { 'Nav Menu' }
352
+ trait(:section_locator) { { xpath: '//XCUIElementTypeScrollView' } }
353
+
354
+ # Nav Menu UI elements
355
+ buttons close_button: { accessibility_id: 'close menu' },
356
+ webview_button: { accessibility_id: 'menu item webview' },
357
+ qr_code_button: { accessibility_id: 'menu item qr code scanner' },
358
+ geo_location_button: { accessibility_id: 'menu item geo location' },
359
+ drawing_button: { accessibility_id: 'menu item drawing' },
360
+ report_a_bug_button: { accessibility_id: 'menu item report a bug' },
361
+ about_button: { accessibility_id: 'menu item about' },
362
+ reset_app_button: { accessibility_id: 'menu item reset app' },
363
+ biometrics_button: { accessibility_id: 'menu item biometrics' },
364
+ log_in_button: { accessibility_id: 'menu item log in' },
365
+ log_out_button: { accessibility_id: 'menu item log out' },
366
+ api_calls_button: { accessibility_id: 'menu item api calls' },
367
+ sauce_video_button: { accessibility_id: 'menu item sauce bot video' }
368
+ end
534
369
 
535
- Page sections are typically made up of UI elements like text fields, check boxes, combo boxes, radio buttons, tables, lists, buttons, etc.
536
- **UI Elements** are added to your **PageSection** class definition as shown below:
537
370
 
538
- class SearchForm < TestCentricity::PageSection
539
- trait(:section_locator) { 'form#gnav-search' }
540
- trait(:section_name) { 'Search widget' }
541
-
542
- # Search Form UI elements
543
- textfield :search_field, 'input#search-query'
544
- button :search_button, 'button[type=submit]'
545
- end
371
+ ### Adding Methods to your ScreenSection
546
372
 
373
+ You can add methods to your `ScreenSection` class definition, as shown below:
547
374
 
548
- ### Adding Methods to your PageSection Object
375
+ class NavMenu < TestCentricity::ScreenSection
376
+ trait(:section_name) { 'Nav Menu' }
377
+ trait(:section_locator) { { xpath: '//XCUIElementTypeScrollView' } }
549
378
 
550
- You can add high level methods to your **PageSection** class definition, as shown below:
379
+ # Nav Menu UI elements
380
+ buttons close_button: { accessibility_id: 'close menu' },
381
+ webview_button: { accessibility_id: 'menu item webview' },
382
+ qr_code_button: { accessibility_id: 'menu item qr code scanner' },
383
+ geo_location_button: { accessibility_id: 'menu item geo location' },
384
+ drawing_button: { accessibility_id: 'menu item drawing' },
385
+ report_a_bug_button: { accessibility_id: 'menu item report a bug' },
386
+ about_button: { accessibility_id: 'menu item about' },
387
+ reset_app_button: { accessibility_id: 'menu item reset app' },
388
+ biometrics_button: { accessibility_id: 'menu item biometrics' },
389
+ log_in_button: { accessibility_id: 'menu item log in' },
390
+ log_out_button: { accessibility_id: 'menu item log out' },
391
+ api_calls_button: { accessibility_id: 'menu item api calls' },
392
+ sauce_video_button: { accessibility_id: 'menu item sauce bot video' }
551
393
 
552
- class SearchForm < TestCentricity::PageSection
553
- trait(:section_locator) { 'form#gnav-search' }
554
- trait(:section_name) { 'Search widget' }
555
-
556
- # Search Form UI elements
557
- textfield :search_field, 'input#search-query'
558
- button :search_button, 'button[type=submit]'
394
+ def verify_ui
395
+ ui = {
396
+ self => { visible: true },
397
+ close_button => { visible: true, enabled: true },
398
+ webview_button => { visible: true, enabled: true, caption: 'Webview' },
399
+ qr_code_button => { visible: true, enabled: true, caption: 'QR Code Scanner' },
400
+ geo_location_button => { visible: true, enabled: true, caption: 'Geo Location' },
401
+ drawing_button => { visible: true, enabled: true, caption: 'Drawing' },
402
+ report_a_bug_button => { visible: true, enabled: true, caption: 'Report A Bug' },
403
+ about_button => { visible: true, enabled: true, caption: 'About' },
404
+ reset_app_button => { visible: true, enabled: true, caption: 'Reset App State' },
405
+ biometrics_button => { visible: true, enabled: true, caption: 'FaceID' },
406
+ log_in_button => { visible: true, enabled: true, caption: 'Log In' },
407
+ log_out_button => { visible: true, enabled: true, caption: 'Log Out' },
408
+ api_calls_button => { visible: true, enabled: true, caption: 'Api Calls' },
409
+ sauce_video_button => { visible: true, enabled: true, caption: 'Sauce Bot Video' }
410
+ }
411
+ verify_ui_states(ui)
412
+ end
559
413
 
560
- def search_for(value)
561
- search_field.set(value)
562
- search_button.click
414
+ def close
415
+ close_button.click
416
+ self.wait_until_hidden(3)
417
+ end
418
+
419
+ def verify_closed
420
+ verify_ui_states(close_button => { visible: false })
563
421
  end
564
422
  end
565
423
 
566
424
 
567
- ### Adding PageSection Objects to your Page Object
425
+ ### Adding ScreenSections to your ScreenObject
568
426
 
569
- You add a **PageSection Object** to its associated **Page Object** as shown below:
427
+ You add a `ScreenSection` to its associated `ScreenObject` as shown below:
570
428
 
571
- class HomePage < TestCentricity::PageObject
572
- trait(:page_name) { 'Home' }
573
- trait(:page_url) { '/dashboard' }
574
- trait(:page_locator) { 'body.dashboard' }
575
-
576
- # Home page Section Objects
577
- section :search_form, SearchForm
429
+ class BaseAppScreen < TestCentricity::ScreenObject
430
+ # Base App screen UI elements
431
+ label :header_label, { accessibility_id: 'container header' }
432
+ sections nav_bar: NavBar,
433
+ nav_menu: NavMenu
578
434
  end
579
435
 
580
- Once your **Page Object** has been instantiated, you can call its **PageSection** methods as shown below:
436
+ Once your `ScreenObject` has been instantiated, you can call its `ScreenSection` methods as shown below:
581
437
 
582
- home_page.search_form.search_for('ocarina')
583
-
584
-
438
+ base_screen.nav_menu.verify_ui
585
439
 
586
- ## UI Elements
587
440
 
588
- **Page Objects** and **PageSection Objects** are typically made up of **UI Element** like text fields, check boxes, combo boxes, radio buttons,
589
- tables, lists, buttons, etc. **UI Elements** are declared and instantiated within the class definition of the **Page Object** or **PageSection
590
- Object** in which they are contained. With TestCentricity Web, all UI elements are based on the **UIElement** class.
441
+ ## AppUIElements
591
442
 
443
+ Native app `ScreenObjects` and `ScreenSections` are typically made up of **UI Element** like text fields, switches, lists,
444
+ buttons, etc. **UI Elements** are declared and instantiated within the class definition of the `ScreenObject` or `ScreenSection`
445
+ in which they are contained. With TestCentricity, all native app screen UI elements are based on the `AppUIElement` class.
592
446
 
593
- ### Declaring and Instantiating UI Element
594
447
 
595
- Single **UIElement** declarations have the following format:
596
-
597
- elementType :element Name, locator
448
+ ### Declaring and Instantiating AppUIElements
598
449
 
599
- * The `element name` is the unique name that you will use to refer to the UI element and is specified as a symbol.
600
- * The `locator` is the CSS or XPath attribute that uniquely and unambiguously identifies the UI element.
450
+ Single `AppUIElement` declarations have the following format:
601
451
 
602
- Multiple **UIElement** declarations for a collection of elements of the same type can be performed by passing a hash table containing the
603
- names and locators of each individual element.
452
+ elementType :elementName, { locator_strategy, locator_identifier }
604
453
 
605
- ### Example UI Element Declarations
454
+ * The `elementName` is the unique name that you will use to refer to the UI element and is specified as a `Symbol`.
455
+ * The `locator_strategy` specifies the [selector strategy](https://appium.io/docs/en/commands/element/find-elements/index.html#selector-strategies)
456
+ that Appium will use to find the `AppUIElement`. Valid selectors are `accessibility_id:`, `id:`, `name:`, `class:`, `xpath:`,
457
+ `predicate:` (iOS only), `class_chain:` (iOS only), and `css:` (WebViews in hybrid apps only).
458
+ * The `locator_identifier` is the value or attribute that uniquely and unambiguously identifies the `AppUIElement`.
606
459
 
607
- Supported **UI Element** elementTypes and their declarations have the following format:
460
+ Multiple `AppUIElement` declarations for a collection of elements of the same type can be performed by passing a hash table
461
+ containing the names and locators of each individual element.
462
+
463
+ ### Example AppUIElement Declarations
464
+
465
+ Supported `AppUIElement` elementTypes and their declarations have the following format:
608
466
 
609
467
  *Single element declarations:*
610
468
 
611
- class SamplePage < TestCentricity::PageObject
612
-
613
- button :button_name, locator
614
- textfield :field_name, locator
615
- checkbox :checkbox_name, locator
616
- radio :radio_button_name, locator
617
- label :label_name, locator
618
- link :link_name, locator
619
- selectlist :select_name, locator
620
- list :list_name, locator
621
- table :table_name, locator
622
- image :image_name, locator
623
- filefield :filefield_name, locator
624
-
469
+ class SampleScreen < TestCentricity::ScreenObject
470
+ button :button_name, { locator_strategy, locator_identifier }
471
+ textfield :field_name, { locator_strategy, locator_identifier }
472
+ checkbox :checkbox_name, { locator_strategy, locator_identifier }
473
+ label :label_name, { locator_strategy, locator_identifier }
474
+ selectlist :select_name, { locator_strategy, locator_identifier }
475
+ list :list_name, { locator_strategy, locator_identifier }
476
+ image :image_name, { locator_strategy, locator_identifier }
477
+ switch :switch_name, { locator_strategy, locator_identifier }
478
+ element :element_name, { locator_strategy, locator_identifier }
479
+ alert :alert_name, { locator_strategy, locator_identifier }
625
480
  end
626
-
481
+
627
482
  *Multiple element declarations:*
628
483
 
629
- class SamplePage < TestCentricity::PageObject
630
-
631
- buttons button_1_name: locator,
632
- button_2_name: locator,
633
- button_X_name: locator
634
- textfields field_1_name: locator,
635
- field_2_name: locator,
636
- field_X_name: locator
637
- checkboxes check_1_name: locator,
638
- check_2_name: locator,
639
- check_X_name: locator
640
- radios radio_1_name: locator,
641
- radio_X_name: locator
642
- labels label_1_name: locator,
643
- label_X_name: locator
644
- links link_1_name: locator,
645
- link_X_name: locator
646
- selectlists selectlist_1_name: locator,
647
- selectlist_X_name: locator
648
- lists list_1_name: locator,
649
- list_X_name: locator
650
- tables table_1_name: locator,
651
- table_X_name: locator
652
- images image_1_name: locator,
653
- image_X_name: locator
654
- filefields filefield_1_name: locator,
655
- filefield_X_name: locator
656
-
484
+ class SampleScreen < TestCentricity::ScreenObject
485
+ buttons button_1_name: { locator_strategy, locator_identifier },
486
+ button_2_name: { locator_strategy, locator_identifier },
487
+ button_X_name: { locator_strategy, locator_identifier }
488
+ textfields field_1_name: { locator_strategy, locator_identifier },
489
+ field_2_name: { locator_strategy, locator_identifier },
490
+ field_X_name: { locator_strategy, locator_identifier }
491
+ checkboxes check_1_name: { locator_strategy, locator_identifier },
492
+ check_2_name: { locator_strategy, locator_identifier },
493
+ check_X_name: { locator_strategy, locator_identifier }
494
+ labels label_1_name: { locator_strategy, locator_identifier },
495
+ label_X_name: { locator_strategy, locator_identifier }
496
+ images image_1_name: { locator_strategy, locator_identifier },
497
+ image_X_name: { locator_strategy, locator_identifier }
657
498
  end
658
499
 
659
-
660
- Refer to the Class List documentation for the **PageObject** and **PageSection** classes for details on the class methods used for declaring
661
- and instantiating **UI Elements**. Examples of UI element declarations can be found in the ***Adding UI Elements to your Page Object*** and
662
- ***Adding UI Elements to your PageSection Object*** sections above.
500
+ Refer to the Class List documentation for the `ScreenObject` and `ScreenSection` classes for details on the class methods used
501
+ for declaring and instantiating `AppUIElements`. Examples of UI element declarations can be found in the ***Adding UI Elements
502
+ to your ScreenObject*** and ***Adding UI Elements to your ScreenSection*** sections above.
663
503
 
664
504
 
665
- ### UIElement Inherited Methods
505
+ ### AppUIElement Inherited Methods
666
506
 
667
- With TestCentricity, all UI elements are based on the **UIElement** class, and inherit the following methods:
507
+ With TestCentricity, all native app UI elements are based on the `AppUIElement` class, and inherit the following methods:
668
508
 
669
509
  **Action methods:**
670
510
 
671
511
  element.click
672
- element.double_click
673
- element.right_click
674
- element.click_at(x, y)
675
- element.hover
676
- element.drag_by(right_offset, down_offset)
677
- element.drag_and_drop(target, right_offset, down_offset)
512
+ element.tap
513
+ element.double_tap
514
+ element.hover_at(x, y)
515
+ element.scroll(direction)
516
+ element.swipe(direction)
678
517
 
679
518
  **Object state methods:**
680
519
 
@@ -683,15 +522,14 @@ With TestCentricity, all UI elements are based on the **UIElement** class, and i
683
522
  element.hidden?
684
523
  element.enabled?
685
524
  element.disabled?
686
- element.displayed?
687
- element.get_value
525
+ element.selected?
526
+ element.tag_name
688
527
  element.width
689
528
  element.height
690
- element.x
691
- element.y
529
+ element.x_loc
530
+ element.y_loc
692
531
  element.get_attribute(attrib)
693
- element.get_native_attribute(attrib)
694
-
532
+
695
533
  **Waiting methods:**
696
534
 
697
535
  element.wait_until_exists(seconds)
@@ -702,79 +540,260 @@ With TestCentricity, all UI elements are based on the **UIElement** class, and i
702
540
  element.wait_until_value_changes(seconds)
703
541
 
704
542
 
705
- ## Instantiating your Page Objects
543
+ ### Populating your ScreenObject or ScreenSection with data
706
544
 
707
- Before you can call the methods in your **Page Objects** and **PageSection Objects**, you must instantiate the **Page Objects** of your
708
- web application, as well as create instance variables which can be used when calling a **Page Objects** methods from your step definitions.
709
- There are several ways to instantiate your **Page Objects**.
545
+ A typical automated test may be required to perform the entry of test data by interacting with various `AppUIElements` on your
546
+ `ScreenObject` or `ScreenSection`. This data entry can be performed using the various object action methods (listed above) for
547
+ each `AppUIElement` that needs to be interacted with.
710
548
 
711
- One common implementation is shown below:
549
+ The `ScreenObject.populate_data_fields` and `ScreenSection.populate_data_fields` methods support the entry of test data into a
550
+ collection of `AppUIElements`. The `populate_data_fields` method accepts a hash containing key/hash pairs of `AppUIElements`
551
+ and their associated data to be entered. Data values must be in the form of a `String` for `textfield` controls. For `checkbox`
552
+ controls, data must either be a `Boolean` or a `String` that evaluates to a `Boolean` value (Yes, No, 1, 0, true, false).
712
553
 
713
- module WorldPages
714
- def login_page
715
- @login_page ||= LoginPage.new
716
- end
717
-
718
- def home_page
719
- @home_page ||= HomePage.new
720
- end
721
-
722
- def registration_page
723
- @registration_page ||= RegistrationPage.new
724
- end
725
-
726
- def search_results_page
727
- @search_results_page ||= SearchResultsPage.new
728
- end
554
+ The `populate_data_fields` method verifies that data attributes associated with each `AppUIElement` is not `nil` or `empty`
555
+ before attempting to enter data into the `AppUIElement`.
556
+
557
+ The optional `wait_time` parameter is used to specify the time (in seconds) to wait for each `AppUIElement` to become viable
558
+ for data entry (the `AppUIElement` must be visible and enabled) before entering the associated data value. This option is
559
+ useful in situations where entering data, or setting the state of a `AppUIElement` might cause other `AppUIElements` to become
560
+ visible or active. Specifying a wait_time value ensures that the subsequent `AppUIElements` will be ready to be interacted with
561
+ as states are changed. If the wait time is `nil`, then the wait time will be 5 seconds.
562
+
563
+ def enter_data(user_data)
564
+ fields = {
565
+ first_name_field => user_data.first_name,
566
+ last_name_field => user_data.last_name,
567
+ email_field => user_data.email,
568
+ phone_number_field => user_data.phone_number
569
+ }
570
+ populate_data_fields(fields, wait_time = 2)
729
571
  end
730
-
731
- World(WorldPages)
732
572
 
733
- The `WorldPages` module above can be defined in your `env.rb` file, or you can define it in a separate `world_pages.rb` file in the
734
- `features/support` folder.
735
573
 
736
- While this approach is effective for small web applications with only a few pages (and hence few **Page Objects**), it quickly becomes
737
- cumbersome to manage if your web application has dozens of **Page Objects** that need to be instantiated and managed.
574
+ ### Verifying AppUIElements on your ScreenObject or ScreenSection
738
575
 
739
- ### Using the PageManager
576
+ A typical automated test executes one or more interactions with the user interface, and then performs a validation to verify
577
+ whether the expected state of the UI has been achieved. This verification can be performed using the various object state methods
578
+ (listed above) for each `AppUIElement` that requires verification. Depending on the complexity and number of `AppUIElements` to
579
+ be verified, the code required to verify the presence of `AppUIElements` and their correct states can become cumbersome.
580
+
581
+ The `ScreenObject.verify_ui_states` and `ScreenSection.verify_ui_states` methods support the verification of multiple properties
582
+ of multiple UI elements on a `ScreenObject` or `ScreenSection`. The `verify_ui_states` method accepts a hash containing key/hash
583
+ pairs of UI elements and their properties or attributes to be verified.
584
+
585
+ ui = {
586
+ object1 => { property: state },
587
+ object2 => { property: state, property: state },
588
+ object3 => { property: state }
589
+ }
590
+ verify_ui_states(ui)
591
+
592
+ The `verify_ui_states` method queues up any exceptions that occur while verifying each object's properties until all `AppUIElements`
593
+ and their properties have been checked, and then posts any exceptions encountered upon completion. Posted exceptions include a
594
+ screenshot of the screen where expected results did not match actual results.
595
+
596
+ The `verify_ui_states` method supports the following property/state pairs:
597
+
598
+ **All Objects:**
599
+
600
+ :exists Boolean
601
+ :enabled Boolean
602
+ :disabled Boolean
603
+ :visible Boolean
604
+ :hidden Boolean
605
+ :width Integer
606
+ :height Integer
607
+ :x Integer
608
+ :y Integer
609
+ :class String
610
+ :value or :caption String
611
+ :attribute Hash
612
+
613
+ **Text Fields:**
614
+
615
+ :placeholder String
616
+ :readonly Boolean (WebViews only)
617
+ :maxlength Integer (WebViews only)
618
+
619
+ **Checkboxes:**
620
+
621
+ :checked Boolean
622
+
623
+ #### Comparison States
624
+
625
+ The `verify_ui_states` method supports comparison states using property/comparison state pairs:
626
+
627
+ object => { property: { comparison_state: value } }
628
+
629
+ Comparison States:
630
+
631
+ :lt or :less_than Integer or String
632
+ :lt_eq or :less_than_or_equal Integer or String
633
+ :gt or :greater_than Integer or String
634
+ :gt_eq or :greater_than_or_equal Integer or String
635
+ :starts_with String
636
+ :ends_with String
637
+ :contains String
638
+ :not_contains or :does_not_contain Integer or String
639
+ :not_equal Integer, String, or Boolean
640
+
641
+
642
+ #### I18n Translation Validation
643
+
644
+ The `verify_ui_states` method also supports I18n string translations using property/I18n key name pairs:
645
+
646
+ object => { property: { translate_key: 'name of key in I18n compatible .yml file' } }
647
+
648
+ **I18n Translation Keys:**
649
+
650
+ :translate String
651
+ :translate_upcase String
652
+ :translate_downcase String
653
+ :translate_capitalize String
654
+ :translate_titlecase String
655
+
656
+ The example below depicts the usage of the `verify_ui_states` method to verify that the captions for menu items are correctly
657
+ translated.
658
+
659
+ def verify_menu
660
+ ui = {
661
+ account_settings_item => { visible: true, caption: { translate: 'Header.settings.account' } },
662
+ help_item => { visible: true, caption: { translate: 'Header.settings.help' } },
663
+ feedback_item => { visible: true, caption: { translate: 'Header.settings.feedback' } },
664
+ legal_item => { visible: true, caption: { translate: 'Header.settings.legal' } },
665
+ institution_item => { visible: true, caption: { translate: 'Header.settings.institution' } },
666
+ configurations_item => { visible: true, caption: { translate: 'Header.settings.configurations' } },
667
+ contact_us_item => { visible: true, caption: { translate: 'Header.settings.contact' } },
668
+ downloads_item => { visible: true, caption: { translate: 'Header.settings.downloads' } }
669
+ }
670
+ verify_ui_states(ui)
671
+ end
672
+
673
+ Each supported language/locale combination has a corresponding `.yml` file. I18n `.yml` file naming convention uses
674
+ [ISO-639 language codes and ISO-3166 country codes](https://docs.oracle.com/cd/E13214_01/wli/docs92/xref/xqisocodes.html).
675
+ For example:
676
+
677
+ | Language (Country) | File name |
678
+ |-----------------------|-----------|
679
+ | English | en.yml |
680
+ | English (Canada) | en-CA.yml |
681
+ | French (Canada) | fr-CA.yml |
682
+ | French | fr.yml |
683
+ | Spanish | es.yml |
684
+ | German | de.yml |
685
+ | Portuguese (Brazil) | pt-BR.yml |
686
+ | Portuguese (Portugal) | pt-PT.yml |
687
+
688
+ I18n `.yml` files contain key/value pairs representing the name of a translated string (key) and the string value.
689
+
690
+ Baseline translation strings are stored in `.yml` files in the `config/locales/` folder.
691
+
692
+ my_automation_project
693
+ ├── config
694
+ │ ├── locales
695
+ │ │ ├── en.yml
696
+ │ │ ├── es.yml
697
+ │ │ ├── fr.yml
698
+ │ │ ├── fr-CA.yml
699
+ │ │ └── en-AU.yml
700
+ │ ├── test_data
701
+ │ └── cucumber.yml
702
+ ├── features
703
+ ├── Gemfile
704
+ └── README.md
705
+
706
+
707
+ ## Instantiating ScreenObjects and Utilizing the PageManager
708
+
709
+ Before you can call the methods in your `ScreenObjects` and `ScreenSections`, you must instantiate the `ScreenObjects` of your
710
+ native mobile application, as well as create instance variables which can be used when calling `ScreenObject` methods from
711
+ your step definitions or specs.
712
+
713
+ The `PageManager` class provides methods for supporting the instantiation and management of `ScreenObjects` and `PageObjects`.
714
+ In the code example below, the `page_objects` method contains a hash table of your `ScreenObject` instances and their associated
715
+ `ScreenObject` classes to be instantiated by `PageManager`:
740
716
 
741
- The **PageManager** class provides methods for supporting the instantiation and management of **Page Objects**. In the code example below,
742
- the `page_objects` method contains a hash table of your **Page Object** instances and their associated **Page Object** class names
743
- to be instantiated by **PageManager**:
744
-
745
717
  module WorldPages
746
718
  def page_objects
747
- { :login_page => LoginPage,
748
- :home_page => HomePage,
749
- :registration_page => RegistrationPage,
750
- :search_results_page => SearchResultsPage,
751
- :products_grid_page => ProductsCollectionPage,
752
- :product_detail_page => ProductDetailPage,
753
- :shopping_basket_page => ShoppingBasketPage,
754
- :payment_method_page => PaymentMethodPage,
755
- :confirm_purchase_page => PurchaseConfirmationPage,
756
- :my_account_page => MyAccountPage,
757
- :my_order_history_page => MyOrderHistoryPage,
758
- :my_ship_to_addresses_page => MyShipToAddressesPage,
759
- :terms_conditions_page => TermsConditionsPage,
760
- :privacy_policy_page => PrivacyPolicyPage,
761
- :faqs_page => FAQsPage,
762
- :contact_us_page => ContactUsPage
719
+ {
720
+ login_screen: LoginScreen,
721
+ registration_screen: RegistrationScreen,
722
+ search_results_screen: SearchResultsScreen,
723
+ products_grid_screen: ProductsCollectionScreen,
724
+ product_detail_screen: ProductDetailScreen,
725
+ shopping_basket_screen: ShoppingBasketScreen,
726
+ payment_method_screen: PaymentMethodScreen,
727
+ confirm_purchase_screen: PurchaseConfirmationScreen,
728
+ my_account_screen: MyAccountScreen,
729
+ my_order_history_screen: MyOrderHistoryScreen
763
730
  }
764
731
  end
765
732
  end
766
733
 
767
734
  World(WorldPages)
768
-
735
+
736
+
769
737
  The `WorldPages` module above should be defined in the `world_pages.rb` file in the `features/support` folder.
770
738
 
771
- Include the code below in your `env.rb` file to ensure that your **Page Objects** are instantiated before your Cucumber scenarios are
772
- executed:
773
-
739
+ Include the code below in your `env.rb` file to ensure that your `ScreenObjects` are instantiated before your Cucumber scenarios
740
+ are executed:
741
+
774
742
  include WorldPages
775
743
  WorldPages.instantiate_page_objects
776
-
777
- **NOTE:** If you intend to use the **PageManager**, you must define a `page_name` trait for each of the **Page Objects** to be registered.
744
+
745
+ **NOTE:** If you intend to use the `PageManager`, you must define a `page_name` trait for each of the `ScreenObjects` to be registered.
746
+
747
+
748
+ ### Instantiating ScreenObjects and PageObjects for a combined native iOS/Android app and web app
749
+
750
+ If your native mobile apps share feature parity with a responsive desktop/mobile web UI, you can define iOS and Android specific
751
+ `ScreenObjects` and the corresponding web specific `PageObjects`. If you use the `PLATFORM` Environment Variable to specify the target
752
+ test platform (`ios`, `android`, or `web`) at test run time, the following implementation of the `page_objects` method will ensure
753
+ instantiation of the correct `ScreenObjects` or `PageObjects` at run time:
754
+
755
+ module WorldPages
756
+ def page_objects
757
+ case ENV['PLATFORM'].downcase.to_sym
758
+ when :ios, :android
759
+ native_app_screen_objects
760
+ when :web
761
+ web_page_objects
762
+ end
763
+ end
764
+ end
765
+
766
+ def native_app_screen_objects
767
+ {
768
+ login_screen: LoginScreen,
769
+ registration_screen: RegistrationScreen,
770
+ search_results_screen: SearchResultsScreen,
771
+ products_grid_screen: ProductsCollectionScreen,
772
+ product_detail_screen: ProductDetailScreen,
773
+ shopping_basket_screen: ShoppingBasketScreen,
774
+ payment_method_screen: PaymentMethodScreen,
775
+ confirm_purchase_screen: PurchaseConfirmationScreen,
776
+ my_account_screen: MyAccountScreen,
777
+ my_order_history_screen: MyOrderHistoryScreen
778
+ }
779
+ end
780
+
781
+ def web_page_objects
782
+ {
783
+ login_screen: LoginPage,
784
+ registration_screen: RegistrationPage,
785
+ search_results_screen: SearchResultsPage,
786
+ products_grid_screen: ProductsCollectionPage,
787
+ product_detail_screen: ProductDetailPage,
788
+ shopping_basket_screen: ShoppingBasketPage,
789
+ payment_method_screen: PaymentMethodPage,
790
+ confirm_purchase_screen: PurchaseConfirmationPage,
791
+ my_account_screen: MyAccountPage,
792
+ my_order_history_screen: MyOrderHistoryPage
793
+ }
794
+ end
795
+
796
+ World(WorldPages)
778
797
 
779
798
 
780
799
  ### Leveraging the PageManager in your Cucumber tests
@@ -782,914 +801,449 @@ executed:
782
801
  Many Cucumber based automated tests suites include scenarios that verify that web pages are correctly loaded, displayed, or can be
783
802
  navigated to by clicking associated links. One such Cucumber navigation scenario is displayed below:
784
803
 
785
- Scenario Outline: Verify Home page navigation links
786
- Given I am on the Home page
787
- When I click the <page> navigation link
788
- Then I expect the <page> page to be correctly displayed
789
-
804
+ Scenario Outline: Verify screen navigation features
805
+ Given I am on the Products screen
806
+ When I tap the <screen_name> navigation menu item
807
+ Then I expect the <screen_name> screen to be correctly displayed
808
+
790
809
  Examples:
791
- |page |
792
- |Registration |
793
- |My Account |
794
- |Terms & Conditions |
795
- |Privacy Policy |
796
- |FAQs |
797
- |Contact Us |
798
-
799
- In the above example, the step definitions associated with the 3 steps might be implemented using a page_dispatcher method using a
800
- `case` statement to parse the `page` parameter as in the example below:
801
-
802
- Given(/^I am on the ([^\"]*) page$/) do |page_name|
803
- target_page = page_dispatcher(page_name)
810
+ |screen_name |
811
+ |Registration |
812
+ |Shopping Basket |
813
+ |My Account |
814
+ |My Order History |
815
+
816
+ In the above example, the step definitions associated with the 3 steps can be implemented using the `PageManager.find_page` method
817
+ to match the specified `screen_name` argument with the corresponding `ScreenObject` as shown below:
818
+
819
+ include TestCentricity
820
+
821
+ When(/^I (?:load|am on) the (.*) (?:page|screen)$/) do |screen_name|
822
+ # find and load the specified target page/screen
823
+ target_page = PageManager.find_page(screen_name)
804
824
  target_page.load_page
805
825
  end
806
826
 
807
- When(/^I click the ([^\"]*) navigation link$/) do |link_name|
808
- target_page = page_dispatcher(link_name)
827
+
828
+ When(/^I (?:click|tap) the ([^\"]*) navigation menu item$/) do |screen_name|
829
+ # find and navigate to the specified target page/screen
830
+ target_page = PageManager.find_page(screen_name)
809
831
  target_page.navigate_to
810
832
  end
811
833
 
812
- Then(/^I expect the ([^\"]*) page to be correctly displayed$/) do |page_name|
813
- target_page = page_dispatcher(page_name)
834
+
835
+ Then(/^I expect the (.*) (?:page|screen) to be correctly displayed$/) do |screen_name|
836
+ # find and verify that the specified target page/screen is loaded
837
+ target_page = PageManager.find_page(screen_name)
814
838
  target_page.verify_page_exists
839
+ # verify that target page/screen is correctly displayed
815
840
  target_page.verify_page_ui
816
841
  end
817
-
818
- # this method takes a page name as a parameter and returns an instance of the associated Page Object
819
- def page_dispatcher(page_name)
820
- case page_name
821
- when 'Registration'
822
- page = registration_page
823
- when 'My Account'
824
- page = my_account_page
825
- when 'Terms & Conditions'
826
- page = terms_conditions_page
827
- when 'Privacy Policy'
828
- page = privacy_policy_page
829
- when 'Contact Us'
830
- page = contact_us_page
831
- when 'FAQs'
832
- page = faqs_page
833
- end
834
- raise "No page object defined for page named '#{page_name}'" unless page
835
- page
836
- end
837
842
 
838
843
 
839
- While this approach may be effective for small web applications with only a few pages (and hence few **Page Objects**), it quickly becomes
840
- cumbersome to manage if your web application has dozens of **Page Objects** that need to be managed.
841
844
 
842
- The **PageManager** class provides a `find_page` method that replaces the cumbersome and difficult to maintain `case` statement used in the
843
- above example. The **PageManager** `current_page` method allows you to set or get an instance of the currently active Page Object.
845
+ ## Connecting to a Mobile Simulator or Device
844
846
 
845
- To use these **PageManager** methods, include the step definitions and code below in a `page_steps.rb` or `generic_steps.rb` file in the
846
- `features/step_definitions` folder:
847
+ The `AppiumConnect.initialize_appium` method configures the appropriate Appium capabilities required to establish a connection
848
+ with a locally or cloud hosted target iOS or Android simulator or real device.
847
849
 
848
- include TestCentricity
849
-
850
- Given(/^I am on the ([^\"]*) page$/) do |page_name|
851
- target_page = page_dispatcher(page_name)
852
- target_page.load_page if target_page
853
- # let PageManager store an instance of the current page object
854
- PageManager.current_page = target_page
855
- end
856
-
857
- When(/^I click the ([^\"]*) navigation link$/) do |link_name|
858
- target_page = page_dispatcher(link_name)
859
- target_page.navigate_to if target_page
860
- end
861
-
862
- Then(/^I expect to see the ([^\"]*) page$/) do |page_name|
863
- target_page = page_dispatcher(page_name)
864
- target_page.verify_page_exists if target_page
865
- # let PageManager store an instance of the current page object
866
- PageManager.current_page = target_page
867
- end
868
-
869
- Then(/^I expect the ([^\"]*) page to be correctly displayed$/) do |page_name|
870
- target_page = page_dispatcher(page_name)
871
- target_page.verify_page_exists
872
- target_page.verify_page_ui
873
- # let PageManager store an instance of the current page object
874
- PageManager.current_page = target_page
850
+
851
+ ### Starting and stopping Appium Server
852
+
853
+ The Appium server must be running prior to invoking Cucumber to run your features/scenarios on locally hosted mobile simulators
854
+ or physical device. To programmatically control the starting and stopping of Appium server with the execution of your automated
855
+ tests, place the code shown below into your `hooks.rb` file.
856
+
857
+ BeforeAll do
858
+ # start Appium Server if command line option was specified and target browser is mobile simulator or device
859
+ if ENV['APPIUM_SERVER'] == 'run' && Environ.driver == :appium
860
+ end
875
861
  end
876
862
 
877
- # this method takes a page name as a parameter and returns an instance of the associated Page Object
878
- def page_dispatcher(page_name)
879
- page = PageManager.find_page(page_name)
880
- raise "No page object defined for page named '#{page_name}'" unless page
881
- page
863
+ AfterAll do
864
+ # terminate Appium Server if command line option was specified and target browser is mobile simulator or device
865
+ if ENV['APPIUM_SERVER'] == 'run' && Environ.driver == :appium && $server.running?
866
+ $server.stop
867
+ end
882
868
  end
883
869
 
884
870
 
871
+ The `APPIUM_SERVER` environment variable must be set to `run` in order to programmatically start and stop Appium server. This can be
872
+ set by adding the following to your `cucumber.yml` file and including `-p run_appium` in your command line when starting your Cucumber
873
+ test suite(s):
874
+
875
+ run_appium: APPIUM_SERVER=run
876
+
885
877
 
886
- ## Connecting to a Web Browser
887
-
888
- The `TestCentricity::WebDriverConnect.initialize_web_driver` method configures the appropriate selenium-webdriver capabilities required to establish a
889
- connection with a target web browser, and sets the base host URL of the web site you are running your tests against.
890
-
891
- The `TestCentricity::WebDriverConnect.initialize_web_driver` method accepts a single optional parameter - the base host URL. Cucumber **Environment
892
- Variables** are used to specify the target local or remote web browser, and the various webdriver capability parameters required to configure
893
- the connection.
894
-
895
-
896
- ### Locally hosted desktop web browser
897
-
898
- For locally hosted desktop web browsers running on macOS (OS X) or Windows platforms, the `WEB_BROWSER` Environment Variable must be set to one of the
899
- values from the table below:
900
-
901
- `WEB_BROWSER` | **Desktop Platform**
902
- --------------|----------------
903
- `firefox` | macOS (OS X) or Windows
904
- `chrome` | macOS (OS X) or Windows
905
- `safari` | macOS (OS X) only
906
- `ie` | Windows only
907
- `poltergeist` | macOS (OS X) or Windows
908
-
909
- To set the size of a desktop browser window, you set the `BROWSER_SIZE` Environment Variable to the desired width and height in pixels as shown below:
910
-
911
- BROWSER_SIZE=1600,1000
912
-
913
- To maximize a desktop browser window, you set the `BROWSER_SIZE` Environment Variable to 'max' as shown below:
914
-
915
- BROWSER_SIZE=max
916
-
917
-
918
- ### Locally hosted emulated mobile web browser
919
-
920
- You can run your tests against mobile device browsers that are emulated within a locally hosted instance of a Chrome desktop browser on OS X or
921
- Windows. The specified mobile browser's user agent, CSS screen dimensions, and default screen orientation will be automatically set within the
922
- local Chrome browser instance. You may even specify the emulated device's screen orientation. For locally hosted emulated mobile web browsers,
923
- the `WEB_BROWSER` Environment Variable must be set to one of the values from the table below:
924
-
925
- `WEB_BROWSER` | `HOST_BROWSER` | **CSS Screen Dimensions** | **Default Orientation** | **OS Version**
926
- ----------------------|----------------------|-----------|----------|---------
927
- `ipad` |`chrome` |1024 x 768 |landscape |iOS 10
928
- `ipad_pro` |`chrome` |1366 x 1024|landscape |iOS 11
929
- `ipad_pro_10_5` |`chrome` |1112 x 834 |landscape |iOS 11
930
- `ipad_chrome` |`chrome` |1024 x 768 |landscape |iOS 10 - Mobile Chrome browser for iOS
931
- `ipad_firefox` |`chrome` |1024 x 768 |landscape |iOS 10 - Mobile Firefox browser for iOS
932
- `ipad_edge` |`chrome` |1024 x 768 |landscape |iOS 10 - Mobile Edge browser for iOS
933
- `android_tablet` |`chrome` |1024 x 768 |landscape |Android 3.0
934
- `kindle_fire` |`chrome` |1024 x 600 |landscape |
935
- `kindle_firehd7` |`chrome` |800 x 480 |landscape |Fire OS 3
936
- `kindle_firehd8` |`chrome` |1280 x 800 |landscape |Fire OS 5
937
- `kindle_firehd10` |`chrome` |1920 x 1200 |landscape |Fire OS 5
938
- `surface` |`chrome` |1366 x 768 |landscape |
939
- `blackberry_playbook` |`chrome` |1024 x 600 |landscape |BlackBerry Tablet OS
940
- `samsung_galaxy_tab` |`chrome` |1280 x 800 |landscape |Android 4.0.4
941
- `google_nexus7` |`chrome` |960 x 600 |landscape |Android 4.4.4
942
- `google_nexus9` |`chrome` |1024 x 768 |landscape |Android 5.1
943
- `google_nexus10` |`chrome` |1280 x 800 |landscape |Android 5.1
944
- `iphone` |`chrome` |320 x 480 |portrait |iOS 9.1
945
- `iphone4` |`chrome` |320 x 480 |portrait |iOS 9.1
946
- `iphone5` |`chrome` |320 x 568 |portrait |iOS 9.1
947
- `iphone6` |`chrome` |375 x 667 |portrait |iOS 9.1
948
- `iphone6_plus` |`chrome` |414 x 736 |portrait |iOS 9.1
949
- `iphone7` |`chrome` |375 x 667 |portrait |iOS 10
950
- `iphone7_plus` |`chrome` |414 x 736 |portrait |iOS 10
951
- `iphone7_chrome` |`chrome` |375 x 667 |portrait |iOS 11 - Mobile Chrome browser for iOS
952
- `iphone7_firefox` |`chrome` |375 x 667 |portrait |iOS 11 - Mobile Firefox browser for iOS
953
- `iphone7_edge` |`chrome` |375 x 667 |portrait |iOS 11 - Microsoft Edge browser for iOS
954
- `iphone8` |`chrome` |375 x 667 |portrait |iOS 11
955
- `iphone8_plus` |`chrome` |414 x 736 |portrait |iOS 11
956
- `iphonex` |`chrome` |375 x 812 |portrait |iOS 11
957
- `android_phone` |`chrome` |360 x 640 |portrait |Android 4.2.1
958
- `nexus6` |`chrome` |411 x 731 |portrait |Android 6
959
- `pixel` |`chrome` |411 x 731 |portrait |Android 8
960
- `pixel_xl` |`chrome` |411 x 731 |portrait |Android 8
961
- `samsung_galaxy_s4` |`chrome` |360 x 640 |portrait |Android 5.0.1
962
- `samsung_galaxy_s5` |`chrome` |360 x 640 |portrait |Android 6.0.1
963
- `samsung_galaxy_s6` |`chrome` |360 x 640 |portrait |Android 6.0.1
964
- `windows_phone7` |`chrome` |320 x 480 |portrait |Windows Phone OS 7.5
965
- `windows_phone8` |`chrome` |320 x 480 |portrait |Windows Phone OS 8.0
966
- `lumia_950_xl` |`chrome` |360 x 640 |portrait |Windows Phone OS 10
967
- `blackberry_z10` |`chrome` |384 x 640 |portrait |BlackBerry 10 OS
968
- `blackberry_z30` |`chrome` |360 x 640 |portrait |BlackBerry 10 OS
969
- `blackberry_leap` |`chrome` |360 x 640 |portrait |BlackBerry 10 OS
970
- `blackberry_passport` |`chrome` |504 x 504 |square |BlackBerry 10 OS
971
-
972
- To change the emulated device's screen orientation from the default setting, set the `ORIENTATION` Environment Variable to either `portrait` or `landscape`.
973
-
974
- To use a local instance of the Chrome desktop browser to host the emulated mobile web browser, you must set the `HOST_BROWSER` Environment Variable
975
- to `chrome`.
976
-
977
-
978
- ### Mobile Safari browser on iOS Simulators or iOS Physical Devices
979
-
980
- You can run your mobile web tests against the mobile Safari browser on simulated iOS devices or physically connected iOS devices using Appium and XCode on
981
- OS X. You must install Appium, XCode, and the iOS version-specific device simulators for XCode. You must also ensure that the `appium_capybara` gem is
982
- installed and required as described in **section 2.4 (Setup - Using Appium)** above.
983
-
984
- Information about Appium setup and configuration requirements for testing on physically connected iOS devices can be found on [this page](https://github.com/appium/appium/blob/master/docs/en/drivers/ios-xcuitest-real-devices.md).
878
+ ### Connecting to Locally Hosted iOS Simulators or Physical Devices
879
+
880
+ You can run your automated tests on locally hosted iOS simulators or physically connected devices using Appium and XCode on macOS. You
881
+ must install Appium, XCode, and the iOS version-specific device simulators for XCode. Information about Appium setup and configuration
882
+ requirements for testing on physically connected iOS devices can be found on [this page](https://github.com/appium/appium/blob/master/docs/en/drivers/ios-xcuitest-real-devices.md).
985
883
  The Appium server must be running prior to invoking Cucumber to run your features/scenarios.
986
884
 
987
885
  Once your test environment is properly configured, the following **Environment Variables** must be set as described in the table below.
988
886
 
989
- **Environment Variable** | **Description**
990
- --------------- | ----------------
991
- `WEB_BROWSER` | Must be set to `appium`
992
- `APP_PLATFORM_NAME` | Must be set to `iOS`
993
- `APP_BROWSER` | Must be set to `Safari`
994
- `APP_VERSION` | Must be set to `11.2`, `10.3`, `9.3`, or which ever iOS version you wish to run within the XCode Simulator
995
- `APP_DEVICE` | Set to iOS device name supported by the iOS Simulator (`iPhone 6s Plus`, `iPad Pro (10.5-inch)`, `iPad Air 2`, etc.) or name of physically connected iOS device
996
- `DEVICE_TYPE` | Must be set to `phone` or `tablet`
997
- `APP_UDID` | UDID of physically connected iOS device (not used for simulators)
998
- `TEAM_ID` | unique 10-character Apple developer team identifier string (not used for simulators)
999
- `TEAM_NAME` | String representing a signing certificate (not used for simulators)
1000
- `APP_ALLOW_POPUPS` | [Optional] Allow javascript to open new windows in Safari. Set to `true` or `false`
1001
- `APP_IGNORE_FRAUD_WARNING` | [Optional] Prevent Safari from showing a fraudulent website warning. Set to `true` or `false`
1002
- `APP_NO_RESET` | [Optional] Don't reset app state after each test. Set to `true` or `false`
1003
- `APP_FULL_RESET` | [Optional] Perform a complete reset. Set to `true` or `false`
1004
- `APP_INITIAL_URL` | [Optional] Initial URL, default is a local welcome page. e.g. `http://www.apple.com`
1005
- `WDA_LOCAL_PORT` | [Optional] Used to forward traffic from Mac host to real iOS devices over USB. Default value is same as port number used by WDA on device.
1006
- `LOCALE` | [Optional] Locale to set for the simulator. e.g. `fr_CA`
1007
- `LANGUAGE` | [Optional] Language to set for the simulator. e.g. `fr`
1008
- `ORIENTATION` | [Optional] Set to `portrait` or `landscape` (only for iOS simulators)
1009
- `NEW_COMMAND_TIMEOUT` | [Optional] Time (in Seconds) that Appium will wait for a new command from the client
1010
-
1011
-
1012
- ### Mobile Chrome or Android browsers on Android Studio Virtual Device emulators
1013
-
1014
- You can run your mobile web tests against the mobile Chrome or Android browser on emulated Android devices using Appium and Android Studio on OS X. You
1015
- must install Android Studio, the desired Android version-specific virtual device emulators, and Appium. Refer to [this page](https://github.com/appium/ruby_console/blob/master/osx.md)
1016
- for information on configuring Appium to work with the Android SDK. You must also ensure that the `appium_capybara` gem is installed and required as
1017
- described in **section 2.4 (Setup - Using Appium)** above.
1018
-
1019
- The Appium server must be running prior to invoking Cucumber to run your features/scenarios. Refer to [this page](https://appium.io/docs/en/writing-running-appium/web/chromedriver/index.html)
1020
- for information on configuring Appium to use the correct version of Chromedriver required to work with the web browser supported by each Android OS version.
887
+ | **Environment Variable** | **Description** |
888
+ |----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
889
+ | `WEB_BROWSER` | Must be set to `appium` |
890
+ | `APP_PLATFORM_NAME` | Must be set to `iOS` |
891
+ | `AUTOMATION_ENGINE` | Must be set to `XCUITest` |
892
+ | `APP_VERSION` | Must be set to `15.4`, `14.5`, or which ever iOS version you wish to run within the XCode Simulator |
893
+ | `APP_DEVICE` | Set to iOS device name supported by the iOS Simulator (`iPhone 13 Pro Max`, `iPad Pro (12.9-inch) (5th generation)`, etc.) or name of physically connected iOS device |
894
+ | `DEVICE_TYPE` | Must be set to `phone` or `tablet` |
895
+ | `APP_UDID` | UDID of physically connected iOS device (not used for simulators) |
896
+ | `TEAM_ID` | unique 10-character Apple developer team identifier string (not used for simulators) |
897
+ | `TEAM_NAME` | String representing a signing certificate (not used for simulators) |
898
+ | `APP_NO_RESET` | [Optional] Don't reset app state after each test. Set to `true` or `false` |
899
+ | `APP_FULL_RESET` | [Optional] Perform a complete reset. Set to `true` or `false` |
900
+ | `WDA_LOCAL_PORT` | [Optional] Used to forward traffic from Mac host to real iOS devices over USB. Default value is same as port number used by WDA on device. |
901
+ | `LOCALE` | [Optional] Locale to set for the simulator. e.g. `fr_CA` |
902
+ | `LANGUAGE` | [Optional] Language to set for the simulator. e.g. `fr` |
903
+ | `ORIENTATION` | [Optional] Set to `portrait` or `landscape` (only for iOS simulators) |
904
+ | `NEW_COMMAND_TIMEOUT` | [Optional] Time (in Seconds) that Appium will wait for a new command from the client |
1021
905
 
1022
- Once your test environment is properly configured, the following **Environment Variables** must be set as described in the table below.
1023
906
 
1024
- **Environment Variable** | **Description**
1025
- --------------- | ----------------
1026
- `WEB_BROWSER` | Must be set to `appium`
1027
- `APP_PLATFORM_NAME` | Must be set to `Android`
1028
- `APP_BROWSER` | Must be set to `Chrome` or `Browser`
1029
- `APP_VERSION` | Must be set to `8.0`, `7.0`, or which ever Android OS version you wish to run with the Android Virtual Device
1030
- `APP_DEVICE` | Set to Android Virtual Device ID (`Pixel_2_XL_API_26`, `Nexus_6_API_23`, etc.) found in Advanced Settings of AVD Configuration
1031
- `DEVICE_TYPE` | Must be set to `phone` or `tablet`
1032
- `ORIENTATION` | [Optional] Set to `portrait` or `landscape`
1033
- `APP_INITIAL_URL` | [Optional] Initial URL, default is a local welcome page. e.g. `http://www.apple.com`
1034
- `APP_NO_RESET` | [Optional] Don't reset app state after each test. Set to `true` or `false`
1035
- `APP_FULL_RESET` | [Optional] Perform a complete reset. Set to `true` or `false`
1036
- `LOCALE` | [Optional] Locale to set for the simulator. e.g. `fr_CA`
1037
- `LANGUAGE` | [Optional] Language to set for the simulator. e.g. `fr`
1038
- `NEW_COMMAND_TIMEOUT` | [Optional] Time (in Seconds) that Appium will wait for a new command from the client
1039
- `CHROMEDRIVER_EXECUTABLE` | [Optional] Absolute local path to webdriver executable
907
+ Refer to **section 9.5 (Using Configuration Specific Profiles in cucumber.yml)** below.
1040
908
 
1041
909
 
1042
- ### Remotely hosted desktop and mobile web browsers
910
+ ### Connecting to Locally Hosted Android Simulators or Physical Devices
1043
911
 
1044
- You can run your automated tests against remotely hosted desktop and mobile web browsers using the BrowserStack, CrossBrowserTesting,
1045
- Sauce Labs, or TestingBot services. If your tests are running against a web site hosted on your local computer (`localhost`), or on a
1046
- staging server inside your LAN, you must set the `TUNNELING` Environment Variable to `true`.
912
+ You can run your automated tests on emulated Android devices using Appium and Android Studio on macOS. You must install Android
913
+ Studio, the desired Android version-specific virtual device emulators, and Appium. Refer to [this page](http://appium.io/docs/en/drivers/android-uiautomator2/index.html)
914
+ for information on configuring Appium to work with the Android SDK. The Appium server must be running prior to invoking Cucumber
915
+ to run your features/scenarios.
1047
916
 
917
+ Once your test environment is properly configured, the following **Environment Variables** must be set as described in the table below.
1048
918
 
1049
- #### Remote desktop browsers on the BrowserStack service
919
+ | **Environment Variable** | **Description** |
920
+ |---------------------------|--------------------------------------------------------------------------------------------------------------------------------|
921
+ | `WEB_BROWSER` | Must be set to `appium` |
922
+ | `APP_PLATFORM_NAME` | Must be set to `Android` |
923
+ | `AUTOMATION_ENGINE` | Must be set to `UiAutomator2` |
924
+ | `APP_VERSION` | Must be set to `12.0`, or which ever Android OS version you wish to run with the Android Virtual Device |
925
+ | `APP_DEVICE` | Set to Android Virtual Device ID (`Pixel_2_XL_API_26`, `Nexus_6_API_23`, etc.) found in Advanced Settings of AVD Configuration |
926
+ | `DEVICE_TYPE` | Must be set to `phone` or `tablet` |
927
+ | `APP_UDID` | UDID of physically connected Android device (not used for simulators) |
928
+ | `ORIENTATION` | [Optional] Set to `portrait` or `landscape` |
929
+ | `APP_NO_RESET` | [Optional] Don't reset app state after each test. Set to `true` or `false` |
930
+ | `APP_FULL_RESET` | [Optional] Perform a complete reset. Set to `true` or `false` |
931
+ | `LOCALE` | [Optional] Locale to set for the simulator. e.g. `fr_CA` |
932
+ | `LANGUAGE` | [Optional] Language to set for the simulator. e.g. `fr` |
933
+ | `NEW_COMMAND_TIMEOUT` | [Optional] Time (in Seconds) that Appium will wait for a new command from the client |
1050
934
 
1051
- For remotely hosted desktop web browsers on the BrowserStack service, the following **Environment Variables** must be set as described in
1052
- the table below. Refer to the [Browserstack-specific capabilities chart page](https://www.browserstack.com/automate/capabilities#capabilities-browserstack)
1053
- for information regarding the specific capabilities.
1054
935
 
1055
- **Environment Variable** | **Description**
1056
- --------------- | ----------------
1057
- `WEB_BROWSER` | Must be set to `browserstack`
1058
- `BS_USERNAME` | Must be set to your BrowserStack account user name
1059
- `BS_AUTHKEY` | Must be set to your BrowserStack account access key
1060
- `BS_OS` | Must be set to `OS X` or `Windows`
1061
- `BS_OS_VERSION` | Refer to `os_version` capability in chart
1062
- `BS_BROWSER` | Refer to `browser` capability in chart
1063
- `BS_VERSION` | [Optional] Refer to `browser_version` capability in chart. If not specified, latest stable version of browser will be used.
1064
- `TUNNELING` | Must be `true` if you are testing against internal/local servers (`true` or `false`). If `true`, the BrowserStack Local instance will be automatically started.
1065
- `RESOLUTION` | [Optional] Refer to supported screen `resolution` capability in chart
1066
- `BROWSER_SIZE` | [Optional] Specify width, height of browser window
1067
- `RECORD_VIDEO` | [Optional] Enable screen video recording during test execution (`true` or `false`)
1068
- `TIME_ZONE` | [Optional] Specify custom time zone. Refer to `browserstack.timezone` capability in chart
1069
-
1070
- If the BrowserStack Local instance is running (`TUNNELING` Environment Variable is `true`), call the`TestCentricity::WebDriverConnect.close_tunnel` method
1071
- upon completion of your test suite to stop the Local instance. Place the code shown below in your `env.rb` file.
1072
-
1073
- # Code to stop BrowserStack Local instance after end of test (if tunneling is enabled)
1074
- at_exit do
1075
- TestCentricity::WebDriverConnect.close_tunnel if Environ.tunneling
1076
- end
936
+ Refer to **section 9.5 (Using Configuration Specific Profiles in cucumber.yml)** below.
937
+
938
+
939
+ ### Connecting to Remote Cloud Hosted iOS and Android Simulators or Physical Devices
1077
940
 
941
+ You can run your automated tests against remote cloud hosted iOS and Android simulators and real devices using the BrowserStack,
942
+ SauceLabs, or TestingBot services. Refer to **section 9.5 (Using Configuration Specific Profiles in cucumber.yml)** below.
1078
943
 
1079
- #### Remote mobile browsers on the BrowserStack service
1080
944
 
1081
- For remotely hosted mobile web browsers on the BrowserStack service, the following **Environment Variables** must be set as described in
1082
- the table below. Refer to the [Browserstack-specific capabilities chart page](https://www.browserstack.com/automate/capabilities#capabilities-browserstack)
945
+ #### Remote iOS and Android Physical Devices on the BrowserStack service
946
+
947
+ For remotely hosted iOS and Android simulators and real devices on the BrowserStack service, the following **Environment Variables**
948
+ must be set as described in the table below. Refer to the [Browserstack-specific capabilities chart page](https://www.browserstack.com/app-automate/capabilities?tag=w3c)
1083
949
  for information regarding the specific capabilities.
1084
950
 
1085
- **Environment Variable** | **Description**
1086
- --------------- | ----------------
1087
- `WEB_BROWSER` | Must be set to `browserstack`
1088
- `BS_USERNAME` | Must be set to your BrowserStack account user name
1089
- `BS_AUTHKEY` | Must be set to your BrowserStack account access key
1090
- `BS_OS` | Must be set to `ios` or `android`
1091
- `BS_BROWSER` | Must be set to `iPhone`, `iPad`, or `android`
1092
- `BS_PLATFORM` | Must be set to `MAC` (for iOS) or `ANDROID`
1093
- `BS_DEVICE` | Refer to `device` capability in chart
1094
- `BS_REAL_MOBILE` | Set to `true` if running against a real device
1095
- `DEVICE_TYPE` | Must be set to `phone` or `tablet`
1096
- `TUNNELING` | Must be `true` if you are testing against internal/local servers (`true` or `false`). If `true`, the BrowserStack Local instance will be automatically started.
1097
- `ORIENTATION` | [Optional] Set to `portrait` or `landscape`
1098
- `RECORD_VIDEO` | [Optional] Enable screen video recording during test execution (`true` or `false`)
1099
- `TIME_ZONE` | [Optional] Specify custom time zone. Refer to `browserstack.timezone` capability in chart
1100
-
1101
-
1102
-
1103
- #### Remote desktop browsers on the CrossBrowserTesting service
1104
-
1105
- For remotely hosted desktop web browsers on the CrossBrowserTesting service, the following **Environment Variables** must be set as described in
1106
- the table below. Use the Configuration Wizard on the [Start a Selenium Test page](https://app.crossbrowsertesting.com/selenium/run) to obtain
1107
- information regarding the specific capabilities.
1108
-
1109
- **Environment Variable** | **Description**
1110
- --------------- | ----------------
1111
- `WEB_BROWSER` | Must be set to `crossbrowser`
1112
- `CB_USERNAME` | Must be set to your CrossBrowserTesting account user name or email address
1113
- `CB_AUTHKEY` | Must be set to your CrossBrowserTesting account access key
1114
- `CB_OS` | Refer to `os_api_name` capability in the sample script of the Wizard
1115
- `CB_BROWSER` | Refer to `browser_api_name` capability in the sample script of the Wizard
1116
- `RESOLUTION` | [Optional] Refer to supported `screen_resolution` capability in the sample script of the Wizard
1117
- `BROWSER_SIZE` | [Optional] Specify width, height of browser window
1118
- `RECORD_VIDEO` | [Optional] Enable screen video recording during test execution (`true` or `false`)
1119
-
1120
-
1121
- #### Remote mobile browsers on the CrossBrowserTesting service
1122
-
1123
- For remotely hosted mobile web browsers on the CrossBrowserTesting service, the following **Environment Variables** must be set as described in
1124
- the table below. Use the Configuration Wizard on the [Start a Selenium Test page](https://app.crossbrowsertesting.com/selenium/run) to obtain
1125
- information regarding the specific capabilities.
1126
-
1127
- **Environment Variable** | **Description**
1128
- --------------- | ----------------
1129
- `WEB_BROWSER` | Must be set to `crossbrowser`
1130
- `CB_USERNAME` | Must be set to your CrossBrowserTesting account user name or email address
1131
- `CB_AUTHKEY` | Must be set to your CrossBrowserTesting account access key
1132
- `CB_PLATFORM` | Refer to `os_api_name` capability in the sample script of the Wizard
1133
- `CB_BROWSER` | Refer to `browser_api_name` capability in the sample script of the Wizard
1134
- `RESOLUTION` | Refer to supported `screen_resolution` capability in the sample script of the Wizard
1135
- `DEVICE_TYPE` | Must be set to `phone` or `tablet`
1136
- `RECORD_VIDEO` | [Optional] Enable screen video recording during test execution (`true` or `false`)
1137
-
1138
-
1139
-
1140
- #### Remote desktop browsers on the Sauce Labs service
1141
-
1142
- For remotely hosted desktop web browsers on the Sauce Labs service, the following **Environment Variables** must be set as described in
1143
- the table below. Use the Selenium API on the [Platform Configurator page](https://wiki.saucelabs.com/display/DOCS/Platform+Configurator#/) to obtain
1144
- information regarding the specific capabilities.
1145
-
1146
- **Environment Variable** | **Description**
1147
- --------------- | ----------------
1148
- `WEB_BROWSER` | Must be set to `saucelabs`
1149
- `SL_USERNAME` | Must be set to your Sauce Labs account user name or email address
1150
- `SL_AUTHKEY` | Must be set to your Sauce Labs account access key
1151
- `SL_OS` | Refer to `platform` capability in the Copy Code section of the Platform Configurator page
1152
- `SL_BROWSER` | Must be set to `chrome`, `firefox`, `safari`, `internet explorer`, or `edge`
1153
- `SL_VERSION` | Refer to `version` capability in the Copy Code section of the Platform Configurator page
1154
- `RESOLUTION` | [Optional] Refer to supported `screenResolution` capability in the Copy Code section of the Platform Configurator page
1155
- `BROWSER_SIZE `| [Optional] Specify width, height of browser window
1156
- `RECORD_VIDEO` | [Optional] Enable screen video recording during test execution (`true` or `false`)
1157
-
1158
-
1159
- #### Remote desktop browsers on the TestingBot service
1160
-
1161
- For remotely hosted desktop web browsers on the TestingBot service, the following **Environment Variables** must be set as described in
1162
- the table below. Refer to the [TestingBot List of Available Browsers page](https://testingbot.com/support/getting-started/browsers.html) for information
1163
- regarding the specific capabilities.
1164
-
1165
- **Environment Variable** | **Description**
1166
- --------------- | ----------------
1167
- `WEB_BROWSER` | Must be set to `testingbot`
1168
- `TB_USERNAME` | Must be set to your TestingBot account user name
1169
- `TB_AUTHKEY` | Must be set to your TestingBot account access key
1170
- `TB_OS` | Refer to `platform` capability in chart
1171
- `TB_BROWSER` | Refer to `browserName` capability in chart
1172
- `TB_VERSION` | Refer to `version` capability in chart
1173
- `TUNNELING` | Must be `true` if you are testing against internal/local servers (`true` or `false`)
1174
- `RESOLUTION` | [Optional] Possible values: `800x600`, `1024x768`, `1280x960`, `1280x1024`, `1600x1200`, `1920x1200`, `2560x1440`
1175
- `BROWSER_SIZE`| [Optional] Specify width, height of browser window
1176
-
1177
-
1178
- #### Remote mobile browsers on the TestingBot service
1179
-
1180
- For remotely hosted mobile web browsers on the TestingBot service, the following **Environment Variables** must be set as described in
1181
- the table below. Refer to the [TestingBot List of Available Browsers page](https://testingbot.com/support/getting-started/browsers.html) for information
1182
- regarding the specific capabilities.
1183
-
1184
- **Environment Variable** | **Description**
1185
- --------------- | ----------------
1186
- `WEB_BROWSER` | Must be set to `testingbot`
1187
- `TB_USERNAME` | Must be set to your TestingBot account user name
1188
- `TB_AUTHKEY` | Must be set to your TestingBot account access key
1189
- `TB_OS` | Must be set to `MAC` (for iOS) or `ANDROID`
1190
- `TB_BROWSER` | Must be set to `safari` (for iOS) or `browser` (for Android)
1191
- `TB_VERSION` | Refer to `version` capability in chart
1192
- `TB_PLATFORM` | Must be set to `iOS` or `ANDROID`
1193
- `TB_DEVICE` | Refer to `deviceName` capability in chart
1194
- `DEVICE_TYPE` | Must be set to `phone` or `tablet`
1195
- `TUNNELING` | Must be `true` if you are testing against internal/local servers (`true` or `false`)
1196
- `ORIENTATION` | [Optional] Set to `portrait` or `landscape`
1197
-
951
+ | **Environment Variable** | **Description** |
952
+ |--------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
953
+ | `WEB_BROWSER` | Must be set to `browserstack` |
954
+ | `BS_USERNAME` | Must be set to your BrowserStack account user name |
955
+ | `BS_AUTHKEY` | Must be set to your BrowserStack account access key |
956
+ | `BS_OS` | Must be set to `ios` or `android` |
957
+ | `BS_DEVICE` | Refer to `deviceName` capability in chart |
958
+ | `BS_OS_VERSION` | Set to the OS version specified in the `platformVersion` capability in the chart |
959
+ | `DEVICE_TYPE` | Must be set to `phone` or `tablet` |
960
+ | `ORIENTATION` | [Optional] Set to `portrait` or `landscape` |
961
+ | `RECORD_VIDEO` | [Optional] Enable screen video recording during test execution (`true` or `false`) |
962
+ | `TIME_ZONE` | [Optional] Specify custom time zone. Refer to `browserstack.timezone` capability in chart |
963
+ | `IP_GEOLOCATION` | [Optional] Specify IP Geolocation. Refer to [IP Geolocation](https://www.browserstack.com/ip-geolocation) to select a country code. |
964
+ | `SCREENSHOTS` | [Optional] Generate screenshots for debugging (`true` or `false`) |
965
+ | `NETWORK_LOGS` | [Optional] Capture network logs (`true` or `false`) |
966
+ | `APPIUM_LOGS` | [Optional] Generate Appium logs (`true` or `false`) |
967
+
968
+
969
+ #### Remote iOS and Android Physical Devices and Simulators on the Sauce Labs service
970
+
971
+ For remotely hosted iOS and Android simulators and real devices on the Sauce Labs service, the following **Environment Variables**
972
+ must be set as described in the table below. Refer to the [Platform Configurator page](https://saucelabs.com/platform/platform-configurator)
973
+ to obtain information regarding the specific capabilities.
974
+
975
+ | **Environment Variable** | **Description** |
976
+ |--------------------------|-----------------------------------------------------------------------------------------------------------------|
977
+ | `WEB_BROWSER` | Must be set to `saucelabs` |
978
+ | `SL_USERNAME` | Must be set to your Sauce Labs account user name or email address |
979
+ | `SL_AUTHKEY` | Must be set to your Sauce Labs account access key |
980
+ | `DATA_CENTER` | Must be set to your Sauce Labs account Data Center assignment (`us-west-1`, `eu-central-1`, `apac-southeast-1`) |
981
+ | `SL_OS` | Must be set to `ios` or `android` |
982
+ | `SL_DEVICE` | Refer to `deviceName` capability in chart |
983
+ | `SL_OS_VERSION` | Refer to `platformVersion` capability in the Config Script section of the Platform Configurator page |
984
+ | `DEVICE_TYPE` | Must be set to `phone` or `tablet` |
985
+ | `ORIENTATION` | [Optional] Set to `portrait` or `landscape` |
986
+ | `RECORD_VIDEO` | [Optional] Enable screen video recording during test execution (`true` or `false`) |
987
+ | `SCREENSHOTS` | [Optional] Generate screenshots for debugging (`true` or `false`) |
988
+
989
+
990
+ #### Remote iOS and Android Physical Devices and Simulators on the TestingBot service
991
+
992
+ For remotely hosted iOS and Android simulators and real devices on the TestingBot service, the following **Environment Variables**
993
+ must be set as described in the table below. Refer to the [TestingBot List of Devices page](https://testingbot.com/support/devices)
994
+ for information regarding the specific capabilities.
1198
995
 
1199
- ### Using Browser specific Profiles in cucumber.yml
996
+ | **Environment Variable** | **Description** |
997
+ |--------------------------|---------------------------------------------------|
998
+ | `WEB_BROWSER` | Must be set to `testingbot` |
999
+ | `TB_USERNAME` | Must be set to your TestingBot account user name |
1000
+ | `TB_AUTHKEY` | Must be set to your TestingBot account access key |
1001
+ | `TB_OS` | Must be set to `ios` or `android` |
1002
+ | `TB_DEVICE` | Refer to `deviceName` capability in chart |
1003
+ | `TB_OS_VERSION` | Refer to `version` capability in chart |
1004
+ | `DEVICE_TYPE` | Must be set to `phone` or `tablet` |
1005
+ | `REAL_DEVICE` | Must be set to `true` for real devices |
1200
1006
 
1201
- While you can set **Environment Variables** in the command line when invoking Cucumber, a preferred method of specifying and managing
1202
- target web browsers is to create browser specific **Profiles** that set the appropriate **Environment Variables** for each target browser
1203
- in your `cucumber.yml` file.
1204
1007
 
1205
- Below is a list of Cucumber **Profiles** for supported locally and remotely hosted desktop and mobile web browsers (put these in in your
1206
- `cucumber.yml` file). Before you can use the BrowserStack, CrossBrowserTesting, Sauce Labs, or TestingBot services, you will need to
1207
- replace the *INSERT USER NAME HERE* and *INSERT PASSWORD HERE* placeholder text with your user account and authorization code for the cloud
1208
- service(s) that you intend to connect with.
1209
1008
 
1009
+ ### Using Configuration Specific Profiles in cucumber.yml
1210
1010
 
1211
- <% desktop = "--tags ~@wip --tags ~@failing --tags @desktop --require features BROWSER_SIZE=1600,1000" %>
1212
- <% mobile = "--tags ~@wip --tags ~@failing --tags @mobile --require features" %>
1213
-
1214
- #==============
1215
- # profiles for locally hosted desktop web browsers
1216
- #==============
1217
-
1218
- firefox: WEB_BROWSER=firefox <%= desktop %>
1219
- safari: WEB_BROWSER=safari <%= desktop %>
1220
- chrome: WEB_BROWSER=chrome <%= desktop %>
1221
- ie: WEB_BROWSER=ie <%= desktop %>
1222
- headless: WEB_BROWSER=poltergeist <%= desktop %>
1223
-
1224
- #==============
1225
- # profiles for locally hosted mobile web browsers (emulated locally in Firefox browser)
1226
- # NOTE: to host emulated mobile browsers in Chrome set the HOST_BROWSER=chrome
1227
- #==============
1228
-
1229
- ipad: WEB_BROWSER=ipad HOST_BROWSER=chrome <%= mobile %>
1230
- ipad_pro: WEB_BROWSER=ipad_pro HOST_BROWSER=chrome <%= mobile %>
1231
- ipad_pro_10_5: WEB_BROWSER=ipad_pro_10_5 HOST_BROWSER=chrome <%= mobile %>
1232
- ipad_chrome: WEB_BROWSER=ipad_chrome HOST_BROWSER=chrome <%= mobile %>
1233
- ipad_firefox: WEB_BROWSER=ipad_firefox HOST_BROWSER=chrome <%= mobile %>
1234
- ipad_edge: WEB_BROWSER=ipad_edge HOST_BROWSER=chrome <%= mobile %>
1235
- iphone: WEB_BROWSER=iphone HOST_BROWSER=chrome <%= mobile %>
1236
- iphone4: WEB_BROWSER=iphone4 HOST_BROWSER=chrome <%= mobile %>
1237
- iphone5: WEB_BROWSER=iphone5 HOST_BROWSER=chrome <%= mobile %>
1238
- iphone6: WEB_BROWSER=iphone6 HOST_BROWSER=chrome <%= mobile %>
1239
- iphone6_plus: WEB_BROWSER=iphone6_plus HOST_BROWSER=chrome <%= mobile %>
1240
- iphone7: WEB_BROWSER=iphone7 HOST_BROWSER=chrome <%= mobile %>
1241
- iphone7_plus: WEB_BROWSER=iphone7_plus HOST_BROWSER=chrome <%= mobile %>
1242
- iphone7_chrome: WEB_BROWSER=iphone7_chrome HOST_BROWSER=chrome <%= mobile %>
1243
- iphone7_firefox: WEB_BROWSER=iphone7_firefox HOST_BROWSER=chrome <%= mobile %>
1244
- iphone7_edge: WEB_BROWSER=iphone7_edge HOST_BROWSER=chrome <%= mobile %>
1245
- iphone8: WEB_BROWSER=iphone8 HOST_BROWSER=chrome <%= mobile %>
1246
- iphone8_plus: WEB_BROWSER=iphone8_plus HOST_BROWSER=chrome <%= mobile %>
1247
- iphoneX: WEB_BROWSER=iphonex HOST_BROWSER=chrome <%= mobile %>
1248
- android_phone: WEB_BROWSER=android_phone HOST_BROWSER=chrome <%= mobile %>
1249
- nexus6: WEB_BROWSER=nexus6 HOST_BROWSER=chrome <%= mobile %>
1250
- android_tablet: WEB_BROWSER=android_tablet HOST_BROWSER=chrome <%= mobile %>
1251
- kindle_fire: WEB_BROWSER=kindle_fire HOST_BROWSER=chrome <%= mobile %>
1252
- kindle_firehd7: WEB_BROWSER=kindle_firehd7 HOST_BROWSER=chrome <%= mobile %>
1253
- kindle_firehd8: WEB_BROWSER=kindle_firehd8 HOST_BROWSER=chrome <%= mobile %>
1254
- kindle_firehd10: WEB_BROWSER=kindle_firehd10 HOST_BROWSER=chrome <%= tablet %>
1255
- surface: WEB_BROWSER=surface HOST_BROWSER=chrome <%= mobile %>
1256
- blackberry_playbook: WEB_BROWSER=blackberry_playbook HOST_BROWSER=chrome <%= mobile %>
1257
- samsung_galaxy_tab: WEB_BROWSER=samsung_galaxy_tab HOST_BROWSER=chrome <%= mobile %>
1258
- google_nexus7: WEB_BROWSER=google_nexus7 HOST_BROWSER=chrome <%= mobile %>
1259
- google_nexus9: WEB_BROWSER=google_nexus9 HOST_BROWSER=chrome <%= mobile %>
1260
- google_nexus10: WEB_BROWSER=google_nexus10 HOST_BROWSER=chrome <%= mobile %>
1261
- samsung_galaxy_s4: WEB_BROWSER=samsung_galaxy_s4 HOST_BROWSER=chrome <%= mobile %>
1262
- samsung_galaxy_s5: WEB_BROWSER=samsung_galaxy_s5 HOST_BROWSER=chrome <%= mobile %>
1263
- samsung_galaxy_s6: WEB_BROWSER=samsung_galaxy_s6 HOST_BROWSER=chrome <%= mobile %>
1264
- pixel: WEB_BROWSER=pixel HOST_BROWSER=chrome <%= mobile %>
1265
- pixel_xl: WEB_BROWSER=pixel_xl HOST_BROWSER=chrome <%= mobile %>
1266
- windows_phone7: WEB_BROWSER=windows_phone7 HOST_BROWSER=chrome <%= mobile %>
1267
- windows_phone8: WEB_BROWSER=windows_phone8 HOST_BROWSER=chrome <%= mobile %>
1268
- lumia_950_xl: WEB_BROWSER=lumia_950_xl HOST_BROWSER=chrome <%= mobile %>
1269
- blackberry_z10: WEB_BROWSER=blackberry_z10 HOST_BROWSER=chrome <%= mobile %>
1270
- blackberry_z30: WEB_BROWSER=blackberry_z30 HOST_BROWSER=chrome <%= mobile %>
1271
- blackberry_leap: WEB_BROWSER=blackberry_leap HOST_BROWSER=chrome <%= mobile %>
1272
- blackberry_passport: WEB_BROWSER=blackberry_passport HOST_BROWSER=chrome <%= mobile %>
1011
+ While you can set **Environment Variables** in the command line when invoking Cucumber, a preferred method of specifying and managing
1012
+ target platforms is to create platform specific **Profiles** that set the appropriate **Environment Variables** for each target
1013
+ platform in your `cucumber.yml` file.
1014
+
1015
+ Below is a list of Cucumber **Profiles** for supported locally and remotely hosted iOS and Android simulators and real devices (put
1016
+ these in in your `cucumber.yml` file). Before you can use the BrowserStack, SauceLabs, TestingBot or LambdaTest services, you will
1017
+ need to replace the *INSERT USER NAME HERE* and *INSERT PASSWORD HERE* placeholder text with your user account and authorization
1018
+ code for the cloud service(s) that you intend to connect with.
1273
1019
 
1274
-
1275
1020
  #==============
1276
- # profiles for mobile device screen orientation
1021
+ # conditionally load Page and Screen Object implementations based on which target platform we're running on
1277
1022
  #==============
1278
1023
 
1279
- portrait: ORIENTATION=portrait
1280
- landscape: ORIENTATION=landscape
1024
+ ios: PLATFORM=ios --tags @ios -r features/support/ios -e features/support/android
1025
+ android: PLATFORM=android --tags @android -r features/support/android -e features/support/ios
1026
+ web: PLATFORM=web --tags @web -r features/support/web -e features/support/ios -e features/support/android
1281
1027
 
1282
1028
 
1283
1029
  #==============
1284
- # profiles for mobile Safari web browsers hosted within XCode iOS simulator
1285
- # NOTE: Requires installation of XCode, iOS version specific target simulators, Appium, and the appium_capybara gem
1030
+ # profiles for mobile device screen orientation
1286
1031
  #==============
1287
1032
 
1288
- appium_ios: WEB_BROWSER=appium APP_PLATFORM_NAME="iOS" APP_BROWSER="Safari" <%= mobile %>
1289
- app_ios_10: --profile appium_ios APP_VERSION="10.3"
1290
- app_ios_11: --profile appium_ios APP_VERSION="11.2"
1033
+ landscape: ORIENTATION=landscape
1034
+ portrait: ORIENTATION=portrait
1291
1035
 
1292
- iphone_7_plus_10_sim: --profile app_ios_10 DEVICE_TYPE=phone APP_DEVICE="iPhone 7 Plus"
1293
- iphone_7_10_sim: --profile app_ios_10 DEVICE_TYPE=phone APP_DEVICE="iPhone 7"
1294
- iphone_7se_10_sim: --profile app_ios_10 DEVICE_TYPE=phone APP_DEVICE="iPhone SE"
1295
- iphone_6s_plus_10_sim: --profile app_ios_10 DEVICE_TYPE=phone APP_DEVICE="iPhone 6s Plus"
1296
- iphone_6s_10_sim: --profile app_ios_10 DEVICE_TYPE=phone APP_DEVICE="iPhone 6s"
1297
- iphone_SE_10_sim: --profile app_ios_10 DEVICE_TYPE=phone APP_DEVICE="iPhone SE"
1298
- iphone_X_11_sim: --profile app_ios_11 DEVICE_TYPE=phone APP_DEVICE="iPhone X"
1299
- iphone_8_11_sim: --profile app_ios_11 DEVICE_TYPE=phone APP_DEVICE="iPhone 8"
1300
- iphone_8_plus_11_sim: --profile app_ios_11 DEVICE_TYPE=phone APP_DEVICE="iPhone 8 Plus"
1301
- iphone_7_plus_11_sim: --profile app_ios_11 DEVICE_TYPE=phone APP_DEVICE="iPhone 7 Plus"
1302
- iphone_7_11_sim: --profile app_ios_11 DEVICE_TYPE=phone APP_DEVICE="iPhone 7"
1303
- iphone_7se_11_sim: --profile app_ios_11 DEVICE_TYPE=phone APP_DEVICE="iPhone SE"
1304
- iphone_6s_plus_11_sim: --profile app_ios_11 DEVICE_TYPE=phone APP_DEVICE="iPhone 6s Plus"
1305
- iphone_6s_11_sim: --profile app_ios_11 DEVICE_TYPE=phone APP_DEVICE="iPhone 6s"
1306
- iphone_SE_11_sim: --profile app_ios_11 DEVICE_TYPE=phone APP_DEVICE="iPhone SE"
1307
1036
 
1308
- ipad_pro_12_9_11_sim: --profile app_ios_11 DEVICE_TYPE=tablet APP_DEVICE="iPad Pro (12.9-inch)"
1309
- ipad_pro_12_9_10_sim: --profile app_ios_10 DEVICE_TYPE=tablet APP_DEVICE="iPad Pro (12.9-inch)"
1310
- ipad_pro_10_5_11_sim: --profile app_ios_11 DEVICE_TYPE=tablet APP_DEVICE="iPad Pro (10.5-inch)"
1311
- ipad_pro_10_5_10_sim: --profile app_ios_10 DEVICE_TYPE=tablet APP_DEVICE="iPad Pro (10.5-inch)"
1312
- ipad_pro_9_7_11_sim: --profile app_ios_11 DEVICE_TYPE=tablet APP_DEVICE="iPad Pro (9.7-inch)"
1313
- ipad_pro_9_7_10_sim: --profile app_ios_10 DEVICE_TYPE=tablet APP_DEVICE="iPad Pro (9.7-inch)"
1314
- ipad_air_2_11_sim: --profile app_ios_11 DEVICE_TYPE=tablet APP_DEVICE="iPad Air 2"
1315
- ipad_air_2_10_sim: --profile app_ios_10 DEVICE_TYPE=tablet APP_DEVICE="iPad Air 2"
1316
-
1317
-
1318
1037
  #==============
1319
- # profiles for mobile Safari web browsers running on physically connected iOS devices
1320
- # NOTE: Requires installation of XCode, Appium, and the appium_capybara gem
1321
- #==============
1322
-
1323
- my_ios_10_3_iphone: --profile app_ios_10 DEVICE_TYPE=phone APP_DEVICE="My Test iPhone6" APP_UDID="INSERT YOUR DEVICE UDID"
1324
- my_ios_10_3_ipad: --profile app_ios_10 DEVICE_TYPE=tablet APP_DEVICE="My Test iPad Pro" APP_UDID="INSERT YOUR DEVICE UDID"
1325
-
1326
-
1327
- #==============
1328
- # profiles for Android mobile web browsers hosted within Android Studio Android Virtual Device emulators
1329
- # NOTE: Requires installation of Android Studio, Android version specific virtual device simulators, Appium, and the appium_capybara gem
1038
+ # profile to start Appium Server prior to running mobile browser tests on iOS or Android simulators or physical devices
1330
1039
  #==============
1040
+ run_appium: APPIUM_SERVER=run
1331
1041
 
1332
- appium_android: WEB_BROWSER=appium APP_PLATFORM_NAME="Android" <%= mobile %>
1333
- android_api_26: --profile appium_android APP_BROWSER="Chrome" APP_VERSION="8.0"
1334
- android_api_23: --profile appium_android APP_BROWSER="Browser" APP_VERSION="6.0"
1335
- pixel_xl_api26_sim: --profile android_api_26 DEVICE_TYPE=phone APP_DEVICE="Pixel_XL_API_26"
1336
- pixel_2_xl_api26_sim: --profile android_api_26 DEVICE_TYPE=phone APP_DEVICE="Pixel_2_XL_API_26"
1337
- nexus_6_api23_sim: --profile android_api_23 DEVICE_TYPE=phone APP_DEVICE="Nexus_6_API_23"
1338
1042
 
1339
1043
  #==============
1340
- # profiles for remotely hosted web browsers on the BrowserStack service
1044
+ # profiles for native iOS apps hosted within XCode iOS simulators
1045
+ # NOTE: Requires installation of XCode, iOS version specific target simulators, and Appium
1341
1046
  #==============
1342
1047
 
1343
- browserstack: WEB_BROWSER=browserstack BS_USERNAME=<INSERT USER NAME HERE> BS_AUTHKEY=<INSERT PASSWORD HERE>
1344
- bs_desktop: --profile browserstack <%= desktop %> RESOLUTION="1920x1080"
1345
- bs_mobile: --profile browserstack <%= mobile %>
1346
-
1347
- # BrowserStack OS X desktop browser profiles
1348
- bs_macos_high_sierra: --profile bs_desktop BS_OS="OS X" BS_OS_VERSION="High Sierra"
1349
- bs_ff_high_sierra: --profile bs_macos_high_sierra BS_BROWSER="Firefox"
1350
- bs_chrome_high_sierra: --profile bs_macos_high_sierra BS_BROWSER="Chrome"
1351
- bs_safari_high_sierra: --profile bs_macos_high_sierra BS_BROWSER="Safari"
1352
-
1353
- bs_macos_sierra: --profile bs_desktop BS_OS="OS X" BS_OS_VERSION="Sierra"
1354
- bs_ff_sierra: --profile bs_macos_sierra BS_BROWSER="Firefox"
1355
- bs_chrome_sierra: --profile bs_macos_sierra BS_BROWSER="Chrome"
1356
- bs_safari_sierra: --profile bs_macos_sierra BS_BROWSER="Safari"
1357
-
1358
- bs_osx_el_capitan: --profile bs_desktop BS_OS="OS X" BS_OS_VERSION="El Capitan"
1359
- bs_ff_el_cap: --profile bs_osx_el_capitan BS_BROWSER="Firefox"
1360
- bs_chrome_el_cap: --profile bs_osx_el_capitan BS_BROWSER="Chrome"
1361
- bs_safari_el_cap: --profile bs_osx_el_capitan BS_BROWSER="Safari"
1362
-
1363
- bs_osx_yosemite: --profile bs_desktop BS_OS="OS X" BS_OS_VERSION="Yosemite"
1364
- bs_ff_yos: --profile bs_osx_yosemite BS_BROWSER="Firefox"
1365
- bs_chrome_yos: --profile bs_osx_yosemite BS_BROWSER="Chrome"
1366
- bs_safari_yos: --profile bs_osx_yosemite BS_BROWSER="Safari"
1048
+ appium_ios: WEB_BROWSER=appium --profile ios AUTOMATION_ENGINE=XCUITest APP_PLATFORM_NAME="iOS" NEW_COMMAND_TIMEOUT="30" <%= mobile %>
1049
+ app_ios_14: --profile appium_ios APP_VERSION="14.5"
1050
+ app_ios_15: --profile appium_ios APP_VERSION="15.4"
1367
1051
 
1368
- bs_osx_mavericks: --profile bs_desktop BS_OS="OS X" BS_OS_VERSION="Mavericks"
1369
- bs_ff_mav: --profile bs_osx_mavericks BS_BROWSER="Firefox"
1370
- bs_chrome_mav: --profile bs_osx_mavericks BS_BROWSER="Chrome"
1371
- bs_safari_mav: --profile bs_osx_mavericks BS_BROWSER="Safari"
1052
+ iphone_12PM_14_sim: --profile app_ios_14 DEVICE_TYPE=phone APP_DEVICE="iPhone 12 Pro Max"
1053
+ iphone_13PM_15_sim: --profile app_ios_15 DEVICE_TYPE=phone APP_DEVICE="iPhone 13 Pro Max"
1054
+ iphone_11_14_sim: --profile app_ios_14 DEVICE_TYPE=phone APP_DEVICE="iPhone 11"
1055
+ ipad_pro_12_15_sim: --profile app_ios_15 DEVICE_TYPE=tablet APP_DEVICE="iPad Pro (12.9-inch) (5th generation)"
1372
1056
 
1373
- # BrowserStack Windows desktop browser profiles
1374
- bs_win7: --profile bs_desktop BS_OS="Windows" BS_OS_VERSION="7"
1375
- bs_win8: --profile bs_desktop BS_OS="Windows" BS_OS_VERSION="8"
1376
- bs_win10: --profile bs_desktop BS_OS="Windows" BS_OS_VERSION="10"
1377
- bs_ff_win7: --profile bs_win7 BS_BROWSER="Firefox"
1378
- bs_ff_win8: --profile bs_win8 BS_BROWSER="Firefox"
1379
- bs_ff_win10: --profile bs_win10 BS_BROWSER="Firefox"
1380
- bs_chrome_win7: --profile bs_win7 BS_BROWSER="Chrome"
1381
- bs_chrome_win8: --profile bs_win8 BS_BROWSER="Chrome"
1382
- bs_chrome_win10: --profile bs_win10 BS_BROWSER="Chrome"
1383
-
1384
- bs_ie_win7: --profile bs_win7 BS_BROWSER="IE"
1385
- bs_ie11_win7: --profile bs_ie_win7 BS_VERSION="11.0"
1386
- bs_ie10_win7: --profile bs_ie_win7 BS_VERSION="10.0"
1387
- bs_ie9_win7: --profile bs_ie_win7 BS_VERSION="9.0"
1388
- bs_ie10_win8: --profile bs_win8 BS_BROWSER="IE" BS_VERSION="10.0"
1389
- bs_ie11_win8: --profile bs_desktop BS_OS="Windows" BS_OS_VERSION="8.1" BS_BROWSER="IE" BS_VERSION="11.0"
1390
- bs_ie11_win10: --profile bs_win10 BS_BROWSER="IE" BS_VERSION="11.0"
1391
- bs_edge_win10: --profile bs_win10 BS_BROWSER="Edge" BS_VERSION="15.0"
1392
-
1393
- # BrowserStack iOS mobile browser profiles
1394
- bs_iphone: --profile bs_mobile BS_PLATFORM=MAC BS_OS=ios BS_BROWSER=iPhone DEVICE_TYPE=phone
1395
- bs_iphone6s_plus: --profile bs_iphone BS_DEVICE="iPhone 6S Plus"
1396
- bs_iphone6s: --profile bs_iphone BS_DEVICE="iPhone 6S"
1397
- bs_iphone6_plus: --profile bs_iphone BS_DEVICE="iPhone 6 Plus"
1398
- bs_iphone6: --profile bs_iphone BS_DEVICE="iPhone 6"
1399
- bs_iphone5s: --profile bs_iphone BS_DEVICE="iPhone 5S"
1400
- bs_iphone4s: --profile bs_iphone BS_DEVICE="iPhone 4S (6.0)"
1401
-
1402
- bs_ipad: --profile bs_mobile BS_PLATFORM=MAC BS_BROWSER=iPad DEVICE_TYPE=tablet
1403
- bs_ipad_pro: --profile bs_ipad BS_DEVICE="iPad Pro"
1404
- bs_ipad_air2: --profile bs_ipad BS_DEVICE="iPad Air 2"
1405
- bs_ipad_air: --profile bs_ipad BS_DEVICE="iPad Air"
1406
- bs_ipad_mini: --profile bs_ipad BS_DEVICE="iPad Mini 4"
1407
-
1408
- # BrowserStack iOS real device mobile browser profiles
1409
- bs_iphone_device: --profile bs_iphone BS_REAL_MOBILE="true"
1410
- bs_iphoneX: --profile bs_iphone_device BS_OS_VERSION="11.0" BS_DEVICE="iPhone X"
1411
- bs_iphone8_plus: --profile bs_iphone_device BS_OS_VERSION="11.0" BS_DEVICE="iPhone 8 Plus"
1412
- bs_iphone8: --profile bs_iphone_device BS_OS_VERSION="11.0" BS_DEVICE="iPhone 8"
1413
- bs_iphone7_plus: --profile bs_iphone_device BS_OS_VERSION="10.3" BS_DEVICE="iPhone 7 Plus"
1414
- bs_iphone7: --profile bs_iphone_device BS_OS_VERSION="10.3" BS_DEVICE="iPhone 7"
1415
-
1416
- bs_ipad_device: --profile bs_ipad BS_REAL_MOBILE="true"
1417
- bs_ipad5: --profile bs_ipad_device BS_OS_VERSION="11.0" BS_DEVICE="iPad 5th"
1418
-
1419
- # BrowserStack Android mobile browser profiles
1420
- bs_android: --profile bs_mobile BS_PLATFORM=ANDROID BS_BROWSER=android BS_OS=android
1421
- bs_android_phone: --profile bs_android DEVICE_TYPE=phone
1422
- bs_galaxy_s5: --profile bs_android_phone BS_DEVICE="Samsung Galaxy S5"
1423
- bs_nexus5: --profile bs_android_phone BS_DEVICE="Google Nexus 5"
1424
- bs_moto_razr: --profile bs_android_phone BS_DEVICE="Motorola Razr"
1425
- bs_sony_xperia: --profile bs_android_phone BS_DEVICE="Sony Xperia Tipo"
1426
-
1427
- bs_android_tablet: --profile bs_android DEVICE_TYPE=tablet
1428
- bs_kindle_fire_hd89: --profile bs_android_tablet BS_DEVICE="Amazon Kindle Fire HD 8.9"
1429
- bs_kindle_fire_hdx7: --profile bs_android_tablet BS_DEVICE="Amazon Kindle Fire HDX 7"
1430
- bs_kindle_fire2: --profile bs_android_tablet BS_DEVICE="Amazon Kindle Fire 2"
1431
- bs_nexus7: --profile bs_android_tablet BS_DEVICE="Google Nexus 7"
1432
-
1433
- # BrowserStack Android real device mobile browser profiles
1434
- bs_android_device: --profile bs_mobile BS_BROWSER=android BS_OS=android BS_REAL_MOBILE="true"
1435
- bs_google_pixel8: --profile bs_android_device BS_DEVICE="Google Pixel" BS_OS_VERSION="8.0" DEVICE_TYPE=phone
1436
- bs_google_pixel71: --profile bs_android_device BS_DEVICE="Google Pixel" BS_OS_VERSION="7.1" DEVICE_TYPE=phone
1437
- bs_nexus6: --profile bs_android_device BS_DEVICE="Google Nexus 6" DEVICE_TYPE=phone
1438
- bs_galaxy_s8_plus: --profile bs_android_device BS_DEVICE="Samsung Galaxy S8 Plus" DEVICE_TYPE=phone
1439
- bs_galaxy_s8: --profile bs_android_device BS_DEVICE="Samsung Galaxy S8" DEVICE_TYPE=phone
1440
- bs_galaxy_s7: --profile bs_android_device BS_DEVICE="Samsung Galaxy S7" DEVICE_TYPE=phone
1441
- bs_galaxy_s6: --profile bs_android_device BS_DEVICE="Samsung Galaxy S6" DEVICE_TYPE=phone
1442
- bs_galaxy_note4: --profile bs_android_device BS_DEVICE="Samsung Galaxy Note 4" DEVICE_TYPE=tablet
1443
- bs_nexus9: --profile bs_android_device BS_DEVICE="Google Nexus 9" DEVICE_TYPE=tablet
1444
-
1445
1057
 
1446
1058
  #==============
1447
- # profiles for remotely hosted web browsers on the CrossBrowserTesting service
1059
+ # profiles for native Android apps hosted within Android Studio Android Virtual Device emulators
1060
+ # NOTE: Requires installation of Android Studio, Android version specific virtual device simulators, and Appium
1448
1061
  #==============
1449
1062
 
1450
- crossbrowser: WEB_BROWSER=crossbrowser CB_USERNAME=<INSERT USER NAME HERE> CB_AUTHKEY=<INSERT PASSWORD HERE>
1451
- cb_desktop: --profile crossbrowser <%= desktop %>
1452
- cb_mobile: --profile crossbrowser <%= mobile %>
1453
-
1454
- # CrossBrowserTesting OS X desktop browser profiles
1455
- cb_osx: --profile cb_desktop RESOLUTION="1920x1200"
1456
- cb_macos_sierra: --profile cb_osx CB_OS="Mac10.12"
1457
- cb_chrome_sierra: --profile cb_macos_sierra CB_BROWSER="Chrome53x64"
1458
- cb_safari_sierra: --profile cb_macos_sierra CB_BROWSER="Safari10"
1459
-
1460
- cb_osx_el_capitan: --profile cb_osx CB_OS="Mac10.11"
1461
- cb_ff_el_cap: --profile cb_osx_el_capitan CB_BROWSER="FF46"
1462
- cb_chrome_el_cap: --profile cb_osx_el_capitan CB_BROWSER="Chrome48x64"
1463
- cb_safari_el_cap: --profile cb_osx_el_capitan CB_BROWSER="Safari9"
1464
-
1465
- cb_osx_yosemite: --profile cb_osx CB_OS="Mac10.10"
1466
- cb_ff_yos: --profile cb_osx_yosemite CB_BROWSER="FF46"
1467
- cb_chrome_yos: --profile cb_osx_yosemite CB_BROWSER="Chrome48x64"
1468
- cb_safari_yos: --profile cb_osx_yosemite CB_BROWSER="Safari8"
1469
-
1470
- cb_osx_mavericks: --profile cb_osx CB_OS="Mac10.9"
1471
- cb_ff_mav: --profile cb_osx_mavericks CB_BROWSER="FF46"
1472
- cb_chrome_mav: --profile cb_osx_mavericks CB_BROWSER="Chrome48x64"
1473
- cb_safari_mav: --profile cb_osx_mavericks CB_BROWSER="Safari7"
1474
-
1475
- # CrossBrowserTesting Windows desktop browser profiles
1476
- cb_win: --profile cb_desktop RESOLUTION="1920x1080"
1477
- cb_win7: --profile cb_win CB_OS="Win7x64-C1"
1478
- cb_win8: --profile cb_win CB_OS="Win8"
1479
- cb_win10: --profile cb_win CB_OS="Win10"
1480
- cb_ff_win7: --profile cb_win7 CB_BROWSER="FF46"
1481
- cb_ff_win8: --profile cb_win8 CB_BROWSER="FF46"
1482
- cb_ff_win10: --profile cb_win10 CB_BROWSER="FF46"
1483
- cb_chrome_win7: --profile cb_win7 CB_BROWSER="Chrome48x64"
1484
- cb_chrome_win8: --profile cb_win8 CB_BROWSER="Chrome48x64"
1485
- cb_chrome_win10: --profile cb_win10 CB_BROWSER="Chrome48x64"
1486
- cb_edge_win10: --profile cb_win10 CB_BROWSER="Edge20"
1487
-
1488
- cb_ie11_win7: --profile cb_win7 CB_BROWSER="IE11"
1489
- cb_ie10_win7: --profile cb_win7 CB_BROWSER="IE10"
1490
- cb_ie9_win7: --profile cb_win7 CB_BROWSER="IE9"
1491
- cb_ie11_win8: --profile cb_win8 CB_BROWSER="IE11"
1492
- cb_ie10_win8: --profile cb_win8 CB_BROWSER="IE10"
1493
- cb_ie11_win10: --profile cb_win10 CB_BROWSER="IE11"
1494
-
1495
- # CrossBrowserTesting iOS mobile browser profiles
1496
- cb_iphone6s_plus: --profile cb_mobile DEVICE_TYPE=phone CB_PLATFORM="iPhone6sPlus-iOS9sim" CB_BROWSER="MblSafari9.0" RESOLUTION="1242x2208"
1497
- cb_iphone6s: --profile cb_mobile DEVICE_TYPE=phone CB_PLATFORM="iPhone6s-iOS9sim" CB_BROWSER="MblSafari9.0" RESOLUTION="750x1334"
1498
- cb_iphone6_plus: --profile cb_mobile DEVICE_TYPE=phone CB_PLATFORM="iPhone6Plus-iOS8sim" CB_BROWSER="MblSafari8.0" RESOLUTION="1242x2208"
1499
- cb_iphone6: --profile cb_mobile DEVICE_TYPE=phone CB_PLATFORM="iPhone6-iOS8sim" CB_BROWSER="MblSafari8.0" RESOLUTION="750x1334"
1500
- cb_iphone5s: --profile cb_mobile DEVICE_TYPE=phone CB_PLATFORM="iPhone5s-iOS7sim" CB_BROWSER="MblSafari7.0" RESOLUTION="640x1136"
1501
- cb_ipad_pro: --profile cb_mobile DEVICE_TYPE=tablet CB_PLATFORM="iPadPro-iOS9Sim" CB_BROWSER="MblSafari9.0" RESOLUTION="2732x2048"
1502
- cb_ipad_air2: --profile cb_mobile DEVICE_TYPE=tablet CB_PLATFORM="iPadAir2-iOS9Sim" CB_BROWSER="MblSafari9.0" RESOLUTION="2048x1536"
1503
- cb_ipad_air: --profile cb_mobile DEVICE_TYPE=tablet CB_PLATFORM="iPadAir-iOS8Sim" CB_BROWSER="MblSafari8.0" RESOLUTION="2048x1536"
1504
- cb_ipad_mini: --profile cb_mobile DEVICE_TYPE=tablet CB_PLATFORM="iPadMiniRetina-iOS7Sim" CB_BROWSER="MblSafari7.0" RESOLUTION="2048x1536"
1505
-
1506
- # CrossBrowserTesting Android mobile browser profiles
1507
- cb_nexus7: --profile cb_mobile CB_PLATFORM="Nexus7-And42" CB_BROWSER="MblChrome37" RESOLUTION="800x1280"
1508
- cb_galaxy_tab2: --profile cb_mobile CB_PLATFORM="GalaxyTab2-And41" CB_BROWSER="MblChrome38" RESOLUTION="1280x800"
1509
- cb_galaxy_s5: --profile cb_mobile CB_PLATFORM="GalaxyS5-And44" CB_BROWSER="MblChrome35" RESOLUTION="1080x1920"
1510
- cb_galaxy_s4: --profile cb_mobile CB_PLATFORM="GalaxyS4-And42" CB_BROWSER="MblChrome33" RESOLUTION="1080x1920"
1063
+ appium_android: WEB_BROWSER=appium --profile android AUTOMATION_ENGINE=UiAutomator2 APP_PLATFORM_NAME="Android" <%= mobile %>
1064
+ app_android_12: --profile appium_android APP_VERSION="12.0"
1065
+ pixel_5_api31_sim: --profile app_android_12 DEVICE_TYPE=phone APP_DEVICE="Pixel_5_API_31"
1511
1066
 
1512
1067
 
1513
1068
  #==============
1514
- # profiles for remotely hosted web browsers on the SauceLabs service
1069
+ # profiles for remotely hosted devices on the BrowserStack service
1070
+ # WARNING: Credentials should not be stored as text in your cucumber.yml file where it can be exposed by anyone with access
1071
+ # to your version control system
1515
1072
  #==============
1516
1073
 
1517
- saucelabs: WEB_BROWSER=saucelabs SL_USERNAME=<INSERT USER NAME HERE> SL_AUTHKEY=<INSERT PASSWORD HERE>
1518
- sl_desktop: --profile saucelabs <%= desktop %>
1519
-
1520
- # SauceLabs OS X desktop browser profiles
1521
- sl_osx_sierra: --profile sl_desktop SL_OS="macOS 10.12"
1522
- sl_ff_sierra: --profile sl_osx_sierra SL_BROWSER="firefox"
1523
- sl_chrome_sierra: --profile sl_osx_sierra SL_BROWSER="chrome"
1524
- sl_safari_sierra: --profile sl_osx_sierra SL_BROWSER="safari"
1525
-
1526
- sl_osx_el_capitan: --profile sl_desktop SL_OS="OS X 10.11"
1527
- sl_ff_el_cap: --profile sl_osx_el_capitan SL_BROWSER="firefox"
1528
- sl_chrome_el_cap: --profile sl_osx_el_capitan SL_BROWSER="chrome"
1529
- sl_safari_el_cap: --profile sl_osx_el_capitan SL_BROWSER="safari"
1074
+ browserstack: WEB_BROWSER=browserstack BS_USERNAME="<INSERT USER NAME HERE>" BS_AUTHKEY="<INSERT PASSWORD HERE>" TEST_CONTEXT="TestCentricity"
1530
1075
 
1531
- sl_osx_yosemite: --profile sl_desktop SL_OS="OS X 10.10" RESOLUTION="1920x1200"
1532
- sl_ff_yos: --profile sl_osx_yosemite SL_BROWSER="firefox"
1533
- sl_chrome_yos: --profile sl_osx_yosemite SL_BROWSER="chrome"
1534
- sl_safari_yos: --profile sl_osx_yosemite SL_BROWSER="safari"
1076
+ # BrowserStack iOS real device native app profiles
1077
+ bs_ios: --profile browserstack --profile ios BS_OS=ios <%= mobile %>
1078
+ bs_iphone: --profile bs_ios DEVICE_TYPE=phone
1079
+ bs_iphone13PM_15: --profile bs_iphone BS_OS_VERSION="15" BS_DEVICE="iPhone 13 Pro Max"
1080
+ bs_iphone11_14: --profile bs_iphone BS_OS_VERSION="14" BS_DEVICE="iPhone 11"
1535
1081
 
1536
- sl_osx_mavericks: --profile sl_desktop SL_OS="OS X 10.9" RESOLUTION="1920x1200"
1537
- sl_ff_mav: --profile sl_osx_mavericks SL_BROWSER="firefox"
1538
- sl_chrome_mav: --profile sl_osx_mavericks SL_BROWSER="chrome"
1539
- sl_safari_mav: --profile sl_osx_mavericks SL_BROWSER="safari"
1540
-
1541
- # SauceLabs Windows desktop browser profiles
1542
- sl_win7: --profile sl_desktop SL_OS="Windows 7" RESOLUTION="1920x1200"
1543
- sl_win8: --profile sl_desktop SL_OS="Windows 8.1" RESOLUTION="1280x1024"
1544
- sl_win10: --profile sl_desktop SL_OS="Windows 10" RESOLUTION="1280x1024"
1545
- sl_ff_win7: --profile sl_win7 SL_BROWSER="firefox"
1546
- sl_ff_win8: --profile sl_win8 SL_BROWSER="firefox"
1547
- sl_ff_win10: --profile sl_win10 SL_BROWSER="firefox"
1548
- sl_chrome_win7: --profile sl_win7 SL_BROWSER="chrome"
1549
- sl_chrome_win8: --profile sl_win8 SL_BROWSER="chrome"
1550
- sl_chrome_win10: --profile sl_win10 SL_BROWSER="chrome"
1551
-
1552
- sl_ie11_win7: --profile sl_win7 SL_BROWSER="internet explorer" SL_VERSION="11.0"
1553
- sl_ie10_win7: --profile sl_win7 SL_BROWSER="internet explorer" SL_VERSION="10.0"
1554
- sl_ie9_win7: --profile sl_win7 SL_BROWSER="internet explorer" SL_VERSION="9.0"
1555
- sl_ie11_win8: --profile sl_win8 SL_BROWSER="internet explorer" SL_VERSION="11.0"
1556
- sl_ie11_win10: --profile sl_win10 SL_BROWSER="internet explorer"
1082
+ # BrowserStack Android real device native app profiles
1083
+ bs_android: --profile browserstack --profile android BS_OS=android <%= mobile %>
1084
+ bs_pixel5: --profile bs_android BS_DEVICE="Google Pixel 5" BS_OS_VERSION="12.0" DEVICE_TYPE=phone
1557
1085
 
1558
1086
 
1559
1087
  #==============
1560
- # profiles for remotely hosted web browsers on the TestingBot service
1088
+ # profiles for remotely hosted devices on the SauceLabs service
1089
+ # WARNING: Credentials should not be stored as text in your cucumber.yml file where it can be exposed by anyone with access
1090
+ # to your version control system
1561
1091
  #==============
1562
1092
 
1563
- testingbot: WEB_BROWSER=testingbot TB_USERNAME=<INSERT USER NAME HERE> TB_AUTHKEY=<INSERT PASSWORD HERE>
1564
- tb_desktop: --profile testingbot <%= desktop %> RESOLUTION="1920x1200"
1565
- tb_mobile: --profile testingbot <%= mobile %>
1566
-
1567
- # TestingBot OS X desktop browser profiles
1568
- tb_macos_sierra: --profile tb_desktop TB_OS="SIERRA"
1569
- tb_ff_sierra: --profile tb_macos_sierra TB_BROWSER="firefox"
1570
- tb_chrome_sierra: --profile tb_macos_sierra TB_BROWSER="chrome"
1571
- tb_safari_sierra: --profile tb_macos_sierra TB_BROWSER="safari" TB_VERSION="10"
1572
-
1573
- tb_osx_el_capitan: --profile tb_desktop TB_OS="CAPITAN"
1574
- tb_ff_el_cap: --profile tb_osx_el_capitan TB_BROWSER="firefox"
1575
- tb_chrome_el_cap: --profile tb_osx_el_capitan TB_BROWSER="chrome"
1576
- tb_safari_el_cap: --profile tb_osx_el_capitan TB_BROWSER="safari" TB_VERSION="9"
1577
-
1578
- tb_osx_yosemite: --profile tb_desktop TB_OS="YOSEMITE"
1579
- tb_ff_yos: --profile tb_osx_yosemite TB_BROWSER="firefox"
1580
- tb_chrome_yos: --profile tb_osx_yosemite TB_BROWSER="chrome"
1581
- tb_safari_yos: --profile tb_osx_yosemite TB_BROWSER="safari" TB_VERSION="8"
1093
+ saucelabs: WEB_BROWSER=saucelabs SL_USERNAME="<INSERT USER NAME HERE>" SL_AUTHKEY="<INSERT PASSWORD HERE>" DATA_CENTER="us-west-1" AUTOMATE_PROJECT="TestCentricity - SauceLabs"
1582
1094
 
1583
- tb_osx_mavericks: --profile tb_desktop TB_OS="MAVERICKS"
1584
- tb_ff_mav: --profile tb_osx_mavericks TB_BROWSER="firefox"
1585
- tb_chrome_mav: --profile tb_osx_mavericks TB_BROWSER="chrome"
1586
- tb_safari_mav: --profile tb_osx_mavericks TB_BROWSER="safari" TB_VERSION="7"
1095
+ # SauceLabs iOS real device native app profiles
1096
+ sl_ios: --profile saucelabs --profile ios SL_OS=ios <%= mobile %>
1097
+ sl_iphone: --profile sl_ios DEVICE_TYPE=phone
1098
+ sl_iphone13PM_15: --profile sl_iphone SL_DEVICE="iPhone 13 Pro Max Simulator" SL_OS_VERSION="15.4"
1587
1099
 
1588
- # TestingBot Windows desktop browser profiles
1589
- tb_win7: --profile tb_desktop TB_OS="WIN7"
1590
- tb_win8: --profile tb_desktop TB_OS="WIN8"
1591
- tb_win10: --profile tb_desktop TB_OS="WIN10"
1592
- tb_ff_win7: --profile tb_win7 TB_BROWSER="firefox"
1593
- tb_ff_win8: --profile tb_win8 TB_BROWSER="firefox"
1594
- tb_ff_win10: --profile tb_win10 TB_BROWSER="firefox"
1595
- tb_chrome_win7: --profile tb_win7 TB_BROWSER="chrome"
1596
- tb_chrome_win8: --profile tb_win8 TB_BROWSER="chrome"
1597
- tb_chrome_win10: --profile tb_win10 TB_BROWSER="chrome"
1100
+ # SauceLabs Android real device native app profiles
1101
+ sl_android: --profile saucelabs --profile android SL_OS=android <%= mobile %>
1102
+ sl_pixel5: --profile sl_android SL_DEVICE="Google Pixel 5 GoogleAPI Emulator" SL_OS_VERSION="12.0" DEVICE_TYPE=phone
1598
1103
 
1599
- tb_ie9_win7: --profile tb_win7 TB_BROWSER="internet explorer" TB_VERSION="9"
1600
- tb_ie11_win8: --profile tb_win8 TB_BROWSER="internet explorer" TB_VERSION="11"
1601
- tb_ie10_win8: --profile tb_win8 TB_BROWSER="internet explorer" TB_VERSION="10"
1602
- tb_ie11_win10: --profile tb_win10 TB_BROWSER="internet explorer" TB_VERSION="11"
1603
- tb_edge_win10: --profile tb_win10 TB_BROWSER="microsoftedge" TB_VERSION="14"
1604
1104
 
1605
- # TestingBot iOS mobile browser profiles
1606
- tb_ios: --profile tb_mobile TB_OS="MAC" TB_BROWSER="safari" TB_PLATFORM="iOS"
1607
- tb_iphone6s_plus_10: --profile tb_ios DEVICE_TYPE=phone TB_VERSION="10.0" TB_DEVICE="iPhone 6s Plus"
1608
- tb_iphone6s_plus_93: --profile tb_ios DEVICE_TYPE=phone TB_VERSION="9.3" TB_DEVICE="iPhone 6s Plus"
1609
- tb_iphone6_plus_10: --profile tb_ios DEVICE_TYPE=phone TB_VERSION="10.0" TB_DEVICE="iPhone 6 Plus"
1610
- tb_iphone6_plus_93: --profile tb_ios DEVICE_TYPE=phone TB_VERSION="9.3" TB_DEVICE="iPhone 6 Plus"
1611
- tb_iphone6s_10: --profile tb_ios DEVICE_TYPE=phone TB_VERSION="10.0" TB_DEVICE="iPhone 6s"
1612
- tb_iphone6s_93: --profile tb_ios DEVICE_TYPE=phone TB_VERSION="9.3" TB_DEVICE="iPhone 6s"
1613
- tb_iphone5s_10: --profile tb_ios DEVICE_TYPE=phone TB_VERSION="10.0" TB_DEVICE="iPhone 5s"
1614
- tb_iphone5s_93: --profile tb_ios DEVICE_TYPE=phone TB_VERSION="9.3" TB_DEVICE="iPhone 5s"
1615
- tb_ipad_pro_10: --profile tb_ios DEVICE_TYPE=tablet TB_VERSION="10.0" TB_DEVICE="iPad Pro"
1616
- tb_ipad_pro_93: --profile tb_ios DEVICE_TYPE=tablet TB_VERSION="9.3" TB_DEVICE="iPad Pro"
1617
- tb_ipad_air2_10: --profile tb_ios DEVICE_TYPE=tablet TB_VERSION="10.0" TB_DEVICE="iPad Air 2"
1618
- tb_ipad_air2_93: --profile tb_ios DEVICE_TYPE=tablet TB_VERSION="9.3" TB_DEVICE="iPad Air 2"
1105
+ #==============
1106
+ # profiles for remotely hosted devices on the TestingBot service
1107
+ # WARNING: Credentials should not be stored as text in your cucumber.yml file where it can be exposed by anyone with access
1108
+ # to your version control system
1109
+ #==============
1619
1110
 
1111
+ testingbot: WEB_BROWSER=testingbot TB_USERNAME="<INSERT USER NAME HERE>" TB_AUTHKEY="<INSERT PASSWORD HERE>" AUTOMATE_PROJECT="TestCentricity - TestingBot"
1620
1112
 
1621
- # TestingBot Android mobile browser profiles
1622
- tb_android: --profile tb_mobile TB_OS="ANDROID" TB_BROWSER="browser" TB_PLATFORM="Android"
1623
- tb_nexus_s: --profile tb_android TB_VERSION="6.0" TB_DEVICE="Nexus S"
1624
- tb_nexus_1: --profile tb_android TB_VERSION="5.0" TB_DEVICE="Nexus 1"
1625
- tb_nexus_4: --profile tb_android TB_VERSION="6.0" TB_DEVICE="Nexus 4"
1626
- tb_galaxy_nexus: --profile tb_android TB_VERSION="4.4" TB_DEVICE="Galaxy Nexus"
1627
- tb_galaxy_s4: --profile tb_android TB_VERSION="4.4" TB_DEVICE="Galaxy S4"
1628
- tb_galaxy_s5: --profile tb_android TB_VERSION="5.0" TB_DEVICE="Galaxy S5"
1629
- tb_galaxy_s6: --profile tb_android TB_VERSION="6.0" TB_DEVICE="Galaxy S6"
1630
-
1631
-
1632
- To specify a locally hosted target browser using a profile at runtime, you use the flag `--profile` or `-p` followed by the profile name when
1633
- invoking Cucumber in the command line. For instance, the following command invokes Cucumber and specifies that a local instance of Chrome
1634
- will be used as the target web browser:
1113
+ # TestingBot iOS real device native app profiles
1114
+ tb_ios: --profile testingbot --profile ios TB_OS=iOS <%= mobile %>
1115
+ tb_iphone: --profile tb_ios DEVICE_TYPE=phone
1116
+ tb_iphone11_14_dev: --profile tb_iphone TB_OS_VERSION="14.0" TB_DEVICE="iPhone 11" REAL_DEVICE=true
1117
+ tb_iphone11_14_sim: --profile tb_iphone TB_OS_VERSION="14.2" TB_DEVICE="iPhone 11"
1118
+ tb_iphone13PM_15_sim: --profile tb_iphone TB_OS_VERSION="15.4" TB_DEVICE="iPhone 13 Pro Max"
1635
1119
 
1636
- $ cucumber -p chrome
1120
+ # TestingBot Android real device native app profiles
1121
+ tb_android: --profile testingbot --profile android TB_OS=Android <%= mobile %>
1122
+ tb_pixel_dev: --profile tb_android TB_DEVICE="Pixel" TB_OS_VERSION="9.0" DEVICE_TYPE=phone REAL_DEVICE=true
1123
+ tb_pixel6_sim: --profile tb_android TB_DEVICE="Pixel 6" TB_OS_VERSION="12.0" DEVICE_TYPE=phone
1637
1124
 
1638
1125
 
1639
- The following command specifies that Cucumber will run tests against a local instance of Firefox, which will be used to emulate an iPad Pro
1640
- in landscape orientation:
1641
-
1642
- $ cucumber -p ipad_pro -p landscape
1643
-
1126
+ To specify a mobile simulator or real device target using a profile at runtime, you use the flag `--profile` or `-p` followed
1127
+ by the profile name when invoking Cucumber in the command line. For instance, the following command specifies that Cucumber will
1128
+ run tests against an iPad Pro (12.9-inch) (5th generation) with iOS version 15.4 in an XCode Simulator in portrait orientation:
1644
1129
 
1645
- The following command specifies that Cucumber will run tests against an iPad Pro with iOS version 9.3 in an XCode Simulator
1646
- in landscape orientation:
1647
-
1648
- $ cucumber -p ipad_pro_93_sim -p landscape
1130
+ cucumber -p ipad_pro_12_15_sim -p portrait
1649
1131
 
1650
1132
  NOTE: Appium must be running prior to executing this command
1651
1133
 
1134
+ You can ensure that Appium Server is running by including `-p run_appium` in your command line:
1652
1135
 
1653
- The following command specifies that Cucumber will run tests against a remotely hosted Safari web browser running on an OS X Yosemite
1654
- virtual machine on the BrowserStack service:
1136
+ cucumber -p ipad_pro_12_15_sim -p portrait -p run_appium
1655
1137
 
1656
- cucumber -p bs_safari_yos
1657
-
1658
1138
 
1659
- The following command specifies that Cucumber will run tests against a remotely hosted Mobile Safari web browser on an iPhone 6s Plus in
1660
- landscape orientation running on the BrowserStack service:
1139
+ The following command specifies that Cucumber will run tests against a cloud hosted iPhone 13 Pro Max running iOS 15.4 on the
1140
+ BrowserStack service:
1661
1141
 
1662
- $ cucumber -p bs_iphone6_plus -p landscape
1142
+ cucumber -p bs_iphone13PM_15
1663
1143
 
1664
1144
 
1665
1145
 
1666
- ## Web Test Automation Framework Implementation
1146
+ ## Recommended Project Organization and Structure
1667
1147
 
1668
- <img src="http://i.imgur.com/RvpxjzW.jpg" width="1024" alt="Web Framework Overview" title="Web Framework Overview">
1148
+ Below is an example of the project structure of a typical Cucumber based native mobile app test automation framework with a Screen
1149
+ Object Model architecture. `ScreenObject` class definitions should be stored in the `/features/support/<platform>/screens`
1150
+ folders, organized in functional area sub-folders as needed. Likewise, `ScreenSection` class definitions should be stored in
1151
+ the `/features/support/<platform>/sections` folder, where `<platform>` is typically `ios` or `android`.
1669
1152
 
1153
+ Common embedded WebViews for native and hybrid apps that are shared with both iOS and Android platforms should be stored in
1154
+ the `/features/support/shared_webviews` folder.
1670
1155
 
1156
+ my_automation_project
1157
+ ├── config
1158
+ │ ├── locales
1159
+ │ ├── test_data
1160
+ │ └── cucumber.yml
1161
+ ├── features
1162
+ │ ├── step_definitions
1163
+ │ ├── support
1164
+ │ │ ├── android
1165
+ | | | ├── screens
1166
+ | | | └── sections
1167
+ │ │ ├── ios
1168
+ | | | ├── screens
1169
+ | | | └── sections
1170
+ │ │ ├── shared_webviews
1171
+ │ │ ├── env.rb
1172
+ │ │ ├── hooks.rb
1173
+ │ │ └── world_pages.rb
1174
+ ├── Gemfile
1175
+ └── README.md
1671
1176
 
1672
1177
 
1673
- ## Copyright and License
1178
+ <img src="https://i.imgur.com/DdoDOxV.jpg" alt="TestCentricity Native Mobile App Framework Overview" title="TestCentricity Native Mobile App Framework Overview">
1674
1179
 
1675
- TestCentricity™ Framework is Copyright (c) 2014-2018, Tony Mrozinski.
1676
- All rights reserved.
1677
1180
 
1181
+ ### Combined native iOS/Android app and web app project
1182
+
1183
+ If your native mobile apps share feature parity and a common user experience with a responsive web UI that is accessed via
1184
+ desktop/mobile web browsers, you can effectively create one set of Cucumber feature files and scenarios that can be used
1185
+ to test across all three platforms - iOS, Android, and web.
1186
+
1187
+ Below is an example of the project structure of a typical Cucumber based native mobile app and web UI test automation framework
1188
+ with a Screen and Page Object Model architecture. `ScreenObject` class definitions should be stored in the `/features/support/<platform>/screens`
1189
+ folders, organized in functional area sub-folders as needed. Likewise, `ScreenSection` class definitions should be stored in
1190
+ the `/features/support/<platform>/sections` folder. `PageObject` class definitions should be stored in the `/features/support/web/pages`
1191
+ folders, organized in functional area sub-folders as needed, while `PageSection` class definitions should be stored in the
1192
+ the `/features/support/web/sections` folder.
1678
1193
 
1679
- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions
1680
- are met:
1194
+ my_automation_project
1195
+ ├── config
1196
+ │ ├── locales
1197
+ │ ├── test_data
1198
+ │ └── cucumber.yml
1199
+ ├── features
1200
+ │ ├── step_definitions
1201
+ │ ├── support
1202
+ │ │ ├── android
1203
+ | | | ├── screens
1204
+ | | | └── sections
1205
+ │ │ ├── ios
1206
+ | | | ├── screens
1207
+ | | | └── sections
1208
+ │ │ ├── web
1209
+ | | | ├── pages
1210
+ | | | └── sections
1211
+ │ │ ├── env.rb
1212
+ │ │ ├── hooks.rb
1213
+ │ │ └── world_pages.rb
1214
+ ├── Gemfile
1215
+ └── README.md
1681
1216
 
1682
- 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer.
1683
1217
 
1684
- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in
1685
- the documentation and/or other materials provided with the distribution.
1218
+ <img src="https://i.imgur.com/uzFhvu4.jpg" alt="TestCentricity Native Mobile App and Web Framework Overview" title="TestCentricity Native Mobile App and Web Framework Overview">
1686
1219
 
1687
- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from
1688
- this software without specific prior written permission.
1689
1220
 
1690
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1691
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1692
- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1693
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
1694
- ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1695
- USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1221
+ ## Copyright and License
1222
+
1223
+ TestCentricity™ Framework is Copyright (c) 2014-2022, Tony Mrozinski.
1224
+ All rights reserved.
1225
+
1226
+ Redistribution and use in source and binary forms, with or without
1227
+ modification, are permitted provided that the following conditions are met:
1228
+
1229
+ 1. Redistributions of source code must retain the above copyright notice,
1230
+ this list of conditions and the following disclaimer.
1231
+
1232
+ 2. Redistributions in binary form must reproduce the above copyright
1233
+ notice, this list of conditions and the following disclaimer in the
1234
+ documentation and/or other materials provided with the distribution.
1235
+
1236
+ 3. Neither the name of the copyright holder nor the names of its contributors
1237
+ may be used to endorse or promote products derived from this software without
1238
+ specific prior written permission.
1239
+
1240
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
1241
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1242
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1243
+ IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
1244
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1245
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
1246
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
1247
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1248
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1249
+ POSSIBILITY OF SUCH DAMAGE.