testcentricity_apps 4.0.15 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -14
- data/LICENSE.md +1 -1
- data/README.md +374 -248
- data/lib/testcentricity_apps/app_core/appium_connect_helper.rb +58 -70
- data/lib/testcentricity_apps/app_core/screen_object.rb +58 -12
- data/lib/testcentricity_apps/app_core/screen_objects_helper.rb +29 -15
- data/lib/testcentricity_apps/app_core/screen_section.rb +63 -20
- data/lib/testcentricity_apps/app_elements/alert.rb +8 -8
- data/lib/testcentricity_apps/app_elements/app_element.rb +39 -9
- data/lib/testcentricity_apps/app_elements/list.rb +4 -4
- data/lib/testcentricity_apps/app_elements/menu.rb +2 -2
- data/lib/testcentricity_apps/app_elements/menubar.rb +0 -22
- data/lib/testcentricity_apps/app_elements/selectlist.rb +5 -5
- data/lib/testcentricity_apps/app_elements/switch.rb +1 -1
- data/lib/testcentricity_apps/app_elements/table.rb +397 -0
- data/lib/testcentricity_apps/data_objects/data_objects_helper.rb +3 -7
- data/lib/testcentricity_apps/data_objects/environment.rb +2 -54
- data/lib/testcentricity_apps/exception_queue_helper.rb +9 -10
- data/lib/testcentricity_apps/utility_helpers.rb +1 -0
- data/lib/testcentricity_apps/version.rb +1 -1
- data/lib/testcentricity_apps.rb +1 -0
- metadata +23 -22
data/README.md
CHANGED
|
@@ -15,12 +15,12 @@ or locally or cloud hosted iOS and Android real devices or simulators.
|
|
|
15
15
|
The TestCentricity™ For Apps gem supports automated testing of MacOS desktop apps and native iOS and Android apps running
|
|
16
16
|
on the following mobile test targets:
|
|
17
17
|
* locally hosted MacOS desktop apps (using Appium 2.x, the Mac2 driver, and XCode on macOS)
|
|
18
|
-
* locally hosted iOS device simulators or physical iOS devices (using Appium, the XCUItest driver, and XCode on macOS)
|
|
19
|
-
* locally hosted Android devices or Android Studio virtual device emulators (using Appium, the UIAutomator2 driver, and Android Studio)
|
|
18
|
+
* locally hosted iOS device simulators or physical iOS devices (using Appium 2.x, the XCUItest driver, and XCode on macOS)
|
|
19
|
+
* locally hosted Android devices or Android Studio virtual device emulators (using Appium 2.x, the UIAutomator2 driver, and Android Studio)
|
|
20
20
|
* cloud hosted iOS or Android physical devices and simulators from the following service:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
* [Browserstack](https://www.browserstack.com/list-of-browsers-and-platforms/app_automate)
|
|
22
|
+
* [Sauce Labs](https://saucelabs.com/platform/mobile-testing)
|
|
23
|
+
* [TestingBot](https://testingbot.com/mobile/realdevicetesting)
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
## What's New
|
|
@@ -31,13 +31,12 @@ The RubyDocs for this gem can be found [here](https://www.rubydoc.info/gems/test
|
|
|
31
31
|
|
|
32
32
|
Three example projects that demonstrates the implementation of a screen object model framework using TestCentricity™ For Apps
|
|
33
33
|
and Cucumber can be found at the following:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
* [tc_mac_calculator_demo](https://github.com/TestCentricity/tc_mac_calculator_demo)
|
|
35
|
+
* [tc_mobile_react_native_demo](https://github.com/TestCentricity/tc_mobile_react_native_demo)
|
|
36
|
+
* [tc_mobile_wdio_demo](https://github.com/TestCentricity/tc_mobile_wdio_demo)
|
|
37
37
|
|
|
38
|
-
Refer to [this wiki page](https://github.com/TestCentricity/testcentricity_apps/wiki/XCUItest-driver-bug-impacts-iOS-dialogs-managed-by-com.apple.springboard) for
|
|
39
|
-
|
|
40
|
-
verify iOS system level modal dialogs.
|
|
38
|
+
Refer to [this wiki page](https://github.com/TestCentricity/testcentricity_apps/wiki/XCUItest-driver-bug-impacts-iOS-dialogs-managed-by-com.apple.springboard) for information on a bug with the latest versions of the XCUItest driver that affects Appium's
|
|
39
|
+
ability to interact with and verify iOS system level modal dialogs.
|
|
41
40
|
|
|
42
41
|
|
|
43
42
|
### Which gem should I use?
|
|
@@ -55,7 +54,7 @@ verify iOS system level modal dialogs.
|
|
|
55
54
|
|
|
56
55
|
## Installation
|
|
57
56
|
|
|
58
|
-
TestCentricity For Apps requires Ruby 3.
|
|
57
|
+
TestCentricity For Apps requires Ruby 3.1.0 or later. To install the TestCentricity For Apps gem, add this line to your
|
|
59
58
|
automation project's `Gemfile`:
|
|
60
59
|
|
|
61
60
|
gem 'testcentricity_apps'
|
|
@@ -110,33 +109,33 @@ Your `ScreenObject` class definitions should be contained within individual `.rb
|
|
|
110
109
|
folder of your test automation project, where `<platform>` is typically `mac`, `ios`, or `android`. For each screen in your app,
|
|
111
110
|
you will typically have to define a `ScreenObject` for each platform version of your app.
|
|
112
111
|
|
|
113
|
-
|
|
114
|
-
├── config
|
|
115
|
-
├── features
|
|
116
|
-
│ ├── step_definitions
|
|
117
|
-
│ ├── support
|
|
118
|
-
│ │ ├── android
|
|
119
|
-
| | | └── screens
|
|
120
|
-
│ │ ├── ios
|
|
121
|
-
| | | └── screens
|
|
122
|
-
│ │ ├── mac
|
|
123
|
-
| | | └── screens
|
|
124
|
-
│ │ ├── env.rb
|
|
125
|
-
│ │ └── hooks.rb
|
|
126
|
-
├── Gemfile
|
|
127
|
-
└── README.md
|
|
112
|
+
📁 my_automation_project
|
|
113
|
+
├── 📁 config
|
|
114
|
+
├── 📁 features
|
|
115
|
+
│ ├── 📁 step_definitions
|
|
116
|
+
│ ├── 📁 support
|
|
117
|
+
│ │ ├── 📁 android
|
|
118
|
+
| | | └── 📁 screens
|
|
119
|
+
│ │ ├── 📁 ios
|
|
120
|
+
| | | └── 📁 screens
|
|
121
|
+
│ │ ├── 📁 mac
|
|
122
|
+
| | | └── 📁 screens
|
|
123
|
+
│ │ ├── 📄 env.rb
|
|
124
|
+
│ │ └── 📄 hooks.rb
|
|
125
|
+
├── 📄 Gemfile
|
|
126
|
+
└── 📄 README.md
|
|
128
127
|
|
|
129
128
|
|
|
130
129
|
You define a new `ScreenObject` as shown below:
|
|
131
130
|
```ruby
|
|
132
131
|
class LoginScreen < TestCentricity::ScreenObject
|
|
133
132
|
end
|
|
134
|
-
|
|
135
|
-
|
|
133
|
+
|
|
134
|
+
|
|
136
135
|
class ProductsScreen < TestCentricity::ScreenObject
|
|
137
136
|
end
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
|
|
138
|
+
|
|
140
139
|
class CheckoutAddressScreen < TestCentricity::ScreenObject
|
|
141
140
|
end
|
|
142
141
|
```
|
|
@@ -169,15 +168,15 @@ You define your screen's **Traits** as shown below:
|
|
|
169
168
|
trait(:screen_locator) { { accessibility_id: 'login screen' } }
|
|
170
169
|
trait(:deep_link) { 'mydemoapprn://login' }
|
|
171
170
|
end
|
|
172
|
-
|
|
173
|
-
|
|
171
|
+
|
|
172
|
+
|
|
174
173
|
class ProductsScreen < TestCentricity::ScreenObject
|
|
175
174
|
trait(:screen_name) { 'Products' }
|
|
176
175
|
trait(:screen_locator) { { accessibility_id: 'products screen' } }
|
|
177
176
|
trait(:deep_link) { 'mydemoapprn://store-overview' }
|
|
178
177
|
end
|
|
179
|
-
|
|
180
|
-
|
|
178
|
+
|
|
179
|
+
|
|
181
180
|
class CheckoutAddressScreen < TestCentricity::ScreenObject
|
|
182
181
|
trait(:screen_name) { 'Checkout - Address' }
|
|
183
182
|
trait(:screen_locator) { { accessibility_id: 'checkout address screen' } }
|
|
@@ -194,7 +193,7 @@ buttons, etc. **UI Elements** are added to your `ScreenObject` class definition
|
|
|
194
193
|
trait(:screen_name) { 'Login' }
|
|
195
194
|
trait(:screen_locator) { { accessibility_id: 'login screen' } }
|
|
196
195
|
trait(:deep_link) { 'mydemoapprn://login' }
|
|
197
|
-
|
|
196
|
+
|
|
198
197
|
# Login screen UI elements
|
|
199
198
|
labels username_label: { accessibility_id: 'Username'},
|
|
200
199
|
password_label: { xpath: '(//XCUIElementTypeStaticText[@name="Password"])[1]'},
|
|
@@ -211,7 +210,7 @@ buttons, etc. **UI Elements** are added to your `ScreenObject` class definition
|
|
|
211
210
|
trait(:screen_name) { 'Checkout - Address' }
|
|
212
211
|
trait(:screen_locator) { { accessibility_id: 'checkout address screen' } }
|
|
213
212
|
trait(:deep_link) { 'mydemoapprn://checkout-address' }
|
|
214
|
-
|
|
213
|
+
|
|
215
214
|
# Checkout Address screen UI elements
|
|
216
215
|
textfields fullname_field: { accessibility_id: 'Full Name* input field' },
|
|
217
216
|
address1_field: { accessibility_id: 'Address Line 1* input field' },
|
|
@@ -234,7 +233,7 @@ class definition for interacting with the UI to hide implementation details, as
|
|
|
234
233
|
trait(:screen_name) { 'Login' }
|
|
235
234
|
trait(:screen_locator) { { accessibility_id: 'login screen' } }
|
|
236
235
|
trait(:deep_link) { 'mydemoapprn://login' }
|
|
237
|
-
|
|
236
|
+
|
|
238
237
|
# Login screen UI elements
|
|
239
238
|
labels username_label: { accessibility_id: 'Username'},
|
|
240
239
|
password_label: { xpath: '(//XCUIElementTypeStaticText[@name="Password"])[1]'},
|
|
@@ -244,7 +243,7 @@ class definition for interacting with the UI to hide implementation details, as
|
|
|
244
243
|
textfields username_field: { accessibility_id: 'Username input field' },
|
|
245
244
|
password_field: { accessibility_id: 'Password input field' }
|
|
246
245
|
button :login_button, { accessibility_id: 'Login button' }
|
|
247
|
-
|
|
246
|
+
|
|
248
247
|
def verify_screen_ui
|
|
249
248
|
ui = {
|
|
250
249
|
header_label => { visible: true, caption: 'Login' },
|
|
@@ -256,7 +255,7 @@ class definition for interacting with the UI to hide implementation details, as
|
|
|
256
255
|
}
|
|
257
256
|
verify_ui_states(ui)
|
|
258
257
|
end
|
|
259
|
-
|
|
258
|
+
|
|
260
259
|
def login(username, password)
|
|
261
260
|
fields = {
|
|
262
261
|
username_field => username,
|
|
@@ -265,7 +264,7 @@ class definition for interacting with the UI to hide implementation details, as
|
|
|
265
264
|
populate_data_fields(fields)
|
|
266
265
|
login_button.tap
|
|
267
266
|
end
|
|
268
|
-
|
|
267
|
+
|
|
269
268
|
def verify_entry_error(reason)
|
|
270
269
|
ui = case reason.gsub(/\s+/, '_').downcase.to_sym
|
|
271
270
|
when :invalid_password, :invalid_user
|
|
@@ -326,7 +325,7 @@ object. A `ScreenSection` may contain other `ScreenSection` objects.
|
|
|
326
325
|
|
|
327
326
|
Below is an example of a footer navigation bar feature that is common to multiple screen -
|
|
328
327
|
|
|
329
|
-
 
|
|
330
329
|
|
|
331
330
|
|
|
332
331
|
### Defining a ScreenSection
|
|
@@ -335,24 +334,24 @@ Your `ScreenSection` class definitions should be contained within individual `.r
|
|
|
335
334
|
folder of your test automation project, where `<platform>` is typically `mac`, `ios`, or `android`. For each screen section in your
|
|
336
335
|
app, you will typically have to define a `ScreenSection` for each platform version of your app.
|
|
337
336
|
|
|
338
|
-
|
|
339
|
-
├── config
|
|
340
|
-
├── features
|
|
341
|
-
│ ├── step_definitions
|
|
342
|
-
│ ├── support
|
|
343
|
-
│ │ ├── android
|
|
344
|
-
| | | ├── screens
|
|
345
|
-
| | | └── sections
|
|
346
|
-
│ │ ├── ios
|
|
347
|
-
| | | ├── screens
|
|
348
|
-
| | | └── sections
|
|
337
|
+
📁 my_automation_project
|
|
338
|
+
├── 📁 config
|
|
339
|
+
├── 📁 features
|
|
340
|
+
│ ├── 📁 step_definitions
|
|
341
|
+
│ ├── 📁 support
|
|
342
|
+
│ │ ├── 📁 android
|
|
343
|
+
| | | ├── 📁 screens
|
|
344
|
+
| | | └── 📁 sections
|
|
345
|
+
│ │ ├── 📁 ios
|
|
346
|
+
| | | ├── 📁 screens
|
|
347
|
+
| | | └── 📁 sections
|
|
349
348
|
│ │ ├── mac
|
|
350
|
-
| | | ├── screens
|
|
351
|
-
| | | └── sections
|
|
352
|
-
│ │ ├── env.rb
|
|
353
|
-
│ │ └── hooks.rb
|
|
354
|
-
├── Gemfile
|
|
355
|
-
└── README.md
|
|
349
|
+
| | | ├── 📁 screens
|
|
350
|
+
| | | └── 📁 sections
|
|
351
|
+
│ │ ├── 📄 env.rb
|
|
352
|
+
│ │ └── 📄 hooks.rb
|
|
353
|
+
├── 📄 Gemfile
|
|
354
|
+
└── 📄 README.md
|
|
356
355
|
|
|
357
356
|
|
|
358
357
|
You define a new `ScreenSection` as shown below:
|
|
@@ -382,7 +381,7 @@ Elements** are added to your `ScreenSection` class definition as shown below:
|
|
|
382
381
|
class NavMenu < TestCentricity::ScreenSection
|
|
383
382
|
trait(:section_name) { 'Nav Menu' }
|
|
384
383
|
trait(:section_locator) { { xpath: '//XCUIElementTypeScrollView' } }
|
|
385
|
-
|
|
384
|
+
|
|
386
385
|
# Nav Menu UI elements
|
|
387
386
|
buttons close_button: { accessibility_id: 'close menu' },
|
|
388
387
|
webview_button: { accessibility_id: 'menu item webview' },
|
|
@@ -407,7 +406,7 @@ You can add methods to your `ScreenSection` class definition, as shown below:
|
|
|
407
406
|
class NavMenu < TestCentricity::ScreenSection
|
|
408
407
|
trait(:section_name) { 'Nav Menu' }
|
|
409
408
|
trait(:section_locator) { { xpath: '//XCUIElementTypeScrollView' } }
|
|
410
|
-
|
|
409
|
+
|
|
411
410
|
# Nav Menu UI elements
|
|
412
411
|
buttons close_button: { accessibility_id: 'close menu' },
|
|
413
412
|
webview_button: { accessibility_id: 'menu item webview' },
|
|
@@ -422,36 +421,36 @@ You can add methods to your `ScreenSection` class definition, as shown below:
|
|
|
422
421
|
log_out_button: { accessibility_id: 'menu item log out' },
|
|
423
422
|
api_calls_button: { accessibility_id: 'menu item api calls' },
|
|
424
423
|
sauce_video_button: { accessibility_id: 'menu item sauce bot video' }
|
|
425
|
-
|
|
424
|
+
|
|
426
425
|
def verify_ui
|
|
427
426
|
ui = {
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
427
|
+
self => { visible: true },
|
|
428
|
+
close_button => { visible: true, enabled: true },
|
|
429
|
+
webview_button => { visible: true, enabled: true, caption: 'Webview' },
|
|
430
|
+
qr_code_button => { visible: true, enabled: true, caption: 'QR Code Scanner' },
|
|
431
|
+
geo_location_button => { visible: true, enabled: true, caption: 'Geo Location' },
|
|
432
|
+
drawing_button => { visible: true, enabled: true, caption: 'Drawing' },
|
|
433
|
+
report_a_bug_button => { visible: true, enabled: true, caption: 'Report A Bug' },
|
|
434
|
+
about_button => { visible: true, enabled: true, caption: 'About' },
|
|
435
|
+
reset_app_button => { visible: true, enabled: true, caption: 'Reset App State' },
|
|
436
|
+
biometrics_button => { visible: true, enabled: true, caption: 'FaceID' },
|
|
437
|
+
log_in_button => { visible: true, enabled: true, caption: 'Log In' },
|
|
438
|
+
log_out_button => { visible: true, enabled: true, caption: 'Log Out' },
|
|
439
|
+
api_calls_button => { visible: true, enabled: true, caption: 'Api Calls' },
|
|
440
|
+
sauce_video_button => { visible: true, enabled: true, caption: 'Sauce Bot Video' }
|
|
442
441
|
}
|
|
443
442
|
verify_ui_states(ui)
|
|
444
443
|
end
|
|
445
|
-
|
|
444
|
+
|
|
446
445
|
def close
|
|
447
446
|
close_button.click
|
|
448
447
|
self.wait_until_hidden(3)
|
|
449
448
|
end
|
|
450
|
-
|
|
449
|
+
|
|
451
450
|
def verify_closed
|
|
452
451
|
ui = {
|
|
453
|
-
|
|
454
|
-
|
|
452
|
+
self => { visible: true },
|
|
453
|
+
close_button => { visible: false }
|
|
455
454
|
}
|
|
456
455
|
verify_ui_states(ui)
|
|
457
456
|
end
|
|
@@ -526,6 +525,9 @@ Supported `AppUIElement` elementTypes and their declarations have the following
|
|
|
526
525
|
switch :switch_name, { locator_strategy: locator_identifier }
|
|
527
526
|
element :element_name, { locator_strategy: locator_identifier }
|
|
528
527
|
alert :alert_name, { locator_strategy: locator_identifier }
|
|
528
|
+
menu :menu_name, { locator_strategy: locator_identifier }
|
|
529
|
+
menubar :menubar_name, { locator_strategy: locator_identifier }
|
|
530
|
+
table :table_name, { locator_strategy: locator_identifier }
|
|
529
531
|
end
|
|
530
532
|
```
|
|
531
533
|
*Multiple element declarations:*
|
|
@@ -552,6 +554,8 @@ Supported `AppUIElement` elementTypes and their declarations have the following
|
|
|
552
554
|
image_X_name: { locator_strategy: locator_identifier }
|
|
553
555
|
alerts alert_1_name: { locator_strategy: locator_identifier },
|
|
554
556
|
alert_X_name: { locator_strategy: locator_identifier }
|
|
557
|
+
tables table_1_name: { locator_strategy: locator_identifier },
|
|
558
|
+
table_X_name: { locator_strategy: locator_identifier }
|
|
555
559
|
end
|
|
556
560
|
```
|
|
557
561
|
Refer to the Class List documentation for the `ScreenObject` and `ScreenSection` classes for details on the class methods
|
|
@@ -650,11 +654,11 @@ properties of multiple UI elements on a `ScreenObject` or `ScreenSection`. The `
|
|
|
650
654
|
containing key/hash pairs of UI elements and their properties or attributes to be verified.
|
|
651
655
|
```ruby
|
|
652
656
|
ui = {
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
657
|
+
object1 => { property: expected_state },
|
|
658
|
+
object2 => { property1: expected_state, property2: expected_state },
|
|
659
|
+
object3 => { property: expected_state }
|
|
660
|
+
}
|
|
661
|
+
verify_ui_states(ui)
|
|
658
662
|
```
|
|
659
663
|
The `verify_ui_states` method automatically scrolls UI elements that are expected to be visible into view. Auto-scrolling
|
|
660
664
|
only occurs on the vertical axis (down, then up). Setting the `auto_scroll` parameter to `false` prevents automatic scrolling
|
|
@@ -713,6 +717,15 @@ The `verify_ui_states` method supports the following property/state pairs:
|
|
|
713
717
|
:itemcount Integer
|
|
714
718
|
:item_data Array of Hash
|
|
715
719
|
|
|
720
|
+
**Tables**
|
|
721
|
+
|
|
722
|
+
:rowcount Integer
|
|
723
|
+
:columncount Integer
|
|
724
|
+
:columnheaders Array of String
|
|
725
|
+
:cell Hash
|
|
726
|
+
:row Hash
|
|
727
|
+
:column Hash
|
|
728
|
+
|
|
716
729
|
#### Comparison States
|
|
717
730
|
|
|
718
731
|
The `verify_ui_states` method supports comparison states using property/comparison state pairs:
|
|
@@ -749,42 +762,42 @@ The `verify_ui_states` method also supports I18n string translations using prope
|
|
|
749
762
|
The example below depicts the usage of the `verify_ui_states` method to verify that the captions for navigation menu items
|
|
750
763
|
are correctly translated.
|
|
751
764
|
|
|
752
|
-

|
|
753
766
|
```ruby
|
|
754
767
|
def verify_menu
|
|
755
768
|
ui = {
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
769
|
+
menu_title => {
|
|
770
|
+
visible: true,
|
|
771
|
+
caption: { translate: 'NavMenu.title' }
|
|
772
|
+
},
|
|
773
|
+
recipes_item => {
|
|
774
|
+
visible: true,
|
|
775
|
+
caption: { translate: 'NavMenu.recipes' }
|
|
776
|
+
},
|
|
777
|
+
browser_item => {
|
|
778
|
+
visible: true,
|
|
779
|
+
caption: { translate: 'NavMenu.browser' }
|
|
780
|
+
},
|
|
781
|
+
groceries_item => {
|
|
782
|
+
visible: true,
|
|
783
|
+
caption: { translate: 'NavMenu.groceries' }
|
|
784
|
+
},
|
|
785
|
+
pantry_item => {
|
|
786
|
+
visible: true,
|
|
787
|
+
caption: { translate: 'NavMenu.pantry' }
|
|
788
|
+
},
|
|
789
|
+
meals_item => {
|
|
790
|
+
visible: true,
|
|
791
|
+
caption: { translate: 'NavMenu.meals' }
|
|
792
|
+
},
|
|
793
|
+
menus_item => {
|
|
794
|
+
visible: true,
|
|
795
|
+
caption: { translate: 'NavMenu.menus' }
|
|
796
|
+
},
|
|
797
|
+
settings_item => {
|
|
798
|
+
visible: true,
|
|
799
|
+
caption: { translate: 'NavMenu.settings' }
|
|
800
|
+
}
|
|
788
801
|
}
|
|
789
802
|
verify_ui_states(ui)
|
|
790
803
|
end
|
|
@@ -838,9 +851,10 @@ Each supported language/locale combination has a corresponding `.yml` file. I18n
|
|
|
838
851
|
| Language (Country) | File name |
|
|
839
852
|
|-----------------------|-----------|
|
|
840
853
|
| English | en.yml |
|
|
854
|
+
| English (Australia) | en-AU.yml |
|
|
841
855
|
| English (Canada) | en-CA.yml |
|
|
842
|
-
| French (Canada) | fr-CA.yml |
|
|
843
856
|
| French | fr.yml |
|
|
857
|
+
| French (Canada) | fr-CA.yml |
|
|
844
858
|
| Spanish | es.yml |
|
|
845
859
|
| German | de.yml |
|
|
846
860
|
| Portuguese (Brazil) | pt-BR.yml |
|
|
@@ -848,19 +862,23 @@ Each supported language/locale combination has a corresponding `.yml` file. I18n
|
|
|
848
862
|
|
|
849
863
|
Baseline translation strings are stored in `.yml` files in the `config/locales/` folder.
|
|
850
864
|
|
|
851
|
-
|
|
852
|
-
├── config
|
|
853
|
-
│ ├── locales
|
|
854
|
-
│ │ ├── en.yml
|
|
855
|
-
│ │ ├──
|
|
856
|
-
│ │ ├──
|
|
857
|
-
│ │ ├──
|
|
858
|
-
│ │
|
|
859
|
-
│ ├──
|
|
860
|
-
│
|
|
861
|
-
|
|
862
|
-
├──
|
|
863
|
-
└──
|
|
865
|
+
📁 my_automation_project/
|
|
866
|
+
├── 📁 config/
|
|
867
|
+
│ ├── 📁 locales/
|
|
868
|
+
│ │ ├── 📄 en.yml
|
|
869
|
+
│ │ ├── 📄 en-AU.yml
|
|
870
|
+
│ │ ├── 📄 es.yml
|
|
871
|
+
│ │ ├── 📄 de.yml
|
|
872
|
+
│ │ ├── 📄 fr.yml
|
|
873
|
+
│ │ ├── 📄 fr-CA.yml
|
|
874
|
+
│ │ ├── 📄 pt-BR.yml
|
|
875
|
+
│ │ └── 📄 pt-PT.yml
|
|
876
|
+
│ ├── 📁 test_data/
|
|
877
|
+
│ └── 📄 cucumber.yml
|
|
878
|
+
├── 📁 downloads/
|
|
879
|
+
├── 📁 features/
|
|
880
|
+
├── 📄 Gemfile
|
|
881
|
+
└── 📄 README.md
|
|
864
882
|
|
|
865
883
|
|
|
866
884
|
### Working With Custom AppUIElements
|
|
@@ -872,13 +890,13 @@ be different for iOS vs. Android mobile platforms. Below is an example of the ve
|
|
|
872
890
|
for a cross-platform application implemented using React Native (iOS version on the left, Android version on the right).
|
|
873
891
|
Each ListView contains 30 items:
|
|
874
892
|
|
|
875
|
-

|
|
876
894
|
|
|
877
895
|
While the iOS and Android ListViews appear to be identical in the app, performing an inspection of each application's GUI
|
|
878
896
|
using Appium Inspector reveals differences in the object hierarchy as depicted below (iOS version on left, Android version
|
|
879
897
|
on the right):
|
|
880
898
|
|
|
881
|
-

|
|
882
900
|
|
|
883
901
|
The inspection of the ListView object hierarchy reveals that for the iOS version of the app, list items are made up of
|
|
884
902
|
`XCUIElementTypeOther` objects, and that for the Android version of the app, list items are made up of `android.view.ViewGroup`
|
|
@@ -905,10 +923,10 @@ iOS Cloud List `ScreenObject`
|
|
|
905
923
|
class CloudListScreen < TestCentricity::ScreenObject
|
|
906
924
|
trait(:screen_name) { 'Cloud List' }
|
|
907
925
|
trait(:screen_locator) { { class_chain: '**/XCUIElementTypeWindow/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther' } }
|
|
908
|
-
|
|
926
|
+
|
|
909
927
|
# Cloud List screen UI elements
|
|
910
928
|
list :cloud_list, { class_chain: '**/XCUIElementTypeScrollView/XCUIElementTypeOther' }
|
|
911
|
-
|
|
929
|
+
|
|
912
930
|
def initialize
|
|
913
931
|
super
|
|
914
932
|
# define the list item element for the Cloud list object
|
|
@@ -923,10 +941,10 @@ Android CloudListScreen `ScreenObject`
|
|
|
923
941
|
class CloudListScreen < TestCentricity::ScreenObject
|
|
924
942
|
trait(:screen_name) { 'Cloud List' }
|
|
925
943
|
trait(:screen_locator) { { xpath: '//android.widget.FrameLayout[@resource-id="android:id/content"]/android.view.ViewGroup' } }
|
|
926
|
-
|
|
944
|
+
|
|
927
945
|
# Cloud List screen UI elements
|
|
928
946
|
list :cloud_list, { xpath: '//android.widget.ScrollView/android.view.ViewGroup' }
|
|
929
|
-
|
|
947
|
+
|
|
930
948
|
def initialize
|
|
931
949
|
super
|
|
932
950
|
# define the list item element for the Cloud list object
|
|
@@ -942,13 +960,13 @@ Android CloudListScreen `ScreenObject`
|
|
|
942
960
|
Below is an example of a horizontal scrolling "Carousel" style ListView implementations on the Swipe screen of a cross-platform
|
|
943
961
|
application. Each ListView contains 6 list items.
|
|
944
962
|
|
|
945
|
-

|
|
946
964
|
|
|
947
965
|
While the iOS and Android ListViews appear to be identical in the app, performing an inspection of each application's GUI
|
|
948
966
|
using Appium Inspector reveals differences in the object hierarchy as depicted below (iOS version on left, Android version
|
|
949
967
|
on the right):
|
|
950
968
|
|
|
951
|
-

|
|
952
970
|
|
|
953
971
|
As in the previous example for the vertical scrolling ListView, the inspection of the Carousel ListView object hierarchy
|
|
954
972
|
reveals that for the iOS version of the app, list items are again made up of `XCUIElementTypeOther` objects, and that for
|
|
@@ -966,10 +984,10 @@ iOS Swipe `ScreenObject`
|
|
|
966
984
|
class SwipeScreen < TestCentricity::ScreenObject
|
|
967
985
|
trait(:screen_name) { 'Swipe' }
|
|
968
986
|
trait(:screen_locator) { { accessibility_id: 'Swipe-screen' } }
|
|
969
|
-
|
|
987
|
+
|
|
970
988
|
# Swipe screen UI elements
|
|
971
989
|
list :carousel_list, { accessibility_id: 'Carousel' }
|
|
972
|
-
|
|
990
|
+
|
|
973
991
|
def initialize
|
|
974
992
|
super
|
|
975
993
|
# define the list item element for the Carousel list object
|
|
@@ -987,10 +1005,10 @@ Android Swipe `ScreenObject`
|
|
|
987
1005
|
class SwipeScreen < TestCentricity::ScreenObject
|
|
988
1006
|
trait(:screen_name) { 'Swipe' }
|
|
989
1007
|
trait(:screen_locator) { { accessibility_id: 'Swipe-screen' } }
|
|
990
|
-
|
|
1008
|
+
|
|
991
1009
|
# Swipe screen UI elements
|
|
992
1010
|
list :carousel_list, { accessibility_id: 'Carousel' }
|
|
993
|
-
|
|
1011
|
+
|
|
994
1012
|
def initialize
|
|
995
1013
|
super
|
|
996
1014
|
# define the list item element for the Carousel list object
|
|
@@ -1000,7 +1018,7 @@ Android Swipe `ScreenObject`
|
|
|
1000
1018
|
}
|
|
1001
1019
|
carousel_list.define_list_elements(list_spec)
|
|
1002
1020
|
end
|
|
1003
|
-
|
|
1021
|
+
end
|
|
1004
1022
|
```
|
|
1005
1023
|
|
|
1006
1024
|
|
|
@@ -1009,12 +1027,12 @@ Android Swipe `ScreenObject`
|
|
|
1009
1027
|
Below is an example of a PickerWheel (iOS) and Popup (Android) style ListView implementations on the Form Components screen
|
|
1010
1028
|
of a cross-platform application.
|
|
1011
1029
|
|
|
1012
|
-

|
|
1013
1031
|
|
|
1014
1032
|
Performing an inspection of each application's GUI using Appium Inspector reveals differences in the object hierarchy as
|
|
1015
1033
|
depicted below (iOS version on left, Android version on the right):
|
|
1016
1034
|
|
|
1017
|
-

|
|
1018
1036
|
|
|
1019
1037
|
The inspection of the PickerWheel and Popup ListView object hierarchies reveals that for the iOS version of the app, list
|
|
1020
1038
|
items are again made up of `XCUIElementTypeOther` objects, and that for the Android version of the app, list items are made
|
|
@@ -1038,10 +1056,10 @@ Android FormScreen `ScreenObject`
|
|
|
1038
1056
|
class FormScreen < TestCentricity::ScreenObject
|
|
1039
1057
|
trait(:screen_name) { 'Form' }
|
|
1040
1058
|
trait(:screen_locator) { { accessibility_id: 'Forms-screen' } }
|
|
1041
|
-
|
|
1059
|
+
|
|
1042
1060
|
# Form screen UI elements
|
|
1043
1061
|
list :drop_down_menu, { id: 'com.wdiodemoapp:id/select_dialog_listview' }
|
|
1044
|
-
|
|
1062
|
+
|
|
1045
1063
|
def initialize
|
|
1046
1064
|
super
|
|
1047
1065
|
# define the list item element for the drop-down list object
|
|
@@ -1051,6 +1069,100 @@ Android FormScreen `ScreenObject`
|
|
|
1051
1069
|
end
|
|
1052
1070
|
```
|
|
1053
1071
|
|
|
1072
|
+
#### Table AppUIElements
|
|
1073
|
+
|
|
1074
|
+
The basic iOS or MacOS `AppTable` element is typically composed of the parent `XCUIElementTypeTable` object, containing
|
|
1075
|
+
one or more rows (`XCUIElementTypeTableRow`), and containing one or more columns (`XCUIElementTypeTableColumn`). Tables
|
|
1076
|
+
can also include an optional header (`XCUIElementTypeGroup`) containing one or more header cells (`XCUIElementTypeButton`).
|
|
1077
|
+
|
|
1078
|
+
Table cells are typically embedded in each parent row object, and are implemented using a parent `XCUIElementTypeCell`
|
|
1079
|
+
with a child `XCUIElementTypeStaticText` object that provides access to the text content of the table cell.
|
|
1080
|
+
|
|
1081
|
+
As such, when an iOS or MacOS `AppTable` element is instantiated in a `ScreenObject` or `ScreenSection`, the table's component
|
|
1082
|
+
objects and their locator strategies are defined as follows:
|
|
1083
|
+
```ruby
|
|
1084
|
+
{
|
|
1085
|
+
table_row: { class: 'XCUIElementTypeTableRow' },
|
|
1086
|
+
table_column: { class: 'XCUIElementTypeTableColumn' },
|
|
1087
|
+
table_cell: { class_chain: '**/XCUIElementTypeCell/XCUIElementTypeStaticText' },
|
|
1088
|
+
table_header: { class: 'XCUIElementTypeGroup' },
|
|
1089
|
+
table_header_cell: { class: 'XCUIElementTypeButton' }
|
|
1090
|
+
}
|
|
1091
|
+
```
|
|
1092
|
+
|
|
1093
|
+
An example of this table implementation in the MacOS Shortcuts app, and its object hierarchy as viewed by Appium Inspector,
|
|
1094
|
+
is depicted below:
|
|
1095
|
+
|
|
1096
|
+

|
|
1097
|
+
|
|
1098
|
+
The above table object hierarchy for the Shortcuts table shows that access to the text content of the table's cells will
|
|
1099
|
+
fail using the typical implementation of `XCUIElementTypeCell/XCUIElementTypeStaticText` cell objects. This is due to the
|
|
1100
|
+
presence of an `XCUIElementTypeGroup` object between the `XCUIElementTypeCell` parent object and the `XCUIElementTypeStaticText`
|
|
1101
|
+
cell text caption object.
|
|
1102
|
+
|
|
1103
|
+
The `AppTable.define_table_elements` method provides a means of specifying the various elements that make up the key
|
|
1104
|
+
components of an `AppTable` object, or for overriding the default component locator strategy. The method accepts a hash
|
|
1105
|
+
of table component designators (key) and a locator strategy (value) for identifying the component in the `AppTable` object
|
|
1106
|
+
hierarchy.
|
|
1107
|
+
|
|
1108
|
+
Valid table component designators are:
|
|
1109
|
+
* `table_row:`
|
|
1110
|
+
* `table_column:`
|
|
1111
|
+
* `table_cell:`
|
|
1112
|
+
* `table_header:`
|
|
1113
|
+
* `table_header_cell:`
|
|
1114
|
+
|
|
1115
|
+
Valid component `locator_strategy` are:
|
|
1116
|
+
* `class:`
|
|
1117
|
+
* `xpath:`
|
|
1118
|
+
* `predicate:` (MacOS and iOS only)
|
|
1119
|
+
* `class_chain:` (MacOS and iOS only)
|
|
1120
|
+
|
|
1121
|
+
If you were developing automated tests for the MacOS Shortcuts app, your `ShortcutsAppScreen` screen object's `initialize`
|
|
1122
|
+
method would use the `AppTable.define_table_elements` method to define the locator strategy for the `table_cell` component.
|
|
1123
|
+
```ruby
|
|
1124
|
+
class ShortcutsAppScreen < TestCentricity::ScreenObject
|
|
1125
|
+
trait(:screen_name) { 'Shortcuts' }
|
|
1126
|
+
trait(:screen_locator) { { class_chain: '**/XCUIElementTypeWindow' } }
|
|
1127
|
+
|
|
1128
|
+
# Shortcuts screen UI elements
|
|
1129
|
+
tables sidebar_table: { predicate: 'identifier == "library.sidebar"' },
|
|
1130
|
+
view_table: { predicate: 'identifier == "view.library.table"' }
|
|
1131
|
+
|
|
1132
|
+
def initialize
|
|
1133
|
+
super
|
|
1134
|
+
# define the cell element for the Shortcuts table object
|
|
1135
|
+
table_spec = { table_cell: { class_chain: '**/XCUIElementTypeCell/XCUIElementTypeGroup/XCUIElementTypeStaticText' } }
|
|
1136
|
+
view_table.define_table_elements(table_spec)
|
|
1137
|
+
end
|
|
1138
|
+
end
|
|
1139
|
+
```
|
|
1140
|
+
|
|
1141
|
+
Another `AppTable` implementation using elements other than the default `AppTable` components can be found in the MacOS
|
|
1142
|
+
Activity Monitor app (see below). An inspection of the Activity Monitor's table object hierarchy for the app reveals that
|
|
1143
|
+
it is an `XCUIElementTypeOutline` object comprised of `XCUIElementTypeOutlineRow` elements representing the table's rows.
|
|
1144
|
+
|
|
1145
|
+

|
|
1146
|
+
|
|
1147
|
+
The `ActivityMonitorScreen` screen object's `initialize` method in the code snippet below demonstrates the use of the
|
|
1148
|
+
`AppTable.define_table_elements` method to define the locator strategy for the `table_row` component.
|
|
1149
|
+
```ruby
|
|
1150
|
+
class ActivityMonitorScreen < TestCentricity::ScreenObject
|
|
1151
|
+
trait(:screen_name) { 'Activity Monitor' }
|
|
1152
|
+
trait(:screen_locator) { { class_chain: '**/XCUIElementTypeWindow' } }
|
|
1153
|
+
|
|
1154
|
+
# Shortcuts screen UI elements
|
|
1155
|
+
table :process_table, { class_chain: '**/XCUIElementTypeScrollView/XCUIElementTypeOutline' }
|
|
1156
|
+
|
|
1157
|
+
def initialize
|
|
1158
|
+
super
|
|
1159
|
+
# define the row element for the Activity Monitor table object
|
|
1160
|
+
table_spec = { table_row: { class: 'XCUIElementTypeOutlineRow' } }
|
|
1161
|
+
process_table.define_table_elements(table_spec)
|
|
1162
|
+
end
|
|
1163
|
+
end
|
|
1164
|
+
```
|
|
1165
|
+
|
|
1054
1166
|
|
|
1055
1167
|
---
|
|
1056
1168
|
## MacOS Application Menu Bar and Menus
|
|
@@ -1077,6 +1189,20 @@ You define a new `MenuBar` as shown below:
|
|
|
1077
1189
|
end
|
|
1078
1190
|
```
|
|
1079
1191
|
|
|
1192
|
+
### Adding a MenuBar to your App's Primary ScreenObject
|
|
1193
|
+
|
|
1194
|
+
You add a `MenuBar` to your app's primary `ScreenObject` as shown below:
|
|
1195
|
+
```ruby
|
|
1196
|
+
class CalculatorAppScreen < TestCentricity::ScreenObject
|
|
1197
|
+
# Calculator App screen UI elements
|
|
1198
|
+
menubar :calc_menu_bar, CalculatorMenuBar
|
|
1199
|
+
end
|
|
1200
|
+
```
|
|
1201
|
+
Once your `ScreenObject` has been instantiated, you can call its `MenuBar` methods as shown below:
|
|
1202
|
+
```ruby
|
|
1203
|
+
num_menus = calculator_screen.calc_menu_bar.get_item_count
|
|
1204
|
+
```
|
|
1205
|
+
|
|
1080
1206
|
### Adding Menus to your MenuBar
|
|
1081
1207
|
|
|
1082
1208
|
A `MenuBar` is typically made up of one or more `Menu` objects, which are added to your `MenuBar` class definition as shown
|
|
@@ -1094,7 +1220,7 @@ below:
|
|
|
1094
1220
|
speech_menu: { class_chain: '**/XCUIElementTypeMenuBarItem[7]' },
|
|
1095
1221
|
window_menu: { class_chain: '**/XCUIElementTypeMenuBarItem[8]' },
|
|
1096
1222
|
help_menu: { class_chain: '**/XCUIElementTypeMenuBarItem[9]' }
|
|
1097
|
-
|
|
1223
|
+
end
|
|
1098
1224
|
```
|
|
1099
1225
|
|
|
1100
1226
|
### Adding Methods to your MenuBar
|
|
@@ -1113,7 +1239,7 @@ You can add methods to your `MenuBar` class definition, as shown below:
|
|
|
1113
1239
|
speech_menu: { class_chain: '**/XCUIElementTypeMenuBarItem[7]' },
|
|
1114
1240
|
window_menu: { class_chain: '**/XCUIElementTypeMenuBarItem[8]' },
|
|
1115
1241
|
help_menu: { class_chain: '**/XCUIElementTypeMenuBarItem[9]' }
|
|
1116
|
-
|
|
1242
|
+
|
|
1117
1243
|
def choose_menu_item(menu, item, method = :mouse)
|
|
1118
1244
|
menu_map = {
|
|
1119
1245
|
calc: calc_menu,
|
|
@@ -1130,7 +1256,7 @@ You can add methods to your `MenuBar` class definition, as shown below:
|
|
|
1130
1256
|
raise "#{menu} is not a supported menu" if menu_obj.nil?
|
|
1131
1257
|
menu_obj.choose_menu_item(item, method)
|
|
1132
1258
|
end
|
|
1133
|
-
|
|
1259
|
+
|
|
1134
1260
|
def verify_menu_bar
|
|
1135
1261
|
ui = {
|
|
1136
1262
|
self => {
|
|
@@ -1181,11 +1307,11 @@ the `initialize` method of your app's `MenuBar` control.
|
|
|
1181
1307
|
The code snippet below demonstrate the use of the `AppMenu.define_menu_elements` method in the `CalculatorMenuBar` object's
|
|
1182
1308
|
`initialize` method to define the keyboard shortcut mapping for 4 of the menu items in the **View** menu and 1 of the menu
|
|
1183
1309
|
items in the **Window** menu of the MacOS Calculator app. Keyboard shortcuts are assigned to the **View** menu items by
|
|
1184
|
-
index (menu items 1,2,3, and 7) and to the **Window** menu by menu item caption (menu item *Show Paper Tape*).
|
|
1310
|
+
index (menu items 1, 2, 3, and 7) and to the **Window** menu by menu item caption (menu item *Show Paper Tape*).
|
|
1185
1311
|
|
|
1186
1312
|
```ruby
|
|
1187
1313
|
class CalculatorMenuBar < TestCentricity::MenuBar
|
|
1188
|
-
|
|
1314
|
+
|
|
1189
1315
|
def initialize(name, parent, locator, context)
|
|
1190
1316
|
super
|
|
1191
1317
|
# define key map for View menu
|
|
@@ -1219,19 +1345,26 @@ key. TestCentricity and XCTest defines the following possible bitmasks for modif
|
|
|
1219
1345
|
```
|
|
1220
1346
|
Refer to [this page](https://github.com/appium/appium-mac2-driver?tab=readme-ov-file#macos-keys) for more information on MacOS keyboard `modifierFlags`.
|
|
1221
1347
|
|
|
1222
|
-
### Adding
|
|
1348
|
+
### Adding Popup Menus to your ScreenObject or ScreenSection
|
|
1223
1349
|
|
|
1224
|
-
|
|
1350
|
+
A MocOS desktop app may have one or more popup menus that can appear on a `ScreenObject` or `ScreenSection`. Below is an
|
|
1351
|
+
example of two different popup menus that can be invoked on the MacOS Shortcuts app - one on sidebar list items, and the
|
|
1352
|
+
other on Shortcuts table items.
|
|
1353
|
+
|
|
1354
|
+

|
|
1355
|
+
|
|
1356
|
+
It is typically not necessary to define more than one popup menu object in your `ScreenObject` or `ScreenSection` class
|
|
1357
|
+
definition, even if there are multiple popups that can be interacted with. Since only one popup can be visible at a time,
|
|
1358
|
+
you only need to define a single popup menu object.
|
|
1359
|
+
|
|
1360
|
+
Popup menus are added to your `ScreenObject` or `ScreenSection` class definition as shown below:
|
|
1225
1361
|
```ruby
|
|
1226
|
-
class
|
|
1227
|
-
#
|
|
1228
|
-
|
|
1362
|
+
class ShortcutsAppScreen < TestCentricity::ScreenObject
|
|
1363
|
+
# Shortcuts App screen UI elements
|
|
1364
|
+
menu :popup_menu, { class_chain: '**/XCUIElementTypeTable/XCUIElementTypeMenu' }
|
|
1365
|
+
menubar :shortcuts_menu_bar, ShortcutsMenuBar
|
|
1229
1366
|
end
|
|
1230
1367
|
```
|
|
1231
|
-
Once your `ScreenObject` has been instantiated, you can call its `MenuBar` methods as shown below:
|
|
1232
|
-
```ruby
|
|
1233
|
-
num_menus = calculator_screen.calc_menu_bar.get_item_count
|
|
1234
|
-
```
|
|
1235
1368
|
|
|
1236
1369
|
|
|
1237
1370
|
---
|
|
@@ -1287,7 +1420,7 @@ scenario is displayed below:
|
|
|
1287
1420
|
Given I am on the Products screen
|
|
1288
1421
|
When I tap the <screen_name> navigation menu item
|
|
1289
1422
|
Then I expect the <screen_name> screen to be correctly displayed
|
|
1290
|
-
|
|
1423
|
+
|
|
1291
1424
|
Examples:
|
|
1292
1425
|
|screen_name |
|
|
1293
1426
|
|Registration |
|
|
@@ -1490,13 +1623,13 @@ Refer to [**Section 10.4 (Using Configuration Specific Profiles in `cucumber.yml
|
|
|
1490
1623
|
##### Local iOS Simulators or Physical Devices using the `options` Hash
|
|
1491
1624
|
|
|
1492
1625
|
When using the `options` hash, the following options and capabilities must be specified:
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1626
|
+
- `driver:` must be set to `:appium`
|
|
1627
|
+
- `device_type:` must be set to `:tablet` or `:phone`
|
|
1628
|
+
- `platformName:` must be set to `ios` in the `capabilities:` hash
|
|
1629
|
+
- `'appium:automationName':` must be set to `xcuitest` in the `capabilities:` hash
|
|
1630
|
+
- `'appium:platformVersion':` must be set to the version of iOS on the simulator or physical device
|
|
1631
|
+
- `'appium:deviceName':` must be set to the name of the iOS simulator or physical device
|
|
1632
|
+
- `'appium:app'`: must be set to path where iOS app can be accessed and loaded
|
|
1500
1633
|
|
|
1501
1634
|
```ruby
|
|
1502
1635
|
options = {
|
|
@@ -1525,21 +1658,21 @@ Below is an example of an `options` hash for specifying a connection to a locall
|
|
|
1525
1658
|
simulator. The `options` hash includes options for specifying the driver name, global driver scope, and setting the simulated
|
|
1526
1659
|
device orientation to portrait mode.
|
|
1527
1660
|
```ruby
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
}
|
|
1661
|
+
options = {
|
|
1662
|
+
driver: :appium,
|
|
1663
|
+
device_type: :tablet,
|
|
1664
|
+
driver_name: :my_custom_ipad_driver,
|
|
1665
|
+
global_driver: true,
|
|
1666
|
+
capabilities: {
|
|
1667
|
+
platformName: :ios,
|
|
1668
|
+
'appium:platformVersion': '15.4',
|
|
1669
|
+
'appium:deviceName': 'iPad Pro (12.9-inch) (5th generation)',
|
|
1670
|
+
'appium:automationName': 'XCUITest',
|
|
1671
|
+
'appium:orientation': 'PORTRAIT',
|
|
1672
|
+
'appium:app': Environ.current.ios_app_path
|
|
1541
1673
|
}
|
|
1542
|
-
|
|
1674
|
+
}
|
|
1675
|
+
AppiumConnect.initialize_appium(options)
|
|
1543
1676
|
```
|
|
1544
1677
|
|
|
1545
1678
|
#### Connecting to Locally Hosted Android Simulators or Physical Devices
|
|
@@ -1577,13 +1710,13 @@ Refer to [**Section 10.4 (Using Configuration Specific Profiles in `cucumber.yml
|
|
|
1577
1710
|
##### Local Android Simulators or Physical Devices using the `options` Hash
|
|
1578
1711
|
|
|
1579
1712
|
When using the `options` hash, the following options and capabilities must be specified:
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1713
|
+
- `driver:` must be set to `:appium`
|
|
1714
|
+
- `device_type:` must be set to `:tablet` or `:phone`
|
|
1715
|
+
- `platformName:` must be set to `Android` in the `capabilities:` hash
|
|
1716
|
+
- `'appium:automationName':` must be set to `UiAutomator2` in the `capabilities:` hash
|
|
1717
|
+
- `'appium:platformVersion':` must be set to the version of Android on the simulator or physical device
|
|
1718
|
+
- `'appium:deviceName':` must be set to the Android Virtual Device ID
|
|
1719
|
+
- `'appium:app'`: must be set to path where Android `.apk` file can be accessed and loaded
|
|
1587
1720
|
|
|
1588
1721
|
```ruby
|
|
1589
1722
|
options = {
|
|
@@ -1606,7 +1739,7 @@ When using the `options` hash, the following options and capabilities must be sp
|
|
|
1606
1739
|
>
|
|
1607
1740
|
> ℹ️ If an `endpoint:` is not specified in the `options` hash, then the default remote endpoint URL of ``http://127.0.0.1:4723/wd/hub``
|
|
1608
1741
|
will be used.
|
|
1609
|
-
>
|
|
1742
|
+
>
|
|
1610
1743
|
> ℹ️ If `global_driver:` is not specified in the `options` hash, then the driver will be initialized without global scope.
|
|
1611
1744
|
|
|
1612
1745
|
|
|
@@ -1645,7 +1778,7 @@ tests, place the code shown below in your `hooks.rb` file.
|
|
|
1645
1778
|
$server.start
|
|
1646
1779
|
end
|
|
1647
1780
|
end
|
|
1648
|
-
|
|
1781
|
+
|
|
1649
1782
|
AfterAll do
|
|
1650
1783
|
# close Appium driver
|
|
1651
1784
|
TestCentricity::AppiumConnect.quit_driver
|
|
@@ -1682,7 +1815,7 @@ body of an example group:
|
|
|
1682
1815
|
$server = TestCentricity::AppiumServer.new
|
|
1683
1816
|
$server.start
|
|
1684
1817
|
end
|
|
1685
|
-
|
|
1818
|
+
|
|
1686
1819
|
after(:context) do
|
|
1687
1820
|
# terminate Appium Server after all of the examples in this group
|
|
1688
1821
|
$server.stop if Environ.driver == :appium && $server.running?
|
|
@@ -1709,9 +1842,9 @@ devices. BrowserStack uses only real physical devices - simulators are not avail
|
|
|
1709
1842
|
|
|
1710
1843
|
Refer to the following pages for information on uploading your iOS `.ipa` or Android `.apk` app files to the BrowserStack
|
|
1711
1844
|
servers:
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1845
|
+
- [Upload apps from filesystem](https://www.browserstack.com/docs/app-automate/appium/upload-app-from-filesystem)
|
|
1846
|
+
- [Upload apps using public URL](https://www.browserstack.com/docs/app-automate/appium/upload-app-using-public-url)
|
|
1847
|
+
- [Define custom ID for app](https://www.browserstack.com/docs/app-automate/appium/upload-app-define-custom-id)
|
|
1715
1848
|
|
|
1716
1849
|
The preferred method of uploading an app to BrowserStack is to define a custom test ID for your apps to avoid having to
|
|
1717
1850
|
modify your test configuration data with a new `app_url` after every app upload. Use the same custom test ID every time
|
|
@@ -1755,13 +1888,13 @@ Refer to [**Section 10.4 (Using Configuration Specific Profiles in `cucumber.yml
|
|
|
1755
1888
|
##### BrowserStack Mobile Devices using the `options` Hash
|
|
1756
1889
|
|
|
1757
1890
|
When using the `options` hash, the following options and capabilities must be specified:
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1891
|
+
- `driver:` must be set to `:browserstack`
|
|
1892
|
+
- `device_type:` must be set to `:tablet` or `:phone`
|
|
1893
|
+
- `platformName:` must be set to `ios` or `android` in the `capabilities:` hash
|
|
1894
|
+
- `'appium:automationName':` must be set to to `XCUITest` for iOS or `UiAutomator2` for Android in the `capabilities:` hash
|
|
1895
|
+
- `'appium:platformVersion':` must be set to the version of iOS on the simulator or physical device
|
|
1896
|
+
- `'appium:deviceName':` must be set to the name of the iOS simulator or physical device
|
|
1897
|
+
- `'appium:app'`: must be set to URL or custom test ID of uploaded iOS `.ipa` or Android `.apk` file
|
|
1765
1898
|
|
|
1766
1899
|
```ruby
|
|
1767
1900
|
options = {
|
|
@@ -1963,7 +2096,7 @@ Refer to the following pages for information on uploading your iOS `.ipa` or `.a
|
|
|
1963
2096
|
Sauce Labs servers:
|
|
1964
2097
|
- [Mobile App Storage](https://docs.saucelabs.com/mobile-apps/app-storage/)
|
|
1965
2098
|
|
|
1966
|
-
The TestCentricity For Apps gem does not currently support automatic upload of app files to Sauce Labs servers. Uploading
|
|
2099
|
+
The TestCentricity For Apps gem does not currently support automatic upload of app files to Sauce Labs servers. Uploading
|
|
1967
2100
|
will have to be performed manually or via your CI workflow. If you have not specified a custom test ID for your apps, your
|
|
1968
2101
|
tests will most likely fail as a new `app_url` will be generated, and you will have to update your test configuration data
|
|
1969
2102
|
to use the new `app_url`. If you have specified a custom test ID for your apps, your tests should be able to run without
|
|
@@ -2042,16 +2175,16 @@ on other cloud hosting services that are currently not supported. You must call
|
|
|
2042
2175
|
with an `options` hash - Environment Variables cannot be used to specify a user-defined custom Appium driver instance.
|
|
2043
2176
|
|
|
2044
2177
|
Prior to calling the `AppiumConnect.initialize_appium` method, you must set the following `Environ` attributes:
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2178
|
+
- `Environ.platform` set to `:mobile`
|
|
2179
|
+
- `Environ.device_os` to either `:ios` or `:android`
|
|
2180
|
+
- `Environ.device` to either `:simulator` or `:device`, dependent on whether the target mobile platform is a real device
|
|
2181
|
+
or simulator.
|
|
2182
|
+
- `Environ.device_name` set to device name specified by hosting service
|
|
2050
2183
|
|
|
2051
2184
|
The following options and capabilities must be specified:
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2185
|
+
- `driver:` must be set to `:custom`
|
|
2186
|
+
- `device_type:` must be set to `:tablet` or `:phone`
|
|
2187
|
+
- `endpoint:` must be set to the endpoint URL configuration specified by the hosting service
|
|
2055
2188
|
|
|
2056
2189
|
All other required capabilities specified by the hosting service configuration documentation should be included in the
|
|
2057
2190
|
`capabilities:` hash.
|
|
@@ -2092,11 +2225,9 @@ and authorization code for the cloud service(s) that you intend to connect with.
|
|
|
2092
2225
|
> ⚠️ Cloud service credentials should not be stored as text in your `cucumber.yml` file where it can be exposed by anyone
|
|
2093
2226
|
with access to your version control system.
|
|
2094
2227
|
|
|
2095
|
-
|
|
2096
2228
|
#==============
|
|
2097
2229
|
# conditionally load Screen Object implementations based on which target platform we're running on
|
|
2098
2230
|
#==============
|
|
2099
|
-
|
|
2100
2231
|
ios: PLATFORM=ios --tags @ios -r features/support/ios -e features/support/android
|
|
2101
2232
|
android: PLATFORM=android --tags @android -r features/support/android -e features/support/ios
|
|
2102
2233
|
|
|
@@ -2104,7 +2235,6 @@ with access to your version control system.
|
|
|
2104
2235
|
#==============
|
|
2105
2236
|
# profiles for mobile device screen orientation
|
|
2106
2237
|
#==============
|
|
2107
|
-
|
|
2108
2238
|
landscape: ORIENTATION=landscape
|
|
2109
2239
|
portrait: ORIENTATION=portrait
|
|
2110
2240
|
|
|
@@ -2121,7 +2251,6 @@ with access to your version control system.
|
|
|
2121
2251
|
# profiles for native iOS apps hosted within XCode iOS simulators
|
|
2122
2252
|
# NOTE: Requires installation of XCode, iOS version specific target simulators, and Appium
|
|
2123
2253
|
#==============
|
|
2124
|
-
|
|
2125
2254
|
appium_ios: DRIVER=appium --profile ios AUTOMATION_ENGINE=XCUITest APP_PLATFORM_NAME="iOS" NEW_COMMAND_TIMEOUT="30" <%= mobile %>
|
|
2126
2255
|
app_ios_14: --profile appium_ios APP_VERSION="14.5"
|
|
2127
2256
|
app_ios_15: --profile appium_ios APP_VERSION="15.4"
|
|
@@ -2136,7 +2265,6 @@ with access to your version control system.
|
|
|
2136
2265
|
# profiles for native Android apps hosted within Android Studio Android Virtual Device emulators
|
|
2137
2266
|
# NOTE: Requires installation of Android Studio, Android version specific virtual device simulators, and Appium
|
|
2138
2267
|
#==============
|
|
2139
|
-
|
|
2140
2268
|
appium_android: DRIVER=appium --profile android AUTOMATION_ENGINE=UiAutomator2 APP_PLATFORM_NAME="Android" <%= mobile %>
|
|
2141
2269
|
app_android_12: --profile appium_android APP_VERSION="12.0"
|
|
2142
2270
|
pixel_5_api31_sim: --profile app_android_12 DEVICE_TYPE=phone APP_DEVICE="Pixel_5_API_31"
|
|
@@ -2147,7 +2275,6 @@ with access to your version control system.
|
|
|
2147
2275
|
# WARNING: Credentials should not be stored as text in your cucumber.yml file where it can be exposed by anyone with access
|
|
2148
2276
|
# to your version control system
|
|
2149
2277
|
#==============
|
|
2150
|
-
|
|
2151
2278
|
browserstack: DRIVER=browserstack BS_USERNAME="<INSERT USER NAME HERE>" BS_AUTHKEY="<INSERT PASSWORD HERE>" TEST_CONTEXT="TestCentricity"
|
|
2152
2279
|
|
|
2153
2280
|
# BrowserStack iOS real device native app profiles
|
|
@@ -2166,7 +2293,6 @@ with access to your version control system.
|
|
|
2166
2293
|
# WARNING: Credentials should not be stored as text in your cucumber.yml file where it can be exposed by anyone with access
|
|
2167
2294
|
# to your version control system
|
|
2168
2295
|
#==============
|
|
2169
|
-
|
|
2170
2296
|
saucelabs: DRIVER=saucelabs SL_USERNAME="<INSERT USER NAME HERE>" SL_AUTHKEY="<INSERT PASSWORD HERE>" DATA_CENTER="us-west-1" AUTOMATE_PROJECT="TestCentricity - SauceLabs"
|
|
2171
2297
|
|
|
2172
2298
|
# SauceLabs iOS real device native app profiles
|
|
@@ -2184,7 +2310,6 @@ with access to your version control system.
|
|
|
2184
2310
|
# WARNING: Credentials should not be stored as text in your cucumber.yml file where it can be exposed by anyone with access
|
|
2185
2311
|
# to your version control system
|
|
2186
2312
|
#==============
|
|
2187
|
-
|
|
2188
2313
|
testingbot: DRIVER=testingbot TB_USERNAME="<INSERT USER NAME HERE>" TB_AUTHKEY="<INSERT PASSWORD HERE>" AUTOMATE_PROJECT="TestCentricity - TestingBot"
|
|
2189
2314
|
|
|
2190
2315
|
# TestingBot iOS real device native app profiles
|
|
@@ -2233,31 +2358,32 @@ in the `/features/support/<platform>/screens` folders, organized in functional a
|
|
|
2233
2358
|
`ScreenSection` class definitions should be stored in the `/features/support/<platform>/sections` folder, where `<platform>`
|
|
2234
2359
|
is typically `mac`, `ios`, or `android`.
|
|
2235
2360
|
|
|
2236
|
-
|
|
2237
|
-
├── config
|
|
2238
|
-
│ ├── locales
|
|
2239
|
-
│ ├── test_data
|
|
2240
|
-
│ └── cucumber.yml
|
|
2241
|
-
├──
|
|
2242
|
-
|
|
2243
|
-
│ ├──
|
|
2244
|
-
│
|
|
2245
|
-
|
|
2246
|
-
| | |
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
| | |
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
| | |
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
| | |
|
|
2256
|
-
|
|
2257
|
-
│ │ ├──
|
|
2258
|
-
│ │
|
|
2259
|
-
|
|
2260
|
-
|
|
2361
|
+
📁 my_automation_project/
|
|
2362
|
+
├── 📁 config/
|
|
2363
|
+
│ ├── 📁 locales/
|
|
2364
|
+
│ ├── 📁 test_data/
|
|
2365
|
+
│ └── 📄 cucumber.yml
|
|
2366
|
+
├── 📁 downloads/
|
|
2367
|
+
├── 📁 features/
|
|
2368
|
+
│ ├── 📁 step_definitions/
|
|
2369
|
+
│ ├── 📁 support
|
|
2370
|
+
│ │ ├── 📁 android
|
|
2371
|
+
| | | ├── 📁 screens
|
|
2372
|
+
| | | └── 📁 sections
|
|
2373
|
+
│ │ ├── 📁 ios
|
|
2374
|
+
| | | ├── 📁 screens
|
|
2375
|
+
| | | └── 📁 sections
|
|
2376
|
+
│ │ ├── 📁 mac
|
|
2377
|
+
| | | ├── 📁 screens
|
|
2378
|
+
| | | └── 📁 sections
|
|
2379
|
+
│ │ ├── 📁 shared_components
|
|
2380
|
+
| | | ├── 📁 screens
|
|
2381
|
+
| | | └── 📁 sections
|
|
2382
|
+
│ │ ├── 📄 env.rb
|
|
2383
|
+
│ │ ├── 📄 hooks.rb
|
|
2384
|
+
│ │ └── 📄 world_screens.rb
|
|
2385
|
+
├── 📄 Gemfile
|
|
2386
|
+
└── 📄 README.md
|
|
2261
2387
|
|
|
2262
2388
|
|
|
2263
2389
|
---
|
|
@@ -2269,7 +2395,7 @@ is typically `mac`, `ios`, or `android`.
|
|
|
2269
2395
|
---
|
|
2270
2396
|
## Copyright and License
|
|
2271
2397
|
|
|
2272
|
-
All TestCentricity™ Frameworks are Copyright (c) 2014-
|
|
2398
|
+
All TestCentricity™ Frameworks are Copyright (c) 2014-2025, A.J. Mrozinski.
|
|
2273
2399
|
All rights reserved.
|
|
2274
2400
|
|
|
2275
2401
|
Redistribution and use in source and binary forms, with or without
|