testcentricity_web 4.1.5 → 4.1.8

Sign up to get free protection for your applications and to get access to all the features.
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.