Skip to content

Commit

Permalink
separate find_element/s for uiautomator and xpath (#547)
Browse files Browse the repository at this point in the history
* separate find_element/s for uiautomator and xpath

* fix button methods

* check uiautomator2 for button methods

* fix rubocop

* add somments
  • Loading branch information
KazuCocoa authored Apr 18, 2017
1 parent 9492690 commit d721297
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 24 deletions.
98 changes: 82 additions & 16 deletions lib/appium_lib/android/element/button.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,47 @@ module Android
private

# @private
def _button_visible_selectors
def _button_visible_selectors_xpath
"//#{Button}|#{ImageButton}"
end

def _button_visible_selectors(opts = {})
button_index = opts.fetch :button_index, false
image_button_index = opts.fetch :image_button_index, false

if button_index && image_button_index
"new UiSelector().className(#{Button}).instance(#{button_index});" \
"new UiSelector().className(#{ImageButton}).instance(#{image_button_index});"
else
"new UiSelector().className(#{Button});" \
"new UiSelector().className(#{ImageButton});"
end
end

# @private
# For automationName is uiautomator2
def _button_exact_string_xpath(value)
string_visible_exact_xpath(Button, value) +
string_visible_exact_xpath(ImageButton, value).sub(/\A\/\//, '|')
end

def _button_exact_string(value)
string_visible_exact(Button, value) +
string_visible_exact(ImageButton, value).sub(/\A\/\//, '|')
button = string_visible_exact Button, value
image_button = string_visible_exact ImageButton, value
button + image_button
end

# @private
# For automationName is uiautomator2
def _button_contains_string_xpath(value)
string_visible_contains_xpath(Button, value) +
string_visible_contains_xpath(ImageButton, value).sub(/\A\/\//, '|')
end

def _button_contains_string(value)
string_visible_contains(Button, value) +
string_visible_contains(ImageButton, value).sub(/\A\/\//, '|')
button = string_visible_contains Button, value
image_button = string_visible_contains ImageButton, value
button + image_button
end

public
Expand All @@ -36,49 +63,88 @@ def button(value)
index = value
raise "#{index} is not a valid index. Must be >= 1" if index <= 0

result = find_elements(:xpath, _button_visible_selectors)[value - 1]
raise Selenium::WebDriver::Error::NoSuchElementError unless result
if automation_name_is_uiautomator2?
result = find_elements(:xpath, _button_visible_selectors_xpath)[value - 1]
raise Selenium::WebDriver::Error::NoSuchElementError unless result
else
result = find_element :uiautomator, _button_visible_selectors(index: index)
end

return result
end

find_element :xpath, _button_contains_string(value)
if automation_name_is_uiautomator2?
find_element :xpath, _button_contains_string_xpath(value)
else
find_element :uiautomator, _button_contains_string(value)
end
end

# Find all buttons containing value.
# If value is omitted, all buttons are returned.
# @param value [String] the value to search for
# @return [Array<Button>]
def buttons(value = false)
return find_elements :xpath, _button_visible_selectors unless value
find_elements :xpath, _button_contains_string(value)
if automation_name_is_uiautomator2?
return find_elements :xpath, _button_visible_selectors_xpath unless value
find_elements :xpath, _button_contains_string_xpath(value)
else
return find_elements :uiautomator, _button_visible_selectors unless value
find_elements :uiautomator, _button_contains_string(value)
end
end

# Find the first button.
# @return [Button]
def first_button
find_element :xpath, _button_visible_selectors
if automation_name_is_uiautomator2?
find_element :xpath, _button_visible_selectors_xpath
else
find_element :uiautomator, _button_visible_selectors(button_index: 0, image_button_index: 0)
end
end

# Find the last button.
# @return [Button]
def last_button
result = find_elements(:xpath, _button_visible_selectors).last
raise Selenium::WebDriver::Error::NoSuchElementError unless result
result
if automation_name_is_uiautomator2?
result = find_elements(:xpath, _button_visible_selectors_xpath).last
raise Selenium::WebDriver::Error::NoSuchElementError unless result
result
else
# uiautomator index doesn't support last
# and it's 0 indexed
button_index = tags(Button).length
button_index -= 1 if button_index > 0
image_button_index = tags(ImageButton).length
image_button_index -= 1 if image_button_index > 0

find_element :uiautomator,
_button_visible_selectors(button_index: button_index,
image_button_index: image_button_index)
end
end

# Find the first button that exactly matches value.
# @param value [String] the value to match exactly
# @return [Button]
def button_exact(value)
find_element :xpath, _button_exact_string(value)
if automation_name_is_uiautomator2?
find_element :xpath, _button_exact_string_xpath(value)
else
find_element :uiautomator, _button_exact_string(value)
end
end

# Find all buttons that exactly match value.
# @param value [String] the value to match exactly
# @return [Array<Button>]
def buttons_exact(value)
find_elements :xpath, _button_exact_string(value)
if automation_name_is_uiautomator2?
find_elements :xpath, _button_exact_string_xpath(value)
else
find_elements :uiautomator, _button_exact_string(value)
end
end
end # module Android
end # module Appium
74 changes: 66 additions & 8 deletions lib/appium_lib/android/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -279,13 +279,13 @@ def resource_id(string, on_match)
end

# Returns a string that matches the first element that contains value
#
# example: complex_find_contains 'UIATextField', 'sign in'
# For automationName is uiautomator2
# example: string_visible_contains_xpath 'UIATextField', 'sign in'
#
# @param class_name [String] the class name for the element
# @param value [String] the value to search for
# @return [String]
def string_visible_contains(class_name, value)
def string_visible_contains_xpath(class_name, value)
r_id = resource_id(value, " or @resource-id='#{value}'")

if class_name == '*'
Expand All @@ -297,28 +297,58 @@ def string_visible_contains(class_name, value)
" or contains(translate(@content-desc,'#{value.upcase}', '#{value}'), '#{value}')" + r_id + ']'
end

# Returns a string that matches the first element that contains value
# For automationName is Appium
# example: string_visible_contains 'UIATextField', 'sign in'
#
# @param class_name [String] the class name for the element
# @param value [String] the value to search for
# @return [String]
def string_visible_contains(class_name, value)
value = %("#{value}")
if class_name == '*'
return (resource_id(value, "new UiSelector().resourceId(#{value});") +
"new UiSelector().descriptionContains(#{value});" \
"new UiSelector().textContains(#{value});")
end

class_name = %("#{class_name}")
resource_id(value, "new UiSelector().className(#{class_name}).resourceId(#{value});") +
"new UiSelector().className(#{class_name}).descriptionContains(#{value});" \
"new UiSelector().className(#{class_name}).textContains(#{value});"
end

# Find the first element that contains value
# @param element [String] the class name for the element
# @param value [String] the value to search for
# @return [Element]
def complex_find_contains(element, value)
find_element :xpath, string_visible_contains(element, value)
if automation_name_is_uiautomator2?
find_element :xpath, string_visible_contains_xpath(element, value)
else
find_element :uiautomator, string_visible_contains(element, value)
end
end

# Find all elements containing value
# @param element [String] the class name for the element
# @param value [String] the value to search for
# @return [Array<Element>]
def complex_finds_contains(element, value)
find_elements :xpath, string_visible_contains(element, value)
if automation_name_is_uiautomator2?
find_elements :xpath, string_visible_contains_xpath(element, value)
else
find_elements :uiautomator, string_visible_contains(element, value)
end
end

# @private
# Create an string to exactly match the first element with target value
# For automationName is uiautomator2
# @param class_name [String] the class name for the element
# @param value [String] the value to search for
# @return [String]
def string_visible_exact(class_name, value)
def string_visible_exact_xpath(class_name, value)
r_id = resource_id(value, " or @resource-id='#{value}'")

if class_name == '*'
Expand All @@ -328,20 +358,48 @@ def string_visible_exact(class_name, value)
"//#{class_name}[@text='#{value}' or @content-desc='#{value}'" + r_id + ']'
end

# @private
# Create an string to exactly match the first element with target value
# @param class_name [String] the class name for the element
# @param value [String] the value to search for
# @return [String]
def string_visible_exact(class_name, value)
value = %("#{value}")

if class_name == '*'
return (resource_id(value, "new UiSelector().resourceId(#{value});") +
"new UiSelector().description(#{value});" \
"new UiSelector().text(#{value});")
end

class_name = %("#{class_name}")
resource_id(value, "new UiSelector().className(#{class_name}).resourceId(#{value});") +
"new UiSelector().className(#{class_name}).description(#{value});" \
"new UiSelector().className(#{class_name}).text(#{value});"
end

# Find the first element exactly matching value
# @param class_name [String] the class name for the element
# @param value [String] the value to search for
# @return [Element]
def complex_find_exact(class_name, value)
find_element :xpath, string_visible_exact(class_name, value)
if automation_name_is_uiautomator2?
find_element :xpath, string_visible_exact_xpath(class_name, value)
else
find_element :uiautomator, string_visible_exact(class_name, value)
end
end

# Find all elements exactly matching value
# @param class_name [String] the class name for the element
# @param value [String] the value to search for
# @return [Element]
def complex_finds_exact(class_name, value)
find_elements :xpath, string_visible_exact(class_name, value)
if automation_name_is_uiautomator2?
find_elements :xpath, string_visible_exact_xpath(class_name, value)
else
find_elements :uiautomator, string_visible_exact(class_name, value)
end
end

# Returns XML string for the current page
Expand Down
6 changes: 6 additions & 0 deletions lib/appium_lib/driver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,12 @@ def automation_name_is_xcuitest?
!@automation_name.nil? && 'xcuitest'.casecmp(@automation_name).zero?
end

# Return true if automationName is 'uiautomator2'
# @return [Boolean]
def automation_name_is_uiautomator2?
!@automation_name.nil? && 'uiautomator2'.casecmp(@automation_name).zero?
end

# Return true if the target Appium server is over REQUIRED_VERSION_XCUITEST.
# If the Appium server is under REQUIRED_VERSION_XCUITEST, then error is raised.
# @return [Boolean]
Expand Down

0 comments on commit d721297

Please sign in to comment.