# encoding: utf-8 # Generic helper methods not specific # to a particular tag name module Appium::Common # json and ap are required for the source method. require 'json' require 'ap' # awesome print require 'timeout' # for wait # iOS .name returns the accessibility attribute if it's set. if not set, the string value is used. # Android .name returns the accessibility attribute and nothing if it's not set. # # .text should be cross platform so prefer that over name, unless both # Android and iOS have proper accessibility attributes. # .text and .value should be the same so use .text over .value. # # secure tag_name is iOS only because it can't be implemented using uiautomator for Android. # # find_element :text doesn't work so use XPath to find by text. # Check every 0.5 seconds to see if block.call doesn't raise an exception. # if .call raises an exception then it will be tried again. # if .call doesn't raise an exception then it will stop waiting. # # Example: wait { name('back').click } # # Give up after 30 seconds. # @param max_wait [Integer] the maximum time in seconds to wait for # @param interval [Float] the time in seconds to wait after calling the block # @param block [Block] the block to call # @return [Object] the result of block.call def wait max_wait=30, interval=0.5, &block # Rescue Timeout::Error: execution expired result = nil timeout max_wait do until (result = begin; block.call || true; rescue; end) sleep interval end end result end # Check every 0.5 seconds to see if block.call returns true. nil is considered a failure. # Give up after 30 seconds. # @param max_wait [Integer] the maximum time in seconds to wait for # @param interval [Float] the time in seconds to wait after calling the block # @param block [Block] the block to call # @return [Object] the result of block.call def wait_true max_wait=30, interval=0.5, &block # Rescue Timeout::Error: execution expired result = nil timeout max_wait do until (result = begin; block.call; rescue; end) sleep interval end end result end # Find by id. Useful for selendroid # @param id [String] the id to search for # @return [Element] def id id find_element :id, id end # Navigate back. # @return [void] def back @driver.navigate.back end # For Sauce Labs reporting. Returns the current session id. def session_id @driver.session_id end # Returns the first element that matches the provided xpath. # # @param xpath_str [String] the XPath string # @return [Element] def xpath xpath_str find_element :xpath, xpath_str end # Returns all elements that match the provided xpath. # # @param xpath_str [String] the XPath string # @return [Array] def xpaths xpath_str find_elements :xpath, xpath_str end # Get the element of type tag_name at matching index. # @param tag_name [String] the tag name to find # @param index [Integer] the index # @return [Element] the found element of type tag_name def ele_index tag_name, index # XPath index starts at 1. ruby_lib index starts at 0 find_element :xpath, "//#{tag_name}[#{index + 1}]" end # Get all elements exactly matching tag name # @param tag_name [String] the tag name to find # @return [Array] the found elements of type tag_name def find_eles tag_name @driver.find_elements :tag_name, tag_name end # Get the first tag that exactly matches tag and text. # @param tag [String] the tag name to match # @param text [String] the text to exactly match # @return [Element] the element of type tag exactly matching text def find_ele_by_text tag, text @driver.find_element :xpath, %Q(#{tag}[@text='#{text}']) end # Get all tags that exactly match tag and text. # @param tag [String] the tag name to match # @param text [String] the text to exactly match # @return [Array] the elements of type tag exactly matching text def find_eles_by_text tag, text @driver.find_elements :xpath, %Q(#{tag}[@text='#{text}']) end # Get the first tag by attribute that exactly matches value. # @param tag [String] the tag name to match # @param attr [String] the attribute to compare # @param value [String] the value of the attribute that the element must include # @return [Element] the element of type tag who's attribute includes value def find_ele_by_attr_include tag, attr, value @driver.find_element :xpath, %Q(#{tag}[contains(@#{attr}, '#{value}')]) end # Get tags by attribute that include value. # @param tag [String] the tag name to match # @param attr [String] the attribute to compare # @param value [String] the value of the attribute that the element must include # @return [Array] the elements of type tag who's attribute includes value def find_eles_by_attr_include tag, attr, value @driver.find_elements :xpath, %Q(#{tag}[contains(@#{attr}, '#{value}')]) end # Get the first tag that includes text. # @param tag [String] the tag name to match # @param text [String] the text the element must include # @return [Element] the element of type tag that includes text # element.attribute(:text).include? text def find_ele_by_text_include tag, text find_ele_by_attr_include tag, :text, text end # Get the tags that include text. # @param tag [String] the tag name to match # @param text [String] the text the element must include # @return [Array] the elements of type tag that includes text # element.attribute(:text).include? text def find_eles_by_text_include tag, text find_eles_by_attr_include tag, :text, text end # Get the first tag that matches tag_name # @param tag_name [String] the tag to match # @return [Element] def first_ele tag_name # XPath index starts at 1 find_element :xpath, "//#{tag_name}[1]" end # Get the last tag that matches tag_name # @param tag_name [String] the tag to match # @return [Element] def last_ele tag_name xpath "//#{tag_name}[last()]" end # Prints a JSON view of the current page # @return [void] def source ap get_source end # Gets a JSON view of the current page # @return [JSON] def get_source # must set max nesting. default limit of 20 is too low for selendroid JSON.parse @driver.page_source, max_nesting: 9999 end # Returns the first element that matches name # # @param name [String] the name to match # @return [Element] def find_name name find_element :name, name end # Returns all elements that match name # # @param name [String] the name to match # @return [Array] def find_names name find_elements :name, name end end # module Appium::Common