page-object 1.0.3 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +10 -0
  3. data/features/button.feature +13 -3
  4. data/features/html/indexed_property.html +3 -0
  5. data/features/html/static_elements.html +2 -0
  6. data/features/indexed_property.feature +20 -1
  7. data/features/section.feature +132 -0
  8. data/features/step_definitions/accessor_steps.rb +4 -0
  9. data/features/step_definitions/button_steps.rb +5 -0
  10. data/features/step_definitions/indexed_property_steps.rb +36 -2
  11. data/features/step_definitions/section_steps.rb +268 -0
  12. data/lib/page-object.rb +19 -7
  13. data/lib/page-object/accessors.rb +48 -0
  14. data/lib/page-object/elements/element.rb +4 -4
  15. data/lib/page-object/indexed_properties.rb +7 -3
  16. data/lib/page-object/loads_platform.rb +24 -5
  17. data/lib/page-object/platforms/selenium_webdriver.rb +14 -2
  18. data/lib/page-object/platforms/selenium_webdriver/button.rb +3 -3
  19. data/lib/page-object/platforms/selenium_webdriver/element.rb +1 -1
  20. data/lib/page-object/platforms/selenium_webdriver/page_object.rb +50 -0
  21. data/lib/page-object/platforms/watir_webdriver.rb +15 -3
  22. data/lib/page-object/platforms/watir_webdriver/element.rb +1 -1
  23. data/lib/page-object/platforms/watir_webdriver/page_object.rb +30 -0
  24. data/lib/page-object/sections.rb +29 -0
  25. data/lib/page-object/version.rb +1 -1
  26. data/page-object.gemspec +3 -3
  27. data/spec/page-object/elements/button_spec.rb +14 -0
  28. data/spec/page-object/elements/selenium_element_spec.rb +5 -0
  29. data/spec/page-object/elements/watir_element_spec.rb +4 -0
  30. data/spec/page-object/loads_platform_spec.rb +3 -3
  31. data/spec/page-object/page-object_spec.rb +1 -0
  32. data/spec/page-object/page_section_spec.rb +73 -0
  33. data/spec/spec_helper.rb +3 -1
  34. metadata +15 -6
data/lib/page-object.rb CHANGED
@@ -7,8 +7,15 @@ 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/sections'
10
11
  require 'page-object/widgets'
11
12
 
13
+ require 'watir-webdriver'
14
+ require 'page-object/platforms/watir_webdriver/element'
15
+ require 'page-object/platforms/watir_webdriver/page_object'
16
+ require 'page-object/platforms/selenium_webdriver/element'
17
+ require 'page-object/platforms/selenium_webdriver/page_object'
18
+
12
19
  require 'selenium/webdriver/common/error'
13
20
  #
14
21
  # Module that when included adds functionality to a page object. This module
@@ -53,19 +60,20 @@ module PageObject
53
60
  # a method named initialize_accessors if it exists. Upon initialization of
54
61
  # the page it will call a method named initialize_page if it exists.
55
62
  #
56
- # @param [Watir::Browser or Selenium::WebDriver::Driver] the platform browser to use
63
+ # @param [Watir::Browser, Watir::HTMLElement or Selenium::WebDriver::Driver, Selenium::WebDriver::Element] the platform browser/element to use
57
64
  # @param [bool] open the page if page_url is set
58
65
  #
59
- def initialize(browser, visit=false)
66
+ def initialize(root, visit=false)
60
67
  initialize_accessors if respond_to?(:initialize_accessors)
61
- initialize_browser(browser)
68
+ initialize_browser(root)
62
69
  goto if visit && respond_to?(:goto)
63
70
  initialize_page if respond_to?(:initialize_page)
64
71
  end
65
72
 
66
- def initialize_browser(browser)
67
- @browser = browser
68
- include_platform_driver(browser)
73
+ def initialize_browser(root)
74
+ @root_element = root_element_for root, PageObject::Platforms.get
75
+ @browser = browser_for root, PageObject::Platforms.get
76
+ include_platform_driver(root)
69
77
  end
70
78
 
71
79
  # @private
@@ -144,7 +152,7 @@ module PageObject
144
152
  # Returns the text of the current page
145
153
  #
146
154
  def text
147
- platform.text
155
+ root.text
148
156
  end
149
157
 
150
158
  #
@@ -399,6 +407,10 @@ module PageObject
399
407
 
400
408
  private
401
409
 
410
+ def root
411
+ @root_element || browser_root_for(browser, PageObject::Platforms.get)
412
+ end
413
+
402
414
  def include_platform_driver(browser)
403
415
  @platform = load_platform(browser, PageObject::Platforms.get)
404
416
  end
@@ -1229,6 +1229,54 @@ module PageObject
1229
1229
  end
1230
1230
  end
1231
1231
 
1232
+ #
1233
+ # adds a method to return a page object rooted at an element
1234
+ #
1235
+ # @example
1236
+ # page_section(:navigation_bar, NavigationBar, :id => 'nav-bar')
1237
+ # # will generate 'navigation_bar' and 'navigation_bar?'
1238
+ #
1239
+ # @param [Symbol] the name used for the generated methods
1240
+ # @param [Class] the class to instantiate for the element
1241
+ # @param [Hash] identifier how we find an element. You can use multiple parameters
1242
+ # by combining of any of the following except xpath. The valid keys are:
1243
+ # * :class => Watir and Selenium
1244
+ # * :css => Selenium only
1245
+ # * :id => Watir and Selenium
1246
+ # * :index => Watir and Selenium
1247
+ # * :name => Watir and Selenium
1248
+ # * :xpath => Watir and Selenium
1249
+ #
1250
+ def page_section(name, section_class, identifier)
1251
+ define_method(name) do
1252
+ platform.page_for(identifier, section_class)
1253
+ end
1254
+ end
1255
+
1256
+ #
1257
+ # adds a method to return a collection of page objects rooted at elements
1258
+ #
1259
+ # @example
1260
+ # page_sections(:articles, Article, :class => 'article')
1261
+ # # will generate 'articles'
1262
+ #
1263
+ # @param [Symbol] the name used for the generated method
1264
+ # @param [Class] the class to instantiate for each element
1265
+ # @param [Hash] identifier how we find an element. You can use a multiple parameters
1266
+ # by combining of any of the following except xpath. The valid keys are:
1267
+ # * :class => Watir and Selenium
1268
+ # * :css => Selenium only
1269
+ # * :id => Watir and Selenium
1270
+ # * :index => Watir and Selenium
1271
+ # * :name => Watir and Selenium
1272
+ # * :xpath => Watir and Selenium
1273
+ #
1274
+ def page_sections(name, section_class, identifier)
1275
+ define_method(name) do
1276
+ platform.pages_for(identifier, section_class)
1277
+ end
1278
+ end
1279
+
1232
1280
  #
1233
1281
  # methods to generate accessors for types that follow the same
1234
1282
  # pattern as element
@@ -208,19 +208,19 @@ module PageObject
208
208
 
209
209
  def include_platform_for platform
210
210
  if platform[:platform] == :watir_webdriver
211
- require 'page-object/platforms/watir_webdriver/element'
212
- require 'page-object/platforms/watir_webdriver/page_object'
213
211
  self.class.send :include, ::PageObject::Platforms::WatirWebDriver::Element
214
212
  @platform = ::PageObject::Platforms::WatirWebDriver::PageObject.new(@element)
215
213
  elsif platform[:platform] == :selenium_webdriver
216
- require 'page-object/platforms/selenium_webdriver/element'
217
- require 'page-object/platforms/selenium_webdriver/page_object'
218
214
  self.class.send :include, ::PageObject::Platforms::SeleniumWebDriver::Element
219
215
  @platform = ::PageObject::Platforms::SeleniumWebDriver::PageObject.new(@element)
220
216
  else
221
217
  raise ArgumentError, "expect platform to be :watir_webdriver or :selenium_webdriver"
222
218
  end
223
219
  end
220
+
221
+ def to_ary
222
+ nil
223
+ end
224
224
  end
225
225
  end
226
226
  end
@@ -20,16 +20,20 @@ module PageObject
20
20
  name = identifier[1]
21
21
  how_and_what = identifier[2].clone # Cannot modify the original...
22
22
  how_and_what.each do |key, value|
23
- how_and_what[key] = value % index
23
+ if key == :index
24
+ how_and_what[key] = (value % index).to_i
25
+ else
26
+ how_and_what[key] = value % index
27
+ end
24
28
  end
25
- self.class.send type, name, how_and_what unless self.class.instance_methods.include? name
29
+ self.class.send type, name, how_and_what unless Class.instance_methods.include? name
26
30
  end
27
31
  end
28
32
  }
29
33
  end
30
34
 
31
35
  def [] (index)
32
- @indexed_property_class.new(@browser,index,@identifier_list)
36
+ @indexed_property_class.new(@browser, index, @identifier_list)
33
37
  end
34
38
  end
35
39
  end
@@ -15,12 +15,31 @@ module PageObject
15
15
  # @returns [PageObject]
16
16
  #
17
17
  def load_platform(browser, adapters)
18
- adapters.each_value { |adapter|
19
- return adapter.create_page_object(browser) if adapter.is_for?(browser)
18
+ adapter_for(browser,adapters).create_page_object(browser)
19
+ end
20
+
21
+ def browser_for root,adapters
22
+ adapter_for(root,adapters).browser_for(root)
23
+ end
24
+
25
+ def adapter_for element_or_browser, adapters
26
+ adapter = adapters.values.find { |adapter|
27
+ adapter.is_for?(element_or_browser)
20
28
  }
21
- message = 'Unable to pick a platform for the provided browser.'
22
- message += "\nnil was passed to the PageObject constructor instead of a valid browser object." if browser.nil?
23
- raise message
29
+ unless adapter
30
+ message = "Unable to pick a platform for the provided browser or element: #{element_or_browser.inspect}."
31
+ message += "\nnil was passed to the PageObject constructor instead of a valid browser or element object." if element_or_browser.nil?
32
+ raise message
33
+ end
34
+ adapter
35
+ end
36
+
37
+ def root_element_for root, adapters
38
+ adapter_for(root,adapters).root_element_for(root)
39
+ end
40
+
41
+ def browser_root_for browser, adapters
42
+ adapter_for(browser,adapters).browser_root_for(browser)
24
43
  end
25
44
  end
26
45
  end
@@ -3,13 +3,25 @@ module PageObject
3
3
  module SeleniumWebDriver
4
4
 
5
5
  def self.create_page_object(browser)
6
- require 'page-object/platforms/selenium_webdriver/page_object'
7
6
  SeleniumWebDriver::PageObject.new(browser)
8
7
  end
9
8
 
10
9
  def self.is_for?(browser)
11
10
  require 'selenium-webdriver'
12
- browser.is_a? ::Selenium::WebDriver::Driver
11
+ browser.is_a?(::Selenium::WebDriver::Driver) || browser.is_a?(::Selenium::WebDriver::Element)
12
+ end
13
+
14
+ def self.browser_for root
15
+ return root if root.is_a?(::Selenium::WebDriver::Driver)
16
+ Selenium::WebDriver::Driver.new(root.send(:bridge))
17
+ end
18
+
19
+ def self.root_element_for root
20
+ Elements::Element.new root, platform: :selenium_webdriver if root.is_a?(::Selenium::WebDriver::Element)
21
+ end
22
+
23
+ def self.browser_root_for browser
24
+ browser.find_element(tag_name: 'html')
13
25
  end
14
26
  end
15
27
  end
@@ -3,11 +3,11 @@ module PageObject
3
3
  module SeleniumWebDriver
4
4
  module Button
5
5
  #
6
- # Override PageObject::PLatforms::SeleniumElement#text because
7
- # #text does not reliably return a value in Selenium
6
+ # Override PageObject::PLatforms::SeleniumElement#text
7
+ # to get #text from buttons and #attribute('value') from inputs
8
8
  #
9
9
  def text
10
- raise "text is not available on button element in Selenium"
10
+ element.tag_name == 'button' ? element.text : element.attribute('value')
11
11
  end
12
12
  end
13
13
  end
@@ -67,7 +67,7 @@ module PageObject
67
67
  # compare this element to another to determine if they are equal
68
68
  #
69
69
  def ==(other)
70
- element == other.element
70
+ other.is_a? self.class and element == other.element
71
71
  end
72
72
 
73
73
  #
@@ -988,6 +988,22 @@ module PageObject
988
988
  find_selenium_elements(identifier, Elements::Element, tag.to_s)
989
989
  end
990
990
 
991
+ #
992
+ # platform method to return a PageObject rooted at an element
993
+ # See PageObject::Accessors#page_section
994
+ #
995
+ def page_for(identifier, page_class)
996
+ find_selenium_page(identifier, page_class)
997
+ end
998
+
999
+ #
1000
+ # platform method to return a collection of PageObjects rooted at elements
1001
+ # See PageObject::Accessors#page_sections
1002
+ #
1003
+ def pages_for(identifier, page_class)
1004
+ SectionCollection.new(find_selenium_pages(identifier, page_class))
1005
+ end
1006
+
991
1007
  #
992
1008
  # platform method to return a svg element
993
1009
  #
@@ -1071,6 +1087,40 @@ module PageObject
1071
1087
  elements.map { |element| type.new(element, :platform => :selenium_webdriver) }
1072
1088
  end
1073
1089
 
1090
+ def find_selenium_pages(identifier, page_class)
1091
+ regexp = delete_regexp(identifier)
1092
+ how, what, frame_identifiers = parse_identifiers(identifier, Elements::Element, 'element')
1093
+ switch_to_frame(frame_identifiers)
1094
+ unless regexp
1095
+ elements = @browser.find_elements(how, what)
1096
+ else
1097
+ eles = @browser.find_elements(how, what)
1098
+ elements = eles.find_all {|ele| matches_selector?(ele, regexp[0], regexp[1])}
1099
+ end
1100
+ @browser.switch_to.default_content unless frame_identifiers.nil?
1101
+ elements.map { |element| page_class.new(element) }
1102
+ end
1103
+
1104
+ def find_selenium_page(identifier, page_class)
1105
+ type, tag = Elements::Element, 'element'
1106
+ regexp = delete_regexp(identifier)
1107
+ how, what, frame_identifiers = parse_identifiers(identifier, type, tag)
1108
+ switch_to_frame(frame_identifiers)
1109
+ begin
1110
+ unless regexp
1111
+ element = @browser.find_element(how, what)
1112
+ else
1113
+ elements = @browser.find_elements(how, what)
1114
+ element = elements.find {|ele| matches_selector?(ele, regexp[0], regexp[1])}
1115
+ end
1116
+ rescue Selenium::WebDriver::Error::NoSuchElementError
1117
+ @browser.switch_to.default_content unless frame_identifiers.nil?
1118
+ return build_null_object(identifier, type, tag, nil)
1119
+ end
1120
+ @browser.switch_to.default_content unless frame_identifiers.nil?
1121
+ page_class.new(element)
1122
+ end
1123
+
1074
1124
  def build_null_object(identifier, type, tag, other)
1075
1125
  null_element = SurrogateSeleniumElement.new
1076
1126
  null_element.identifier = identifier
@@ -1,15 +1,27 @@
1
1
  module PageObject
2
2
  module Platforms
3
3
  module WatirWebDriver
4
-
4
+
5
5
  def self.create_page_object(browser)
6
- require 'page-object/platforms/watir_webdriver/page_object'
7
6
  return WatirWebDriver::PageObject.new(browser)
8
7
  end
9
8
 
10
9
  def self.is_for?(browser)
11
10
  require 'watir-webdriver'
12
- browser.is_a?(::Watir::Browser)
11
+ browser.is_a?(::Watir::Browser) || browser.is_a?(::Watir::HTMLElement)
12
+ end
13
+
14
+ def self.browser_for root
15
+ return root if root.is_a?(::Watir::Browser)
16
+ root.browser
17
+ end
18
+
19
+ def self.root_element_for root
20
+ Elements::Element.new root, :platform => :watir_webdriver if root.is_a? ::Watir::HTMLElement
21
+ end
22
+
23
+ def self.browser_root_for browser
24
+ browser.element
13
25
  end
14
26
  end
15
27
  end
@@ -60,7 +60,7 @@ module PageObject
60
60
  # compare this element to another to determine if they are equal
61
61
  #
62
62
  def ==(other)
63
- element == other.element
63
+ other.is_a? self.class and element == other.element
64
64
  end
65
65
 
66
66
  #
@@ -917,6 +917,22 @@ module PageObject
917
917
  find_watir_elements("#{tag.to_s}s(identifier)", Elements::Element, identifier, tag.to_s)
918
918
  end
919
919
 
920
+ #
921
+ # platform method to return a PageObject rooted at an element
922
+ # See PageObject::Accessors#page_section
923
+ #
924
+ def page_for(identifier, page_class)
925
+ find_watir_page(identifier, page_class)
926
+ end
927
+
928
+ #
929
+ # platform method to return a collection of PageObjects rooted at elements
930
+ # See PageObject::Accessors#page_sections
931
+ #
932
+ def pages_for(identifier, page_class)
933
+ SectionCollection.new(find_watir_pages(identifier, page_class))
934
+ end
935
+
920
936
  #
921
937
  # platform method to return a svg element
922
938
  #
@@ -970,6 +986,20 @@ module PageObject
970
986
  type.new(element, :platform => :watir_webdriver)
971
987
  end
972
988
 
989
+ def find_watir_pages(identifier, page_class)
990
+ identifier, frame_identifiers = parse_identifiers(identifier, Elements::Element, 'element')
991
+ elements = @browser.instance_eval "#{nested_frames(frame_identifiers)}elements(identifier)"
992
+ switch_to_default_content(frame_identifiers)
993
+ elements.map { |element| page_class.new(element) }
994
+ end
995
+
996
+ def find_watir_page(identifier, page_class)
997
+ identifier, frame_identifiers = parse_identifiers(identifier, Elements::Element, 'element')
998
+ element = @browser.instance_eval "#{nested_frames(frame_identifiers)}element(identifier)"
999
+ switch_to_default_content(frame_identifiers)
1000
+ page_class.new(element)
1001
+ end
1002
+
973
1003
  def process_watir_call(the_call, type, identifier, value=nil, tag_name=nil)
974
1004
  identifier, frame_identifiers = parse_identifiers(identifier, type, tag_name)
975
1005
  value = @browser.instance_eval "#{nested_frames(frame_identifiers)}#{the_call}"
@@ -0,0 +1,29 @@
1
+ module PageObject
2
+ class SectionCollection
3
+ include Enumerable
4
+
5
+ def initialize sections
6
+ @sections = sections
7
+ end
8
+
9
+ def each &block
10
+ @sections.each &block
11
+ end
12
+
13
+ def [] index
14
+ @sections[index]
15
+ end
16
+
17
+ def find_by values_hash
18
+ @sections.find {|section|
19
+ values_hash.all? {|method,value| value === section.public_send(method)}
20
+ }
21
+ end
22
+
23
+ def select_by values_hash
24
+ SectionCollection.new @sections.select {|section|
25
+ values_hash.all? {|method,value| value === section.public_send(method)}
26
+ }
27
+ end
28
+ end
29
+ end
@@ -1,4 +1,4 @@
1
1
  module PageObject
2
2
  # @private
3
- VERSION = "1.0.3"
3
+ VERSION = "1.1.0"
4
4
  end