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
@@ -0,0 +1,208 @@
1
+ # Page Object class definition for Media Test page with CSS locators
2
+
3
+ class MediaTestPage < BaseTestPage
4
+ trait(:page_name) { 'Media Test' }
5
+ trait(:page_locator) { 'div.media-page-body' }
6
+ trait(:page_url) { '/media_page.html' }
7
+ trait(:navigator) { header_nav.open_media_page }
8
+ trait(:page_title) { 'Media Page'}
9
+
10
+ # Media Test page UI elements
11
+ videos video_player_1: 'video#video_player1'
12
+ audios audio_player: 'audio#audio_player'
13
+
14
+ def verify_page_ui
15
+ super
16
+
17
+ preload = case
18
+ when Environ.browser == :safari
19
+ 'auto'
20
+ when Environ.device_os == :ios && Environ.driver != :webdriver
21
+ 'auto'
22
+ when %i[firefox firefox_headless].include?(Environ.browser)
23
+ ''
24
+ else
25
+ 'metadata'
26
+ end
27
+ video_player_1.wait_until_ready_state_is(4, 10)
28
+ audio_player.wait_until_ready_state_is(4, 10)
29
+ ui = {
30
+ video_player_1 => {
31
+ visible: true,
32
+ paused: true,
33
+ autoplay: false,
34
+ loop: false,
35
+ ended: false,
36
+ controls: true,
37
+ current_time: 0,
38
+ ready_state: 4,
39
+ default_playback_rate: 1,
40
+ playback_rate: 1,
41
+ seeking: false,
42
+ default_muted: false,
43
+ muted: false,
44
+ volume: 1,
45
+ preload: preload,
46
+ poster: '',
47
+ src: '',
48
+ duration: 17.6
49
+ },
50
+ audio_player => {
51
+ visible: true,
52
+ paused: true,
53
+ autoplay: false,
54
+ loop: false,
55
+ ended: false,
56
+ controls: true,
57
+ current_time: 0,
58
+ ready_state: 4,
59
+ default_playback_rate: 1,
60
+ playback_rate: 1,
61
+ seeking: false,
62
+ default_muted: false,
63
+ muted: false,
64
+ volume: 1,
65
+ preload: preload,
66
+ src: '',
67
+ duration: 3.45
68
+ }
69
+ }
70
+ verify_ui_states(ui)
71
+ unless Environ.browser == :safari
72
+ ui = { video_player_1 => {
73
+ width: video_player_1.video_width,
74
+ height: video_player_1.video_height
75
+ }
76
+ }
77
+ verify_ui_states(ui)
78
+ end
79
+ end
80
+
81
+ def perform_action(media_type, action)
82
+ player = dispatch_player(media_type)
83
+ case action.downcase.to_sym
84
+ when :play
85
+ player.play
86
+ player.send_keys(:enter) if player.paused?
87
+ player.click_at(25, 25) if player.paused?
88
+ when :pause
89
+ player.pause
90
+ when :mute
91
+ player.mute
92
+ when :unmute
93
+ player.unmute
94
+ else
95
+ raise "#{action} is not a valid selector"
96
+ end
97
+ sleep(2)
98
+ end
99
+
100
+ def verify_media_state(media_type, state)
101
+ player = dispatch_player(media_type)
102
+ duration = player.duration
103
+ props = case state.downcase.to_sym
104
+ when :playing
105
+ {
106
+ visible: true,
107
+ paused: false,
108
+ ended: false,
109
+ current_time: { greater_than: 0 },
110
+ seeking: false
111
+ }
112
+ when :paused
113
+ {
114
+ visible: true,
115
+ paused: true,
116
+ ended: false,
117
+ current_time: { greater_than: 0 },
118
+ seeking: false
119
+ }
120
+ when :ended
121
+ {
122
+ visible: true,
123
+ paused: true,
124
+ ended: true,
125
+ current_time: duration,
126
+ seeking: false
127
+ }
128
+ when :muted
129
+ {
130
+ visible: true,
131
+ muted: true
132
+ }
133
+ when :unmuted
134
+ {
135
+ visible: true,
136
+ muted: false
137
+ }
138
+ else
139
+ raise "#{state} is not a valid selector"
140
+ end
141
+ verify_ui_states(player => props)
142
+ end
143
+
144
+ def set_playback_rate(media_type, rate)
145
+ player = dispatch_player(media_type)
146
+ player.playback_rate = rate.to_f
147
+ reset_play(player)
148
+ end
149
+
150
+ def verify_playback_rate(media_type, rate)
151
+ player = dispatch_player(media_type)
152
+ ui = {
153
+ player => {
154
+ playback_rate: rate.to_f,
155
+ visible: true,
156
+ paused: false,
157
+ current_time: { greater_than: 0 },
158
+ seeking: false
159
+ }
160
+ }
161
+ verify_ui_states(ui)
162
+ end
163
+
164
+ def set_volume(media_type, volume)
165
+ player = dispatch_player(media_type)
166
+ player.volume = volume.to_f
167
+ reset_play(player)
168
+ end
169
+
170
+ def verify_volume(media_type, volume)
171
+ player = dispatch_player(media_type)
172
+ ui = {
173
+ player => {
174
+ volume: volume.to_f,
175
+ visible: true,
176
+ muted: false,
177
+ paused: false,
178
+ current_time: { greater_than: 0 },
179
+ seeking: false
180
+ }
181
+ }
182
+ verify_ui_states(ui)
183
+ end
184
+
185
+ private
186
+
187
+ def dispatch_player(media_type)
188
+ player = case media_type.downcase.to_sym
189
+ when :video
190
+ video_player_1
191
+ when :audio
192
+ audio_player
193
+ else
194
+ raise "#{media_type} is not a valid selector"
195
+ end
196
+ player.wait_until_ready_state_is(4, 10)
197
+ player
198
+ end
199
+
200
+ def reset_play(player)
201
+ player.pause
202
+ player.current_time = 0
203
+ player.play
204
+ player.send_keys(:enter) if player.paused?
205
+ player.click_at(25, 25) if player.paused?
206
+ sleep(1)
207
+ end
208
+ end
@@ -0,0 +1,39 @@
1
+ # Section Object class definition for Top Navigation Bar
2
+
3
+ class NavHeader < TestCentricity::PageSection
4
+ trait(:section_locator) { 'div#nav_bar' }
5
+ trait(:section_name) { 'Top Navigation Bar' }
6
+
7
+ # Top Navigation Bar UI elements
8
+ links form_link: 'a#form_link',
9
+ media_link: 'a#media_link',
10
+ indexed_sections_link: 'a#indexed_sections_link',
11
+ custom_controls_link: 'a#custom_controls_link'
12
+
13
+ def open_form_page
14
+ form_link.click
15
+ end
16
+
17
+ def open_media_page
18
+ media_link.click
19
+ end
20
+
21
+ def open_indexed_sections_page
22
+ indexed_sections_link.click
23
+ end
24
+
25
+ def open_custom_controls_page
26
+ custom_controls_link.click
27
+ end
28
+
29
+ def verify_nav_bar
30
+ ui = {
31
+ self => { exists: true, visible: true, class: 'topnav' },
32
+ form_link => { visible: true, caption: 'Basic HTML Form' },
33
+ media_link => { visible: true, caption: 'Media' },
34
+ indexed_sections_link => { visible: true, caption: 'Indexed Sections' },
35
+ custom_controls_link => { visible: true, caption: 'Custom Controls' },
36
+ }
37
+ verify_ui_states(ui)
38
+ end
39
+ end
@@ -0,0 +1,12 @@
1
+ module WorldData
2
+ #
3
+ # data_objects method returns a hash table of your web app's data objects and associated data object classes to be instantiated
4
+ # by the TestCentricity™ DataManager. Data Object class definitions are contained in the features/support/data folder.
5
+ #
6
+ def data_objects
7
+ { form_data_source: FormDataSource }
8
+ end
9
+ end
10
+
11
+
12
+ World(WorldData)
@@ -0,0 +1,18 @@
1
+ module WorldPages
2
+ #
3
+ # page_objects method returns a hash table of your web app's page objects and associated page classes to be instantiated
4
+ # by the TestCentricity™ PageManager. Page Object class definitions are contained in the features/support/pages folder.
5
+ #
6
+ def page_objects
7
+ {
8
+ basic_css_form_page: BasicCSSFormPage,
9
+ basic_xpath_form_page: BasicXpathFormPage,
10
+ media_test_page: MediaTestPage,
11
+ indexed_sections_page: IndexedSectionsPage,
12
+ custom_controls_page: CustomControlsPage
13
+ }
14
+ end
15
+ end
16
+
17
+
18
+ World(WorldPages)
@@ -18,10 +18,12 @@ module TestCentricity
18
18
  def start
19
19
  # terminate any currently running Appium Server
20
20
  if running?
21
+ # :nocov:
21
22
  system('killall -9 node')
22
23
  puts 'Terminating existing Appium Server'
23
24
  sleep(5)
24
25
  puts 'Appium Server is being restarted'
26
+ # :nocov:
25
27
  else
26
28
  puts 'Appium Server is starting'
27
29
  end
@@ -56,6 +58,7 @@ module TestCentricity
56
58
 
57
59
  private
58
60
 
61
+ # :nocov:
59
62
  def parameters
60
63
  cmd = ['appium']
61
64
  @params.each do |key, value|
@@ -64,5 +67,7 @@ module TestCentricity
64
67
  end
65
68
  cmd
66
69
  end
70
+ # :nocov:
67
71
  end
68
72
  end
73
+
@@ -52,6 +52,7 @@ module TestCentricity
52
52
  @current = current
53
53
  end
54
54
 
55
+ # :nocov:
55
56
  def to_hash(node_name = nil)
56
57
  data = {}
57
58
  if node_name.nil?
@@ -79,9 +80,12 @@ module TestCentricity
79
80
  def write_json_data(file_name, mode, node_name = nil)
80
81
  File.open(file_name, mode) { |file| file.write(to_json(node_name)) }
81
82
  end
83
+
84
+ # :nocov:
82
85
  end
83
86
 
84
87
 
88
+ # :nocov:
85
89
  class DataSource
86
90
  attr_accessor :file_path
87
91
  attr_accessor :node
@@ -135,6 +139,7 @@ module TestCentricity
135
139
  result.to_s
136
140
  end
137
141
  end
142
+ # :nocov:
138
143
 
139
144
 
140
145
  class ExcelDataSource < TestCentricity::DataSource
@@ -159,6 +164,7 @@ module TestCentricity
159
164
  ExcelData.read_row_data(pick_excel_data_source(sheet, @row_spec), sheet, @row_spec)
160
165
  end
161
166
 
167
+ # :nocov:
162
168
  def read_excel_pool_data(sheet, row_name, parallel = false)
163
169
  @row_spec = parallel == :parallel && ENV['PARALLEL'] ? "#{row_name}#{ENV['TEST_ENV_NUMBER']}" : row_name
164
170
  ExcelData.read_row_from_pool(pick_excel_data_source(sheet, row_name), sheet, @row_spec)
@@ -173,6 +179,7 @@ module TestCentricity
173
179
  @row_spec = parallel == :parallel && ENV['PARALLEL'] ? "#{row_name}#{ENV['TEST_ENV_NUMBER']}" : row_name
174
180
  ExcelData.write_row_data(pick_excel_data_source(sheet, @row_spec), sheet, @row_spec, row_data)
175
181
  end
182
+ # :nocov:
176
183
  end
177
184
  end
178
185
 
@@ -71,6 +71,7 @@ module TestCentricity
71
71
  @screen_shots = []
72
72
 
73
73
  attr_accessor :test_environment
74
+ attr_accessor :app_host
74
75
  attr_accessor :browser
75
76
  attr_accessor :browser_size
76
77
  attr_accessor :headless
@@ -133,9 +134,20 @@ module TestCentricity
133
134
  @db_username = data['DB_USERNAME']
134
135
  @db_password = data['DB_PASSWORD']
135
136
 
137
+ url = @hostname.blank? ? "#{@base_url}#{@append}" : "#{@hostname}/#{@base_url}#{@append}"
138
+ @app_host = if @user_id.blank? || @password.blank?
139
+ "#{@protocol}://#{url}"
140
+ else
141
+ "#{@protocol}://#{@user_id}:#{@password}@#{url}"
142
+ end
143
+
136
144
  super
137
145
  end
138
146
 
147
+ def self.app_host
148
+ @app_host
149
+ end
150
+
139
151
  def self.session_code
140
152
  if @session_code.nil?
141
153
  characters = ('a'..'z').to_a
@@ -328,6 +340,10 @@ module TestCentricity
328
340
  @platform = platform
329
341
  end
330
342
 
343
+ def self.platform
344
+ @platform
345
+ end
346
+
331
347
  def self.is_mobile?
332
348
  @platform == :mobile
333
349
  end
@@ -380,6 +396,7 @@ module TestCentricity
380
396
  @screen_shots = []
381
397
  end
382
398
 
399
+ # :nocov:
383
400
  def self.report_header
384
401
  report_header = "\n<b><u>TEST ENVIRONMENT</u>:</b> #{ENV['TEST_ENVIRONMENT']}\n"\
385
402
  " <b>Browser:</b>\t #{Environ.browser.capitalize}\n"
@@ -395,6 +412,7 @@ module TestCentricity
395
412
  report_header = "#{report_header} <b>WCAG Accessibility Standard:</b>\t #{ENV['ACCESSIBILITY_STANDARD']}\n" if ENV['ACCESSIBILITY_STANDARD']
396
413
  "#{report_header}\n\n"
397
414
  end
415
+ # :nocov:
398
416
  end
399
417
  end
400
418
 
@@ -52,6 +52,65 @@ module TestCentricity
52
52
  exists
53
53
  end
54
54
 
55
+ def self.read_row_data(file, sheet, row_spec, columns = nil)
56
+ raise "File #{file} does not exists" unless File.exist?(file)
57
+ work_book = Spreadsheet.open(file)
58
+ work_sheet = work_book.worksheet(sheet)
59
+ # get column headings from row 0 of worksheet
60
+ headings = work_sheet.row(0)
61
+ # if row_spec is a string then we have to find a matching row name
62
+ if row_spec.is_a? String
63
+ column_number = 0
64
+ found = false
65
+ headings.each do |heading|
66
+ if heading == 'ROW_NAME'
67
+ found = true
68
+ break
69
+ end
70
+ column_number += 1
71
+ end
72
+ raise "Could not find a column named ROW_NAME in worksheet #{sheet}" unless found
73
+ # find first cell in ROW_NAME column containing a string that matches the row_spec parameter
74
+ found = false
75
+ row_number = 0
76
+ work_sheet.each do |row|
77
+ if row[column_number] == row_spec
78
+ found = true
79
+ break
80
+ end
81
+ row_number += 1
82
+ end
83
+ raise "Could not find a row named '#{row_spec}' in worksheet #{sheet}" unless found
84
+ data = work_sheet.row(row_number)
85
+ # if row_spec is a number then ensure that it doesn't exceed the number of available rows
86
+ elsif row_spec.is_a? Numeric
87
+ raise "Row # #{row_spec} is greater than number of rows in worksheet #{sheet}" if row_spec > work_sheet.last_row_index
88
+ data = work_sheet.row(row_spec)
89
+ end
90
+
91
+ # if no columns have been specified, return all columns
92
+ columns = headings if columns.nil?
93
+ # create results hash table
94
+ result = Hash.new
95
+ columns.each do |column|
96
+ column_number = 0
97
+ found = false
98
+ headings.each do |heading|
99
+ if column == heading
100
+ value = data[column_number].to_s
101
+ value = calculate_dynamic_value(value) if value.start_with? 'eval!'
102
+ result[column] = value
103
+ found = true
104
+ break
105
+ end
106
+ column_number += 1
107
+ end
108
+ raise "Could not find a column named '#{column}' in worksheet #{sheet}" unless found
109
+ end
110
+ result
111
+ end
112
+
113
+ # :nocov:
55
114
  def self.read_row_from_pool(file, sheet, row_spec, columns = nil)
56
115
  raise "File #{file} does not exists" unless File.exist?(file)
57
116
  work_book = Spreadsheet.open(file)
@@ -118,64 +177,6 @@ module TestCentricity
118
177
  read_row_data(file, sheet, new_row, columns)
119
178
  end
120
179
 
121
- def self.read_row_data(file, sheet, row_spec, columns = nil)
122
- raise "File #{file} does not exists" unless File.exist?(file)
123
- work_book = Spreadsheet.open(file)
124
- work_sheet = work_book.worksheet(sheet)
125
- # get column headings from row 0 of worksheet
126
- headings = work_sheet.row(0)
127
- # if row_spec is a string then we have to find a matching row name
128
- if row_spec.is_a? String
129
- column_number = 0
130
- found = false
131
- headings.each do |heading|
132
- if heading == 'ROW_NAME'
133
- found = true
134
- break
135
- end
136
- column_number += 1
137
- end
138
- raise "Could not find a column named ROW_NAME in worksheet #{sheet}" unless found
139
- # find first cell in ROW_NAME column containing a string that matches the row_spec parameter
140
- found = false
141
- row_number = 0
142
- work_sheet.each do |row|
143
- if row[column_number] == row_spec
144
- found = true
145
- break
146
- end
147
- row_number += 1
148
- end
149
- raise "Could not find a row named '#{row_spec}' in worksheet #{sheet}" unless found
150
- data = work_sheet.row(row_number)
151
- # if row_spec is a number then ensure that it doesn't exceed the number of available rows
152
- elsif row_spec.is_a? Numeric
153
- raise "Row # #{row_spec} is greater than number of rows in worksheet #{sheet}" if row_spec > work_sheet.last_row_index
154
- data = work_sheet.row(row_spec)
155
- end
156
-
157
- # if no columns have been specified, return all columns
158
- columns = headings if columns.nil?
159
- # create results hash table
160
- result = Hash.new
161
- columns.each do |column|
162
- column_number = 0
163
- found = false
164
- headings.each do |heading|
165
- if column == heading
166
- value = data[column_number].to_s
167
- value = calculate_dynamic_value(value) if value.start_with? 'eval!'
168
- result[column] = value
169
- found = true
170
- break
171
- end
172
- column_number += 1
173
- end
174
- raise "Could not find a column named '#{column}' in worksheet #{sheet}" unless found
175
- end
176
- result
177
- end
178
-
179
180
  def self.read_range_data(file, sheet, range_spec)
180
181
  raise "File #{file} does not exists" unless File.exist?(file)
181
182
  work_book = Spreadsheet.open(file)
@@ -270,6 +271,6 @@ module TestCentricity
270
271
  # rename new Excel document, replacing the original
271
272
  File.rename(outfile, file)
272
273
  end
274
+ # :nocov:
273
275
  end
274
276
  end
275
-
@@ -1,3 +1,3 @@
1
1
  module TestCentricityWeb
2
- VERSION = '4.1.5'
2
+ VERSION = '4.1.8'
3
3
  end
@@ -1,3 +1,5 @@
1
+ # :nocov:
2
+
1
3
  module CapybaraExtension
2
4
  def drag_by(right_by, down_by)
3
5
  base.drag_by(right_by, down_by)
@@ -11,5 +13,7 @@ module CapybaraSeleniumExtension
11
13
  end
12
14
  end
13
15
 
16
+ # :nocov:
17
+
14
18
  ::Capybara::Selenium::Node.send :include, CapybaraSeleniumExtension
15
19
  ::Capybara::Node::Element.send :include, CapybaraExtension
@@ -1,5 +1,9 @@
1
1
  module TestCentricity
2
2
  class PageObject < BasePageSectionObject
3
+ def initialize
4
+ set_locator_type(page_locator) if defined?(page_locator)
5
+ end
6
+
3
7
  # Declare and instantiate a single generic UI Element for this page object.
4
8
  #
5
9
  # @param element_name [Symbol] name of UI object (as a symbol)
@@ -308,19 +312,15 @@ module TestCentricity
308
312
  end
309
313
 
310
314
  def open_portal
311
- environment = Environ.current
312
- url = environment.hostname.blank? ? "#{environment.base_url}#{environment.append}" : "#{environment.hostname}/#{environment.base_url}#{environment.append}"
313
- if environment.user_id.blank? || environment.password.blank?
314
- visit "#{environment.protocol}://#{url}"
315
- else
316
- visit "#{environment.protocol}://#{environment.user_id}:#{environment.password}@#{url}"
317
- end
315
+ visit Environ.current.app_host
318
316
  Environ.portal_state = :open
319
317
  end
320
318
 
321
319
  def verify_page_exists
322
320
  raise "Page object #{self.class.name} does not have a page_locator trait defined" unless defined?(page_locator)
323
- unless page.has_selector?(page_locator)
321
+
322
+ set_locator_type(page_locator) if @locator_type.blank?
323
+ unless page.has_selector?(@locator_type, page_locator)
324
324
  body_class = find(:xpath, '//body')[:class]
325
325
  error_message = %(
326
326
  Expected page to have selector '#{page_locator}' but found '#{body_class}' instead.
@@ -6,6 +6,26 @@ module TestCentricity
6
6
  include Capybara::Node::Matchers
7
7
  include Test::Unit::Assertions
8
8
 
9
+ attr_accessor :locator_type
10
+
11
+ XPATH_SELECTORS = ['//', '[@', '[contains(']
12
+ CSS_SELECTORS = ['#', ':nth-child(', ':first-child', ':last-child', ':nth-of-type(', ':first-of-type', ':last-of-type', '^=', '$=', '*=', ':contains(']
13
+
14
+ def set_locator_type(locator = nil)
15
+ locator = @locator if locator.nil?
16
+ is_xpath = XPATH_SELECTORS.any? { |selector| locator.include?(selector) }
17
+ is_css = CSS_SELECTORS.any? { |selector| locator.include?(selector) }
18
+ @locator_type = if is_xpath && !is_css
19
+ :xpath
20
+ elsif is_css && !is_xpath
21
+ :css
22
+ elsif !is_css && !is_xpath
23
+ :css
24
+ else
25
+ :css
26
+ end
27
+ end
28
+
9
29
  # Define a trait for this page or section object.
10
30
  #
11
31
  # @param trait_name [Symbol] name of trait (as a symbol)
@@ -31,6 +51,8 @@ module TestCentricity
31
51
  ui_object.get_attribute(:name)
32
52
  when :title
33
53
  ui_object.title
54
+ when :secure
55
+ ui_object.secure?
34
56
  when :exists
35
57
  ui_object.exists?
36
58
  when :enabled
@@ -43,6 +65,8 @@ module TestCentricity
43
65
  ui_object.hidden?
44
66
  when :displayed
45
67
  ui_object.displayed?
68
+ when :obscured
69
+ ui_object.obscured?
46
70
  when :focused
47
71
  ui_object.focused?
48
72
  when :width
@@ -63,6 +87,8 @@ module TestCentricity
63
87
  ui_object.indeterminate?
64
88
  when :value, :caption
65
89
  ui_object.get_value
90
+ when :required
91
+ ui_object.required?
66
92
  when :maxlength
67
93
  ui_object.get_max_length
68
94
  when :rowcount
@@ -241,8 +267,11 @@ module TestCentricity
241
267
  end
242
268
 
243
269
  # Populate the specified UI elements on this page or section object with the associated data from a Hash passed as an
244
- # argument. Data values must be in the form of a String for textfield and selectlist controls. For checkbox and radio
245
- # buttons, data must either be a Boolean or a String that evaluates to a Boolean value (Yes, No, 1, 0, true, false).
270
+ # argument. Data values must be in the form of a String for textfield, selectlist, and filefield controls. For checkbox
271
+ # and radio buttons, data must either be a Boolean or a String that evaluates to a Boolean value (Yes, No, 1, 0, true,
272
+ # false). For range controls, data must be an Integer. For input(type='color') color picker controls, which are specified
273
+ # as a textfield, data must be in the form of a hex color String. For section objects, data values must be a String, and
274
+ # the section object must have a set method defined.
246
275
  #
247
276
  # The optional wait_time parameter is used to specify the time (in seconds) to wait for each UI element to become
248
277
  # visible before entering the associated data value. This option is useful in situations where entering data, or
@@ -285,14 +314,20 @@ module TestCentricity
285
314
  check_state = data_param.is_a?(String) ? data_param.to_bool : data_param
286
315
  data_field.set_selected_state(check_state)
287
316
  when :textfield
288
- data_field.set("#{data_param}\t")
289
- if integrity_check && data_field.get_value != data_param
290
- data_field.set('')
291
- data_field.send_keys(data_param)
292
- data_field.send_keys(:tab)
317
+ if %w[color number].include?(data_field.get_attribute(:type))
318
+ data_field.set(data_param)
319
+ else
320
+ data_field.set("#{data_param}\t")
321
+ if integrity_check && data_field.get_value != data_param
322
+ data_field.set('')
323
+ data_field.send_keys(data_param)
324
+ data_field.send_keys(:tab)
325
+ end
293
326
  end
294
- when :section
327
+ when :section, :range
295
328
  data_field.set(data_param)
329
+ when :filefield
330
+ data_field.file_upload(data_param)
296
331
  end
297
332
  end
298
333
  end