page-object 1.0.3 → 1.1.0

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