testcentricity_web 4.1.5 → 4.1.8

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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +18 -0
  3. data/.simplecov +9 -0
  4. data/CHANGELOG.md +44 -0
  5. data/Gemfile.lock +60 -2
  6. data/README.md +17 -7
  7. data/Rakefile +86 -1
  8. data/config/cucumber.yml +170 -0
  9. data/config/test_data/LOCAL_data.json +15 -0
  10. data/config/test_data/LOCAL_data.xls +0 -0
  11. data/config/test_data/LOCAL_data.yml +11 -0
  12. data/config/test_data/data.json +25 -0
  13. data/config/test_data/data.xls +0 -0
  14. data/config/test_data/data.yml +20 -0
  15. data/docker-compose-v3.yml +48 -0
  16. data/features/basic_form_page_css.feature +39 -0
  17. data/features/basic_form_page_xpath.feature +26 -0
  18. data/features/media_players.feature +84 -0
  19. data/features/step_definitions/generic_steps.rb.rb +109 -0
  20. data/features/step_definitions/media_steps.rb +30 -0
  21. data/features/support/data/form_data.rb +43 -0
  22. data/features/support/env.rb +50 -0
  23. data/features/support/hooks.rb +265 -0
  24. data/features/support/pages/base_test_page.rb +22 -0
  25. data/features/support/pages/basic_css_form_page.rb +52 -0
  26. data/features/support/pages/basic_form_page.rb +393 -0
  27. data/features/support/pages/basic_xpath_form_page.rb +53 -0
  28. data/features/support/pages/custom_controls_page.rb +13 -0
  29. data/features/support/pages/indexed_sections_page.rb +13 -0
  30. data/features/support/pages/media_test_page.rb +208 -0
  31. data/features/support/sections/header_nav.rb +39 -0
  32. data/features/support/world_data.rb +12 -0
  33. data/features/support/world_pages.rb +18 -0
  34. data/lib/testcentricity_web/appium_server.rb +5 -0
  35. data/lib/testcentricity_web/data_objects/data_objects_helper.rb +7 -0
  36. data/lib/testcentricity_web/data_objects/environment.rb +18 -0
  37. data/lib/testcentricity_web/data_objects/excel_helper.rb +60 -59
  38. data/lib/testcentricity_web/version.rb +1 -1
  39. data/lib/testcentricity_web/web_core/drag_drop_helper.rb +4 -0
  40. data/lib/testcentricity_web/web_core/page_object.rb +8 -8
  41. data/lib/testcentricity_web/web_core/page_objects_helper.rb +43 -8
  42. data/lib/testcentricity_web/web_core/page_section.rb +1 -16
  43. data/lib/testcentricity_web/web_core/webdriver_helper.rb +16 -0
  44. data/lib/testcentricity_web/web_elements/checkbox.rb +3 -4
  45. data/lib/testcentricity_web/web_elements/file_field.rb +9 -5
  46. data/lib/testcentricity_web/web_elements/image.rb +2 -1
  47. data/lib/testcentricity_web/web_elements/media.rb +45 -11
  48. data/lib/testcentricity_web/web_elements/radio.rb +5 -1
  49. data/lib/testcentricity_web/web_elements/select_list.rb +11 -3
  50. data/lib/testcentricity_web/web_elements/ui_elements_helper.rb +33 -7
  51. data/lib/testcentricity_web/web_elements/video.rb +2 -2
  52. data/reports/.keep +1 -0
  53. data/test_site/basic_test_page.html +290 -0
  54. data/test_site/custom_controls_page.html +58 -0
  55. data/test_site/images/Granny.jpg +0 -0
  56. data/test_site/images/Wilder.jpg +0 -0
  57. data/test_site/images/You_Betcha.jpg +0 -0
  58. data/test_site/indexed_sections_page.html +58 -0
  59. data/test_site/media/MIB2-subtitles-pt-BR.vtt +49 -0
  60. data/test_site/media/MIB2.mp4 +0 -0
  61. data/test_site/media/MP4_small.mp4 +0 -0
  62. data/test_site/media/MPS_sample.mp3 +0 -0
  63. data/test_site/media/count_and_bars.mp4 +0 -0
  64. data/test_site/media_page.html +86 -0
  65. data/testcentricity_web.gemspec +5 -0
  66. metadata +131 -4
  67. data/test_site/test_page.html +0 -11
@@ -5,10 +5,6 @@ module TestCentricity
5
5
  attr_accessor :parent
6
6
  attr_accessor :parent_list
7
7
  attr_accessor :list_index
8
- attr_accessor :locator_type
9
-
10
- XPATH_SELECTORS = ['//', '[@', '[contains(']
11
- CSS_SELECTORS = ['#', ':nth-child(', ':first-child', ':last-child', ':nth-of-type(', ':first-of-type', ':last-of-type', '^=', '$=', '*=', ':contains(']
12
8
 
13
9
  def initialize(name, parent, locator, context)
14
10
  @name = name
@@ -17,18 +13,7 @@ module TestCentricity
17
13
  @context = context
18
14
  @parent_list = nil
19
15
  @list_index = nil
20
-
21
- is_xpath = XPATH_SELECTORS.any? { |selector| @locator.include?(selector) }
22
- is_css = CSS_SELECTORS.any? { |selector| @locator.include?(selector) }
23
- @locator_type = if is_xpath && !is_css
24
- :xpath
25
- elsif is_css && !is_xpath
26
- :css
27
- elsif !is_css && !is_xpath
28
- :css
29
- else
30
- :css
31
- end
16
+ set_locator_type
32
17
  end
33
18
 
34
19
  def get_locator
@@ -29,10 +29,12 @@ module TestCentricity
29
29
  # set downloads folder path
30
30
  @downloads_path = "#{Dir.pwd}/downloads"
31
31
  if ENV['PARALLEL']
32
+ # :nocov:
32
33
  Environ.parallel = true
33
34
  Environ.process_num = ENV['TEST_ENV_NUMBER']
34
35
  @downloads_path = "#{@downloads_path}/#{ENV['TEST_ENV_NUMBER']}"
35
36
  Dir.mkdir(@downloads_path) unless Dir.exist?(@downloads_path)
37
+ # :nocov:
36
38
  else
37
39
  Environ.parallel = false
38
40
  end
@@ -50,6 +52,7 @@ module TestCentricity
50
52
  when :appium
51
53
  initialize_appium
52
54
  'Appium'
55
+ # :nocov:
53
56
  when :browserstack
54
57
  initialize_browserstack
55
58
  'Browserstack cloud service'
@@ -62,6 +65,7 @@ module TestCentricity
62
65
  when :testingbot
63
66
  initialize_testingbot
64
67
  'TestingBot cloud service'
68
+ # :nocov:
65
69
  else
66
70
  if ENV['SELENIUM'] == 'remote'
67
71
  initialize_remote
@@ -91,11 +95,13 @@ module TestCentricity
91
95
  def self.initialize_browser_size
92
96
  # tile browser windows if running in multiple parallel threads and BROWSER_TILE environment variable is true
93
97
  if ENV['PARALLEL'] && ENV['BROWSER_TILE']
98
+ # :nocov:
94
99
  thread = ENV['TEST_ENV_NUMBER'].to_i
95
100
  if thread > 1
96
101
  Browsers.set_browser_window_position(100 * thread - 1, 100 * thread - 1)
97
102
  sleep(1)
98
103
  end
104
+ # :nocov:
99
105
  else
100
106
  Browsers.set_browser_window_position(10, 10)
101
107
  sleep(1)
@@ -116,6 +122,7 @@ module TestCentricity
116
122
  Environ.session_state = :running
117
123
  end
118
124
 
125
+ # :nocov:
119
126
  def self.close_tunnel
120
127
  unless @bs_local.nil?
121
128
  @bs_local.stop
@@ -126,6 +133,7 @@ module TestCentricity
126
133
  end
127
134
  end
128
135
  end
136
+ # :nocov:
129
137
 
130
138
  private
131
139
 
@@ -147,10 +155,12 @@ module TestCentricity
147
155
  desired_capabilities[:avd] = ENV['APP_DEVICE'] if Environ.device_os == :android
148
156
  desired_capabilities[:automationName] = ENV['AUTOMATION_ENGINE'] if ENV['AUTOMATION_ENGINE']
149
157
  if ENV['UDID']
158
+ # :nocov:
150
159
  Environ.device = :device
151
160
  desired_capabilities[:udid] = ENV['UDID']
152
161
  desired_capabilities[:xcodeOrgId] = ENV['TEAM_ID'] if ENV['TEAM_ID']
153
162
  desired_capabilities[:xcodeSigningId] = ENV['TEAM_NAME'] if ENV['TEAM_NAME']
163
+ # :nocov:
154
164
  else
155
165
  Environ.device = :simulator
156
166
  desired_capabilities[:orientation] = Environ.device_orientation.upcase if Environ.device_orientation
@@ -179,11 +189,13 @@ module TestCentricity
179
189
  desired_capabilities[:chromedriverExecutable] = ENV['CHROMEDRIVER_EXECUTABLE'] if ENV['CHROMEDRIVER_EXECUTABLE']
180
190
  # set wdaLocalPort (iOS) or systemPort (Android) if PARALLEL_PORT is true
181
191
  if ENV['PARALLEL'] && ENV['PARALLEL_PORT']
192
+ # :nocov:
182
193
  if Environ.device_os == :ios
183
194
  desired_capabilities[:wdaLocalPort] = 8100 + ENV['TEST_ENV_NUMBER'].to_i
184
195
  else
185
196
  desired_capabilities[:systemPort] = 8200 + ENV['TEST_ENV_NUMBER'].to_i
186
197
  end
198
+ # :nocov:
187
199
  else
188
200
  desired_capabilities[:wdaLocalPort] = ENV['WDA_LOCAL_PORT'] if ENV['WDA_LOCAL_PORT']
189
201
  desired_capabilities[:systemPort] = ENV['SYSTEM_PORT'] if ENV['SYSTEM_PORT']
@@ -255,6 +267,7 @@ module TestCentricity
255
267
  Capybara.default_driver = :selenium
256
268
  end
257
269
 
270
+ # :nocov:
258
271
  def self.initialize_browserstack
259
272
  browser = ENV['BS_BROWSER']
260
273
  Environ.grid = :browserstack
@@ -554,6 +567,7 @@ module TestCentricity
554
567
  # configure file_detector for remote uploads if target is desktop web browser
555
568
  config_file_uploads unless ENV['TB_PLATFORM']
556
569
  end
570
+ # :nocov:
557
571
 
558
572
  def self.chrome_edge_options(browser)
559
573
  options = case browser
@@ -599,6 +613,7 @@ module TestCentricity
599
613
  options
600
614
  end
601
615
 
616
+ # :nocov:
602
617
  def self.test_context_message
603
618
  context_message = if ENV['TEST_CONTEXT']
604
619
  "#{Environ.test_environment.to_s.upcase} - #{ENV['TEST_CONTEXT']}"
@@ -636,5 +651,6 @@ module TestCentricity
636
651
  str if File.exist?(str)
637
652
  end
638
653
  end
654
+ # :nocov:
639
655
  end
640
656
  end
@@ -112,11 +112,10 @@ module TestCentricity
112
112
  object_not_found_exception(obj, 'Checkbox')
113
113
  invalid_object_type_exception(obj, 'checkbox')
114
114
  if @proxy.nil?
115
- if obj.native.attribute('ot') == 'JCheckBox'
116
- expected = state.to_bool
117
- obj.click unless expected == obj.checked?
118
- else
115
+ begin
119
116
  obj.set(state)
117
+ rescue
118
+ obj.click unless state == obj.checked?
120
119
  end
121
120
  else
122
121
  page.find(:css, @proxy).click unless state == obj.checked?
@@ -5,17 +5,19 @@ module TestCentricity
5
5
  @type = :filefield
6
6
  end
7
7
 
8
+ def file_upload(file_path)
9
+ obj, = find_element(visible = false)
10
+ obj.send_keys(file_path)
11
+ end
12
+
13
+ # :nocov:
14
+
8
15
  def file_attach(file_path)
9
16
  Capybara.ignore_hidden_elements = false
10
17
  page.attach_file(@locator, file_path)
11
18
  Capybara.ignore_hidden_elements = true
12
19
  end
13
20
 
14
- def file_upload(file_path)
15
- obj, = find_element(visible = false)
16
- obj.send_keys(file_path)
17
- end
18
-
19
21
  def drop_files(files)
20
22
  js_script = 'fileList = Array();'
21
23
  files.count.times do |i|
@@ -41,5 +43,7 @@ module TestCentricity
41
43
  # trigger the fake drop event
42
44
  page.execute_script(js_script)
43
45
  end
46
+
47
+ # :nocov:
44
48
  end
45
49
  end
@@ -14,7 +14,8 @@ module TestCentricity
14
14
  def loaded?
15
15
  obj, = find_element
16
16
  object_not_found_exception(obj, nil)
17
- obj.native.attribute('complete')
17
+ state = obj.native.attribute('complete')
18
+ state.boolean? ? state : state == 'true'
18
19
  end
19
20
 
20
21
  alias is_loaded? loaded?
@@ -125,7 +125,7 @@ module TestCentricity
125
125
  def current_time
126
126
  obj, = find_element(visible = :all)
127
127
  object_not_found_exception(obj, @type)
128
- obj.native.attribute('currentTime').to_f
128
+ obj.native.attribute('currentTime').to_f.round(2)
129
129
  end
130
130
 
131
131
  # Return media defaultPlaybackRate property
@@ -137,7 +137,7 @@ module TestCentricity
137
137
  def default_playback_rate
138
138
  obj, = find_element(visible = :all)
139
139
  object_not_found_exception(obj, @type)
140
- obj.native.attribute('defaultPlaybackRate')
140
+ obj.native.attribute('defaultPlaybackRate').to_f
141
141
  end
142
142
 
143
143
  # Return media duration property
@@ -149,7 +149,7 @@ module TestCentricity
149
149
  def duration
150
150
  obj, = find_element(visible = :all)
151
151
  object_not_found_exception(obj, @type)
152
- obj.native.attribute('duration').to_f
152
+ obj.native.attribute('duration').to_f.round(2)
153
153
  end
154
154
 
155
155
  # Return media playbackRate property
@@ -161,7 +161,7 @@ module TestCentricity
161
161
  def playback_rate
162
162
  obj, = find_element(visible = :all)
163
163
  object_not_found_exception(obj, @type)
164
- obj.native.attribute('playbackRate')
164
+ obj.native.attribute('playbackRate').to_f
165
165
  end
166
166
 
167
167
  # Return media readyState property
@@ -195,7 +195,7 @@ module TestCentricity
195
195
  wait.until { ready_state == value }
196
196
  rescue StandardError
197
197
  if post_exception
198
- raise "Ready state of Audio #{object_ref_message} failed to equal '#{value}' after #{timeout} seconds" unless get_value == value
198
+ raise "Ready state of media #{object_ref_message} failed to equal '#{value}' after #{timeout} seconds" unless get_value == value
199
199
  else
200
200
  ready_state == value
201
201
  end
@@ -247,16 +247,50 @@ module TestCentricity
247
247
  page.execute_script('arguments[0].pause()', obj)
248
248
  end
249
249
 
250
- # Return media crossorigin property
250
+ # Mute the media's audio
251
251
  #
252
- # @return crossorigin value
253
252
  # @example
254
- # with_creds = media_player.crossorigin == 'use-credentials'
253
+ # media_player.mute
255
254
  #
256
- def crossorigin
257
- obj, = find_element
255
+ def mute
256
+ obj, = find_element(visible = :all)
257
+ object_not_found_exception(obj, @type)
258
+ page.execute_script('arguments[0].muted = true;', obj)
259
+ end
260
+
261
+ # Unmute the media's audio
262
+ #
263
+ # @example
264
+ # media_player.unmute
265
+ #
266
+ def unmute
267
+ obj, = find_element(visible = :all)
268
+ object_not_found_exception(obj, @type)
269
+ page.execute_script('arguments[0].muted = false;', obj)
270
+ end
271
+
272
+ # Set the media playbackRate property
273
+ #
274
+ # @param value [Float]
275
+ # @example
276
+ # media_player.playback_rate = 1.5
277
+ #
278
+ def playback_rate=(value)
279
+ obj, = find_element(visible = :all)
280
+ object_not_found_exception(obj, @type)
281
+ page.execute_script('arguments[0].playbackRate = arguments[1]', obj, value)
282
+ end
283
+
284
+ # Set the media volume property
285
+ #
286
+ # @param value [Float] between 0 and 1
287
+ # @example
288
+ # media_player.volume = 0.5
289
+ #
290
+ def volume=(value)
291
+ obj, = find_element(visible = :all)
258
292
  object_not_found_exception(obj, @type)
259
- obj.native.attribute('crossorigin')
293
+ page.execute_script('arguments[0].volume = arguments[1]', obj, value)
260
294
  end
261
295
 
262
296
  # Return media preload property
@@ -101,7 +101,11 @@ module TestCentricity
101
101
  object_not_found_exception(obj, 'Radio')
102
102
  invalid_object_type_exception(obj, 'radio')
103
103
  if @proxy.nil?
104
- obj.set(state)
104
+ begin
105
+ obj.set(state)
106
+ rescue
107
+ obj.click unless state == obj.checked?
108
+ end
105
109
  else
106
110
  page.find(:css, @proxy).click unless state == obj.checked?
107
111
  end
@@ -246,15 +246,23 @@ module TestCentricity
246
246
  def get_selected_option
247
247
  @base_object, = find_element
248
248
  object_not_found_exception(@base_object, nil)
249
- trigger_list
249
+ trigger_list unless @options_list.nil?
250
250
  selection = if @base_object.first(:css, @list_item, minimum: 0, wait: 1, visible: :all)
251
251
  @base_object.first(:css, @selected_item, wait: 1, visible: :all).text
252
252
  elsif @base_object.first(:css, @selected_item, minimum: 0, wait: 1, visible: :all)
253
253
  @base_object.first(:css, @selected_item, visible: :all).text
254
+ elsif @base_object.first('option[selected]', minimum: 0, wait: 1, visible: :all)
255
+ @base_object.first('option[selected]', wait: 1, visible: :all).text
254
256
  else
255
- @base_object.first('option[selected]', visible: :all).text
257
+ index = get_attribute(:selectedIndex).to_i
258
+ if index >= 0
259
+ options = get_options
260
+ options[index]
261
+ else
262
+ ''
263
+ end
256
264
  end
257
- trigger_list
265
+ trigger_list unless @options_list.nil?
258
266
  selection
259
267
  end
260
268
 
@@ -168,7 +168,7 @@ module TestCentricity
168
168
  def scroll_to(position)
169
169
  obj, type = find_element
170
170
  object_not_found_exception(obj, type)
171
- obj.scroll_to(position)
171
+ page.scroll_to(obj, align: position)
172
172
  end
173
173
 
174
174
  def set(value)
@@ -264,6 +264,19 @@ module TestCentricity
264
264
  obj.disabled?
265
265
  end
266
266
 
267
+ # Is UI object's required attribute set?
268
+ #
269
+ # @return [Boolean]
270
+ # @example
271
+ # first_name_field.required?
272
+ #
273
+ def required?
274
+ obj, type = find_element
275
+ object_not_found_exception(obj, type)
276
+ state = get_attribute(:required)
277
+ state.boolean? ? state : state == 'true'
278
+ end
279
+
267
280
  # Is UI object obscured (not currently in viewport and not clickable)?
268
281
  #
269
282
  # @return [Boolean]
@@ -508,12 +521,13 @@ module TestCentricity
508
521
  def get_value(visible = true)
509
522
  obj, type = find_element(visible)
510
523
  object_not_found_exception(obj, type)
511
- case obj.tag_name.downcase
512
- when 'input', 'select', 'textarea'
513
- obj.value
514
- else
515
- obj.text
516
- end
524
+ text = case obj.tag_name.downcase
525
+ when 'input', 'select', 'textarea'
526
+ obj.value
527
+ else
528
+ obj.text
529
+ end
530
+ text.gsub(/[[:space:]]+/, ' ').strip
517
531
  end
518
532
 
519
533
  alias get_caption get_value
@@ -985,6 +999,18 @@ module TestCentricity
985
999
  state.boolean? ? state : state == 'true'
986
1000
  end
987
1001
 
1002
+ # Return crossorigin property
1003
+ #
1004
+ # @return crossorigin value
1005
+ # @example
1006
+ # with_creds = media_player.crossorigin == 'use-credentials'
1007
+ #
1008
+ def crossorigin
1009
+ obj, = find_element
1010
+ object_not_found_exception(obj, @type)
1011
+ obj.native.attribute('crossorigin')
1012
+ end
1013
+
988
1014
  def get_attribute(attrib)
989
1015
  obj, type = find_element(visible = false)
990
1016
  object_not_found_exception(obj, type)
@@ -14,7 +14,7 @@ module TestCentricity
14
14
  def video_height
15
15
  obj, = find_element
16
16
  object_not_found_exception(obj, :video)
17
- obj.native.attribute('videoHeight')
17
+ obj.native.attribute('videoHeight').to_i
18
18
  end
19
19
 
20
20
  # Return video Width property
@@ -26,7 +26,7 @@ module TestCentricity
26
26
  def video_width
27
27
  obj, = find_element
28
28
  object_not_found_exception(obj, :video)
29
- obj.native.attribute('videoWidth')
29
+ obj.native.attribute('videoWidth').to_i
30
30
  end
31
31
 
32
32
  # Return video poster property
data/reports/.keep ADDED
@@ -0,0 +1 @@
1
+ Placeholder file to allow the reports folder to be saved to repository. This folder is required for Jenkins test jobs using the Cucumber Reporting plug-in.