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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +18 -0
  3. data/.simplecov +5 -0
  4. data/CHANGELOG.md +43 -1
  5. data/Gemfile.lock +60 -2
  6. data/README.md +166 -21
  7. data/Rakefile +60 -1
  8. data/config/cucumber.yml +163 -0
  9. data/config/test_data/data.json +12 -0
  10. data/config/test_data/data.xls +0 -0
  11. data/config/test_data/data.yml +12 -0
  12. data/docker-compose-v3.yml +48 -0
  13. data/features/basic_test_page_css.feature +35 -0
  14. data/features/basic_test_page_xpath.feature +27 -0
  15. data/features/media_players.feature +87 -0
  16. data/features/step_definitions/generic_steps.rb.rb +44 -0
  17. data/features/step_definitions/media_steps.rb +30 -0
  18. data/features/support/env.rb +50 -0
  19. data/features/support/hooks.rb +245 -0
  20. data/features/support/pages/base_test_page.rb +11 -0
  21. data/features/support/pages/basic_css_test_page.rb +52 -0
  22. data/features/support/pages/basic_test_page.rb +297 -0
  23. data/features/support/pages/basic_xpath_test_page.rb +53 -0
  24. data/features/support/pages/custom_controls_page.rb +16 -0
  25. data/features/support/pages/indexed_sections_page.rb +16 -0
  26. data/features/support/pages/media_test_page.rb +195 -0
  27. data/features/support/sections/header_nav.rb +28 -0
  28. data/features/support/world_data.rb +12 -0
  29. data/features/support/world_pages.rb +18 -0
  30. data/lib/testcentricity_web/data_objects/environment.rb +16 -0
  31. data/lib/testcentricity_web/version.rb +1 -1
  32. data/lib/testcentricity_web/web_core/page_object.rb +8 -8
  33. data/lib/testcentricity_web/web_core/page_objects_helper.rb +41 -8
  34. data/lib/testcentricity_web/web_core/page_section.rb +1 -16
  35. data/lib/testcentricity_web/web_core/webdriver_helper.rb +77 -120
  36. data/lib/testcentricity_web/web_elements/checkbox.rb +3 -4
  37. data/lib/testcentricity_web/web_elements/media.rb +50 -4
  38. data/lib/testcentricity_web/web_elements/radio.rb +5 -1
  39. data/lib/testcentricity_web/web_elements/select_list.rb +18 -7
  40. data/lib/testcentricity_web/web_elements/ui_elements_helper.rb +13 -0
  41. data/reports/.keep +1 -0
  42. data/test_site/basic_test_page.html +290 -0
  43. data/test_site/custom_controls_page.html +58 -0
  44. data/test_site/images/Granny.jpg +0 -0
  45. data/test_site/images/Wilder.jpg +0 -0
  46. data/test_site/images/You_Betcha.jpg +0 -0
  47. data/test_site/indexed_sections_page.html +58 -0
  48. data/test_site/media/MIB2-subtitles-pt-BR.vtt +49 -0
  49. data/test_site/media/MIB2.mp4 +0 -0
  50. data/test_site/media/MP4_small.mp4 +0 -0
  51. data/test_site/media/MPS_sample.mp3 +0 -0
  52. data/test_site/media_page.html +86 -0
  53. data/testcentricity_web.gemspec +5 -0
  54. metadata +125 -4
  55. data/test_site/test_page.html +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ee1ff6311bce503168094dbc5546d00419187e6991d67073d590d0cf2dd6beac
4
- data.tar.gz: 5a776195eb96437187dae63eb12f9e6c1cfe0580811dbc369dc09ac75d76e300
3
+ metadata.gz: 58ddfdbcb8747347fcb06efdd2a888509fa904bd5541a0f3d4d303af6469552c
4
+ data.tar.gz: 14f9af8661d7e571d10f79e3d093cafa4e744388d5c1d6f9232e207fe5e82d6f
5
5
  SHA512:
6
- metadata.gz: 5c05c61753313054175c4d3ae0a36dabe8fd089a2178918e6d796a26806be5af5d6a5020a55658b1951b4d62adfb63725c610afa4c0b4b4612e6e675de015b62
7
- data.tar.gz: 279053b4a2323f9089c183bebf286afb6dbb9be22f9bfee0b22264d2810d1ce77e17b33cec22e26d9b1fd6bdd970c41e2cd1cd1c36a11f010fa0d125fd95e80f
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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'simplecov'
4
+
5
+ SimpleCov.start
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
- ### Changed
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)
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.9)
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 and Data
7
- Object Model DSL for use with Cucumber, Capybara (version 3.x), and Selenium-Webdriver (version 4.x). It also facilitates the configuration
8
- of the appropriate Selenium-Webdriver capabilities required to establish a connection with a local or cloud hosted desktop or mobile web browser.
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 *env.rb* file:
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 *env.rb* file:
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 *env.rb* file:
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 `selectlist` controls. For `checkbox` and `radio` controls, data
573
- must either be a `Boolean` or a `String` that evaluates to a `Boolean` value (Yes, No, 1, 0, true, false). For `section` objects, data values
574
- must be a `String`, and the `section` object must have a `set` method defined.
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 Boolean
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.2`, `14.5`, or which ever iOS version you wish to run within the XCode Simulator |
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.2"
1552
- ipad_pro_12_9_15_sim: --profile app_ios_15 DEVICE_TYPE=tablet APP_DEVICE="iPad Pro (12.9-inch) (5th generation)" <%= desktop %>
1553
- ipad_air_15_sim: --profile app_ios_15 DEVICE_TYPE=tablet APP_DEVICE="iPad Air (4th generation)" <%= desktop %>
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.2 in an
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 ipad_pro_12_9_15_sim -p landscape
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 ipad_pro_12_9_15_sim -p landscape -p run_appium
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 'bundler/gem_tasks'
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