testcentricity_web 4.1.4 → 4.1.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +18 -0
- data/.simplecov +5 -0
- data/CHANGELOG.md +43 -1
- data/Gemfile.lock +60 -2
- data/README.md +166 -21
- data/Rakefile +60 -1
- data/config/cucumber.yml +163 -0
- data/config/test_data/data.json +12 -0
- data/config/test_data/data.xls +0 -0
- data/config/test_data/data.yml +12 -0
- data/docker-compose-v3.yml +48 -0
- data/features/basic_test_page_css.feature +35 -0
- data/features/basic_test_page_xpath.feature +27 -0
- data/features/media_players.feature +87 -0
- data/features/step_definitions/generic_steps.rb.rb +44 -0
- data/features/step_definitions/media_steps.rb +30 -0
- data/features/support/env.rb +50 -0
- data/features/support/hooks.rb +245 -0
- data/features/support/pages/base_test_page.rb +11 -0
- data/features/support/pages/basic_css_test_page.rb +52 -0
- data/features/support/pages/basic_test_page.rb +297 -0
- data/features/support/pages/basic_xpath_test_page.rb +53 -0
- data/features/support/pages/custom_controls_page.rb +16 -0
- data/features/support/pages/indexed_sections_page.rb +16 -0
- data/features/support/pages/media_test_page.rb +195 -0
- data/features/support/sections/header_nav.rb +28 -0
- data/features/support/world_data.rb +12 -0
- data/features/support/world_pages.rb +18 -0
- data/lib/testcentricity_web/data_objects/environment.rb +16 -0
- data/lib/testcentricity_web/version.rb +1 -1
- data/lib/testcentricity_web/web_core/page_object.rb +8 -8
- data/lib/testcentricity_web/web_core/page_objects_helper.rb +41 -8
- data/lib/testcentricity_web/web_core/page_section.rb +1 -16
- data/lib/testcentricity_web/web_core/webdriver_helper.rb +77 -120
- data/lib/testcentricity_web/web_elements/checkbox.rb +3 -4
- data/lib/testcentricity_web/web_elements/media.rb +50 -4
- data/lib/testcentricity_web/web_elements/radio.rb +5 -1
- data/lib/testcentricity_web/web_elements/select_list.rb +18 -7
- data/lib/testcentricity_web/web_elements/ui_elements_helper.rb +13 -0
- data/reports/.keep +1 -0
- data/test_site/basic_test_page.html +290 -0
- data/test_site/custom_controls_page.html +58 -0
- data/test_site/images/Granny.jpg +0 -0
- data/test_site/images/Wilder.jpg +0 -0
- data/test_site/images/You_Betcha.jpg +0 -0
- data/test_site/indexed_sections_page.html +58 -0
- data/test_site/media/MIB2-subtitles-pt-BR.vtt +49 -0
- data/test_site/media/MIB2.mp4 +0 -0
- data/test_site/media/MP4_small.mp4 +0 -0
- data/test_site/media/MPS_sample.mp3 +0 -0
- data/test_site/media_page.html +86 -0
- data/testcentricity_web.gemspec +5 -0
- metadata +125 -4
- data/test_site/test_page.html +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 58ddfdbcb8747347fcb06efdd2a888509fa904bd5541a0f3d4d303af6469552c
|
4
|
+
data.tar.gz: 14f9af8661d7e571d10f79e3d093cafa4e744388d5c1d6f9232e207fe5e82d6f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 768e113468d0dfc68f01467bc4304f41903bff09f59db9f2c8dd013545c061523c7e0947669d1befadcf43b1187e57df3cb188d803b3d802d905c0c3467ce852
|
7
|
+
data.tar.gz: 3133dc1f23ff3a839c45e2c6424d152f6c85916497c00dd9a815113f2acb8225f45efab91ce9d7cb4ada454d33115649ad61f4073f109a7dec44e40891971043
|
data/.gitignore
CHANGED
@@ -18,3 +18,21 @@ Thumbs.db
|
|
18
18
|
|
19
19
|
# rspec failure tracking
|
20
20
|
.rspec_status
|
21
|
+
|
22
|
+
# Ignore test-reports
|
23
|
+
reports/*.html
|
24
|
+
reports/*.xml
|
25
|
+
reports/*.json
|
26
|
+
reports/screenshots/
|
27
|
+
test-reports
|
28
|
+
capybara-*.html
|
29
|
+
debug.log
|
30
|
+
|
31
|
+
BrowserStackLocal
|
32
|
+
cbttunnel.jar
|
33
|
+
|
34
|
+
/.yardoc/
|
35
|
+
/local.log
|
36
|
+
.run/*.xml
|
37
|
+
|
38
|
+
echo coverage >> .gitignore
|
data/.simplecov
ADDED
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,48 @@
|
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
4
|
|
5
|
+
## [4.1.7] - 28-MAR-2022
|
6
|
+
|
7
|
+
### Fixed
|
8
|
+
* `CheckBox.set_checkbox_state` and `Radio.set_selected_state` work on iOS simulators again.
|
9
|
+
|
10
|
+
### Changes
|
11
|
+
* `Audio.playback_rate` and `Video.playback_rate` now return value as a `Float` instead of a `String`.
|
12
|
+
* `Audio.default_playback_rate` and `Video.default_playback_rate` now return value as a `Float` instead of a `String`.
|
13
|
+
* `Audio.current_time` and `Video.current_time` now return value as a `Float` rounded to two decimal places.
|
14
|
+
* `Audio.duration` and `Video.duration` now return value as a `Float` rounded to two decimal places.
|
15
|
+
|
16
|
+
### Added
|
17
|
+
* `Audio.mute` and `Video.mute` methods added.
|
18
|
+
* `Audio.unmute` and `Video.unmute` methods added.
|
19
|
+
* `Audio.playback_rate` and `Video.playback_rate` now accept a `Float` value as an input for setting the playback rate
|
20
|
+
of media.
|
21
|
+
* `Audio.volume` and `Video.volume` now accept a `Float` value between 0 and 1 as an input for setting the volume of media.
|
22
|
+
|
23
|
+
|
24
|
+
## [4.1.6] - 21-MAR-2022
|
25
|
+
|
26
|
+
### Fixed
|
27
|
+
* `PageObject.verify_page_exists` now works with `page_locator` traits expressed in Xpath format, and no longer fails with a
|
28
|
+
`invalid selector: An invalid or illegal selector was specified - Selenium::WebDriver::Error::InvalidSelectorError` error.
|
29
|
+
|
30
|
+
### Added
|
31
|
+
* `UIElement.required?` method added.
|
32
|
+
* `PageObject.populate_data_fields` and `PageSection.populate_data_fields` methods now work with the following:
|
33
|
+
* `input(type='color')` color picker controls if they are specified as a `textfield` type element.
|
34
|
+
* `input(type='range')` slider controls if they are specified as a `range` type element.
|
35
|
+
* `input(type='file')` file upload controls if they are specified as a `filefield` type element.
|
36
|
+
|
37
|
+
|
38
|
+
## [4.1.5] - 15-MAR-2022
|
39
|
+
|
40
|
+
### Fixed
|
41
|
+
* `SelectList.selected?` now correctly returns selected value for custom `selectlist` controls.
|
42
|
+
|
43
|
+
### Updated
|
44
|
+
* Updated HTML documentation.
|
45
|
+
|
46
|
+
|
5
47
|
## [4.1.4] - 09-MAR-2022
|
6
48
|
|
7
49
|
### Fixed
|
@@ -19,7 +61,7 @@ All notable changes to this project will be documented in this file.
|
|
19
61
|
|
20
62
|
## [4.1.2] - 07-MAR-2022
|
21
63
|
|
22
|
-
###
|
64
|
+
### Updated
|
23
65
|
* Updated HTML documentation.
|
24
66
|
|
25
67
|
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
testcentricity_web (4.1.
|
4
|
+
testcentricity_web (4.1.7)
|
5
5
|
appium_lib
|
6
6
|
browserstack-local
|
7
7
|
capybara (>= 3.1, < 4)
|
@@ -21,6 +21,9 @@ GEM
|
|
21
21
|
specs:
|
22
22
|
addressable (2.8.0)
|
23
23
|
public_suffix (>= 2.0.2, < 5.0)
|
24
|
+
appium_capybara (2.0.0)
|
25
|
+
appium_lib (~> 12.0.0)
|
26
|
+
capybara (~> 3.36)
|
24
27
|
appium_lib (12.0.0)
|
25
28
|
appium_lib_core (~> 5.0.0)
|
26
29
|
nokogiri (~> 1.8, >= 1.8.1)
|
@@ -33,6 +36,7 @@ GEM
|
|
33
36
|
ice_nine (~> 0.11.0)
|
34
37
|
thread_safe (~> 0.3, >= 0.3.1)
|
35
38
|
browserstack-local (1.3.0)
|
39
|
+
builder (3.2.4)
|
36
40
|
capybara (3.36.0)
|
37
41
|
addressable
|
38
42
|
matrix
|
@@ -46,23 +50,63 @@ GEM
|
|
46
50
|
chronic (0.10.2)
|
47
51
|
coercible (1.0.0)
|
48
52
|
descendants_tracker (~> 0.0.1)
|
49
|
-
concurrent-ruby (1.1.
|
53
|
+
concurrent-ruby (1.1.10)
|
54
|
+
cucumber (7.1.0)
|
55
|
+
builder (~> 3.2, >= 3.2.4)
|
56
|
+
cucumber-core (~> 10.1, >= 10.1.0)
|
57
|
+
cucumber-create-meta (~> 6.0, >= 6.0.1)
|
58
|
+
cucumber-cucumber-expressions (~> 14.0, >= 14.0.0)
|
59
|
+
cucumber-gherkin (~> 22.0, >= 22.0.0)
|
60
|
+
cucumber-html-formatter (~> 17.0, >= 17.0.0)
|
61
|
+
cucumber-messages (~> 17.1, >= 17.1.1)
|
62
|
+
cucumber-wire (~> 6.2, >= 6.2.0)
|
63
|
+
diff-lcs (~> 1.4, >= 1.4.4)
|
64
|
+
mime-types (~> 3.3, >= 3.3.1)
|
65
|
+
multi_test (~> 0.1, >= 0.1.2)
|
66
|
+
sys-uname (~> 1.2, >= 1.2.2)
|
67
|
+
cucumber-core (10.1.1)
|
68
|
+
cucumber-gherkin (~> 22.0, >= 22.0.0)
|
69
|
+
cucumber-messages (~> 17.1, >= 17.1.1)
|
70
|
+
cucumber-tag-expressions (~> 4.1, >= 4.1.0)
|
71
|
+
cucumber-create-meta (6.0.4)
|
72
|
+
cucumber-messages (~> 17.1, >= 17.1.1)
|
73
|
+
sys-uname (~> 1.2, >= 1.2.2)
|
74
|
+
cucumber-cucumber-expressions (14.0.0)
|
75
|
+
cucumber-gherkin (22.0.0)
|
76
|
+
cucumber-messages (~> 17.1, >= 17.1.1)
|
77
|
+
cucumber-html-formatter (17.0.0)
|
78
|
+
cucumber-messages (~> 17.1, >= 17.1.0)
|
79
|
+
cucumber-messages (17.1.1)
|
80
|
+
cucumber-tag-expressions (4.1.0)
|
81
|
+
cucumber-wire (6.2.1)
|
82
|
+
cucumber-core (~> 10.1, >= 10.1.0)
|
83
|
+
cucumber-cucumber-expressions (~> 14.0, >= 14.0.0)
|
50
84
|
descendants_tracker (0.0.4)
|
51
85
|
thread_safe (~> 0.3, >= 0.3.1)
|
86
|
+
diff-lcs (1.5.0)
|
87
|
+
docile (1.4.0)
|
52
88
|
eventmachine (1.2.7)
|
53
89
|
faker (2.20.0)
|
54
90
|
i18n (>= 1.8.11, < 2)
|
55
91
|
faye-websocket (0.11.1)
|
56
92
|
eventmachine (>= 0.12.0)
|
57
93
|
websocket-driver (>= 0.5.1)
|
94
|
+
ffi (1.15.5)
|
58
95
|
i18n (1.10.0)
|
59
96
|
concurrent-ruby (~> 1.0)
|
60
97
|
ice_nine (0.11.2)
|
61
98
|
matrix (0.4.2)
|
99
|
+
mime-types (3.4.1)
|
100
|
+
mime-types-data (~> 3.2015)
|
101
|
+
mime-types-data (3.2022.0105)
|
62
102
|
mini_mime (1.1.2)
|
103
|
+
multi_test (0.1.2)
|
63
104
|
nokogiri (1.13.3-x86_64-darwin)
|
64
105
|
racc (~> 1.4)
|
65
106
|
os (1.1.4)
|
107
|
+
parallel (1.21.0)
|
108
|
+
parallel_tests (3.7.3)
|
109
|
+
parallel
|
66
110
|
power_assert (2.0.1)
|
67
111
|
public_suffix (4.0.6)
|
68
112
|
racc (1.6.0)
|
@@ -72,6 +116,7 @@ GEM
|
|
72
116
|
rake (13.0.6)
|
73
117
|
redcarpet (3.5.1)
|
74
118
|
regexp_parser (2.2.1)
|
119
|
+
require_all (1.5.0)
|
75
120
|
rexml (3.2.5)
|
76
121
|
ruby-ole (1.2.12.2)
|
77
122
|
rubyzip (2.3.2)
|
@@ -79,8 +124,16 @@ GEM
|
|
79
124
|
childprocess (>= 0.5, < 5.0)
|
80
125
|
rexml (~> 3.2, >= 3.2.5)
|
81
126
|
rubyzip (>= 1.2.2)
|
127
|
+
simplecov (0.21.2)
|
128
|
+
docile (~> 1.1)
|
129
|
+
simplecov-html (~> 0.11)
|
130
|
+
simplecov_json_formatter (~> 0.1)
|
131
|
+
simplecov-html (0.12.3)
|
132
|
+
simplecov_json_formatter (0.1.4)
|
82
133
|
spreadsheet (1.1.7)
|
83
134
|
ruby-ole (>= 1.0)
|
135
|
+
sys-uname (1.2.2)
|
136
|
+
ffi (~> 1.1)
|
84
137
|
test-unit (3.5.3)
|
85
138
|
power_assert
|
86
139
|
thread_safe (0.3.6)
|
@@ -103,9 +156,14 @@ PLATFORMS
|
|
103
156
|
x86_64-darwin-21
|
104
157
|
|
105
158
|
DEPENDENCIES
|
159
|
+
appium_capybara
|
106
160
|
bundler
|
161
|
+
cucumber
|
162
|
+
parallel_tests
|
107
163
|
rake
|
108
164
|
redcarpet
|
165
|
+
require_all
|
166
|
+
simplecov (~> 0.18)
|
109
167
|
testcentricity_web!
|
110
168
|
|
111
169
|
BUNDLED WITH
|
data/README.md
CHANGED
@@ -3,9 +3,9 @@
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/testcentricity_web.svg)](https://badge.fury.io/rb/testcentricity_web) [![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
4
|
|
5
5
|
|
6
|
-
The TestCentricity™ Web core generic framework for desktop and mobile web browser-based app testing implements a Page Object
|
7
|
-
|
8
|
-
|
6
|
+
The TestCentricity™ Web core generic framework for desktop and mobile web browser-based app testing implements a Page Object Model DSL
|
7
|
+
for use with Cucumber, Capybara (version 3.x), and Selenium-Webdriver (version 4.x). It also facilitates the configuration of the appropriate
|
8
|
+
Selenium-Webdriver capabilities required to establish a connection with a local or cloud hosted desktop or mobile web browser.
|
9
9
|
|
10
10
|
The TestCentricity™ Web gem supports running automated tests against the following web test targets:
|
11
11
|
* locally hosted desktop browsers (Chrome, Edge, Firefox, Safari, or IE)
|
@@ -49,7 +49,7 @@ Or install it yourself as:
|
|
49
49
|
## Setup
|
50
50
|
### Using Cucumber
|
51
51
|
|
52
|
-
If you are using Cucumber, you need to require the following in your
|
52
|
+
If you are using Cucumber, you need to require the following in your `env.rb` file:
|
53
53
|
|
54
54
|
require 'capybara/cucumber'
|
55
55
|
require 'testcentricity_web'
|
@@ -57,7 +57,7 @@ If you are using Cucumber, you need to require the following in your *env.rb* fi
|
|
57
57
|
|
58
58
|
### Using RSpec
|
59
59
|
|
60
|
-
If you are using RSpec instead, you need to require the following in your
|
60
|
+
If you are using RSpec instead, you need to require the following in your `env.rb` file:
|
61
61
|
|
62
62
|
require 'capybara'
|
63
63
|
require 'capybara/rspec'
|
@@ -67,7 +67,7 @@ If you are using RSpec instead, you need to require the following in your *env.r
|
|
67
67
|
### Using Appium
|
68
68
|
|
69
69
|
If you will be running your tests on mobile Safari browsers on simulated iOS devices using Appium and XCode Simulators, you need to require
|
70
|
-
the following in your
|
70
|
+
the following in your `env.rb` file:
|
71
71
|
|
72
72
|
require 'appium_capybara'
|
73
73
|
|
@@ -239,7 +239,7 @@ the UI to hide implementation details, as shown below:
|
|
239
239
|
remember_checkbox => { exists: true, enabled: true, checked: false },
|
240
240
|
forgot_password_link => { visible: true, caption: 'Forgot your password?' },
|
241
241
|
error_message_label => { visible: false }
|
242
|
-
|
242
|
+
}
|
243
243
|
verify_ui_states(ui)
|
244
244
|
end
|
245
245
|
end
|
@@ -282,7 +282,7 @@ the UI to hide implementation details, as shown below:
|
|
282
282
|
password_field => profile.password,
|
283
283
|
pword_confirm_field => profile.confirm_password,
|
284
284
|
email_opt_in_check => profile.email_opt_in
|
285
|
-
|
285
|
+
}
|
286
286
|
populate_data_fields(fields)
|
287
287
|
sign_up_button.click
|
288
288
|
end
|
@@ -503,6 +503,7 @@ With TestCentricity, all UI elements are based on the `UIElement` class, and inh
|
|
503
503
|
element.displayed?
|
504
504
|
element.obscured?
|
505
505
|
element.focused?
|
506
|
+
element.required?
|
506
507
|
element.content_editable?
|
507
508
|
element.get_value
|
508
509
|
element.count
|
@@ -569,9 +570,10 @@ interacted with.
|
|
569
570
|
|
570
571
|
The `PageObject.populate_data_fields` and `PageSection.populate_data_fields` methods support the entry of test data into a collection of
|
571
572
|
`UIElements`. The `populate_data_fields` method accepts a hash containing key/hash pairs of `UIElements` and their associated data to be
|
572
|
-
entered. Data values must be in the form of a `String` for `textfield` and `
|
573
|
-
must either be a `Boolean` or a `String` that evaluates to a `Boolean` value (Yes, No, 1, 0, true, false). For `
|
574
|
-
must be
|
573
|
+
entered. Data values must be in the form of a `String` for `textfield`, `selectlist`, and `filefield` controls. For `checkbox` and `radio`
|
574
|
+
controls, data must either be a `Boolean` or a `String` that evaluates to a `Boolean` value (Yes, No, 1, 0, true, false). For `range` controls,
|
575
|
+
data must be an `Integer`. For `input(type='color')` color picker controls, which are specified as a `textfield`, data must be in the form
|
576
|
+
of a hex color `String`. For `section` objects, data values must be a `String`, and the `section` object must have a `set` method defined.
|
575
577
|
|
576
578
|
The `populate_data_fields` method verifies that data attributes associated with each `UIElement` is not `nil` or `empty` before attempting to
|
577
579
|
enter data into the `UIElement`.
|
@@ -634,6 +636,14 @@ The `verify_ui_states` method supports the following property/state pairs:
|
|
634
636
|
:class String
|
635
637
|
:value or :caption String
|
636
638
|
:attribute Hash
|
639
|
+
:style String
|
640
|
+
:tabindex Integer
|
641
|
+
:required Boolean
|
642
|
+
|
643
|
+
**Pages:**
|
644
|
+
|
645
|
+
:secure Boolean
|
646
|
+
:title String
|
637
647
|
|
638
648
|
**Text Fields:**
|
639
649
|
|
@@ -646,12 +656,17 @@ The `verify_ui_states` method supports the following property/state pairs:
|
|
646
656
|
|
647
657
|
**Checkboxes:**
|
648
658
|
|
649
|
-
:checked
|
659
|
+
:checked Boolean
|
660
|
+
:indeterminate Boolean
|
650
661
|
|
651
662
|
**Radio Buttons:**
|
652
663
|
|
653
664
|
:selected Boolean
|
654
665
|
|
666
|
+
**Links:**
|
667
|
+
|
668
|
+
:href String
|
669
|
+
|
655
670
|
**Images**
|
656
671
|
|
657
672
|
:loaded Boolean
|
@@ -671,6 +686,8 @@ The `verify_ui_states` method supports the following property/state pairs:
|
|
671
686
|
:items or :options Array of Strings
|
672
687
|
:itemcount or :optioncount Integer
|
673
688
|
:selected String
|
689
|
+
:groupcount Integer
|
690
|
+
:group_headings Array of Strings
|
674
691
|
|
675
692
|
**Tables**
|
676
693
|
|
@@ -706,8 +723,6 @@ The `verify_ui_states` method supports the following property/state pairs:
|
|
706
723
|
|
707
724
|
The `verify_ui_states` method supports the following ARIA accessibility property/state pairs:
|
708
725
|
|
709
|
-
**All Objects:**
|
710
|
-
|
711
726
|
:aria_label String
|
712
727
|
:aria_disabled Boolean
|
713
728
|
:aria_labelledby String
|
@@ -738,8 +753,10 @@ The `verify_ui_states` method supports the following ARIA accessibility property
|
|
738
753
|
:aria_multiline Boolean
|
739
754
|
:aria_multiselectable Boolean
|
740
755
|
:content_editable Boolean
|
756
|
+
:role String
|
741
757
|
|
742
758
|
#### Comparison States
|
759
|
+
|
743
760
|
The `verify_ui_states` method supports comparison states using property/comparison state pairs:
|
744
761
|
|
745
762
|
object => { property: { comparison_state: value } }
|
@@ -844,6 +861,126 @@ Baseline translation strings are stored in `.yml` files in the `config/locales/`
|
|
844
861
|
└── README.md
|
845
862
|
|
846
863
|
|
864
|
+
### Working with custom UIElements
|
865
|
+
|
866
|
+
Many responsive and touch-enabled web based user interfaces are implemented using front-end JavaScript libraries for building user
|
867
|
+
interfaces based on UI components. Popular JS libraries include React, Angular, and Ember.js. These stylized and adorned controls can
|
868
|
+
present a challenge when attempting to interact with them using Capybara and Selenium based automated tests.
|
869
|
+
|
870
|
+
#### Radio and Checkbox UIElements
|
871
|
+
|
872
|
+
Sometimes, radio buttons and checkboxes implemented using JS component libraries cannot be interacted with due to other UI elements
|
873
|
+
being overlaid on top of them and the base `input(type='radio')` or `input(type='checkbox')` element not being visible.
|
874
|
+
|
875
|
+
In the screenshots below of an airline flight search and booking page, the **Roundtrip** and **One-way** radio buttons are adorned with
|
876
|
+
`label` elements that also acts as proxies for their associated `input(type='radio')` elements, and they intercept the `click` actions
|
877
|
+
that would normally be handled by the `input(type='radio')` elements.
|
878
|
+
|
879
|
+
<img src="https://i.imgur.com/7bW5u4c.jpg" alt="Roundtrip Radio button Input" title="Roundtrip Radio button Input">
|
880
|
+
|
881
|
+
|
882
|
+
This screenshot shows the `label` element that is overlaid above the **Roundtrip** `input(type='radio')` element.
|
883
|
+
|
884
|
+
<img src="https://i.imgur.com/2stWiyR.jpg" alt="Roundtrip Radio button Label" title="Roundtrip Radio button Label">
|
885
|
+
|
886
|
+
|
887
|
+
The checkbox controls in this web UI are also adorned with `label` elements that act as proxies for their associated `input(type='checkbox')`
|
888
|
+
elements.
|
889
|
+
|
890
|
+
<img src="https://i.imgur.com/JcOANqZ.jpg" alt="One-way Radio button Label" title="One-way Radio button Label">
|
891
|
+
|
892
|
+
|
893
|
+
The `Radio.define_custom_elements` and `CheckBox.define_custom_elements` methods provide a way to specify the `proxy` and/or `label`
|
894
|
+
elements associated with the `input(type='radio')` or `input(type='checkbox')` elements. The `define_custom_elements` method
|
895
|
+
should be called from an `initialize` method for the `PageObject` or `PageSection` where the `radio` or `checkbox` element is instantiated.
|
896
|
+
The code snippet below demonstrates the use of the `Radio.define_custom_elements` and `CheckBox.define_custom_elements` methods to
|
897
|
+
resolve the testability issues posed by the adorned **Roundtrip** and **One-way** radio buttons and the **Flexible dates** checkbox.
|
898
|
+
|
899
|
+
class FlightBookingPage < TestCentricity::PageObject
|
900
|
+
trait(:page_name) { 'Flight Booking Home' }
|
901
|
+
trait(:page_locator) { "div[class*='bookerContainer']" }
|
902
|
+
|
903
|
+
# Flight Booking page UI elements
|
904
|
+
radios roundtrip_radio: 'input#roundtrip',
|
905
|
+
one_way_radio: 'input#oneway'
|
906
|
+
checkbox :flexible_check, 'input#flexibleDates'
|
907
|
+
|
908
|
+
def initialize
|
909
|
+
# define the custom element components for the Round Trip radio button
|
910
|
+
radio_spec = { proxy: "label[for='roundtrip']" }
|
911
|
+
roundtrip_radio.define_custom_elements(radio_spec)
|
912
|
+
# define the custom element components for the One Way radio button
|
913
|
+
radio_spec = { proxy: "label[for='oneway']" }
|
914
|
+
one_way_radio.define_custom_elements(radio_spec)
|
915
|
+
# define the custom element components for the Flexible Date checkbox
|
916
|
+
check_spec = { proxy: 'label#flexDatesLabel' }
|
917
|
+
flexible_check.define_custom_elements(check_spec)
|
918
|
+
end
|
919
|
+
end
|
920
|
+
|
921
|
+
|
922
|
+
#### SelectList UIElements
|
923
|
+
|
924
|
+
The basic HTML `select` element is typically composed of the parent `select` object, and one or more `option` elements representing
|
925
|
+
the selectable items in the drop-down list. However, `select` type controls implemented using JS component libraries can be composed
|
926
|
+
of multiple elements representing the various components of a drop-down style `selectlist` implementation.
|
927
|
+
|
928
|
+
In the screenshots below of an airline flight search and booking page, there are no `select` or `option` elements associated with the
|
929
|
+
**Month**, **Day**, and **Cabin Type** drop-down style selectors. An inspection of the **Month** selector reveals that it is a `div`
|
930
|
+
element that contains a `button` element (outlined in red) for triggering the drop-down list, a `ul` element (outlined in green) that
|
931
|
+
contains the drop-down list, and multiple `li` elements (outlined in blue) that represent the list items or options that can be
|
932
|
+
selected. The currently selected item or option can be identified by either the `listBoxOptionSelected` snippet in its `class` name or
|
933
|
+
the `aria-selected` attribute (outlined in orange).
|
934
|
+
|
935
|
+
Further examination of the **Day** and **Cabin Type** drop-down style selectors reveal that their composition is identical to the
|
936
|
+
**Month** selector.
|
937
|
+
|
938
|
+
<img src="https://i.imgur.com/LYAC2lh.jpg" alt="Custom SelectList" title="Custom SelectList">
|
939
|
+
|
940
|
+
|
941
|
+
The `SelectList.define_list_elements` method provides a means of specifying the various elements that make up the key components of
|
942
|
+
a `selectlist` control. The method accepts a hash of element designators (key) and a CSS or Xpath expression (value) that expression
|
943
|
+
that uniquely identifies the element. Valid element designators are `list_item:`, `options_list:`, `list_trigger:`, `selected_item:`,
|
944
|
+
`text_field:`, `group_heading:`, and `group_item:`.
|
945
|
+
|
946
|
+
The code snippet below demonstrates the use of the `SelectList.define_list_elements` method to define the common components that make
|
947
|
+
up the **Month**, **Day**, and **Cabin Type** drop-down style selectors. Note the use of the ARIA `role` and `aria-selected` attributes
|
948
|
+
as element locators.
|
949
|
+
|
950
|
+
class FlightBookingPage < TestCentricity::PageObject
|
951
|
+
trait(:page_name) { 'Flight Booking Home' }
|
952
|
+
trait(:page_locator) { "div[class*='bookerContainer']" }
|
953
|
+
|
954
|
+
# Flight Booking page UI elements
|
955
|
+
selectlists month_select: "div[class*='expandFlexMonth']",
|
956
|
+
duration_select: "div[class*='expandFlexDay']",
|
957
|
+
cabin_type_select: "div[class*='bookFlightForm__optionField'] > div[class*='app-components-ListBox']"
|
958
|
+
|
959
|
+
def initialize
|
960
|
+
# define the custom list element components for the Month, Duration, and Cabin Type selectlist objects
|
961
|
+
list_spec = {
|
962
|
+
selected_item: "li[aria-selected=true]",
|
963
|
+
options_list: "ul[role='listbox']",
|
964
|
+
list_item: "li[role='option']",
|
965
|
+
list_trigger: "button[role='combobox']"
|
966
|
+
}
|
967
|
+
month_select.define_list_elements(list_spec)
|
968
|
+
duration_select.define_list_elements(list_spec)
|
969
|
+
cabin_type_select.define_list_elements(list_spec)
|
970
|
+
end
|
971
|
+
end
|
972
|
+
|
973
|
+
|
974
|
+
#### List UIElements
|
975
|
+
|
976
|
+
The basic HTML list is typically composed of the parent `ul` object, and one or more `li` elements representing the items
|
977
|
+
in the list. However, list controls implemented using JS component libraries can be composed of multiple elements representing the
|
978
|
+
components of a list implementation.
|
979
|
+
|
980
|
+
The `List.define_list_elements` method provides a means of specifying the elements that make up the key components of a `list` control.
|
981
|
+
The method accepts a hash of element designators (key) and a CSS or Xpath expression (value) that expression that uniquely identifies
|
982
|
+
the element. Valid element designators are `list_item:`and `selected_item:`.
|
983
|
+
|
847
984
|
|
848
985
|
## Instantiating your PageObjects
|
849
986
|
|
@@ -1220,7 +1357,7 @@ Once your test environment is properly configured, the following **Environment V
|
|
1220
1357
|
| `WEB_BROWSER` | Must be set to `appium` |
|
1221
1358
|
| `APP_PLATFORM_NAME` | Must be set to `iOS` |
|
1222
1359
|
| `APP_BROWSER` | Must be set to `Safari` |
|
1223
|
-
| `APP_VERSION` | Must be set to `15.
|
1360
|
+
| `APP_VERSION` | Must be set to `15.4`, `14.5`, or which ever iOS version you wish to run within the XCode Simulator |
|
1224
1361
|
| `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 |
|
1225
1362
|
| `DEVICE_TYPE` | Must be set to `phone` or `tablet` |
|
1226
1363
|
| `APP_UDID` | UDID of physically connected iOS device (not used for simulators) |
|
@@ -1302,6 +1439,13 @@ the code shown below in your `hooks.rb` file.
|
|
1302
1439
|
end
|
1303
1440
|
|
1304
1441
|
|
1442
|
+
The `APPIUM_SERVER` environment variable must be set to `run` in order to programmatically start and stop Appium server. This can be
|
1443
|
+
set by adding the following to your `cucumber.yml` file and including `-p run_appium` in your command line when starting your Cucumber
|
1444
|
+
test suite(s):
|
1445
|
+
|
1446
|
+
run_appium: APPIUM_SERVER=run
|
1447
|
+
|
1448
|
+
|
1305
1449
|
Refer to **section 8.6 (Using Browser specific Profiles in cucumber.yml)** below.
|
1306
1450
|
|
1307
1451
|
|
@@ -1548,9 +1692,10 @@ that you intend to connect with.
|
|
1548
1692
|
#==============
|
1549
1693
|
|
1550
1694
|
appium_ios: WEB_BROWSER=appium AUTOMATION_ENGINE=XCUITest APP_PLATFORM_NAME="ios" APP_BROWSER="Safari" NEW_COMMAND_TIMEOUT=30 SHOW_SIM_KEYBOARD=false
|
1551
|
-
app_ios_15: --profile appium_ios APP_VERSION="15.
|
1552
|
-
|
1553
|
-
ipad_air_15_sim:
|
1695
|
+
app_ios_15: --profile appium_ios APP_VERSION="15.4"
|
1696
|
+
ipad_pro_12_15_sim: --profile app_ios_15 DEVICE_TYPE=tablet APP_DEVICE="iPad Pro (12.9-inch) (5th generation)"
|
1697
|
+
ipad_air_15_sim: --profile app_ios_15 DEVICE_TYPE=tablet APP_DEVICE="iPad Air (5th generation)" <%= desktop %>
|
1698
|
+
ipad_15_sim: --profile app_ios_15 DEVICE_TYPE=tablet APP_DEVICE="iPad (9th generation)"
|
1554
1699
|
|
1555
1700
|
|
1556
1701
|
#==============
|
@@ -1683,16 +1828,16 @@ in landscape orientation:
|
|
1683
1828
|
cucumber -p ipad_pro -p landscape
|
1684
1829
|
|
1685
1830
|
|
1686
|
-
The following command specifies that Cucumber will run tests against an iPad Pro (12.9-inch) (5th generation) with iOS version 15.
|
1831
|
+
The following command specifies that Cucumber will run tests against an iPad Pro (12.9-inch) (5th generation) with iOS version 15.4 in an
|
1687
1832
|
XCode Simulator in landscape orientation:
|
1688
1833
|
|
1689
|
-
cucumber -p
|
1834
|
+
cucumber -p ipad_pro_12_15_sim -p landscape
|
1690
1835
|
|
1691
1836
|
NOTE: Appium must be running prior to executing this command
|
1692
1837
|
|
1693
1838
|
You can ensure that Appium Server is running by including `-p run_appium` in your command line:
|
1694
1839
|
|
1695
|
-
cucumber -p
|
1840
|
+
cucumber -p ipad_pro_12_15_sim -p landscape -p run_appium
|
1696
1841
|
|
1697
1842
|
|
1698
1843
|
The following command specifies that Cucumber will run tests against a remotely hosted Safari web browser running on a macOS Monterey
|
data/Rakefile
CHANGED
@@ -1 +1,60 @@
|
|
1
|
-
require '
|
1
|
+
require 'rubygems'
|
2
|
+
require 'cucumber'
|
3
|
+
require 'cucumber/rake/task'
|
4
|
+
require 'rake'
|
5
|
+
|
6
|
+
|
7
|
+
namespace :features do
|
8
|
+
Cucumber::Rake::Task.new(:edge_local) do |t|
|
9
|
+
t.profile = 'edge_local'
|
10
|
+
end
|
11
|
+
|
12
|
+
Cucumber::Rake::Task.new(:chrome_local) do |t|
|
13
|
+
t.profile = 'chrome_local'
|
14
|
+
end
|
15
|
+
|
16
|
+
Cucumber::Rake::Task.new(:edge_headless) do |t|
|
17
|
+
t.profile = 'edge_headless'
|
18
|
+
end
|
19
|
+
|
20
|
+
Cucumber::Rake::Task.new(:chrome_headless) do |t|
|
21
|
+
t.profile = 'chrome_headless'
|
22
|
+
end
|
23
|
+
|
24
|
+
Cucumber::Rake::Task.new(:safari_local) do |t|
|
25
|
+
t.profile = 'safari_local'
|
26
|
+
end
|
27
|
+
|
28
|
+
Cucumber::Rake::Task.new(:firefox_local) do |t|
|
29
|
+
t.profile = 'firefox_local'
|
30
|
+
end
|
31
|
+
|
32
|
+
Cucumber::Rake::Task.new(:firefox_headless) do |t|
|
33
|
+
t.profile = 'firefox_headless'
|
34
|
+
end
|
35
|
+
|
36
|
+
Cucumber::Rake::Task.new(:edge_grid) do |t|
|
37
|
+
t.profile = 'edge_grid'
|
38
|
+
end
|
39
|
+
|
40
|
+
Cucumber::Rake::Task.new(:chrome_grid) do |t|
|
41
|
+
t.profile = 'chrome_grid'
|
42
|
+
end
|
43
|
+
|
44
|
+
Cucumber::Rake::Task.new(:firefox_grid) do |t|
|
45
|
+
t.profile = 'firefox_grid'
|
46
|
+
end
|
47
|
+
|
48
|
+
Cucumber::Rake::Task.new(:ios_remote) do |t|
|
49
|
+
t.profile = 'ios_remote'
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
task :required => [:edge_local, :edge_headless, :chrome_local, :chrome_headless, :safari_local]
|
54
|
+
|
55
|
+
task :grid => [:edge_grid, :chrome_grid]
|
56
|
+
|
57
|
+
task :mobile => [:ios_remote]
|
58
|
+
|
59
|
+
task :all => [:edge_local, :edge_headless, :chrome_local, :chrome_headless, :safari_local, :edge_grid, :chrome_grid, :ios_remote]
|
60
|
+
end
|