lib/page-object/elements/element.rb in page-object-2.0.0 vs lib/page-object/elements/element.rb in page-object-2.1
- old
+ new
@@ -1,14 +1,14 @@
require 'page-object/nested_elements'
+require 'watir/extensions/select_text'
module PageObject
module Elements
#
# Contains functionality that is common across all elements.
#
# @see PageObject::Platforms::WatirWebDriver::Element for the Watir version of all common methods
- # @see PageObject::Platforms::SeleniumWebDriver::Element for the Selenium version of all common methods
#
class Element
include ::PageObject::NestedElements
attr_reader :element
@@ -17,38 +17,16 @@
@element = element
include_platform_for platform
end
#
- # click the element
- #
- def click
- element.click
- end
-
-
-
- #
- # return true if the element is enabled
- #
- def enabled?
- element.enabled?
- end
-
- #
# return true if the element is not enabled
#
def disabled?
not enabled?
end
- #
- # get the value of the given CSS property
- #
- def style(property = nil)
- element.style property
- end
def inspect
element.inspect
end
@@ -79,16 +57,173 @@
timed_loop(timeout) do |element|
element.visible?
end
end
+ #
+ # Keeps checking until the element exists
+ #
+ # @param [Integer] (defaults to: 5) seconds to wait before timing out
+ #
def check_exists(timeout=::PageObject.default_element_wait)
timed_loop(timeout) do |element|
element.exists?
end
end
+ #
+ # return true if an element is visible
+ #
+ # def visible?
+ # element.present?
+ # end
+
+ #
+ # compare this element to another to determine if they are equal
+ #
+ def ==(other)
+ other.is_a? self.class and element == other.element
+ end
+
+ #
+ # Get the value of a the given attribute of the element. Will
+ # return the current value, even if this has been modified
+ # after the page has been loaded. More exactly, this method
+ # will return the value of the given attribute, unless that
+ # attribute is not present, in which case the value of the
+ # property with the same name is returned. If neither value is
+ # set, nil is returned. The "style" attribute is converted as
+ # best can be to a text representation with a trailing
+ # semi-colon. The following are deemed to be "boolean"
+ # attributes, and will return either "true" or "false":
+ #
+ # async, autofocus, autoplay, checked, compact, complete,
+ # controls, declare, defaultchecked, defaultselected, defer,
+ # disabled, draggable, ended, formnovalidate, hidden, indeterminate,
+ # iscontenteditable, ismap, itemscope, loop, multiple, muted,
+ # nohref, noresize, noshade, novalidate, nowrap, open, paused,
+ # pubdate, readonly, required, reversed, scoped, seamless, seeking,
+ # selected, spellcheck, truespeed, willvalidate
+ #
+ # Finally, the following commonly mis-capitalized
+ # attribute/property names are evaluated as expected:
+ #
+ # class, readonly
+ #
+ # @param [String]
+ # attribute name
+ # @return [String,nil]
+ # attribute value
+ #
+ def attribute(attribute_name)
+ element.attribute_value attribute_name
+ end
+
+ #
+ # find the parent element
+ #
+ def parent
+ parent = element.parent
+ type = element.type if parent.tag_name.to_sym == :input
+ cls = ::PageObject::Elements.element_class_for(parent.tag_name, type)
+ cls.new(parent, :platform => :watir)
+ end
+
+ #
+ # Waits until the element is present
+ #
+ # @param [Integer] (defaults to: 5) seconds to wait before timing out
+ #
+ def when_present(timeout=::PageObject.default_element_wait)
+ element.wait_until(timeout: timeout, message: "Element not present in #{timeout} seconds", &:present?)
+ self
+ end
+
+ #
+ # Waits until the element is not present
+ #
+ # @param [Integer] (defaults to: 5) seconds to wait before
+ # timing out
+ #
+ def when_not_present(timeout=::PageObject.default_element_wait)
+ element.wait_while(timeout: timeout, message: "Element still present in #{timeout} seconds", &:present?)
+ end
+
+ #
+ # Waits until the element is visible
+ #
+ # @param [Integer] (defaults to: 5) seconds to wait before timing out
+ #
+ def when_visible(timeout=::PageObject.default_element_wait)
+ element.wait_until(timeout: timeout, message: "Element not visible in #{timeout} seconds", &:visible?)
+ self
+ end
+
+ #
+ # Waits until the element is not visible
+ #
+ # @param [Integer] (defaults to: 5) seconds to wait before timing out
+ #
+ def when_not_visible(timeout=::PageObject.default_element_wait)
+ element.wait_while(timeout: timeout, message: "Element still visible after #{timeout} seconds", &:visible?)
+ end
+
+ #
+ # Waits until the block returns true
+ #
+ # @param [Integer] (defaults to: 5) seconds to wait before timing out
+ # @param [String] the message to display if the event timeouts
+ # @param the block to execute when the event occurs
+ #
+ def wait_until(timeout=::PageObject.default_element_wait, message=nil, &block)
+ element.wait_until(timeout: timeout, message: message, &block)
+ end
+
+ #
+ # Scroll until the element is viewable
+ #
+ def scroll_into_view
+ element.wd.location_once_scrolled_into_view
+ end
+
+ #
+ # location of element (x, y)
+ #
+ def location
+ element.wd.location
+ end
+
+ #
+ # size of element (width, height)
+ #
+ def size
+ element.wd.size
+ end
+
+ #
+ # Get height of element
+ #
+ def height
+ element.wd.size['height']
+ end
+
+ #
+ # Get width of element
+ #
+ def width
+ element.wd.size['width']
+ end
+
+ #
+ # Get centre coordinates of element
+ #
+ def centre
+ location = element.wd.location
+ size = element.wd.size
+ {'y' => (location['y'] + (size['height']/2)), 'x' => (location['x'] + (size['width']/2))}
+ end
+
# @private
def self.watir_identifier_for identifier
if should_build_watir_xpath(identifier)
how = :xpath
what = build_xpath_for(identifier)
@@ -102,36 +237,14 @@
end
all_identities
end
# @private
- def self.selenium_identifier_for identifier
- if identifier.length == 1
- identifier = identifier_for identifier, selenium_finders, selenium_mapping
- return identifier.keys.first, identifier.values.first
- elsif identifier.length > 1
- how = :xpath
- what = build_xpath_for identifier
- return how, what
- end
- end
-
- # @private
# delegate calls to driver element
def method_missing(*args, &block)
m = args.shift
- $stderr.puts "*** DEPRECATION WARNING"
- $stderr.puts "*** You are calling a method named #{m} at #{caller[0]}."
- $stderr.puts "*** This method does not exist in page-object so it is being passed to the driver."
- $stderr.puts "*** This feature will be removed in the near future."
- $stderr.puts "*** Please change your code to call the correct page-object method."
- $stderr.puts "*** If you are using functionality that does not exist in page-object please request it be added."
- begin
- element.send m, *args, &block
- rescue Exception => e
- raise
- end
+ element.send m, *args, &block
end
protected
def self.should_build_watir_xpath identifier
@@ -213,49 +326,19 @@
def self.watir_mapping
{}
end
- def self.selenium_finders
- [:class, :css, :id, :index, :name, :xpath]
- end
-
- def self.selenium_mapping
- {}
- end
-
def include_platform_for platform
platform_information = PageObject::Platforms.get
raise ArgumentError,"Expected hash with at least a key :platform for platform information! (#{platform.inspect})" unless platform.class == Hash && platform.has_key?(:platform)
platform_name = platform[:platform]
raise ArgumentError, "Unknown platform #{platform_name}! Expect platform to be one of the following: #{platform_information.keys.inspect}" unless platform_information.keys.include?(platform_name)
base_platform_class = "#{platform_information[platform_name]}::"
- self.send :extend, constantize_classname(base_platform_class + "Element")
@platform = constantize_classname(base_platform_class+ "PageObject").new(@element)
-
- # include class specific code
- class_to_include = case
- when self.class == PageObject::Elements::Element
- # already loaded
- return true
- when self.class.name =~/PageObject:Elements::/
- self.class
- # inherited classes for example the widgets
- else
- parent_classes = self.class.ancestors.select { |item| item.name =~/PageObject::Elements::/ }
- raise RuntimeError,"Could not identify page-object inherited class for #{self.class}!" if parent_classes.empty?
- parent_classes.first
- end
-
- element_type_specific_code = File.expand_path(File.dirname(__FILE__) + "../../platforms/#{platform_name}/"+ get_element_type_underscored(class_to_include) )
- if File.exist? element_type_specific_code + '.rb'
- require element_type_specific_code
- self.send :extend, constantize_classname( base_platform_class + get_element_type(class_to_include) )
- end
-
end
def to_ary
nil
end
@@ -272,23 +355,9 @@
false
end
def constantize_classname name
name.split("::").inject(Object) { |k,n| k.const_get(n) }
- end
-
-
- def get_element_type(class_name = self.class)
- class_name.name.split('::').last
- end
-
- # retrieved from ruby on rails underscore method
- def get_element_type_underscored(class_name = self.class)
- get_element_type(class_name).to_s.gsub(/::/, '/').
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
- tr("-", "_").
- downcase
end
end
end
end