centric_page_object 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +8 -0
  4. data/.rspec +2 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +17 -0
  8. data/ChangeLog +931 -0
  9. data/Gemfile +12 -0
  10. data/Guardfile +20 -0
  11. data/LICENSE +20 -0
  12. data/README.md +114 -0
  13. data/Rakefile +29 -0
  14. data/centric_page_object.gemspec +31 -0
  15. data/cucumber.yml +8 -0
  16. data/lib/page-object/accessors.rb +1201 -0
  17. data/lib/page-object/element_locators.rb +21 -0
  18. data/lib/page-object/elements/area.rb +9 -0
  19. data/lib/page-object/elements/audio.rb +9 -0
  20. data/lib/page-object/elements/bold.rb +9 -0
  21. data/lib/page-object/elements/button.rb +12 -0
  22. data/lib/page-object/elements/canvas.rb +10 -0
  23. data/lib/page-object/elements/check_box.rb +9 -0
  24. data/lib/page-object/elements/date_field.rb +10 -0
  25. data/lib/page-object/elements/div.rb +9 -0
  26. data/lib/page-object/elements/element.rb +212 -0
  27. data/lib/page-object/elements/file_field.rb +9 -0
  28. data/lib/page-object/elements/form.rb +9 -0
  29. data/lib/page-object/elements/heading.rb +14 -0
  30. data/lib/page-object/elements/hidden_field.rb +9 -0
  31. data/lib/page-object/elements/image.rb +10 -0
  32. data/lib/page-object/elements/italic.rb +9 -0
  33. data/lib/page-object/elements/label.rb +9 -0
  34. data/lib/page-object/elements/link.rb +9 -0
  35. data/lib/page-object/elements/list_item.rb +9 -0
  36. data/lib/page-object/elements/media.rb +11 -0
  37. data/lib/page-object/elements/option.rb +9 -0
  38. data/lib/page-object/elements/ordered_list.rb +43 -0
  39. data/lib/page-object/elements/paragraph.rb +9 -0
  40. data/lib/page-object/elements/radio_button.rb +9 -0
  41. data/lib/page-object/elements/select_list.rb +42 -0
  42. data/lib/page-object/elements/span.rb +9 -0
  43. data/lib/page-object/elements/table.rb +85 -0
  44. data/lib/page-object/elements/table_cell.rb +10 -0
  45. data/lib/page-object/elements/table_row.rb +52 -0
  46. data/lib/page-object/elements/text_area.rb +9 -0
  47. data/lib/page-object/elements/text_field.rb +10 -0
  48. data/lib/page-object/elements/unordered_list.rb +42 -0
  49. data/lib/page-object/elements/video.rb +9 -0
  50. data/lib/page-object/elements.rb +62 -0
  51. data/lib/page-object/indexed_properties.rb +41 -0
  52. data/lib/page-object/javascript/angularjs.rb +14 -0
  53. data/lib/page-object/javascript/jquery.rb +14 -0
  54. data/lib/page-object/javascript/prototype.rb +14 -0
  55. data/lib/page-object/javascript/yui.rb +19 -0
  56. data/lib/page-object/javascript_framework_facade.rb +80 -0
  57. data/lib/page-object/locator_generator.rb +183 -0
  58. data/lib/page-object/nested_elements.rb +17 -0
  59. data/lib/page-object/page_factory.rb +108 -0
  60. data/lib/page-object/page_populator.rb +105 -0
  61. data/lib/page-object/platforms/watir/page_object.rb +1155 -0
  62. data/lib/page-object/platforms/watir.rb +50 -0
  63. data/lib/page-object/section_collection.rb +16 -0
  64. data/lib/page-object/version.rb +4 -0
  65. data/lib/page-object/widgets.rb +98 -0
  66. data/lib/page-object.rb +431 -0
  67. data/pageobject.gems +1 -0
  68. metadata +239 -0
@@ -0,0 +1,1201 @@
1
+ require 'erb'
2
+ require 'page-object/locator_generator'
3
+
4
+ module PageObject
5
+ #
6
+ # Contains the class level methods that are inserted into your page objects
7
+ # when you include the PageObject module. These methods will generate another
8
+ # set of methods that provide access to the elements on the web pages.
9
+ #
10
+ module Accessors
11
+
12
+ #
13
+ # Set some values that can be used within the class. This is
14
+ # typically used to provide values that help build dynamic urls in
15
+ # the page_url method
16
+ #
17
+ # @param [Hash] the value to set the params
18
+ #
19
+ def params=(the_params)
20
+ @params = the_params
21
+ end
22
+
23
+ #
24
+ # Return the params that exist on this page class
25
+ #
26
+ def params
27
+ @params ||= {}
28
+ end
29
+
30
+ #
31
+ # Specify the url for the page. A call to this method will generate a
32
+ # 'goto' method to take you to the page.
33
+ #
34
+ # @param [String] the url for the page.
35
+ # @param [Symbol] a method name to call to get the url
36
+ #
37
+ def page_url(url)
38
+ define_method("goto") do
39
+ platform.navigate_to self.page_url_value
40
+ end
41
+
42
+ define_method('page_url_value') do
43
+ lookup = url.kind_of?(Symbol) ? self.send(url) : url
44
+ erb = ERB.new(%Q{#{lookup}})
45
+ merged_params = self.class.instance_variable_get("@merged_params")
46
+ params = merged_params ? merged_params : self.class.params
47
+ erb.result(binding)
48
+ end
49
+ end
50
+ alias_method :direct_url, :page_url
51
+
52
+ #
53
+ # Creates a method that waits the expected_title of a page to match the actual.
54
+ # @param [String] expected_title the literal expected title for the page
55
+ # @param [Regexp] expected_title the expected title pattern for the page
56
+ # @param [optional, Integer] timeout default value is nil - do not wait
57
+ # @return [boolean]
58
+ # @raise An exception if expected_title does not match actual title
59
+ #
60
+ # @example Specify 'Google' as the expected title of a page
61
+ # expected_title "Google"
62
+ # page.has_expected_title?
63
+ #
64
+ def wait_for_expected_title(expected_title, timeout=::PageObject.default_element_wait)
65
+ define_method("wait_for_expected_title?") do
66
+ error_message = lambda { "Expected title '#{expected_title}' instead of '#{title}'" }
67
+
68
+ has_expected_title = (expected_title === title)
69
+ wait_until(timeout, error_message.call) do
70
+ has_expected_title = (expected_title === title)
71
+ end unless has_expected_title
72
+
73
+ raise error_message.call unless has_expected_title
74
+ has_expected_title
75
+ end
76
+ end
77
+
78
+ #
79
+ # Creates a method that compares the expected_title of a page against the actual.
80
+ # @param [String] expected_title the literal expected title for the page
81
+ # @param [Regexp] expected_title the expected title pattern for the page
82
+ # @return [boolean]
83
+ # @raise An exception if expected_title does not match actual title
84
+ #
85
+ # @example Specify 'Google' as the expected title of a page
86
+ # expected_title "Google"
87
+ # page.has_expected_title?
88
+ #
89
+ def expected_title(expected_title)
90
+ define_method("has_expected_title?") do
91
+ page_title = title
92
+ has_expected_title = (expected_title === page_title)
93
+ raise "Expected title '#{expected_title}' instead of '#{page_title}'" unless has_expected_title
94
+ has_expected_title
95
+ end
96
+ end
97
+
98
+ #
99
+ # Creates a method that provides a way to initialize a page based upon an expected element.
100
+ # This is useful for pages that load dynamic content.
101
+ # @param [Symbol] the name given to the element in the declaration
102
+ # @param [optional, Integer] timeout default value is 5 seconds
103
+ # @return [boolean]
104
+ #
105
+ # @example Specify a text box named :address expected on the page within 10 seconds
106
+ # expected_element(:address, 10)
107
+ # page.has_expected_element?
108
+ #
109
+ def expected_element(element_name, timeout=::PageObject.default_element_wait)
110
+ define_method("has_expected_element?") do
111
+ self.respond_to? "#{element_name}_element" and self.send("#{element_name}_element").when_present timeout
112
+ end
113
+ end
114
+
115
+ #
116
+ # Creates a method that provides a way to initialize a page based upon an expected element to become visible.
117
+ # This is useful for pages that load dynamic content and might have hidden elements that are not shown.
118
+ # @param [Symbol] the name given to the element in the declaration
119
+ # @param [optional, Integer] timeout default value is 5 seconds
120
+ # @param [optional, boolean] also check that element to be visible if set to true
121
+ # @return [boolean]
122
+ #
123
+ # @example Specify a text box named :address expected on the page within 10 seconds
124
+ # expected_element_visible(:address, 10)
125
+ # page.has_expected_element_visible?
126
+ #
127
+ def expected_element_visible(element_name, timeout=::PageObject.default_element_wait, check_visible=false)
128
+ define_method("has_expected_element_visible?") do
129
+ self.respond_to? "#{element_name}_element" and self.send("#{element_name}_element").when_present timeout
130
+ self.respond_to? "#{element_name}_element" and self.send("#{element_name}_element").when_visible timeout
131
+ end
132
+ end
133
+
134
+ #
135
+ # Identify an element as existing within a frame . A frame parameter
136
+ # is passed to the block and must be passed to the other calls to PageObject.
137
+ # You can nest calls to in_frame by passing the frame to the next level.
138
+ #
139
+ # @example
140
+ # in_frame(:id => 'frame_id') do |frame|
141
+ # text_field(:first_name, :id => 'fname', :frame => frame)
142
+ # end
143
+ #
144
+ # @param [Hash] identifier how we find the frame. The valid keys are:
145
+ # * :id
146
+ # * :index
147
+ # * :name
148
+ # * :regexp
149
+ # @param frame passed from a previous call to in_frame. Used to nest calls
150
+ # @param block that contains the calls to elements that exist inside the frame.
151
+ #
152
+ def in_frame(identifier, frame=nil, &block)
153
+ frame = frame.nil? ? [] : frame.dup
154
+ frame << {frame: identifier}
155
+ block.call(frame)
156
+ end
157
+
158
+ #
159
+ # Identify an element as existing within an iframe. A frame parameter
160
+ # is passed to the block and must be passed to the other calls to PageObject.
161
+ # You can nest calls to in_frame by passing the frame to the next level.
162
+ #
163
+ # @example
164
+ # in_iframe(:id => 'frame_id') do |frame|
165
+ # text_field(:first_name, :id => 'fname', :frame => frame)
166
+ # end
167
+ #
168
+ # @param [Hash] identifier how we find the frame. The valid keys are:
169
+ # * :id
170
+ # * :index
171
+ # * :name
172
+ # * :regexp
173
+ # @param frame passed from a previous call to in_iframe. Used to nest calls
174
+ # @param block that contains the calls to elements that exist inside the iframe.
175
+ #
176
+ def in_iframe(identifier, frame=nil, &block)
177
+ frame = frame.nil? ? [] : frame.dup
178
+ frame << {iframe: identifier}
179
+ block.call(frame)
180
+ end
181
+
182
+ #
183
+ # adds four methods to the page object - one to set text in a text field,
184
+ # another to retrieve text from a text field, another to return the text
185
+ # field element, another to check the text field's existence.
186
+ #
187
+ # @example
188
+ # text_field(:first_name, :id => "first_name")
189
+ # # will generate 'first_name', 'first_name=', 'first_name_element',
190
+ # # 'first_name?' methods
191
+ #
192
+ # @param [String] the name used for the generated methods
193
+ # @param [Hash] identifier how we find a text field.
194
+ # @param optional block to be invoked when element method is called
195
+ #
196
+ def text_field(name, identifier={:index => 0}, &block)
197
+ standard_methods(name, identifier, 'text_field_for', &block)
198
+ define_method(name) do
199
+ return platform.text_field_value_for identifier.clone unless block_given?
200
+ self.send("#{name}_element").value
201
+ end
202
+ define_method("#{name}=") do |value|
203
+ return platform.text_field_value_set(identifier.clone, value) unless block_given?
204
+ self.send("#{name}_element").value = value
205
+ end
206
+ end
207
+
208
+ #
209
+ # adds four methods to the page object - one to set value in a date field,
210
+ # another to retrieve value from a date field, another to return the date
211
+ # field element, another to check the date field's existence.
212
+ #
213
+ # @example
214
+ # date_field(:date_of_birth, :id => "date_of_birth")
215
+ # # will generate 'date_of_birth', 'date_of_birth=', 'date_of_birth_element',
216
+ # # 'date_of_birth?' methods
217
+ #
218
+ # @param [String] the name used for the generated methods
219
+ # @param [Hash] identifier how we find a date field.
220
+ # @param optional block to be invoked when element method is called
221
+ #
222
+ def date_field(name, identifier={:index => 0}, &block)
223
+ standard_methods(name, identifier, 'date_field_for', &block)
224
+ define_method(name) do
225
+ return platform.date_field_value_for identifier.clone unless block_given?
226
+ self.send("#{name}_element").value
227
+ end
228
+ define_method("#{name}=") do |value|
229
+ return platform.date_field_value_set(identifier.clone, value) unless block_given?
230
+ self.send("#{name}_element").value = value
231
+ end
232
+ end
233
+
234
+ #
235
+ # adds three methods to the page object - one to get the text from a hidden field,
236
+ # another to retrieve the hidden field element, and another to check the hidden
237
+ # field's existence.
238
+ #
239
+ # @example
240
+ # hidden_field(:user_id, :id => "user_identity")
241
+ # # will generate 'user_id', 'user_id_element' and 'user_id?' methods
242
+ #
243
+ # @param [String] the name used for the generated methods
244
+ # @param [Hash] identifier how we find a hidden field.
245
+ # @param optional block to be invoked when element method is called
246
+ #
247
+ def hidden_field(name, identifier={:index => 0}, &block)
248
+ standard_methods(name, identifier, 'hidden_field_for', &block)
249
+ define_method(name) do
250
+ return platform.hidden_field_value_for identifier.clone unless block_given?
251
+ self.send("#{name}_element").value
252
+ end
253
+ end
254
+ alias_method :hidden, :hidden_field
255
+
256
+ #
257
+ # adds four methods to the page object - one to set text in a text area,
258
+ # another to retrieve text from a text area, another to return the text
259
+ # area element, and another to check the text area's existence.
260
+ #
261
+ # @example
262
+ # text_area(:address, :id => "address")
263
+ # # will generate 'address', 'address=', 'address_element',
264
+ # # 'address?' methods
265
+ #
266
+ # @param [String] the name used for the generated methods
267
+ # @param [Hash] identifier how we find a text area.
268
+ # @param optional block to be invoked when element method is called
269
+ #
270
+ def text_area(name, identifier={:index => 0}, &block)
271
+ standard_methods(name, identifier, 'text_area_for', &block)
272
+ define_method(name) do
273
+ return platform.text_area_value_for identifier.clone unless block_given?
274
+ self.send("#{name}_element").value
275
+ end
276
+ define_method("#{name}=") do |value|
277
+ return platform.text_area_value_set(identifier.clone, value) unless block_given?
278
+ self.send("#{name}_element").value = value
279
+ end
280
+ end
281
+ alias_method :textarea, :text_area
282
+
283
+ #
284
+ # adds five methods - one to select an item in a drop-down,
285
+ # another to fetch the currently selected item text, another
286
+ # to retrieve the select list element, another to check the
287
+ # drop down's existence and another to get all the available options
288
+ # to select from.
289
+ #
290
+ # @example
291
+ # select_list(:state, :id => "state")
292
+ # # will generate 'state', 'state=', 'state_element', 'state?', "state_options" methods
293
+ #
294
+ # @param [Symbol] the name used for the generated methods
295
+ # @param [Hash] identifier how we find a select list.
296
+ # @param optional block to be invoked when element method is called
297
+ #
298
+ def select_list(name, identifier={:index => 0}, &block)
299
+ standard_methods(name, identifier, 'select_list_for', &block)
300
+ define_method(name) do
301
+ return platform.select_list_value_for identifier.clone unless block_given?
302
+ self.send("#{name}_element").value
303
+ end
304
+ define_method("#{name}=") do |value|
305
+ return platform.select_list_value_set(identifier.clone, value) unless block_given?
306
+ self.send("#{name}_element").select(value)
307
+ end
308
+ define_method("#{name}_options") do
309
+ element = self.send("#{name}_element")
310
+ (element && element.options) ? element.options.collect(&:text) : []
311
+ end
312
+ end
313
+ alias_method :select, :select_list
314
+
315
+ #
316
+ # adds three methods - one to select a link, another
317
+ # to return a PageObject::Elements::Link object representing
318
+ # the link, and another that checks the link's existence.
319
+ #
320
+ # @example
321
+ # link(:add_to_cart, :text => "Add to Cart")
322
+ # # will generate 'add_to_cart', 'add_to_cart_element', and 'add_to_cart?' methods
323
+ #
324
+ # @param [Symbol] the name used for the generated methods
325
+ # @param [Hash] identifier how we find a link.
326
+ # @param optional block to be invoked when element method is called
327
+ #
328
+ def link(name, identifier={:index => 0}, &block)
329
+ standard_methods(name, identifier, 'link_for', &block)
330
+ define_method(name) do
331
+ return platform.click_link_for identifier.clone unless block_given?
332
+ self.send("#{name}_element").click
333
+ end
334
+ end
335
+ alias_method :a, :link
336
+
337
+ #
338
+ # adds five methods - one to check, another to uncheck, another
339
+ # to return the state of a checkbox, another to return
340
+ # a PageObject::Elements::CheckBox object representing the checkbox, and
341
+ # a final method to check the checkbox's existence.
342
+ #
343
+ # @example
344
+ # checkbox(:active, :name => "is_active")
345
+ # # will generate 'check_active', 'uncheck_active', 'active_checked?',
346
+ # # 'active_element', and 'active?' methods
347
+ #
348
+ # @param [Symbol] the name used for the generated methods
349
+ # @param [Hash] identifier how we find a checkbox.
350
+ # @param optional block to be invoked when element method is called
351
+ #
352
+ def checkbox(name, identifier={:index => 0}, &block)
353
+ standard_methods(name, identifier, 'checkbox_for', &block)
354
+ define_method("check_#{name}") do
355
+ return platform.check_checkbox(identifier.clone) unless block_given?
356
+ self.send("#{name}_element").check
357
+ end
358
+ define_method("uncheck_#{name}") do
359
+ return platform.uncheck_checkbox(identifier.clone) unless block_given?
360
+ self.send("#{name}_element").uncheck
361
+ end
362
+ define_method("#{name}_checked?") do
363
+ return platform.checkbox_checked?(identifier.clone) unless block_given?
364
+ self.send("#{name}_element").checked?
365
+ end
366
+ end
367
+
368
+ #
369
+ # adds four methods - one to select, another to return if a radio button
370
+ # is selected, another method to return a PageObject::Elements::RadioButton
371
+ # object representing the radio button element, and another to check
372
+ # the radio button's existence.
373
+ #
374
+ # @example
375
+ # radio_button(:north, :id => "north")
376
+ # # will generate 'select_north', 'north_selected?',
377
+ # # 'north_element', and 'north?' methods
378
+ #
379
+ # @param [Symbol] the name used for the generated methods
380
+ # @param [Hash] identifier how we find a radio button.
381
+ # @param optional block to be invoked when element method is called
382
+ #
383
+ def radio_button(name, identifier={:index => 0}, &block)
384
+ standard_methods(name, identifier, 'radio_button_for', &block)
385
+ define_method("select_#{name}") do
386
+ return platform.select_radio(identifier.clone) unless block_given?
387
+ self.send("#{name}_element").select
388
+ end
389
+ define_method("#{name}_selected?") do
390
+ return platform.radio_selected?(identifier.clone) unless block_given?
391
+ self.send("#{name}_element").selected?
392
+ end
393
+ end
394
+ alias_method :radio, :radio_button
395
+
396
+ #
397
+ # adds five methods to help interact with a radio button group -
398
+ # a method to select a radio button in the group by given value/text,
399
+ # a method to return the values of all radio buttons in the group, a method
400
+ # to return if a radio button in the group is selected (will return
401
+ # the text of the selected radio button, if true), a method to return
402
+ # an array of PageObject::Elements::RadioButton objects representing
403
+ # the radio button group, and finally a method to check the existence
404
+ # of the radio button group.
405
+ #
406
+ # @example
407
+ # radio_button_group(:color, :name => "preferred_color")
408
+ # will generate 'select_color', 'color_values', 'color_selected?',
409
+ # 'color_elements', and 'color?' methods
410
+ #
411
+ # @param [Symbol] the name used for the generated methods
412
+ # @param [Hash] shared identifier for the radio button group. Typically, a 'name' attribute.
413
+ # The valid keys are:
414
+ # * :name
415
+ #
416
+ def radio_button_group(name, identifier)
417
+ define_method("select_#{name}") do |value|
418
+ platform.radio_buttons_for(identifier.clone).each do |radio_elem|
419
+ if radio_elem.value == value
420
+ return radio_elem.select
421
+ end
422
+ end
423
+ end
424
+ define_method("#{name}_values") do
425
+ result = []
426
+ platform.radio_buttons_for(identifier.clone).each do |radio_elem|
427
+ result << radio_elem.value
428
+ end
429
+ return result
430
+ end
431
+ define_method("#{name}_selected?") do
432
+ platform.radio_buttons_for(identifier.clone).each do |radio_elem|
433
+ return radio_elem.value if radio_elem.selected?
434
+ end
435
+ return false
436
+ end
437
+ define_method("#{name}_elements") do
438
+ return platform.radio_buttons_for(identifier.clone)
439
+ end
440
+ define_method("#{name}?") do
441
+ return platform.radio_buttons_for(identifier.clone).any?
442
+ end
443
+ end
444
+ alias_method :radio_group, :radio_button_group
445
+
446
+ #
447
+ # adds three methods - one to click a button, another to
448
+ # return the button element, and another to check the button's existence.
449
+ #
450
+ # @example
451
+ # button(:purchase, :id => 'purchase')
452
+ # # will generate 'purchase', 'purchase_element', and 'purchase?' methods
453
+ #
454
+ # @param [Symbol] the name used for the generated methods
455
+ # @param [Hash] identifier how we find a button.
456
+ # @param optional block to be invoked when element method is called
457
+ #
458
+ def button(name, identifier={:index => 0}, &block)
459
+ standard_methods(name, identifier, 'button_for', &block)
460
+ define_method(name) do
461
+ return platform.click_button_for identifier.clone unless block_given?
462
+ self.send("#{name}_element").click
463
+ end
464
+ end
465
+
466
+ #
467
+ # adds three methods - one to retrieve the text from a div,
468
+ # another to return the div element, and another to check the div's existence.
469
+ #
470
+ # @example
471
+ # div(:message, :id => 'message')
472
+ # # will generate 'message', 'message_element', and 'message?' methods
473
+ #
474
+ # @param [Symbol] the name used for the generated methods
475
+ # @param [Hash] identifier how we find a div.
476
+ # @param optional block to be invoked when element method is called
477
+ #
478
+ def div(name, identifier={:index => 0}, &block)
479
+ standard_methods(name, identifier, 'div_for', &block)
480
+ define_method(name) do
481
+ return platform.div_text_for identifier.clone unless block_given?
482
+ self.send("#{name}_element").text
483
+ end
484
+ end
485
+
486
+ #
487
+ # adds three methods - one to retrieve the text from a span,
488
+ # another to return the span element, and another to check the span's existence.
489
+ #
490
+ # @example
491
+ # span(:alert, :id => 'alert')
492
+ # # will generate 'alert', 'alert_element', and 'alert?' methods
493
+ #
494
+ # @param [Symbol] the name used for the generated methods
495
+ # @param [Hash] identifier how we find a span.
496
+ # @param optional block to be invoked when element method is called
497
+ #
498
+ def span(name, identifier={:index => 0}, &block)
499
+ standard_methods(name, identifier, 'span_for', &block)
500
+ define_method(name) do
501
+ return platform.span_text_for identifier.clone unless block_given?
502
+ self.send("#{name}_element").text
503
+ end
504
+ end
505
+
506
+ #
507
+ # adds three methods - one to return the text for the table, one
508
+ # to retrieve the table element, and another to
509
+ # check the table's existence.
510
+ #
511
+ # @example
512
+ # table(:cart, :id => 'shopping_cart')
513
+ # # will generate a 'cart', 'cart_element' and 'cart?' method
514
+ #
515
+ # @param [Symbol] the name used for the generated methods
516
+ # @param [Hash] identifier how we find a table.
517
+ # @param optional block to be invoked when element method is called
518
+ #
519
+ def table(name, identifier={:index => 0}, &block)
520
+ standard_methods(name, identifier, 'table_for', &block)
521
+ define_method(name) do
522
+ return platform.table_text_for identifier.clone unless block_given?
523
+ self.send("#{name}_element").text
524
+ end
525
+ end
526
+
527
+ #
528
+ # adds three methods - one to retrieve the text from a table cell,
529
+ # another to return the table cell element, and another to check the cell's
530
+ # existence.
531
+ #
532
+ # @example
533
+ # cell(:total, :id => 'total_cell')
534
+ # # will generate 'total', 'total_element', and 'total?' methods
535
+ #
536
+ # @param [Symbol] the name used for the generated methods
537
+ # @param [Hash] identifier how we find a cell.
538
+ # @param optional block to be invoked when element method is called
539
+ #
540
+ def cell(name, identifier={:index => 0}, &block)
541
+ standard_methods(name, identifier, 'cell_for', &block)
542
+ define_method("#{name}") do
543
+ return platform.cell_text_for identifier.clone unless block_given?
544
+ self.send("#{name}_element").text
545
+ end
546
+ end
547
+ alias_method :td, :cell
548
+
549
+
550
+ #
551
+ # adds three methods - one to retrieve the text from a table row,
552
+ # another to return the table row element, and another to check the row's
553
+ # existence.
554
+ #
555
+ # @example
556
+ # row(:sums, :id => 'sum_row')
557
+ # # will generate 'sums', 'sums_element', and 'sums?' methods
558
+ #
559
+ # @param [Symbol] the name used for the generated methods
560
+ # @param [Hash] identifier how we find a cell.
561
+ # @param optional block to be invoked when element method is called
562
+ #
563
+ def row(name, identifier={:index => 0}, &block)
564
+ standard_methods(name, identifier, 'row_for', &block)
565
+ define_method("#{name}") do
566
+ return platform.row_text_for identifier.clone unless block_given?
567
+ self.send("#{name}_element").text
568
+ end
569
+ end
570
+
571
+ #
572
+ # adds three methods - one to retrieve the image element, another to
573
+ # check the load status of the image, and another to check the
574
+ # image's existence.
575
+ #
576
+ # @example
577
+ # image(:logo, :id => 'logo')
578
+ # # will generate 'logo_element', 'logo_loaded?', and 'logo?' methods
579
+ #
580
+ # @param [Symbol] the name used for the generated methods
581
+ # @param [Hash] identifier how we find an image.
582
+ # @param optional block to be invoked when element method is called
583
+ #
584
+ def image(name, identifier={:index => 0}, &block)
585
+ standard_methods(name, identifier, 'image_for', &block)
586
+ define_method("#{name}_loaded?") do
587
+ return platform.image_loaded_for identifier.clone unless block_given?
588
+ self.send("#{name}_element").loaded?
589
+ end
590
+ end
591
+ alias_method :img, :image
592
+
593
+ #
594
+ # adds two methods - one to retrieve the form element, and another to
595
+ # check the form's existence.
596
+ #
597
+ # @example
598
+ # form(:login, :id => 'login')
599
+ # # will generate 'login_element' and 'login?' methods
600
+ #
601
+ # @param [Symbol] the name used for the generated methods
602
+ # @param [Hash] identifier how we find a form.
603
+ # @param optional block to be invoked when element method is called
604
+ #
605
+ def form(name, identifier={:index => 0}, &block)
606
+ standard_methods(name, identifier, 'form_for', &block)
607
+ end
608
+
609
+ #
610
+ # adds three methods - one to retrieve the text from a list item,
611
+ # another to return the list item element, and another to check the list item's
612
+ # existence.
613
+ #
614
+ # @example
615
+ # list_item(:item_one, :id => 'one')
616
+ # # will generate 'item_one', 'item_one_element', and 'item_one?' methods
617
+ #
618
+ # @param [Symbol] the name used for the generated methods
619
+ # @param [Hash] identifier how we find a list item.
620
+ # @param optional block to be invoked when element method is called
621
+ #
622
+ def list_item(name, identifier={:index => 0}, &block)
623
+ standard_methods(name, identifier, 'list_item_for', &block)
624
+ define_method(name) do
625
+ return platform.list_item_text_for identifier.clone unless block_given?
626
+ self.send("#{name}_element").text
627
+ end
628
+ end
629
+ alias_method :li, :list_item
630
+
631
+ #
632
+ # adds three methods - one to return the text within the unordered
633
+ # list, one to retrieve the unordered list element, and another to
634
+ # check it's existence.
635
+ #
636
+ # @example
637
+ # unordered_list(:menu, :id => 'main_menu')
638
+ # # will generate 'menu', 'menu_element' and 'menu?' methods
639
+ #
640
+ # @param [Symbol] the name used for the generated methods
641
+ # @param [Hash] identifier how we find an unordered list.
642
+ # @param optional block to be invoked when element method is called
643
+ #
644
+ def unordered_list(name, identifier={:index => 0}, &block)
645
+ standard_methods(name, identifier, 'unordered_list_for', &block)
646
+ define_method(name) do
647
+ return platform.unordered_list_text_for identifier.clone unless block_given?
648
+ self.send("#{name}_element").text
649
+ end
650
+ end
651
+ alias_method :ul, :unordered_list
652
+
653
+ #
654
+ # adds three methods - one to return the text within the ordered
655
+ # list, one to retrieve the ordered list element, and another to
656
+ # test it's existence.
657
+ #
658
+ # @example
659
+ # ordered_list(:top_five, :id => 'top')
660
+ # # will generate 'top_five', 'top_five_element' and 'top_five?' methods
661
+ #
662
+ # @param [Symbol] the name used for the generated methods
663
+ # @param [Hash] identifier how we find an ordered list.
664
+ # @param optional block to be invoked when element method is called
665
+ #
666
+ def ordered_list(name, identifier={:index => 0}, &block)
667
+ standard_methods(name, identifier, 'ordered_list_for', &block)
668
+ define_method(name) do
669
+ return platform.ordered_list_text_for identifier.clone unless block_given?
670
+ self.send("#{name}_element").text
671
+ end
672
+ end
673
+ alias_method :ol, :ordered_list
674
+
675
+ #
676
+ # adds three methods - one to retrieve the text of a h1 element, another to
677
+ # retrieve a h1 element, and another to check for it's existence.
678
+ #
679
+ # @example
680
+ # h1(:title, :id => 'title')
681
+ # # will generate 'title', 'title_element', and 'title?' methods
682
+ #
683
+ # @param [Symbol] the name used for the generated methods
684
+ # @param [Hash] identifier how we find a H1. You can use a multiple parameters
685
+ # by combining of any of the following except xpath.
686
+ # @param optional block to be invoked when element method is called
687
+ #
688
+ def h1(name, identifier={:index => 0}, &block)
689
+ standard_methods(name, identifier,'h1_for', &block)
690
+ define_method(name) do
691
+ return platform.h1_text_for identifier.clone unless block_given?
692
+ self.send("#{name}_element").text
693
+ end
694
+ end
695
+
696
+ #
697
+ # adds three methods - one to retrieve the text of a h2 element, another
698
+ # to retrieve a h2 element, and another to check for it's existence.
699
+ #
700
+ # @example
701
+ # h2(:title, :id => 'title')
702
+ # # will generate 'title', 'title_element', and 'title?' methods
703
+ #
704
+ # @param [Symbol] the name used for the generated methods
705
+ # @param [Hash] identifier how we find a H2.
706
+ # @param optional block to be invoked when element method is called
707
+ #
708
+ def h2(name, identifier={:index => 0}, &block)
709
+ standard_methods(name, identifier, 'h2_for', &block)
710
+ define_method(name) do
711
+ return platform.h2_text_for identifier.clone unless block_given?
712
+ self.send("#{name}_element").text
713
+ end
714
+ end
715
+
716
+ #
717
+ # adds three methods - one to retrieve the text of a h3 element,
718
+ # another to return a h3 element, and another to check for it's existence.
719
+ #
720
+ # @example
721
+ # h3(:title, :id => 'title')
722
+ # # will generate 'title', 'title_element', and 'title?' methods
723
+ #
724
+ # @param [Symbol] the name used for the generated methods
725
+ # @param [Hash] identifier how we find a H3.
726
+ # @param optional block to be invoked when element method is called
727
+ #
728
+ def h3(name, identifier={:index => 0}, &block)
729
+ standard_methods(name, identifier, 'h3_for', &block)
730
+ define_method(name) do
731
+ return platform.h3_text_for identifier.clone unless block_given?
732
+ self.send("#{name}_element").text
733
+ end
734
+ end
735
+
736
+ #
737
+ # adds three methods - one to retrieve the text of a h4 element,
738
+ # another to return a h4 element, and another to check for it's existence.
739
+ #
740
+ # @example
741
+ # h4(:title, :id => 'title')
742
+ # # will generate 'title', 'title_element', and 'title?' methods
743
+ #
744
+ # @param [Symbol] the name used for the generated methods
745
+ # @param [Hash] identifier how we find a H4.
746
+ # @param optional block to be invoked when element method is called
747
+ #
748
+ def h4(name, identifier={:index => 0}, &block)
749
+ standard_methods(name, identifier, 'h4_for', &block)
750
+ define_method(name) do
751
+ return platform.h4_text_for identifier.clone unless block_given?
752
+ self.send("#{name}_element").text
753
+ end
754
+ end
755
+
756
+ #
757
+ # adds three methods - one to retrieve the text of a h5 element,
758
+ # another to return a h5 element, and another to check for it's existence.
759
+ #
760
+ # @example
761
+ # h5(:title, :id => 'title')
762
+ # # will generate 'title', 'title_element', and 'title?' methods
763
+ #
764
+ # @param [Symbol] the name used for the generated methods
765
+ # @param [Hash] identifier how we find a H5.
766
+ # @param optional block to be invoked when element method is called
767
+ #
768
+ def h5(name, identifier={:index => 0}, &block)
769
+ standard_methods(name, identifier, 'h5_for', &block)
770
+ define_method(name) do
771
+ return platform.h5_text_for identifier.clone unless block_given?
772
+ self.send("#{name}_element").text
773
+ end
774
+ end
775
+
776
+ #
777
+ # adds three methods - one to retrieve the text of a h6 element,
778
+ # another to return a h6 element, and another to check for it's existence.
779
+ #
780
+ # @example
781
+ # h6(:title, :id => 'title')
782
+ # # will generate 'title', 'title_element', and 'title?' methods
783
+ #
784
+ # @param [Symbol] the name used for the generated methods
785
+ # @param [Hash] identifier how we find a H6.
786
+ # @param optional block to be invoked when element method is called
787
+ #
788
+ def h6(name, identifier={:index => 0}, &block)
789
+ standard_methods(name, identifier, 'h6_for', &block)
790
+ define_method(name) do
791
+ return platform.h6_text_for identifier.clone unless block_given?
792
+ self.send("#{name}_element").text
793
+ end
794
+ end
795
+
796
+ #
797
+ # adds three methods - one to retrieve the text of a paragraph, another
798
+ # to retrieve a paragraph element, and another to check the paragraph's existence.
799
+ #
800
+ # @example
801
+ # paragraph(:title, :id => 'title')
802
+ # # will generate 'title', 'title_element', and 'title?' methods
803
+ #
804
+ # @param [Symbol] the name used for the generated methods
805
+ # @param [Hash] identifier how we find a paragraph.
806
+ # @param optional block to be invoked when element method is called
807
+ #
808
+ def paragraph(name, identifier={:index => 0}, &block)
809
+ standard_methods(name, identifier, 'paragraph_for', &block)
810
+ define_method(name) do
811
+ return platform.paragraph_text_for identifier.clone unless block_given?
812
+ self.send("#{name}_element").text
813
+ end
814
+ end
815
+ alias_method :p, :paragraph
816
+
817
+ #
818
+ # adds three methods - one to set the file for a file field, another to retrieve
819
+ # the file field element, and another to check it's existence.
820
+ #
821
+ # @example
822
+ # file_field(:the_file, :id => 'file_to_upload')
823
+ # # will generate 'the_file=', 'the_file_element', and 'the_file?' methods
824
+ #
825
+ # @param [Symbol] the name used for the generated methods
826
+ # @param [Hash] identifier how we find a file_field.
827
+ # @param optional block to be invoked when element method is called
828
+ #
829
+ def file_field(name, identifier={:index => 0}, &block)
830
+ standard_methods(name, identifier, 'file_field_for', &block)
831
+ define_method("#{name}=") do |value|
832
+ return platform.file_field_value_set(identifier.clone, value) unless block_given?
833
+ self.send("#{name}_element").value = value
834
+ end
835
+ end
836
+
837
+ #
838
+ # adds three methods - one to retrieve the text from a label,
839
+ # another to return the label element, and another to check the label's existence.
840
+ #
841
+ # @example
842
+ # label(:message, :id => 'message')
843
+ # # will generate 'message', 'message_element', and 'message?' methods
844
+ #
845
+ # @param [Symbol] the name used for the generated methods
846
+ # @param [Hash] identifier how we find a label.
847
+ # @param optional block to be invoked when element method is called
848
+ #
849
+ def label(name, identifier={:index => 0}, &block)
850
+ standard_methods(name, identifier, 'label_for', &block)
851
+ define_method(name) do
852
+ return platform.label_text_for identifier.clone unless block_given?
853
+ self.send("#{name}_element").text
854
+ end
855
+ end
856
+
857
+ #
858
+ # adds three methods - one to click the area,
859
+ # another to return the area element, and another to check the area's existence.
860
+ #
861
+ # @example
862
+ # area(:message, :id => 'message')
863
+ # # will generate 'message', 'message_element', and 'message?' methods
864
+ #
865
+ # @param [Symbol] the name used for the generated methods
866
+ # @param [Hash] identifier how we find an area.
867
+ # @param optional block to be invoked when element method is called
868
+ #
869
+ def area(name, identifier={:index => 0}, &block)
870
+ standard_methods(name, identifier, 'area_for', &block)
871
+ define_method(name) do
872
+ return platform.click_area_for identifier.clone unless block_given?
873
+ self.send("#{name}_element").click
874
+ end
875
+ end
876
+
877
+ #
878
+ # adds two methods - one to return the canvas element and another to check
879
+ # the canvas's existence.
880
+ #
881
+ # @example
882
+ # canvas(:my_canvas, :id => 'canvas_id')
883
+ # # will generate 'my_canvas_element' and 'my_canvas?' methods
884
+ #
885
+ # @param [Symbol] the name used for the generated methods
886
+ # @param [Hash] identifier how we find a canvas.
887
+ # @param optional block to be invoked when element method is called
888
+ #
889
+ def canvas(name, identifier={:index => 0}, &block)
890
+ standard_methods(name, identifier, 'canvas_for', &block)
891
+ end
892
+
893
+ #
894
+ # adds two methods - one to return the audio element and another to check
895
+ # the audio's existence.
896
+ #
897
+ # @example
898
+ # audio(:acdc, :id => 'audio_id')
899
+ # # will generate 'acdc_element' and 'acdc?' methods
900
+ #
901
+ # @param [Symbol] the name used for the generated methods
902
+ # @param [Hash] identifier how we find an audio element.
903
+ # @param optional block to be invoked when element method is called
904
+ #
905
+ def audio(name, identifier={:index => 0}, &block)
906
+ standard_methods(name, identifier, 'audio_for', &block)
907
+ end
908
+
909
+ #
910
+ # adds two methods - one to return the video element and another to check
911
+ # the video's existence.
912
+ #
913
+ # @example
914
+ # video(:movie, :id => 'video_id')
915
+ # # will generate 'movie_element' and 'movie?' methods
916
+ #
917
+ # @param [Symbol] the name used for the generated methods
918
+ # @param [Hash] identifier how we find a video element.
919
+ # @param optional block to be invoked when element method is called
920
+ #
921
+ def video(name, identifier={:index => 0}, &block)
922
+ standard_methods(name, identifier, 'video_for', &block)
923
+ end
924
+
925
+ #
926
+ # adds three methods - one to retrieve the text of a b element, another to
927
+ # retrieve a b element, and another to check for it's existence.
928
+ #
929
+ # @example
930
+ # b(:bold, :id => 'title')
931
+ # # will generate 'bold', 'bold_element', and 'bold?' methods
932
+ #
933
+ # @param [Symbol] the name used for the generated methods
934
+ # @param [Hash] identifier how we find a b.
935
+ # @param optional block to be invoked when element method is called
936
+ #
937
+ def b(name, identifier={:index => 0}, &block)
938
+ standard_methods(name, identifier,'b_for', &block)
939
+ define_method(name) do
940
+ return platform.b_text_for identifier.clone unless block_given?
941
+ self.send("#{name}_element").text
942
+ end
943
+ end
944
+
945
+ #
946
+ # adds three methods - one to retrieve the text of a i element, another to
947
+ # retrieve a i element, and another to check for it's existence.
948
+ #
949
+ # @example
950
+ # i(:italic, :id => 'title')
951
+ # # will generate 'italic', 'italic_element', and 'italic?' methods
952
+ #
953
+ # @param [Symbol] the name used for the generated methods
954
+ # @param [Hash] identifier how we find a i.
955
+ # @param optional block to be invoked when element method is called
956
+ #
957
+ def i(name, identifier={:index => 0}, &block)
958
+ standard_methods(name, identifier,'i_for', &block)
959
+ define_method(name) do
960
+ return platform.i_text_for identifier.clone unless block_given?
961
+ self.send("#{name}_element").text
962
+ end
963
+ end
964
+ alias_method :icon, :i
965
+
966
+ #
967
+ # adds two methods - one to retrieve a svg, and another to check
968
+ # the svg's existence.
969
+ #
970
+ # @example
971
+ # svg(:circle, :id => 'circle')
972
+ # # will generate 'circle_element', and 'circle?' methods
973
+ #
974
+ # @param [Symbol] the name used for the generated methods
975
+ # @param [Hash] identifier how we find a svg.
976
+ # @param optional block to be invoked when element method is called
977
+ #
978
+ def svg(name, identifier={:index => 0}, &block)
979
+ standard_methods(name, identifier, 'svg_for', &block)
980
+ end
981
+
982
+
983
+ #
984
+ # adds three methods - one to retrieve the text of an element, another
985
+ # to retrieve an element, and another to check the element's existence.
986
+ #
987
+ # @example
988
+ # element(:title, :header, :id => 'title')
989
+ # # will generate 'title', 'title_element', and 'title?' methods
990
+ #
991
+ # @param [Symbol] the name used for the generated methods
992
+ # @param [Symbol] the name of the tag for the element
993
+ # @param [Hash] identifier how we find an element.
994
+ # @param optional block to be invoked when element method is called
995
+ #
996
+ def element(name, tag=:element, identifier={ :index => 0 }, &block)
997
+ #
998
+ # sets tag as element if not defined
999
+ #
1000
+ if tag.is_a?(Hash)
1001
+ identifier = tag
1002
+ tag = :element
1003
+ end
1004
+
1005
+ standard_methods(name, identifier, 'element_for', &block)
1006
+
1007
+ define_method("#{name}") do
1008
+ element = self.send("#{name}_element")
1009
+
1010
+ %w(Button TextField Radio Hidden CheckBox FileField).each do |klass|
1011
+ next unless element.element.class.to_s == "Watir::#{klass}"
1012
+ self.class.send(klass.gsub(/(.)([A-Z])/,'\1_\2').downcase, name, identifier, &block)
1013
+ return self.send name
1014
+ end
1015
+ element.text
1016
+ end
1017
+ define_method("#{name}_element") do
1018
+ return call_block(&block) if block_given?
1019
+ platform.element_for(tag, identifier.clone)
1020
+ end
1021
+ define_method("#{name}?") do
1022
+ self.send("#{name}_element").exists?
1023
+ end
1024
+ define_method("#{name}=") do |value|
1025
+ element = self.send("#{name}_element")
1026
+
1027
+ klass = case element.element
1028
+ when Watir::TextField
1029
+ 'text_field'
1030
+ when Watir::TextArea
1031
+ 'text_area'
1032
+ when Watir::Select
1033
+ 'select_list'
1034
+ when Watir::FileField
1035
+ 'file_field'
1036
+ else
1037
+ raise "Can not set a #{element.element} element with #="
1038
+ end
1039
+ self.class.send(klass, name, identifier, &block)
1040
+ self.send("#{name}=", value)
1041
+ end
1042
+ end
1043
+
1044
+ #
1045
+ # adds a method to return a collection of generic Element objects
1046
+ # for a specific tag.
1047
+ #
1048
+ # @example
1049
+ # elements(:title, :header, :id => 'title')
1050
+ # # will generate ''title_elements'
1051
+ #
1052
+ # @param [Symbol] the name used for the generated methods
1053
+ # @param [Symbol] the name of the tag for the element
1054
+ # @param [Hash] identifier how we find an element.
1055
+ # @param optional block to be invoked when element method is called
1056
+ #
1057
+ def elements(name, tag=:element, identifier={:index => 0}, &block)
1058
+ #
1059
+ # sets tag as element if not defined
1060
+ #
1061
+ if tag.is_a?(Hash)
1062
+ identifier = tag
1063
+ tag = :element
1064
+ end
1065
+
1066
+ define_method("#{name}_elements") do
1067
+ return call_block(&block) if block_given?
1068
+ platform.elements_for(tag, identifier.clone)
1069
+ end
1070
+ end
1071
+
1072
+ #
1073
+ # adds a method to return a page object rooted at an element
1074
+ #
1075
+ # @example
1076
+ # page_section(:navigation_bar, NavigationBar, :id => 'nav-bar')
1077
+ # # will generate 'navigation_bar'
1078
+ #
1079
+ # @param [Symbol] the name used for the generated methods
1080
+ # @param [Class] the class to instantiate for the element
1081
+ # @param [Hash] identifier how we find an element.
1082
+ #
1083
+ def page_section(name, section_class, identifier)
1084
+ define_method(name) do
1085
+ platform.page_for(identifier, section_class)
1086
+ end
1087
+ end
1088
+
1089
+ #
1090
+ # adds a method to return a collection of page objects rooted at elements
1091
+ #
1092
+ # @example
1093
+ # page_sections(:articles, Article, :class => 'article')
1094
+ # # will generate 'articles'
1095
+ #
1096
+ # @param [Symbol] the name used for the generated method
1097
+ # @param [Class] the class to instantiate for each element
1098
+ # @param [Hash] identifier how we find an element.
1099
+ #
1100
+ def page_sections(name, section_class, identifier)
1101
+ define_method(name) do
1102
+ platform.pages_for(identifier, section_class)
1103
+ end
1104
+ end
1105
+
1106
+ #
1107
+ # methods to generate accessors for types that follow the same
1108
+ # pattern as element
1109
+ #
1110
+ # @example
1111
+ # article(:my_article, :id => "article_id")
1112
+ # will generate 'my_article', 'my_article_element' and 'my_article?'
1113
+ # articles(:my_article, :id => 'article_id')
1114
+ # will generate 'my_article_elements'
1115
+ #
1116
+ # @param [Symbol] the name used for the generated methods
1117
+ # @param [Symbol] the name of the tag for the element
1118
+ # @param [Hash] identifier how we find an element.
1119
+ # @param optional block to be invoked when element method is called
1120
+ #
1121
+ LocatorGenerator::BASIC_ELEMENTS.each do |tag|
1122
+ define_method(tag) do |name, *identifier, &block|
1123
+ identifier = identifier[0] ? identifier[0] : {:index => 0}
1124
+ element(name, tag, identifier, &block)
1125
+ end
1126
+ define_method("#{tag}s") do |name, *identifier, &block|
1127
+ identifier = identifier[0] ? identifier[0] : {:index => 0}
1128
+ elements(name, tag, identifier, &block)
1129
+ end unless tag == :param
1130
+ end
1131
+
1132
+ def standard_methods(name, identifier, method, &block)
1133
+ define_method("#{name}_element") do
1134
+ return call_block(&block) if block_given?
1135
+ platform.send(method, identifier.clone)
1136
+ end
1137
+ define_method("#{name}?") do
1138
+ return call_block(&block).exists? if block_given?
1139
+ platform.send(method, identifier.clone).exists?
1140
+ end
1141
+ end
1142
+
1143
+ #
1144
+ # adds a method that will return an indexed property. The property will respond to
1145
+ # the [] method with an object that has a set of normal page_object properties that
1146
+ # correspond to the definitions included in the identifier_list parameter, with the
1147
+ # "what" of the "how and what" substituted based on the index provided to the []
1148
+ # method.
1149
+ #
1150
+ # @example
1151
+ # indexed_property(:title, [
1152
+ # [:text_field, :field_1, :id => 'table[%s].field_1'],
1153
+ # [:button, :button_1, :id => 'table[%s].button_1'],
1154
+ # [:text_field, :field_2, :name => 'table[%s].field_2']
1155
+ # ])
1156
+ # # will generate a title method that responds to []. title['foo'] will return an object
1157
+ # # that responds to the normal methods expected for two text_fields and a button with the
1158
+ # # given names, using the given how and what with 'foo' substituted for the %s. title[123]
1159
+ # # will do the same, using the integer 123 instead.
1160
+ #
1161
+ # @param [Symbol] the name used for the generated method
1162
+ # @param [Array] definitions an array of definitions to define on the indexed property. Each
1163
+ # entry in the array should contain two symbols and a hash, corresponding to one of the standard
1164
+ # page_object properties with a single substitution marker in each value in the hash,
1165
+ # e.g. [:text_field, :field_1, :id => 'table[%s].field_1']
1166
+ #
1167
+ def indexed_property (name, identifier_list)
1168
+ define_method("#{name}") do
1169
+ IndexedProperties::TableOfElements.new(@browser, identifier_list)
1170
+ end
1171
+ end
1172
+
1173
+ #
1174
+ # methods to fetch multiple elements of the same type
1175
+ #
1176
+ # adds a method to the page object to return all of the matching elements
1177
+ #
1178
+ # @example
1179
+ # text_fields(:first_name, :id => "first_name")
1180
+ # # will generate 'first_name_elements'
1181
+ #
1182
+ # @param [String] the name used for the generated methods
1183
+ # @param [Hash] identifier how we find a text field. You can use a multiple parameters
1184
+ # by combining of any of the following except xpath. The valid
1185
+ # keys are the same ones supported by the standard methods.
1186
+ # @param optional block to be invoked when element method is called
1187
+ #
1188
+ idx = LocatorGenerator::ADVANCED_ELEMENTS.find_index { |type| type == :checkbox }
1189
+ elements = LocatorGenerator::ADVANCED_ELEMENTS.clone
1190
+ elements[idx] = :checkboxe
1191
+ elements.each do |method_name|
1192
+ define_method("#{method_name}s") do |name, *identifier, &block|
1193
+ define_method("#{name}_elements") do
1194
+ return call_block(&block) unless block.nil?
1195
+ platform_method = (method_name == :checkboxe) ? 'checkboxs_for' : "#{method_name.to_s}s_for"
1196
+ platform.send platform_method, (identifier.first ? identifier.first.clone : {})
1197
+ end
1198
+ end
1199
+ end
1200
+ end
1201
+ end