# encoding: utf-8# Generic helper methods not specific# to a particular tag namemoduleAppium::Common# json and ap are required for the source method.require'json'require'ap'# awesome printrequire'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.# Note that max wait 0 means infinity.# @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.calldefwaitmax_wait=30,interval=0.5,&block# Rescue Timeout::Error: execution expiredresult=niltimeoutmax_waitdountil(result=begin;block.call||true;rescue;end)sleepintervalendendresultend# Return block.call and ignore any exceptions.defignore&blockbegin;block.call;rescue;endend# 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.calldefwait_truemax_wait=30,interval=0.5,&block# Rescue Timeout::Error: execution expiredresult=niltimeoutmax_waitdountil(result=begin;block.call;rescue;end)sleepintervalendendresultend# Find by id. Useful for selendroid# @param id [String] the id to search for# @return [Element]defididfind_element:id,idend# Navigate back.# @return [void]defback@driver.navigate.backend# For Sauce Labs reporting. Returns the current session id.defsession_id@driver.session_idend# Returns the first element that matches the provided xpath.## @param xpath_str [String] the XPath string# @return [Element]defxpathxpath_strfind_element:xpath,xpath_strend# Returns all elements that match the provided xpath.## @param xpath_str [String] the XPath string# @return [Array<Element>]defxpathsxpath_strfind_elements:xpath,xpath_strend# 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_namedefele_indextag_name,index# XPath index starts at 1. ruby_lib index starts at 0find_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<Element>] the found elements of type tag_namedeffind_elestag_name@driver.find_elements:tag_name,tag_nameend# 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 textdeffind_ele_by_texttag,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<Element>] the elements of type tag exactly matching textdeffind_eles_by_texttag,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 valuedeffind_ele_by_attr_includetag,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<Element>] the elements of type tag who's attribute includes valuedeffind_eles_by_attr_includetag,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? textdeffind_ele_by_text_includetag,textfind_ele_by_attr_includetag,:text,textend# 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<Element>] the elements of type tag that includes text# element.attribute(:text).include? textdeffind_eles_by_text_includetag,textfind_eles_by_attr_includetag,:text,textend# Get the first tag that matches tag_name# @param tag_name [String] the tag to match# @return [Element]deffirst_eletag_name# XPath index starts at 1find_element:xpath,"//#{tag_name}[1]"end# Get the last tag that matches tag_name# @param tag_name [String] the tag to match# @return [Element]deflast_eletag_namexpath"//#{tag_name}[last()]"end# Prints a JSON view of the current page# @return [void]defsourceapget_sourceend# Gets a JSON view of the current page# @return [JSON]defget_source# must set max nesting. default limit of 20 is too low for selendroidJSON.parse@driver.page_source,max_nesting: 9999end# Returns the first element that exactly matches name## @param name [String] the name to exactly match# @return [Element]deffind_namenamefind_element:name,nameend# Returns all elements that exactly match name## @param name [String] the name to exactly match# @return [Array<Element>]deffind_namesnamefind_elements:name,nameend# Returns the first element matching tag_name## @param tag_name [String] the tag_name to search for# @return [Element]deftagtag_namefind_element:tag_name,tag_nameend# Converts pixel values to window relative values## ```ruby# px_to_window_rel x: 50, y: 150# ```defpx_to_window_relopts={}w=$driver.window_sizex=opts.fetch:x,0y=opts.fetch:y,0OpenStruct.new(x: x.to_f/w.width.to_f,y: y.to_f/w.height.to_f)enddeflazy_load_strings@strings_xml||=mobile(:getStrings)end# Search strings.xml's values for target.# @param target [String] the target to search for in strings.xml values# @return [Array]defxml_keystargetlazy_load_strings@strings_xml.select{|key,value|key.downcase.include?target.downcase}end# Search strings.xml's keys for target.# @param target [String] the target to search for in strings.xml keys# @return [Array]defxml_valuestargetlazy_load_strings@strings_xml.select{|key,value|value.downcase.include?target.downcase}end# Resolve id in strings.xml and return the value.# @param id [String] the id to resolve# @return [String]defresolve_ididlazy_load_strings@strings_xml[id]endend# module Appium::Common