page-object 0.7.6 → 0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,3 +17,7 @@ end
17
17
  Then /^I should see that the ordered list exists$/ do
18
18
  @page.ol_id?.should == true
19
19
  end
20
+
21
+ Then /^the text for the ordered list should contain "(.*)"$/ do |text|
22
+ @page.send("ol_id").should include text
23
+ end
@@ -55,3 +55,7 @@ end
55
55
  Then /^the data for row "([^\"]*)" and column "([^\"]*)" should be nil$/ do |row, column|
56
56
  @element[row][column].should be_nil
57
57
  end
58
+
59
+ Then /^I should see the text includes "([^"]*)" when I retrieve it by "([^"]*)"$/ do |text, how|
60
+ @page.send("table_#{how}").should include text
61
+ end
@@ -16,4 +16,8 @@ end
16
16
 
17
17
  Then /^I should see that the unordered list exists$/ do
18
18
  @page.ul_id?.should == true
19
- end
19
+ end
20
+
21
+ Then /^the text for the unordered list should contain "(.*)"$/ do |text|
22
+ @page.send("ul_id").should include text
23
+ end
@@ -111,3 +111,7 @@ Feature: Table
111
111
  @watir_only
112
112
  Scenario: Finding an existing table
113
113
  Then I should see that the table exists
114
+
115
+ Scenario: Getting the text from a table
116
+ Then I should see the text includes "Data1" when I retrieve it by "id"
117
+ And I should see the text includes "Data2" when I retrieve it by "id"
@@ -49,3 +49,8 @@ Feature: Unordered list
49
49
  Then I should see that the unordered list exists
50
50
  When I get the first item from the list
51
51
  Then the list items text should be "Item One"
52
+
53
+ Scenario: Getting the text from an unordered list
54
+ Then the text for the unordered list should contain "Item One"
55
+ And the text for the unordered list should contain "Item Two"
56
+ And the text for the unordered list should contain "Item Three"
data/lib/page-object.rb CHANGED
@@ -7,6 +7,7 @@ require 'page-object/page_factory'
7
7
  require 'page-object/page_populator'
8
8
  require 'page-object/javascript_framework_facade'
9
9
  require 'page-object/indexed_properties'
10
+ require 'page-object/widgets'
10
11
 
11
12
  require 'selenium/webdriver/common/error'
12
13
  #
@@ -41,7 +42,7 @@ module PageObject
41
42
  include LoadsPlatform
42
43
  include ElementLocators
43
44
  include PagePopulator
44
-
45
+
45
46
  # @return [Watir::Browser or Selenium::WebDriver::Driver] the platform browser passed to the constructor
46
47
  attr_reader :browser
47
48
  # @return [PageObject::WatirPageObject or PageObject::SeleniumPageObject] the platform page object
@@ -251,7 +252,7 @@ module PageObject
251
252
  def execute_script(script)
252
253
  platform.execute_script(script)
253
254
  end
254
-
255
+
255
256
  #
256
257
  # Identify an element as existing within a frame or iframe. A frame parameter
257
258
  # is passed to the block and must be passed to the other calls to PageObject.
@@ -287,7 +288,7 @@ module PageObject
287
288
  #
288
289
  def modal_dialog(&block)
289
290
  script =
290
- %Q{
291
+ %Q{
291
292
  window.showModalDialog = function(sURL, vArguments, sFeatures) {
292
293
  window.dialogArguments = vArguments;
293
294
  modalWin = window.open(sURL, 'modal', sFeatures);
@@ -297,7 +298,7 @@ module PageObject
297
298
  browser.execute_script script
298
299
  yield if block_given?
299
300
  end
300
-
301
+
301
302
  #
302
303
  # Attach to a running window. You can locate the window using either
303
304
  # the window's title or url. If it failes to connect to a window it will
@@ -326,35 +327,35 @@ module PageObject
326
327
  def element_with_focus
327
328
  platform.element_with_focus
328
329
  end
329
-
330
+
330
331
  #
331
332
  # Refresh to current page
332
333
  #
333
334
  def refresh
334
335
  platform.refresh
335
336
  end
336
-
337
+
337
338
  #
338
339
  # Go back to the previous page
339
340
  #
340
341
  def back
341
342
  platform.back
342
343
  end
343
-
344
+
344
345
  #
345
346
  # Go forward to the next page
346
347
  #
347
348
  def forward
348
349
  platform.forward
349
350
  end
350
-
351
+
351
352
  #
352
353
  # Clear the cookies from the browser
353
354
  #
354
355
  def clear_cookies
355
356
  platform.clear_cookies
356
357
  end
357
-
358
+
358
359
  #
359
360
  # Save the current screenshot to the provided url. File
360
361
  # is saved as a png file.
@@ -363,13 +364,17 @@ module PageObject
363
364
  platform.save_screenshot file_name
364
365
  end
365
366
 
367
+ def self.register_widget(widget_tag, widget_class, base_element_tag)
368
+ Widgets.register_widget(widget_tag, widget_class, base_element_tag)
369
+ end
370
+
366
371
  private
367
372
 
368
373
  def include_platform_driver(browser)
369
374
  @platform = load_platform(browser, PageObject::Platforms.get)
370
375
  end
371
-
376
+
372
377
  def call_block(&block)
373
- block.arity == 1 ? block.call(self) : self.instance_eval(&block)
378
+ block.arity == 1 ? block.call(self) : self.instance_eval(&block)
374
379
  end
375
380
  end
@@ -528,13 +528,14 @@ module PageObject
528
528
  end
529
529
 
530
530
  #
531
- # adds two methods - one to retrieve the table element, and another to
531
+ # adds three methods - one to return the text for the table, one
532
+ # to retrieve the table element, and another to
532
533
  # check the table's existence. The existence method does not work
533
534
  # on Selenium so it should not be called.
534
535
  #
535
536
  # @example
536
537
  # table(:cart, :id => 'shopping_cart')
537
- # # will generate a 'cart_element' and 'cart?' method
538
+ # # will generate a 'cart', 'cart_element' and 'cart?' method
538
539
  #
539
540
  # @param [Symbol] the name used for the generated methods
540
541
  # @param [Hash] identifier how we find a table. You can use a multiple paramaters
@@ -548,6 +549,10 @@ module PageObject
548
549
  # @param optional block to be invoked when element method is called
549
550
  #
550
551
  def table(name, identifier={:index => 0}, &block)
552
+ define_method(name) do
553
+ return platform.table_text_for identifier.clone unless block_given?
554
+ self.send("#{name}_element").text
555
+ end
551
556
  define_method("#{name}_element") do
552
557
  return call_block(&block) if block_given?
553
558
  platform.table_for(identifier.clone)
@@ -701,12 +706,13 @@ module PageObject
701
706
  alias_method :li, :list_item
702
707
 
703
708
  #
704
- # adds two methods - one to retrieve the unordered list element, and another to
709
+ # adds three methods - one to return the text within the unorderd
710
+ # list, one to retrieve the unordered list element, and another to
705
711
  # check it's existence.
706
712
  #
707
713
  # @example
708
714
  # unordered_list(:menu, :id => 'main_menu')
709
- # # will generate 'menu_element' and 'menu?' methods
715
+ # # will generate 'menu', 'menu_element' and 'menu?' methods
710
716
  #
711
717
  # @param [Symbol] the name used for the generated methods
712
718
  # @param [Hash] identifier how we find an unordered list. You can use a multiple paramaters
@@ -720,6 +726,10 @@ module PageObject
720
726
  # @param optional block to be invoked when element method is called
721
727
  #
722
728
  def unordered_list(name, identifier={:index => 0}, &block)
729
+ define_method(name) do
730
+ return platform.unordered_list_text_for identifier.clone unless block_given?
731
+ self.send("#{name}_element").text
732
+ end
723
733
  define_method("#{name}_element") do
724
734
  return call_block(&block) if block_given?
725
735
  platform.unordered_list_for(identifier.clone)
@@ -733,12 +743,13 @@ module PageObject
733
743
  alias_method :ul, :unordered_list
734
744
 
735
745
  #
736
- # adds two methods - one to retrieve the ordered list element, and another to
746
+ # adds three methods - one to return the text withing the ordered
747
+ # list, one to retrieve the ordered list element, and another to
737
748
  # test it's existence.
738
749
  #
739
750
  # @example
740
751
  # ordered_list(:top_five, :id => 'top')
741
- # # will generate 'top_five_element' and 'top_five?' methods
752
+ # # will generate 'top_five', 'top_five_element' and 'top_five?' methods
742
753
  #
743
754
  # @param [Symbol] the name used for the generated methods
744
755
  # @param [Hash] identifier how we find an ordered list. You can use a multiple paramaters
@@ -752,6 +763,10 @@ module PageObject
752
763
  # @param optional block to be invoked when element method is called
753
764
  #
754
765
  def ordered_list(name, identifier={:index => 0}, &block)
766
+ define_method(name) do
767
+ return platform.ordered_list_text_for identifier.clone unless block_given?
768
+ self.send("#{name}_element").text
769
+ end
755
770
  define_method("#{name}_element") do
756
771
  return call_block(&block) if block_given?
757
772
  platform.ordered_list_for(identifier.clone)
@@ -1981,5 +1996,55 @@ module PageObject
1981
1996
  IndexedProperties::TableOfElements.new(@browser, identifier_list)
1982
1997
  end
1983
1998
  end
1999
+
2000
+ #
2001
+ # methods to fetch multiple elements of the same type
2002
+ #
2003
+ # adds a method to the page object to retrun all of the matching elements
2004
+ #
2005
+ # @example
2006
+ # text_fields(:first_name, :id => "first_name")
2007
+ # # will generate 'first_name_elements'
2008
+ #
2009
+ # @param [String] the name used for the generated methods
2010
+ # @param [Hash] identifier how we find a text field. You can use a multiple paramaters
2011
+ # by combining of any of the following except xpath. The valid
2012
+ # keys are the same ones supported by the standard methods.
2013
+ # @param optional block to be invoked when element method is called
2014
+ #
2015
+ [:text_fields,
2016
+ :hidden_fields,
2017
+ :text_areas,
2018
+ :select_lists,
2019
+ :links,
2020
+ :checkboxes,
2021
+ :radio_buttons,
2022
+ :buttons,
2023
+ :divs,
2024
+ :spans,
2025
+ :tables,
2026
+ :cells,
2027
+ :images,
2028
+ :forms,
2029
+ :list_items,
2030
+ :unordered_lists,
2031
+ :ordered_lists,
2032
+ :h1s,
2033
+ :h2s,
2034
+ :h3s,
2035
+ :h4s,
2036
+ :h5s,
2037
+ :h6s,
2038
+ :paragraphs,
2039
+ :labels,
2040
+ :file_fields].each do |method_name|
2041
+ define_method(method_name) do |name, identifier, &block|
2042
+ define_method("#{name}_elements") do
2043
+ return call_block(&block) if block_given?
2044
+ platform.send "#{method_name.to_s}_for", identifier.clone
2045
+ end
2046
+ end
2047
+ end
2048
+
1984
2049
  end
1985
2050
  end
@@ -44,6 +44,16 @@ module PageObject
44
44
  element.text
45
45
  end
46
46
 
47
+ #
48
+ # Get the html for the element
49
+ #
50
+ # @return [String]
51
+ #
52
+ def html
53
+ script = "return (%s).apply(null, arguments)" % ATOMS.fetch(:getOuterHtml)
54
+ bridge.executeScript(script, element).strip
55
+ end
56
+
47
57
  #
48
58
  # Get the value of this element
49
59
  #
@@ -525,6 +525,16 @@ module PageObject
525
525
  find_selenium_elements(identifier, Elements::Button, 'input', :type => 'submit')
526
526
  end
527
527
 
528
+ #
529
+ # platform method to return the text for a table
530
+ # See PageObject::Accessors#table
531
+ #
532
+ def table_text_for(identifier)
533
+ process_selenium_call(identifier, Elements::Table, 'table') do |how, what|
534
+ @browser.find_element(how, what).text
535
+ end
536
+ end
537
+
528
538
  #
529
539
  # platform method to retrieve a table element
530
540
  # See PageObject::Accessors#table
@@ -620,6 +630,16 @@ module PageObject
620
630
  find_selenium_elements(identifier, Elements::ListItem, 'li')
621
631
  end
622
632
 
633
+ #
634
+ # platform method to retrieve the text from an unordered list
635
+ # See PageObject::Accessors#unordered_list
636
+ #
637
+ def unordered_list_text_for(identifier)
638
+ process_selenium_call(identifier, Elements::UnorderedList, 'ul') do |how, what|
639
+ @browser.find_element(how, what).text
640
+ end
641
+ end
642
+
623
643
  #
624
644
  # platform method to retrieve an unordered list element
625
645
  # See PageObject::Accessors#unordered_list
@@ -635,6 +655,16 @@ module PageObject
635
655
  find_selenium_elements(identifier, Elements::UnorderedList, 'ul')
636
656
  end
637
657
 
658
+ #
659
+ # platform method to retrieve the text from an ordered list
660
+ # See PageObject::Accessors#ordered_list
661
+ #
662
+ def ordered_list_text_for(identifier)
663
+ process_selenium_call(identifier, Elements::OrderedList, 'ol') do |how, what|
664
+ @browser.find_element(how, what).text
665
+ end
666
+ end
667
+
638
668
  #
639
669
  # platform method to retrieve an ordered list element
640
670
  # See PageObject::Accessors#ordered_list
@@ -36,6 +36,15 @@ module PageObject
36
36
  element.text
37
37
  end
38
38
 
39
+ #
40
+ # Get the html for the element
41
+ #
42
+ # @return [String]
43
+ #
44
+ def html
45
+ element.html
46
+ end
47
+
39
48
  #
40
49
  # Get the value of this element
41
50
  #
@@ -481,6 +481,14 @@ module PageObject
481
481
  find_watir_elements(call, Elements::Button, identifier)
482
482
  end
483
483
 
484
+ #
485
+ # platform method to return the text for a table
486
+ # See PageObject::Accessors#table
487
+ #
488
+ def table_text_for(identifier)
489
+ process_watir_call("table(identifier).text", Elements::Table, identifier, nil, 'table')
490
+ end
491
+
484
492
  #
485
493
  # platform method to retrieve a table element
486
494
  # See PageObject::Accessors#table
@@ -573,6 +581,14 @@ module PageObject
573
581
  find_watir_elements("lis(identifier)", Elements::ListItem, identifier, 'li')
574
582
  end
575
583
 
584
+ #
585
+ # platform method to retrieve the text from an unordered list
586
+ # See PageObject::Accessors#unordered_list
587
+ #
588
+ def unordered_list_text_for(identifier)
589
+ process_watir_call("ul(identifier).text", Elements::UnorderedList, identifier, nil, 'ul')
590
+ end
591
+
576
592
  #
577
593
  # platform method to retrieve an unordered list element
578
594
  # See PageObject::Accessors#unordered_list
@@ -588,6 +604,14 @@ module PageObject
588
604
  find_watir_elements("uls(identifier)", Elements::UnorderedList, identifier, 'ul')
589
605
  end
590
606
 
607
+ #
608
+ # platform method to retrieve the text from an ordered list
609
+ # See PageObject::Accessors#ordered_list
610
+ #
611
+ def ordered_list_text_for(identifier)
612
+ process_watir_call("ol(identifier).text", Elements::OrderedList, identifier, nil, 'ol')
613
+ end
614
+
591
615
  #
592
616
  # platform method to retrieve an ordered list element
593
617
  # See PageObject::Accessors#ordered_list
@@ -1,4 +1,4 @@
1
1
  module PageObject
2
2
  # @private
3
- VERSION = "0.7.6"
3
+ VERSION = "0.8"
4
4
  end
@@ -0,0 +1,120 @@
1
+ require 'page-object/elements'
2
+ require 'page-object/platforms/selenium_webdriver/page_object'
3
+ require 'page-object/platforms/watir_webdriver/page_object'
4
+
5
+ module PageObject
6
+ module Widgets
7
+
8
+ #
9
+ # Module that allows for the registration of widget classes which extend the functionality of PageObject
10
+ # Allows any classes which extend PageObject::Element to be used as PageObject elements.
11
+ # This allows such widgets to be created using the defined tags.
12
+ #
13
+ # @param [Symbol] defines the symbol which will be used as an accessor name.
14
+ # @param [Class] the widget class extending PageObject::Elements::Element
15
+ # @param [Symbol] the symbol of the html element used when searching for this widget.
16
+ #
17
+ #
18
+ def self.register_widget(widget_tag, widget_class, base_element_tag)
19
+ if widget_class.ancestors.include? Elements::Element
20
+ define_accessors(Accessors, widget_tag)
21
+ define_nested_elements(Elements::Element, widget_tag)
22
+ define_locators(PageObject, widget_tag)
23
+ define_selenium_accessors(Platforms::SeleniumWebDriver::PageObject, widget_tag, widget_class, base_element_tag)
24
+ define_watir_accessors(Platforms::WatirWebDriver::PageObject, widget_tag, widget_class, base_element_tag)
25
+ end
26
+ end
27
+
28
+ @private
29
+
30
+ def self.define_accessors(base, widget_tag)
31
+ accessors_module = Module.new do
32
+ class_eval "def #{widget_tag}(name, identifier={}, &block)
33
+ identifier={:index=>0} if identifier.empty?
34
+ define_method(\"\#{name}_element\") do
35
+ return call_block(&block) if block_given?
36
+ platform.#{widget_tag}_for(identifier.clone)
37
+ end
38
+ define_method(\"\#{name}?\") do
39
+ return call_block(&block).exists? if block_given?
40
+ platform.#{widget_tag}_for(identifier.clone).exists?
41
+ end
42
+ end"
43
+ end
44
+
45
+ base.send(:include, accessors_module)
46
+ end
47
+
48
+ def self.define_watir_accessors(base, widget_tag, widget_class, base_element_tag)
49
+ define_singular_watir_accessor(base, base_element_tag, widget_class, widget_tag)
50
+ define_multiple_watir_accessor(base, base_element_tag, widget_class, widget_tag)
51
+ end
52
+
53
+ def self.define_multiple_watir_accessor(base, base_element_tag, widget_class, widget_tag)
54
+ base.send(:define_method, "#{widget_tag}s_for") do |identifier|
55
+ find_watir_elements("#{base_element_tag}(identifier)", widget_class, identifier, base_element_tag)
56
+ end
57
+ end
58
+
59
+ def self.define_singular_watir_accessor(base, base_element_tag, widget_class, widget_tag)
60
+ base.send(:define_method, "#{widget_tag}_for") do |identifier|
61
+ find_watir_element("#{base_element_tag}(identifier)", widget_class, identifier, base_element_tag)
62
+ end
63
+ end
64
+
65
+ def self.define_selenium_accessors(base, widget_tag, widget_class, base_element_tag)
66
+ define_singular_selenium_accessor(base, base_element_tag, widget_class, widget_tag)
67
+ define_multiple_selenium_accessor(base, base_element_tag, widget_class, widget_tag)
68
+ end
69
+
70
+ def self.define_multiple_selenium_accessor(base, base_element_tag, widget_class, widget_tag)
71
+ base.send(:define_method, "#{widget_tag}s_for") do |identifier|
72
+ find_selenium_elements(identifier, widget_class, base_element_tag)
73
+ end
74
+ end
75
+
76
+ def self.define_singular_selenium_accessor(base, base_element_tag, widget_class, widget_tag)
77
+ base.send(:define_method, "#{widget_tag}_for") do |identifier|
78
+ find_selenium_element(identifier, widget_class, base_element_tag)
79
+ end
80
+ end
81
+
82
+ def self.define_nested_elements(base, widget_tag)
83
+ define_singular_nested_accessor(base, widget_tag)
84
+ define_multiple_nested_accessor(base, widget_tag)
85
+ end
86
+
87
+ def self.define_multiple_nested_accessor(base, widget_tag)
88
+ base.send(:define_method, "#{widget_tag}_elements") do |*args|
89
+ identifier = args[0] ? args[0] : {:index => 0}
90
+ @platform.send("#{widget_tag}s_for", identifier.clone)
91
+ end
92
+ end
93
+
94
+ def self.define_singular_nested_accessor(base, widget_tag)
95
+ base.send(:define_method, "#{widget_tag}_element") do |*args|
96
+ identifier = args[0] ? args[0] : {:index => 0}
97
+ @platform.send("#{widget_tag}_for", identifier.clone)
98
+ end
99
+ end
100
+
101
+ def self.define_locators(base, widget_tag)
102
+ define_singular_locator(base, widget_tag)
103
+ define_multiple_locator(base, widget_tag)
104
+ end
105
+
106
+ def self.define_multiple_locator(base, widget_tag)
107
+ base.send(:define_method, "#{widget_tag}_elements") do |*args|
108
+ identifier = args[0] ? args[0] : {}
109
+ platform.send("#{widget_tag}s_for", identifier.clone)
110
+ end
111
+ end
112
+
113
+ def self.define_singular_locator(base, widget_tag)
114
+ base.send(:define_method, "#{widget_tag}_element") do |*args|
115
+ identifier = args[0] ? args[0] : {:index => 0}
116
+ platform.send("#{widget_tag}_for", identifier.clone)
117
+ end
118
+ end
119
+ end
120
+ end