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