testcentricity_web 4.1.3 → 4.1.6

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