druid-ts 1.1.8 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +27 -0
  3. data/features/bold.feature +21 -0
  4. data/features/element.feature +7 -0
  5. data/features/frames.feature +15 -0
  6. data/features/html/frames.html +3 -3
  7. data/features/html/iframes.html +2 -2
  8. data/features/html/multi_elements.html +1 -0
  9. data/features/html/static_elements.html +25 -8
  10. data/features/javascript.feature +10 -1
  11. data/features/link.feature +4 -0
  12. data/features/multi_elements.feature +6 -0
  13. data/features/radio_button_group.feature +28 -0
  14. data/features/section.feature +128 -0
  15. data/features/select_list.feature +4 -0
  16. data/features/step_definations/bold_steps.rb +11 -0
  17. data/features/step_definations/element_steps.rb +8 -0
  18. data/features/step_definations/frame_steps.rb +53 -11
  19. data/features/step_definations/javasript_steps.rb +9 -0
  20. data/features/step_definations/link_steps.rb +8 -0
  21. data/features/step_definations/multi_elements_steps.rb +13 -0
  22. data/features/step_definations/radio_button_group_steps.rb +32 -0
  23. data/features/step_definations/section_steps.rb +262 -0
  24. data/features/step_definations/table_steps.rb +9 -0
  25. data/features/support/env.rb +1 -0
  26. data/features/support/page.rb +16 -5
  27. data/features/table.feature +18 -14
  28. data/lib/druid.rb +42 -30
  29. data/lib/druid/accessors.rb +188 -55
  30. data/lib/druid/assist.rb +46 -4
  31. data/lib/druid/elements.rb +1 -0
  32. data/lib/druid/elements/bold.rb +8 -0
  33. data/lib/druid/elements/element.rb +16 -3
  34. data/lib/druid/elements/link.rb +7 -0
  35. data/lib/druid/elements/radio_button.rb +0 -7
  36. data/lib/druid/elements/select_list.rb +2 -2
  37. data/lib/druid/elements/table.rb +7 -0
  38. data/lib/druid/javascript/angularjs.rb +12 -0
  39. data/lib/druid/javascript_framework_facade.rb +5 -3
  40. data/lib/druid/locator_generator.rb +1 -0
  41. data/lib/druid/page_factory.rb +1 -0
  42. data/lib/druid/page_populator.rb +10 -1
  43. data/lib/druid/sections.rb +29 -0
  44. data/lib/druid/version.rb +1 -1
  45. data/spec/druid/accessors_spec.rb +79 -13
  46. data/spec/druid/druid_spec.rb +2 -1
  47. data/spec/druid/element_locators_spec.rb +26 -4
  48. data/spec/druid/elements/bold_spec.rb +21 -0
  49. data/spec/druid/elements/link_spec.rb +1 -1
  50. data/spec/druid/elements/page_factory_spec.rb +2 -2
  51. data/spec/druid/elements/radio_button_spec.rb +0 -5
  52. data/spec/druid/elements/select_list_spec.rb +3 -3
  53. data/spec/druid/page_factory_spec.rb +15 -15
  54. data/spec/druid/page_populator_spec.rb +4 -4
  55. data/spec/druid/page_section_spec.rb +61 -0
  56. data/spec/spec_helper.rb +1 -0
  57. metadata +20 -1
data/lib/druid.rb CHANGED
@@ -4,6 +4,7 @@ require 'druid/page_factory'
4
4
  require 'druid/core_ext/string'
5
5
  require 'druid/element_locators'
6
6
  require 'druid/page_populator'
7
+ require 'druid/sections'
7
8
  require 'druid/javascript_framework_facade'
8
9
 
9
10
  # require 'watir-webdriver/extensions/alerts'
@@ -39,26 +40,29 @@ module Druid
39
40
  include Assist
40
41
  include ElementLocators
41
42
  include PagePopulator
42
- # include Watir::AlertHelper
43
+
43
44
  # @return [Watir::Browser] the drvier passed to the constructor
44
45
  attr_reader :driver
46
+
45
47
  #
46
48
  # Construct a new druid. Prior to browser initialization it will call
47
49
  # a method named initialize_accessors if it exists. Upon initialization of
48
50
  # the page it will call a method named initialize_page if it exists
49
51
  #
50
- # @param [Watir::Browser] the driver to use
52
+ # @param [Watir::Browser, Watir:HTMLElement] the driver/element to use
51
53
  # @param [bool] open the page if page_url is set
52
54
  #
53
- def initialize(driver, visit=false)
55
+ def initialize(root, visit=false)
54
56
  initialize_accessors if respond_to?(:initialize_accessors)
55
- if driver.is_a? Watir::Browser
56
- @driver ||= driver
57
- goto if visit && respond_to?(:goto)
58
- initialize_page if respond_to?(:initialize_page)
59
- else
60
- raise ArgumentError, "expect Watir::Browser"
61
- end
57
+ initialize_driver root
58
+ goto if visit && respond_to?(:goto)
59
+ initialize_page if respond_to?(:initialize_page)
60
+ end
61
+
62
+ def initialize_driver root
63
+ @driver = root if root.is_a? Watir::HTMLElement or root.is_a? Watir::Browser
64
+ @root_element = Elements::Element.new root if root.is_a? Watir::HTMLElement
65
+ raise "expect Watir::Browser or Watir::HTMLElement" if not root.is_a? Watir::HTMLElement and not root.is_a? Watir::Browser
62
66
  end
63
67
 
64
68
  # @private
@@ -105,7 +109,8 @@ module Druid
105
109
 
106
110
  #
107
111
  # Set the javascript framework to use when determining number of
108
- # ajax requests. Valid frameworks are :jquery, :prototype, and :Dojo
112
+ # ajax requests. Valid frameworks are :jquery, :prototype, and :yui,
113
+ # and :angularjs
109
114
  #
110
115
  def self.javascript_framework=(framework)
111
116
  Druid::JavascriptFrameworkFacade.framework = framework
@@ -135,7 +140,7 @@ module Druid
135
140
  # Returns the text of the current page
136
141
  #
137
142
  def text
138
- driver.text
143
+ root.text
139
144
  end
140
145
 
141
146
  #
@@ -205,7 +210,7 @@ module Druid
205
210
  end
206
211
 
207
212
  #
208
- # Override the normal alert popup so it does not occurr.
213
+ # Override the normal alert popup so it does not occur.
209
214
  #
210
215
  # @example
211
216
  # message = @page.alert do
@@ -228,7 +233,7 @@ module Druid
228
233
  end
229
234
 
230
235
  #
231
- # Override the normal confirm popup so it does not occurr
236
+ # Override the normal confirm popup so it does not occur
232
237
  #
233
238
  # @example
234
239
  # message = @popup.confirm(true) do
@@ -250,7 +255,7 @@ module Druid
250
255
  end
251
256
 
252
257
  #
253
- # Override the normal prompt popup so it does not occurr
258
+ # Override the normal prompt popup so it does not occur
254
259
  #
255
260
  # @example
256
261
  # message = @popup.prompt("Some Value") do
@@ -275,13 +280,14 @@ module Druid
275
280
  #
276
281
  # Execute javascript on the browser
277
282
  #
278
- def execute_script(script)
279
- driver.execute_script(script)
283
+ def execute_script(script, *args)
284
+ args.map! { |e| e.kind_of?(Druid::Elements::Element) ? e.element : e }
285
+ driver.execute_script(script, *args)
280
286
  end
281
287
 
282
288
  #
283
289
  # Attach to a running window. You can locate the window using either
284
- # the window's title or url or index, If it failes to connect to a window it will
290
+ # the window's title or url or index, If it fails to connect to a window it will
285
291
  # pause for 1 second and try again.
286
292
  #
287
293
  # @example
@@ -353,7 +359,7 @@ module Druid
353
359
  end
354
360
 
355
361
  #
356
- # Identify an element as existing within a frame or iframe. A frame parameter is
362
+ # Identify an element as existing within a frame. A frame parameter is
357
363
  # passed to the block and must be passed to the other calls to Druid.
358
364
  # You can nest calls to in_frame by passing the frame to the next level.
359
365
  #
@@ -375,9 +381,9 @@ module Druid
375
381
  end
376
382
 
377
383
  #
378
- # Identify an element as existing within a frame or iframe. A frame parameter is
384
+ # Identify an element as existing within an iframe. Aframe parameter is
379
385
  # passed to the block and must be passed to the other calls to Druid.
380
- # You can nest calls to in_frame by passing the frame to the next level.
386
+ # You can nest calls to in_iframe by passing the frame to the next level.
381
387
  #
382
388
  # @example
383
389
  # @page.in_iframe(:id => 'frame_id') do |frame|
@@ -396,18 +402,24 @@ module Druid
396
402
  block.call(frame)
397
403
  end
398
404
 
399
- # def switch_to_frame(frame_identifiers)
400
- # unless frame_identifiers.nil?
401
- # frame_identifiers.each do |frame|
402
- # frame_id = frame.values.first
403
- # value = frame_id.values.first
404
- # driver.wd.switch_to.frame(value)
405
- # end
406
- # end
407
- # end
405
+ def switch_to_frame(frame_identifiers)
406
+ unless frame_identifiers.nil?
407
+ frame_identifiers.each do |frame|
408
+ frame_id = frame.values.first
409
+ value = frame_id.values.first
410
+ driver.wd.switch_to.frame(value)
411
+ end
412
+ end
413
+ end
408
414
 
409
415
  def call_block(&block)
410
416
  block.arity == 1 ? block.call(self) : self.instance_eval(&block)
411
417
  end
412
418
 
419
+ private
420
+
421
+ def root
422
+ @root_element || driver
423
+ end
424
+
413
425
  end
@@ -37,15 +37,43 @@ module Druid
37
37
  #
38
38
  def page_url(url)
39
39
  define_method("goto") do
40
+ driver.goto self.page_url_value
41
+ end
42
+
43
+ define_method("page_url_value") do
40
44
  lookup = url.kind_of?(Symbol) ? self.send(url) : url
41
45
  erb = ERB.new(%Q{#{lookup}})
42
46
  merged_params = self.class.instance_variable_get("@merged_params")
43
47
  params = merged_params ? merged_params : self.class.params
44
- driver.goto erb.result(binding)
48
+ erb.result(binding)
45
49
  end
46
50
  end
47
51
  alias_method :direct_url, :page_url
48
52
 
53
+ #
54
+ # Creates a method that waits the expected_title of a page to match the actual.
55
+ # @param [String] expected_title the literal expected title for the page
56
+ # @param [Regexp] expected_title the expected title pattern for the page
57
+ # @param [optional, Integer] timeout default value is nil - do not wait
58
+ # @return [boolean]
59
+ # @raise An exception if expected_title does not match actual title
60
+ #
61
+ # @example Specify 'Google' as the expected title of a page
62
+ # wait_for_expected_title "Google"
63
+ # page.wait_for_expected_title?
64
+ #
65
+ def wait_for_expected_title(expected_title, timeout=Druid.default_element_wait)
66
+ define_method("wait_for_expected_title?") do
67
+ error_message = lambda { "Expected title '#{expected_title}' instead of '#{title}'" }
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
+ raise error_message.call unless has_expected_title
73
+ has_expected_title
74
+ end
75
+ end
76
+
49
77
  #
50
78
  # Creates a method that compares the expected_title of a page against the actual.
51
79
  # @param [String] expected_title the literal expected title for the page
@@ -83,6 +111,14 @@ module Druid
83
111
  end
84
112
  end
85
113
 
114
+ def expected_element_visible(element_name, timeout=Druid.default_element_wait)
115
+ define_method("has_expected_element_visible?") do
116
+ self.respond_to? "#{element_name}_element" and self.send("#{element_name}_element").when_present timeout
117
+ self.respond_to? "#{element_name}_element" and self.send("#{element_name}_element").when_visible timeout
118
+ end
119
+
120
+ end
121
+
86
122
  #
87
123
  # Identify an element as existing within a frame or iframe. A frame parameter
88
124
  # is passed to the block and must be passed to the other calls to Druid.
@@ -154,11 +190,11 @@ module Druid
154
190
  # @param optional block to be invoked when element method is called
155
191
  #
156
192
  def link(name, identifier={:index => 0}, &block)
193
+ standard_methods(name, identifier, 'link_for', &block)
157
194
  define_method(name) do
158
195
  return click_link_for identifier.clone unless block_given?
159
196
  self.send("#{name}_element").click
160
197
  end
161
- standard_methods(name, identifier, 'link_for', &block)
162
198
  end
163
199
 
164
200
  alias_method :a, :link
@@ -189,6 +225,7 @@ module Druid
189
225
  # @param optional block to be invoked when element method is called
190
226
  #
191
227
  def text_field(name, identifier={:index => 0}, &block)
228
+ standard_methods(name, identifier, 'text_field_for', &block)
192
229
  define_method(name) do
193
230
  return text_field_value_for identifier.clone unless block_given?
194
231
  self.send("#{name}_element").value
@@ -197,7 +234,6 @@ module Druid
197
234
  return text_field_value_set(identifier.clone, value) unless block_given?
198
235
  self.send("#{name}_element").value = value
199
236
  end
200
- standard_methods(name, identifier, 'text_field_for', &block)
201
237
  end
202
238
 
203
239
  #
@@ -225,6 +261,7 @@ module Druid
225
261
  # @param optional block to be invoked when element method is called
226
262
  #
227
263
  def checkbox(name, identifier={:index => 0}, &block)
264
+ standard_methods(name, identifier, 'checkbox_for', &block)
228
265
  define_method("check_#{name}") do
229
266
  return check_checkbox identifier.clone unless block_given?
230
267
  self.send("#{name}_element").check
@@ -237,7 +274,6 @@ module Druid
237
274
  return checkbox_checked? identifier.clone unless block_given?
238
275
  self.send("#{name}_element").checked?
239
276
  end
240
- standard_methods(name, identifier, 'checkbox_for', &block)
241
277
  end
242
278
 
243
279
  #
@@ -264,6 +300,7 @@ module Druid
264
300
  # @param optional block to be invoked when element method is called
265
301
  #
266
302
  def select_list(name, identifier={:index => 0}, &block)
303
+ standard_methods(name, identifier, 'select_list_for', &block)
267
304
  define_method(name) do
268
305
  return select_list_value_for identifier.clone unless block_given?
269
306
  self.send("#{name}_element").options.each {|o| return o.text if o.selected?}
@@ -276,20 +313,18 @@ module Druid
276
313
  element = self.send("#{name}_element")
277
314
  (element && element.options) ? element.options.collect(&:text) : []
278
315
  end
279
- standard_methods(name, identifier, 'select_list_for', &block)
280
316
  end
281
317
  alias_method :select, :select_list
282
318
 
283
319
  #
284
- # adds five methods - one to select, another to clear,
285
- # another to return if a radio button is selected,
286
- # another method to return a PageObject::Elements::RadioButton
320
+ # adds four methods - one to select, another to return if a radio button
321
+ # is selected, another method to return a PageObject::Elements::RadioButton
287
322
  # object representing the radio button element, and another to check
288
323
  # the radio button's existence.
289
324
  #
290
325
  # @example
291
326
  # radio_button(:north, :id => "north")
292
- # # will generate 'select_north', 'clear_north', 'north_selected?',
327
+ # # will generate 'select_north', 'north_selected?',
293
328
  # # 'north_element', and 'north?' methods
294
329
  #
295
330
  # @param [Symbol] the name used for the generated methods
@@ -306,22 +341,40 @@ module Druid
306
341
  # @param optional block to be invoked when element method is called
307
342
  #
308
343
  def radio_button(name, identifier={:index => 0}, &block)
344
+ standard_methods(name, identifier, 'radio_button_for', &block)
309
345
  define_method("select_#{name}") do
310
346
  return select_radio identifier.clone unless block_given?
311
347
  self.send("#{name}_element").select
312
348
  end
313
- define_method("clear_#{name}") do
314
- return clear_radio identifier.clone unless block_given?
315
- self.send("#{name}_element").clear
316
- end
317
349
  define_method("#{name}_selected?") do
318
350
  return radio_selected? identifier.clone unless block_given?
319
351
  self.send("#{name}_element").selected?
320
352
  end
321
- standard_methods(name, identifier, 'radio_button_for', &block)
322
353
  end
323
354
  alias_method :radio, :radio_button
324
355
 
356
+ def radio_button_group(name, identifier)
357
+ define_method("select_#{name}") do |value|
358
+ radio_buttons_for(identifier.clone).each do |radio_elem|
359
+ return radio_elem.select if radio_elem.value == value
360
+ end
361
+ end
362
+ define_method("#{name}_values") do
363
+ radio_buttons_for(identifier.clone).collect { |e| e.value}
364
+ end
365
+ define_method("#{name}_selected?") do
366
+ radio_buttons_for(identifier.clone).each do |radio_elem|
367
+ return radio_elem.value if radio_elem.selected?
368
+ end
369
+ return false
370
+ end
371
+ define_method("#{name}_elements") do
372
+ radio_buttons_for(identifier.clone)
373
+ end
374
+ define_method("#{name}?") do
375
+ radio_buttons_for(identifier.clone).any?
376
+ end
377
+ end
325
378
  #
326
379
  # adds three methods - one to click a button, another to
327
380
  # return the button element, and another to check the button's existence.
@@ -345,11 +398,11 @@ module Druid
345
398
  # @param optional block to be invoked when element method is called
346
399
  #
347
400
  def button(name, identifier={:index => 0}, &block)
401
+ standard_methods(name, identifier, 'button_for', &block)
348
402
  define_method(name) do
349
403
  return click_button_for identifier.clone unless block_given?
350
404
  self.send("#{name}_element").click
351
405
  end
352
- standard_methods(name, identifier, 'button_for', &block)
353
406
  end
354
407
 
355
408
  #
@@ -375,11 +428,11 @@ module Druid
375
428
  # @param optional block to be invoked when element method is called
376
429
  #
377
430
  def div(name, identifier={:index => 0}, &block)
431
+ standard_methods(name, identifier, 'div_for', &block)
378
432
  define_method(name) do
379
433
  return div_text_for identifier.clone unless block_given?
380
434
  self.send("#{name}_element").text
381
435
  end
382
- standard_methods(name, identifier, 'div_for', &block)
383
436
  end
384
437
 
385
438
  #
@@ -403,11 +456,11 @@ module Druid
403
456
  # @param optional block to be invoked when element method is called
404
457
  #
405
458
  def table(name, identifier={:index => 0}, &block)
459
+ standard_methods(name, identifier, 'table_for', &block)
406
460
  define_method(name) do
407
461
  return table_text_for identifier.clone unless block_given?
408
462
  self.send("#{name}_element").text
409
463
  end
410
- standard_methods(name, identifier, 'table_for', &block)
411
464
  end
412
465
 
413
466
  #
@@ -432,11 +485,11 @@ module Druid
432
485
  # @param optional block to be invoked when element method is called
433
486
  #
434
487
  def cell(name, identifier={:index => 0}, &block)
488
+ standard_methods(name, identifier, 'cell_for', &block)
435
489
  define_method(name) do
436
490
  return cell_text_for identifier.clone unless block_given?
437
491
  self.send("#{name}_element").text
438
492
  end
439
- standard_methods(name, identifier, 'cell_for', &block)
440
493
  end
441
494
  alias_method :td, :cell
442
495
 
@@ -462,11 +515,11 @@ module Druid
462
515
  # @param optional block to be invoked when element method is called
463
516
  #
464
517
  def span(name, identifier={:index => 0}, &block)
518
+ standard_methods(name, identifier, 'span_for', &block)
465
519
  define_method(name) do
466
520
  return span_text_for identifier.clone unless block_given?
467
521
  self.send("#{name}_element").text
468
522
  end
469
- standard_methods(name, identifier, 'span_for', &block)
470
523
  end
471
524
 
472
525
  #
@@ -542,11 +595,11 @@ module Druid
542
595
  # @param optional block to be invoked when element method is called
543
596
  #
544
597
  def hidden_field(name, identifier={:index => 0}, &block)
598
+ standard_methods(name, identifier, 'hidden_field_for', &block)
545
599
  define_method(name) do
546
600
  return hidden_field_value_for identifier.clone unless block_given?
547
601
  self.send("#{name}_element").value
548
602
  end
549
- standard_methods(name, identifier, 'hidden_field_for', &block)
550
603
  end
551
604
  alias_method :hidden, :hidden_field
552
605
 
@@ -572,11 +625,11 @@ module Druid
572
625
  # @param optional block to be invoked when element method is called
573
626
  #
574
627
  def list_item(name, identifier={:index => 0}, &block)
628
+ standard_methods(name, identifier, 'list_item_for', &block)
575
629
  define_method(name) do
576
630
  return list_item_text_for identifier.clone unless block_given?
577
631
  self.send("#{name}_element").text
578
632
  end
579
- standard_methods(name, identifier, 'list_item_for', &block)
580
633
  end
581
634
  alias_method :li, :list_item
582
635
 
@@ -601,11 +654,11 @@ module Druid
601
654
  # @param optional block to be invoked when element method is called
602
655
  #
603
656
  def ordered_list(name, identifier={:index => 0}, &block)
657
+ standard_methods(name, identifier, 'ordered_list_for', &block)
604
658
  define_method(name) do
605
659
  return ordered_list_text_for identifier.clone unless block_given?
606
660
  self.send("#{name}_element").text
607
661
  end
608
- standard_methods(name, identifier, 'ordered_list_for', &block)
609
662
  end
610
663
  alias_method :ol, :ordered_list
611
664
 
@@ -632,6 +685,7 @@ module Druid
632
685
  # @param optional block to be invoked when element method is called
633
686
  #
634
687
  def text_area(name, identifier={:index => 0}, &block)
688
+ standard_methods(name, identifier, 'text_area_for', &block)
635
689
  define_method("#{name}=") do |value|
636
690
  return text_area_value_set(identifier.clone, value) unless block_given?
637
691
  self.send("#{name}_element").value = value
@@ -640,7 +694,6 @@ module Druid
640
694
  return text_area_value_for identifier.clone unless block_given?
641
695
  self.send("#{name}_element").value
642
696
  end
643
- standard_methods(name, identifier, 'text_area_for', &block)
644
697
  end
645
698
  alias_method :textarea, :text_area
646
699
 
@@ -663,11 +716,11 @@ module Druid
663
716
  # * :css
664
717
  # @param optional block to be invoked when element method is called
665
718
  def unordered_list(name, identifier={:index => 0}, &block)
719
+ standard_methods(name, identifier, 'unordered_list_for', &block)
666
720
  define_method(name) do
667
721
  return unordered_list_text_for identifier.clone unless block_given?
668
722
  self.send("#{name}_element").text
669
723
  end
670
- standard_methods(name, identifier, 'unordered_list_for', &block)
671
724
  end
672
725
  alias_method :ul, :unordered_list
673
726
 
@@ -691,11 +744,11 @@ module Druid
691
744
  # @param optional block to be invoked when element method is called
692
745
  #
693
746
  def h1(name, identifier={:index => 0}, &block)
747
+ standard_methods(name, identifier, 'h1_for', &block)
694
748
  define_method(name) do
695
749
  return h1_text_for identifier.clone unless block_given?
696
750
  self.send("#{name}_element").text
697
751
  end
698
- standard_methods(name, identifier, 'h1_for', &block)
699
752
  end
700
753
 
701
754
  #
@@ -718,11 +771,11 @@ module Druid
718
771
  # @param optional block to be invoked when element method is called
719
772
  #
720
773
  def h2(name, identifier={:index => 0}, &block)
774
+ standard_methods(name, identifier, 'h2_for', &block)
721
775
  define_method(name) do
722
776
  return h2_text_for identifier.clone unless block_given?
723
777
  self.send("#{name}_element").text
724
778
  end
725
- standard_methods(name, identifier, 'h2_for', &block)
726
779
  end
727
780
 
728
781
  #
@@ -745,11 +798,11 @@ module Druid
745
798
  # @param optional block to be invoked when element method is called
746
799
  #
747
800
  def h3(name, identifier={:index => 0}, &block)
801
+ standard_methods(name, identifier, 'h3_for', &block)
748
802
  define_method(name) do
749
803
  return h3_text_for identifier.clone unless block_given?
750
804
  self.send("#{name}_element").text
751
805
  end
752
- standard_methods(name, identifier, 'h3_for', &block)
753
806
  end
754
807
 
755
808
  #
@@ -772,11 +825,11 @@ module Druid
772
825
  # @param optional block to be invoked when element method is called
773
826
  #
774
827
  def h4(name, identifier={:index => 0}, &block)
828
+ standard_methods(name, identifier, 'h4_for', &block)
775
829
  define_method(name) do
776
830
  return h4_text_for identifier.clone unless block_given?
777
831
  self.send("#{name}_element").text
778
832
  end
779
- standard_methods(name, identifier, 'h4_for', &block)
780
833
  end
781
834
 
782
835
  #
@@ -799,11 +852,11 @@ module Druid
799
852
  # @param optional block to be invoked when element method is called
800
853
  #
801
854
  def h5(name, identifier={:index => 0}, &block)
855
+ standard_methods(name, identifier, 'h5_for', &block)
802
856
  define_method(name) do
803
857
  return h5_text_for identifier.clone unless block_given?
804
858
  self.send("#{name}_element").text
805
859
  end
806
- standard_methods(name, identifier, 'h5_for', &block)
807
860
  end
808
861
 
809
862
  #
@@ -826,11 +879,11 @@ module Druid
826
879
  # @param optional block to be invoked when element method is called
827
880
  #
828
881
  def h6(name, identifier={:index => 0}, &block)
882
+ standard_methods(name, identifier, 'h6_for', &block)
829
883
  define_method(name) do
830
884
  return h6_text_for identifier.clone unless block_given?
831
885
  self.send("#{name}_element").text
832
886
  end
833
- standard_methods(name, identifier, 'h6_for', &block)
834
887
  end
835
888
 
836
889
  #
@@ -853,11 +906,11 @@ module Druid
853
906
  # @param optional block to be invoked when element method is called
854
907
  #
855
908
  def paragraph(name, identifier={:index => 0}, &block)
909
+ standard_methods(name, identifier, 'paragraph_for', &block)
856
910
  define_method(name) do
857
911
  return paragraph_text_for identifier.clone unless block_given?
858
912
  self.send("#{name}_element").text
859
913
  end
860
- standard_methods(name, identifier, 'paragraph_for', &block)
861
914
  end
862
915
  alias_method :p, :paragraph
863
916
 
@@ -883,11 +936,11 @@ module Druid
883
936
  # @param optional block to be invoked when element method is called
884
937
  #
885
938
  def file_field(name, identifier={:index => 0}, &block)
939
+ standard_methods(name, identifier, 'file_field_for', &block)
886
940
  define_method("#{name}=") do |value|
887
941
  return file_field_value_set(identifier.clone, value) unless block_given?
888
942
  self.send("#{name}_element").value = value
889
943
  end
890
- standard_methods(name, identifier, 'file_field_for', &block)
891
944
  end
892
945
 
893
946
  #
@@ -911,11 +964,11 @@ module Druid
911
964
  # @param optional block to be invoked when element method is called
912
965
  #
913
966
  def label(name, identifier={:index => 0}, &block)
967
+ standard_methods(name, identifier, 'label_for', &block)
914
968
  define_method(name) do
915
969
  return label_text_for identifier.clone unless block_given?
916
970
  self.send("#{name}_element").text
917
971
  end
918
- standard_methods(name, identifier, 'label_for', &block)
919
972
  end
920
973
 
921
974
  #
@@ -939,11 +992,11 @@ module Druid
939
992
  # @param optional block to be invoked when element method is called
940
993
  #
941
994
  def area(name, identifier={:index => 0}, &block)
995
+ standard_methods(name, identifier, 'area_for', &block)
942
996
  define_method(name) do
943
997
  return click_area_for identifier.clone unless block_given?
944
998
  self.send("#{name}_element").click
945
999
  end
946
- standard_methods(name, identifier, 'area_for', &block)
947
1000
  end
948
1001
 
949
1002
  #
@@ -1015,6 +1068,56 @@ module Druid
1015
1068
  standard_methods(name, identifier, 'video_for', &block)
1016
1069
  end
1017
1070
 
1071
+ #
1072
+ # adds three methods - one to retrieve the text of a b element, another to
1073
+ # retrieve a b element, and another to check for it's existence.
1074
+ #
1075
+ # @example
1076
+ # b(:blod, :id => 'title')
1077
+ # # will generate 'bold', 'bold_element', 'bold?' methods
1078
+ #
1079
+ # @param [Symbol] the name used for the generated methods
1080
+ # @param [Hash] identifier how we find a b, You can use a multiple parameters
1081
+ # by combining of any of the following except xpath. The valid keys are:
1082
+ # * :class
1083
+ # * :css
1084
+ # * :id
1085
+ # * :index
1086
+ # * :name
1087
+ # * :xpath
1088
+ # @param optional block to be invoked when element method is called
1089
+ #
1090
+ def b(name, identifier={:index => 0}, &block)
1091
+ standard_methods(name, identifier, 'b_for', &block)
1092
+ define_method(name) do
1093
+ return b_text_for identifier.clone unless block_given?
1094
+ self.send("#{name}_element").text
1095
+ end
1096
+ end
1097
+
1098
+ #
1099
+ # adds two methods - one to retrieve a svg, and another to check
1100
+ # svg's existence.
1101
+ #
1102
+ # @example
1103
+ # svg(:circle, :id => 'circle')
1104
+ # # will generate 'circle_element', and 'circle?' methods
1105
+ #
1106
+ # @param [Symbol] the name used for the generated methods
1107
+ # @param [Hash] identifier how we find a svg. You can use a multiple parameters
1108
+ # by combining of any of the following except xpath. The valid keys are:
1109
+ # * :class
1110
+ # * :css
1111
+ # * :id
1112
+ # * :index
1113
+ # * :name
1114
+ # * :xpath
1115
+ # @param optional block to be invoked when element method is called
1116
+ #
1117
+ def svg(name, identifier={:index => 0}, &block)
1118
+ standard_methods(name, identifier, 'svg_for', &block)
1119
+ end
1120
+
1018
1121
  #
1019
1122
  # adds three methods - one to retrieve the text an element, another
1020
1123
  # to retrieve an element, and another to check the element's existence.
@@ -1074,16 +1177,27 @@ module Druid
1074
1177
  end
1075
1178
  end
1076
1179
 
1180
+ def standard_methods(name, identifier, method, &block)
1181
+ define_method("#{name}_element") do
1182
+ return call_block(&block) if block_given?
1183
+ self.send(method, identifier.clone)
1184
+ end
1185
+ define_method("#{name}?") do
1186
+ return call_block(&block).exist? if block_given?
1187
+ self.send(method, identifier.clone).exist?
1188
+ end
1189
+ end
1190
+
1077
1191
  #
1078
- # adds two methods - one to retrieve a svg, and another to check
1079
- # svg's existence.
1192
+ # adds a method to return a page object rooted at the element
1080
1193
  #
1081
1194
  # @example
1082
- # svg(:circle, :id => 'circle')
1083
- # # will generate 'circle_element', and 'circle?' methods
1195
+ # page_section(:navigation_bar, NavigationBar, :id => 'nav-bar')
1196
+ # # will generate 'navigation_bar'
1084
1197
  #
1085
1198
  # @param [Symbol] the name used for the generated methods
1086
- # @param [Hash] identifier how we find a svg. You can use a multiple parameters
1199
+ # @param [Class] the class to instantiate for the element
1200
+ # @param [Hash] identifier how we find an element. You can use multiple parameters
1087
1201
  # by combining of any of the following except xpath. The valid keys are:
1088
1202
  # * :class
1089
1203
  # * :css
@@ -1091,10 +1205,35 @@ module Druid
1091
1205
  # * :index
1092
1206
  # * :name
1093
1207
  # * :xpath
1094
- # @param optional block to be invoked when element method is called
1095
1208
  #
1096
- def svg(name, identifier={:index => 0}, &block)
1097
- standard_methods(name, identifier, 'svg_for', &block)
1209
+ def page_section(name, section_class, identifier)
1210
+ define_method(name) do
1211
+ page_for(identifier, section_class)
1212
+ end
1213
+ end
1214
+
1215
+ #
1216
+ # adds a method to return a collection of page objects rooted at elements
1217
+ #
1218
+ # @example
1219
+ # page_sections(:articles, Article, :class => 'article')
1220
+ # # will generate 'articles'
1221
+ #
1222
+ # @param [Symbol] the name used for the generated method
1223
+ # @param [Class] the class to instantiate for each element
1224
+ # @param [Hash] identifier how we find an element. You can use a multiple parameters
1225
+ # by combining of any of the following except xpath. The valid keys are:
1226
+ # * :class
1227
+ # * :css
1228
+ # * :id
1229
+ # * :index
1230
+ # * :name
1231
+ # * :xpath
1232
+ #
1233
+ def page_sections(name, section_class, identifier)
1234
+ define_method(name) do
1235
+ pages_for(identifier, section_class)
1236
+ end
1098
1237
  end
1099
1238
 
1100
1239
  #
@@ -1117,22 +1256,16 @@ module Druid
1117
1256
  # * :xpath
1118
1257
  # @param optional block to be invoked when element method is called
1119
1258
  #
1120
- LocatorGenerator::BASIC_ELEMENTS.each do |type|
1121
- define_method(type) do |name, *identifier, &block|
1259
+ LocatorGenerator::BASIC_ELEMENTS.each do |tag|
1260
+ define_method(tag) do |name, *identifier, &block|
1122
1261
  identifier = identifier[0] ? identifier[0] : {:index => 0}
1123
- element(name, type, identifier, &block)
1262
+ element(name, tag, identifier, &block)
1124
1263
  end
1125
- end
1126
1264
 
1127
- def standard_methods(name, identifier, method, &block)
1128
- define_method("#{name}_element") do
1129
- return call_block(&block) if block_given?
1130
- self.send(method, identifier.clone)
1131
- end
1132
- define_method("#{name}?") do
1133
- return call_block(&block).exist? if block_given?
1134
- self.send(method, identifier.clone).exist?
1135
- end
1265
+ define_method("#{tag}s") do |name, *identifier, &block|
1266
+ identifier = identifier[0] ? identifier[0] : {:index => 0}
1267
+ elements(name, tag, identifier, &block)
1268
+ end unless tag == :param
1136
1269
  end
1137
1270
 
1138
1271
  #