testcentricity_web 4.1.3 → 4.1.6

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +18 -0
  3. data/.simplecov +5 -0
  4. data/CHANGELOG.md +30 -1
  5. data/Gemfile.lock +170 -0
  6. data/README.md +287 -102
  7. data/Rakefile +37 -1
  8. data/config/cucumber.yml +150 -0
  9. data/docker-compose-v3.yml +48 -0
  10. data/features/basic_test_page_css.feature +24 -0
  11. data/features/basic_test_page_xpath.feature +24 -0
  12. data/features/step_definitions/generic_steps.rb.rb +37 -0
  13. data/features/support/env.rb +43 -0
  14. data/features/support/hooks.rb +245 -0
  15. data/features/support/pages/basic_css_test_page.rb +49 -0
  16. data/features/support/pages/basic_test_page.rb +238 -0
  17. data/features/support/pages/basic_xpath_test_page.rb +49 -0
  18. data/features/support/pages/media_page.rb +11 -0
  19. data/features/support/world_pages.rb +15 -0
  20. data/lib/testcentricity_web/data_objects/environment.rb +4 -0
  21. data/lib/testcentricity_web/version.rb +1 -1
  22. data/lib/testcentricity_web/web_core/page_object.rb +13 -6
  23. data/lib/testcentricity_web/web_core/page_objects_helper.rb +41 -8
  24. data/lib/testcentricity_web/web_core/page_section.rb +1 -16
  25. data/lib/testcentricity_web/web_core/webdriver_helper.rb +78 -120
  26. data/lib/testcentricity_web/web_elements/select_list.rb +18 -7
  27. data/lib/testcentricity_web/web_elements/ui_elements_helper.rb +13 -0
  28. data/reports/.keep +1 -0
  29. data/test_site/basic_test_page.html +240 -0
  30. data/test_site/images/Granny.jpg +0 -0
  31. data/test_site/images/Wilder.jpg +0 -0
  32. data/test_site/images/You_Betcha.jpg +0 -0
  33. data/test_site/media/MP4_small.mp4 +0 -0
  34. data/test_site/media/MPS_sample.mp3 +0 -0
  35. data/test_site/media_page.html +33 -0
  36. data/testcentricity_web.gemspec +5 -0
  37. metadata +105 -4
  38. data/test_site/test_page.html +0 -11
@@ -0,0 +1,238 @@
1
+ # Page Object class definition for Basic HTML Test page
2
+
3
+ class BasicTestPage < TestCentricity::PageObject
4
+ trait(:page_url) { '/basic_test_page.html' }
5
+ trait(:tab_order) {
6
+ [
7
+ username_field,
8
+ password_field,
9
+ max_length_field,
10
+ read_only_field,
11
+ number_field,
12
+ color_picker,
13
+ slider,
14
+ comments_field,
15
+ upload_file,
16
+ check_1,
17
+ check_2,
18
+ check_3,
19
+ radio_1,
20
+ [
21
+ radio_2,
22
+ radio_3
23
+ ],
24
+ multi_select,
25
+ drop_down_select,
26
+ cancel_button,
27
+ submit_button
28
+ ]
29
+ }
30
+ trait(:safari_tab_order) {
31
+ [
32
+ username_field,
33
+ password_field,
34
+ max_length_field,
35
+ read_only_field,
36
+ number_field,
37
+ comments_field,
38
+ multi_select,
39
+ drop_down_select
40
+ ]
41
+ }
42
+
43
+ def verify_page_ui
44
+ ui = {
45
+ self => { exists: true, secure: false, title: 'Basic HTML Form' },
46
+ header_label => { visible: true, caption: 'Basic HTML Form Example' },
47
+ username_label => { visible: true, caption: 'Username:' },
48
+ username_field => { visible: true, enabled: true, required: true, value: '', placeholder: 'User name' },
49
+ password_label => { visible: true, caption: 'Password:' },
50
+ password_field => { visible: true, enabled: true, required: true, value: '', placeholder: 'Password' },
51
+ max_length_label => { visible: true, caption: 'Max Length:' },
52
+ max_length_field => {
53
+ visible: true,
54
+ enabled: true,
55
+ placeholder: 'up to 64 characters',
56
+ value: '',
57
+ maxlength: 64
58
+ },
59
+ read_only_label => { visible: true, caption: 'Read Only:' },
60
+ read_only_field => {
61
+ visible: true,
62
+ enabled: true,
63
+ readonly: true,
64
+ value: 'I am a read only text field'
65
+ },
66
+ number_label => { visible: true, caption: 'Number:' },
67
+ number_field => {
68
+ visible: true,
69
+ enabled: true,
70
+ value: '41',
71
+ min: 10,
72
+ max: 1024,
73
+ step: 1
74
+ },
75
+ color_label => { visible: true, caption: 'Color:' },
76
+ color_picker => { visible: true, enabled: true, value: '#000000' },
77
+ slider_label => { visible: true, caption: 'Range:' },
78
+ slider => {
79
+ visible: true,
80
+ enabled: true,
81
+ value: 25,
82
+ min: 0,
83
+ max: 50,
84
+ },
85
+ comments_label => { visible: true, caption: 'TextArea:' },
86
+ comments_field => { visible: true, enabled: true, value: '' },
87
+ filename_label => { visible: true, caption: 'Filename:' },
88
+ upload_file => { visible: true, enabled: true, value: '' },
89
+ checkboxes_label => { visible: true, caption: 'Checkbox Items:' },
90
+ check_1 => { visible: true, enabled: true, checked: false },
91
+ check_2 => { visible: true, enabled: true, checked: false },
92
+ check_3 => { visible: true, enabled: true, checked: false },
93
+ check_4 => { visible: true, enabled: false, checked: false },
94
+ radios_label => { visible: true, caption: 'Radio Items:' },
95
+ radio_1 => { visible: true, enabled: true, selected: false },
96
+ radio_2 => { visible: true, enabled: true, selected: false },
97
+ radio_3 => { visible: true, enabled: true, selected: false },
98
+ radio_4 => { visible: true, enabled: false, selected: false },
99
+ multiselect_label => { visible: true, caption: 'Multiple Select Values:' },
100
+ multi_select => {
101
+ visible: true,
102
+ enabled: true,
103
+ optioncount: 4,
104
+ options: ['Selection Item 1', 'Selection Item 2', 'Selection Item 3', 'Selection Item 4'],
105
+ selected: ''
106
+ },
107
+ dropdown_label => { visible: true, caption: 'Dropdown:' },
108
+ drop_down_select => {
109
+ visible: true,
110
+ enabled: true,
111
+ optioncount: 6,
112
+ options: ['Drop Down Item 1', 'Drop Down Item 2', 'Drop Down Item 3', 'Drop Down Item 4', 'Drop Down Item 5', 'Drop Down Item 6'],
113
+ selected: 'Drop Down Item 1'
114
+ },
115
+ table_label => { visible: true, caption: 'Table:' },
116
+ static_table => {
117
+ visible: true,
118
+ columncount: 3,
119
+ rowcount: 4,
120
+ column_headers: %w[Company Contact Country],
121
+ { row: 1 } => [['Alfreds Futterkiste', 'Maria Anders', 'Germany']],
122
+ { row: 2 } => [['Centro comercial Moctezuma', 'Francisco Chang', 'Mexico']],
123
+ { row: 3 } => [['Ernst Handel', 'Roland Mendel', 'Austria']],
124
+ { row: 4 } => [['Island Trading', 'Helen Bennett', 'UK']]
125
+ },
126
+ images_label => { visible: true, caption: 'Images:' },
127
+ image_1 => {
128
+ visible: true,
129
+ broken: false,
130
+ src: { ends_with: 'images/Wilder.jpg' },
131
+ alt: "It's alive"
132
+ },
133
+ image_2 => {
134
+ visible: true,
135
+ broken: false,
136
+ src: { ends_with: 'images/You_Betcha.jpg' },
137
+ alt: 'You Betcha'
138
+ },
139
+ image_3 => {
140
+ visible: true,
141
+ broken: true,
142
+ src: { ends_with: 'wrongname.gif' },
143
+ alt: 'A broken image'
144
+ },
145
+ cancel_button => { visible: true, enabled: true, caption: 'Cancel' },
146
+ submit_button => { visible: true, enabled: true, caption: 'Submit' }
147
+ }
148
+ verify_ui_states(ui)
149
+ end
150
+
151
+ def form_data
152
+ file_path = Environ.platform == :mobile ? nil : "#{Dir.pwd}/test_site/images/Wilder.jpg"
153
+ {
154
+ username: Faker::Name.name,
155
+ password: 'T0p_Sekrit',
156
+ maxlength: Faker::Marketing.buzzwords,
157
+ number: Faker::Number.between(from: 10, to: 1024),
158
+ color: Faker::Color.hex_color,
159
+ slider: 45,
160
+ comments: Faker::Hipster.paragraph,
161
+ filepath: file_path,
162
+ filename: "Wilder.jpg",
163
+ check1: true,
164
+ check2: true,
165
+ check3: false,
166
+ radio1: true,
167
+ radio2: false,
168
+ radio3: false,
169
+ multi_select: 'Selection Item 2',
170
+ drop_select: 'Drop Down Item 5'
171
+ }
172
+ end
173
+
174
+ def populate_form
175
+ @data = form_data
176
+ fields = {
177
+ username_field => @data[:username],
178
+ password_field => @data[:password],
179
+ max_length_field => @data[:maxlength],
180
+ number_field => @data[:number],
181
+ color_picker => @data[:color],
182
+ slider => @data[:slider],
183
+ comments_field => @data[:comments],
184
+ upload_file => @data[:filepath],
185
+ check_1 => @data[:check1],
186
+ check_2 => @data[:check2],
187
+ check_3 => @data[:check3],
188
+ radio_1 => @data[:radio1],
189
+ radio_2 => @data[:radio2],
190
+ radio_3 => @data[:radio3],
191
+ multi_select => @data[:multi_select],
192
+ drop_down_select => @data[:drop_select]
193
+ }
194
+ populate_data_fields(fields)
195
+ end
196
+
197
+ def verify_form_data
198
+ ui = {
199
+ username_field => { value: @data[:username] },
200
+ password_field => { value: @data[:password] },
201
+ max_length_field => { value: @data[:maxlength] },
202
+ number_field => { value: @data[:number].to_s },
203
+ color_picker => { value: @data[:color] },
204
+ slider => { value: @data[:slider] },
205
+ comments_field => { value: @data[:comments] },
206
+ upload_file => { value: { ends_with: @data[:filename] } },
207
+ check_1 => { checked: @data[:check1] },
208
+ check_2 => { checked: @data[:check2] },
209
+ check_3 => { checked: @data[:check3] },
210
+ radio_1 => { selected: @data[:radio1] },
211
+ radio_2 => { selected: @data[:radio2] },
212
+ radio_3 => { selected: @data[:radio3] },
213
+ multi_select => { selected: @data[:multi_select] },
214
+ drop_down_select => { selected: @data[:drop_select] }
215
+ }
216
+ verify_ui_states(ui)
217
+ end
218
+
219
+ def perform_action(action)
220
+ case action
221
+ when :submit
222
+ submit_button.click
223
+ when :cancel
224
+ cancel_button.click
225
+ else
226
+ raise "#{action} is not a valid selector"
227
+ end
228
+ end
229
+
230
+ def verify_tab_order
231
+ order = if Environ.browser == :safari
232
+ safari_tab_order
233
+ else
234
+ tab_order
235
+ end
236
+ verify_focus_order(order)
237
+ end
238
+ end
@@ -0,0 +1,49 @@
1
+ # Page Object class definition for Basic HTML Test page with Xpath locators
2
+
3
+ class BasicXpathTestPage < BasicTestPage
4
+ trait(:page_name) { 'Basic Xpath Test' }
5
+ trait(:page_locator) { "//form[@id='HTMLFormElements']" }
6
+
7
+ # Basic HTML Test page UI elements
8
+ textfields username_field: "//input[@id='username']",
9
+ password_field: "//input[@id='password']",
10
+ max_length_field: "//input[@id='maxlength']",
11
+ read_only_field: "//input[@id='readonly']",
12
+ number_field: "//input[@id='number-field']",
13
+ comments_field: "//textarea[@id='comments']",
14
+ color_picker: "//input[@id='color-picker']"
15
+ range :slider, "//input[@id='slider']"
16
+ filefield :upload_file, "//input[@id='filename']"
17
+ checkboxes check_1: "//input[@id='check1']",
18
+ check_2: "//input[@id='check2']",
19
+ check_3: "//input[@id='check3']",
20
+ check_4: "//input[@id='check4']"
21
+ radios radio_1: "//input[@id='radio1']",
22
+ radio_2: "//input[@id='radio2']",
23
+ radio_3: "//input[@id='radio3']",
24
+ radio_4: "//input[@id='radio4']"
25
+ selectlists multi_select: "//select[@id='multipleselect']",
26
+ drop_down_select: "//select[@id='dropdown']"
27
+ table :static_table, "//table[@id='table']"
28
+ images image_1: "//img[@id='image1']",
29
+ image_2: "//img[@id='image2']",
30
+ image_3: "//img[@id='image3']"
31
+ buttons cancel_button: "//input[@id='cancel']",
32
+ submit_button: "//input[@id='submit']"
33
+ labels header_label: '//h1',
34
+ username_label: "//label[@for='username']",
35
+ password_label: "//label[@for='password']",
36
+ max_length_label: "//label[@for='maxlength']",
37
+ read_only_label: "//label[@for='readonly']",
38
+ number_label: "//label[@for='number-field']",
39
+ color_label: "//label[@for='color-picker']",
40
+ slider_label: "//label[@for='slider']",
41
+ comments_label: "//label[@for='comments']",
42
+ filename_label: "//label[@for='filename']",
43
+ checkboxes_label: "//label[@id='checkboxes']",
44
+ radios_label: "//label[@id='radios']",
45
+ multiselect_label: "//label[@for='multipleselect']",
46
+ dropdown_label: "//label[@for='dropdown']",
47
+ table_label: "//label[@for='table']",
48
+ images_label: "//label[@id='images']"
49
+ end
@@ -0,0 +1,11 @@
1
+ # Page Object class definition for Media Test page with CSS locators
2
+
3
+ class MediaTestPage < TestCentricity::PageObject
4
+ trait(:page_name) { 'Media Test' }
5
+ trait(:page_locator) { 'div.media-page-body' }
6
+ trait(:page_url) { '/media_page.html' }
7
+
8
+ # Media Test page UI elements
9
+ video :video_player, 'video#video_player'
10
+ audio :audio_player, 'audio#audio_player'
11
+ end
@@ -0,0 +1,15 @@
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_test_page: BasicCSSTestPage,
9
+ basic_xpath_test_page: BasicXpathTestPage,
10
+ }
11
+ end
12
+ end
13
+
14
+
15
+ World(WorldPages)
@@ -328,6 +328,10 @@ module TestCentricity
328
328
  @platform = platform
329
329
  end
330
330
 
331
+ def self.platform
332
+ @platform
333
+ end
334
+
331
335
  def self.is_mobile?
332
336
  @platform == :mobile
333
337
  end
@@ -1,3 +1,3 @@
1
1
  module TestCentricityWeb
2
- VERSION = '4.1.3'
2
+ VERSION = '4.1.6'
3
3
  end
@@ -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)
@@ -310,17 +314,20 @@ module TestCentricity
310
314
  def open_portal
311
315
  environment = Environ.current
312
316
  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
317
+ full_url = if environment.user_id.blank? || environment.password.blank?
318
+ "#{environment.protocol}://#{url}"
319
+ else
320
+ "#{environment.protocol}://#{environment.user_id}:#{environment.password}@#{url}"
321
+ end
322
+ visit full_url
318
323
  Environ.portal_state = :open
319
324
  end
320
325
 
321
326
  def verify_page_exists
322
327
  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)
328
+
329
+ set_locator_type(page_locator) if @locator_type.blank?
330
+ unless page.has_selector?(@locator_type, page_locator)
324
331
  body_class = find(:xpath, '//body')[:class]
325
332
  error_message = %(
326
333
  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
@@ -63,6 +85,8 @@ module TestCentricity
63
85
  ui_object.indeterminate?
64
86
  when :value, :caption
65
87
  ui_object.get_value
88
+ when :required
89
+ ui_object.required?
66
90
  when :maxlength
67
91
  ui_object.get_max_length
68
92
  when :rowcount
@@ -241,8 +265,11 @@ module TestCentricity
241
265
  end
242
266
 
243
267
  # 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).
268
+ # argument. Data values must be in the form of a String for textfield, selectlist, and filefield controls. For checkbox
269
+ # and radio buttons, data must either be a Boolean or a String that evaluates to a Boolean value (Yes, No, 1, 0, true,
270
+ # false). For range controls, data must be an Integer. For input(type='color') color picker controls, which are specified
271
+ # as a textfield, data must be in the form of a hex color String. For section objects, data values must be a String, and
272
+ # the section object must have a set method defined.
246
273
  #
247
274
  # The optional wait_time parameter is used to specify the time (in seconds) to wait for each UI element to become
248
275
  # visible before entering the associated data value. This option is useful in situations where entering data, or
@@ -285,14 +312,20 @@ module TestCentricity
285
312
  check_state = data_param.is_a?(String) ? data_param.to_bool : data_param
286
313
  data_field.set_selected_state(check_state)
287
314
  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)
315
+ if data_field.get_attribute(:type) == 'color'
316
+ data_field.set(data_param)
317
+ else
318
+ data_field.set("#{data_param}\t")
319
+ if integrity_check && data_field.get_value != data_param
320
+ data_field.set('')
321
+ data_field.send_keys(data_param)
322
+ data_field.send_keys(:tab)
323
+ end
293
324
  end
294
- when :section
325
+ when :section, :range
295
326
  data_field.set(data_param)
327
+ when :filefield
328
+ data_field.file_upload(data_param)
296
329
  end
297
330
  end
298
331
  end
@@ -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