Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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