module Appium::Android

Constants

BUTTON
Button
EDIT_TEXT
EditText
IMAGE_BUTTON
ImageButton
TEXT_VIEW
TextView

Public Instance Methods

alert_accept() click to toggle source

Accept the alert. The last button is considered “accept.” @return [void]

# File lib/appium_lib/android/element/alert.rb, line 27
def alert_accept
  last_button.click
end
alert_accept_text() click to toggle source

Get the text of the alert’s accept button. The last button is considered “accept.” @return [String]

# File lib/appium_lib/android/element/alert.rb, line 34
def alert_accept_text
  last_button.text
end
alert_click(value) click to toggle source

Click the first alert button that contains value or by index. @param value [Integer, String] either an integer index of the button or the button’s name @return [void]

# File lib/appium_lib/android/element/alert.rb, line 20
def alert_click(value)
  button(value).click
end
alert_dismiss() click to toggle source

Dismiss the alert. The first button is considered “dismiss.” @return [void]

# File lib/appium_lib/android/element/alert.rb, line 41
def alert_dismiss
  first_button.click
end
alert_dismiss_text() click to toggle source

Get the text of the alert’s dismiss button. The first button is considered “dismiss.” @return [String]

# File lib/appium_lib/android/element/alert.rb, line 48
def alert_dismiss_text
  first_button.text
end
button(value) click to toggle source

Find the first button that contains value or by index. @param value [String, Integer] the value to exactly match. If int then the button at that index is returned. @return [BUTTON]

# File lib/appium_lib/android/element/button.rb, line 27
def button(value)
  # Don't use ele_index because that only works on one element type.
  # Android needs to combine button and image button to match iOS.
  if value.is_a? Numeric
    index = value
    raise ArgumentError, "#{index} is not a valid index. Must be >= 1" if index <= 0

    # 1 indexed
    return find_element :uiautomator, _button_visible_selectors(index: index)
  end

  find_element :uiautomator, _button_contains_string(value)
end
button_exact(value) click to toggle source

Find the first button that exactly matches value. @param value [String] the value to match exactly @return [BUTTON]

# File lib/appium_lib/android/element/button.rb, line 75
def button_exact(value)
  find_element :uiautomator, _button_exact_string(value)
end
buttons(value = false) click to toggle source

Find all buttons containing value. If value is omitted, all buttons are returned. @param value [String] the value to search for @return [Array<BUTTON>]

# File lib/appium_lib/android/element/button.rb, line 45
def buttons(value = false)
  return find_elements :uiautomator, _button_visible_selectors unless value

  find_elements :uiautomator, _button_contains_string(value)
end
buttons_exact(value) click to toggle source

Find all buttons that exactly match value. @param value [String] the value to match exactly @return [Array<BUTTON>]

# File lib/appium_lib/android/element/button.rb, line 82
def buttons_exact(value)
  find_elements :uiautomator, _button_exact_string(value)
end
complex_find_contains(class_name, value) click to toggle source

Find the first element that contains value @param class_name [String] the class name for the element @param value [String] the value to search for @return [Element]

# File lib/appium_lib/android/common/helper.rb, line 270
def complex_find_contains(class_name, value)
  find_element :uiautomator, string_visible_contains(class_name, value)
end
complex_find_exact(class_name, value) click to toggle source

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]

# File lib/appium_lib/android/common/helper.rb, line 320
def complex_find_exact(class_name, value)
  find_element :uiautomator, string_visible_exact(class_name, value)
end
complex_finds_contains(class_name, value) click to toggle source

Find all elements containing value @param class_name [String] the class name for the element @param value [String] the value to search for @return [Array<Element>]

# File lib/appium_lib/android/common/helper.rb, line 278
def complex_finds_contains(class_name, value)
  find_elements :uiautomator, string_visible_contains(class_name, value)
end
complex_finds_exact(class_name, value) click to toggle source

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]

# File lib/appium_lib/android/common/helper.rb, line 328
def complex_finds_exact(class_name, value)
  find_elements :uiautomator, string_visible_exact(class_name, value)
end
ele_index(class_name, index) click to toggle source

Find the element of type class_name at matching index. @param class_name [String] the class name to find @param index [Integer] the index @return [Element] the found element of type class_name

# File lib/appium_lib/android/common/helper.rb, line 147
def ele_index(class_name, index)
  results = tags(class_name)
  if index == 'last()'
    index = results.length
    index -= 1 if index >= 0
  else
    raise ArgumentError, 'Index must be >= 1' unless index >= 1

    index -= 1 if index >= 1
  end

  # uiautomator has issues with index/instance so calculate the index
  # client side.
  results[index]
end
find(value) click to toggle source

Find the first element containing value @param value [String] the value to search for @return [Element]

# File lib/appium_lib/android/element/generic.rb, line 20
def find(value)
  complex_find_contains '*', value
end
find_exact(value) click to toggle source

Find the first element exactly matching value @param value [String] the value to search for @return [Element]

# File lib/appium_lib/android/element/generic.rb, line 34
def find_exact(value)
  complex_find_exact '*', value
end
finds(value) click to toggle source

Find all elements containing value @param value [String] the value to search for @return [Array<Element>]

# File lib/appium_lib/android/element/generic.rb, line 27
def finds(value)
  complex_finds_contains '*', value
end
finds_exact(value) click to toggle source

Find all elements exactly matching value @param value [String] the value to search for @return [Array<Element>]

# File lib/appium_lib/android/element/generic.rb, line 41
def finds_exact(value)
  complex_finds_exact '*', value
end
first_button() click to toggle source

Find the first button. @return [BUTTON]

# File lib/appium_lib/android/element/button.rb, line 53
def first_button
  find_element :uiautomator, _button_visible_selectors(button_index: 0, image_button_index: 0)
end
first_ele(class_name) click to toggle source

Find the first element that matches class_name @param class_name [String] the tag to match @return [Element]

# File lib/appium_lib/android/common/helper.rb, line 166
def first_ele(class_name)
  tag(class_name)
end
first_text() click to toggle source

Find the first TextView. @return [TEXT_VIEW]

# File lib/appium_lib/android/element/text.rb, line 43
def first_text
  first_ele TEXT_VIEW
end
first_textfield() click to toggle source

Find the first EditText. @return [EDIT_TEXT]

# File lib/appium_lib/android/element/textfield.rb, line 42
def first_textfield
  first_ele EDIT_TEXT
end
get_android_inspect(class_name = false) click to toggle source

Android only. Returns a string containing interesting elements. The text, content description, and id are returned. @param class_name [String] the class name to filter on. if false (default) then all classes will be inspected @return [String]

# File lib/appium_lib/android/common/helper.rb, line 95
def get_android_inspect(class_name = false)
  source = get_source

  doctype_string = '<!doctyp'
  source_header  = source[0..doctype_string.length].downcase
  source_is_html = source_header.start_with?(doctype_string, '<html')

  parser = if source_is_html # parse html from webview
             @android_html_parser ||= Nokogiri::HTML::SAX::Parser.new(Appium::Common::HTMLElements.new)
           else
             @android_native_parser ||= Nokogiri::XML::SAX::Parser.new(AndroidElements.new)
           end
  parser.document.reset # ensure document is reset before parsing
  parser.document.filter = class_name
  parser.parse source
  result = parser.document.result
  parser.document.reset # clean up any created objects after parsing
  result
end
id(id) click to toggle source

Find the first matching element by id @param id [String] the id to search for @return [Element]

# File lib/appium_lib/android/common/helper.rb, line 130
def id(id)
  # Android auto resolves strings.xml ids
  find_element :id, id
end
ids(id) click to toggle source

Find all matching elements by id @param id [String] the id to search for @return [Element]

# File lib/appium_lib/android/common/helper.rb, line 138
def ids(id)
  # Android auto resolves strings.xml ids
  find_elements :id, id
end
last_button() click to toggle source

Find the last button. @return [BUTTON]

# File lib/appium_lib/android/element/button.rb, line 59
def last_button
  # uiautomator index doesn't support last
  # and it's 0 indexed
  button_index = tags(BUTTON).length
  button_index -= 1 if button_index.positive?
  image_button_index = tags(IMAGE_BUTTON).length
  image_button_index -= 1 if image_button_index.positive?

  find_element :uiautomator,
               _button_visible_selectors(button_index: button_index,
                                         image_button_index: image_button_index)
end
last_ele(class_name) click to toggle source

Find the last element that matches class_name @param class_name [String] the tag to match @return [Element]

# File lib/appium_lib/android/common/helper.rb, line 173
def last_ele(class_name)
  ele_index class_name, 'last()'
end
last_text() click to toggle source

Find the last TextView. @return [TEXT_VIEW]

# File lib/appium_lib/android/element/text.rb, line 49
def last_text
  last_ele TEXT_VIEW
end
last_textfield() click to toggle source

Find the last EditText. @return [EDIT_TEXT]

# File lib/appium_lib/android/element/textfield.rb, line 48
def last_textfield
  last_ele EDIT_TEXT
end
page(opts = {}) click to toggle source

Intended for use with console. Inspects and prints the current page. Will return XHTML for Web contexts because of a quirk with Nokogiri. @option class [Symbol] the class name to filter on. case insensitive include match. if nil (default) then all classes will be inspected @return [void]

# File lib/appium_lib/android/common/helper.rb, line 121
def page(opts = {})
  class_name = opts.is_a?(Hash) ? opts.fetch(:class, nil) : opts
  puts get_android_inspect class_name
  nil
end
resource_id(string, on_match) click to toggle source

@private Detects if the string represents a resourceId resourceId is only supported on API >= 18 devices

@param string [String] the string check for a resourceId

value will be auto unquoted

@param on_match [String] the string to return on resourceId match

@return [String] empty string on failure, on_match on successful match

# File lib/appium_lib/android/common/helper.rb, line 202
def resource_id(string, on_match)
  return '' unless string

  # unquote the string
  # "com.example.Test:id/enter" -> com.example.Test:id/enter
  unquote = string.match(/"(.+)"/)
  string = unquote[1] if unquote

  # java_package : type / name
  #
  # com.example.Test:id/enter
  #
  # ^[a-zA-Z_]      - Java package must start with letter or underscore
  # [a-zA-Z0-9\._]* - Java package may contain letters, numbers, periods and underscores
  # :               - : ends the package and starts the type
  # [^\/]+          - type is made up of at least one non-/ characters
  # \\/             - / ends the type and starts the name
  # [\S]+$          - the name contains at least one non-space character and then the line is ended
  resource_id = /^[a-zA-Z_][a-zA-Z0-9._]*:[^\/]+\/\S+$/
  string.match(resource_id) ? on_match : ''
end
scroll_to(text, scrollable_index = 0) click to toggle source

Scroll to the first element containing target text or description. @param text [String] the text or resourceId to search for in the text value and content description @param scrollable_index [Integer] the index for scrollable views. @return [Element] the element scrolled to

# File lib/appium_lib/android/element/generic.rb, line 54
def scroll_to(text, scrollable_index = 0)
  text = %("#{text}")
  rid  = resource_id(text, "new UiSelector().resourceId(#{text})")
  args = rid.empty? ? ["new UiSelector().textContains(#{text})", "new UiSelector().descriptionContains(#{text})"] : [rid]
  args.each_with_index do |arg, index|
    elem = find_element :uiautomator, scroll_uiselector(arg, scrollable_index)
    return elem
  rescue StandardError => e
    raise e if index == args.size - 1
  end
end
scroll_to_exact(text, scrollable_index = 0) click to toggle source

Scroll to the first element with the exact target text or description. @param text [String] the text or resourceId to search for in the text value and content description @param scrollable_index [Integer] the index for scrollable views. @return [Element] the element scrolled to

# File lib/appium_lib/android/element/generic.rb, line 70
def scroll_to_exact(text, scrollable_index = 0)
  text = %("#{text}")
  rid  = resource_id(text, "new UiSelector().resourceId(#{text})")
  args = rid.empty? ? ["new UiSelector().text(#{text})", "new UiSelector().description(#{text})"] : [rid]
  args.each_with_index do |arg, index|
    elem = find_element :uiautomator, scroll_uiselector(arg, scrollable_index)
    return elem
  rescue StandardError => e
    raise e if index == args.size - 1
  end
end
scroll_uiselector(content, index = 0) click to toggle source

@private

# File lib/appium_lib/android/element/generic.rb, line 46
def scroll_uiselector(content, index = 0)
  "new UiScrollable(new UiSelector().scrollable(true).instance(#{index})).scrollIntoView(#{content}.instance(0));"
end
string_visible_contains(class_name, value) click to toggle source

Returns a string that matches the first element that contains value For automationName is Appium example: string_visible_contains ‘UIATextField’, ‘sign in’ note for XPath: github.com/appium/ruby_lib/pull/561

@param class_name [String] the class name for the element @param value [String] the value to search for @return [String]

# File lib/appium_lib/android/common/helper.rb, line 252
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
string_visible_contains_xpath(class_name, value) click to toggle source

Returns a string that matches the first element that contains value For automationName is uiautomator2 example: string_visible_contains_xpath ‘UIATextField’, ‘sign in’ note for XPath: github.com/appium/ruby_lib/pull/561

@param class_name [String] the class name for the element @param value [String] the value to search for @return [String]

# File lib/appium_lib/android/common/helper.rb, line 232
def string_visible_contains_xpath(class_name, value)
  r_id = resource_id(value, " or @resource-id='#{value}'")

  if class_name == '*'
    return "//*[contains(translate(@text,'#{value.upcase}', '#{value}'), '#{value}') " \
           "or contains(translate(@content-desc,'#{value.upcase}', '#{value}'), '#{value}')" + r_id + ']'
  end

  "//#{class_name}[contains(translate(@text,'#{value.upcase}', '#{value}'), '#{value}') " \
  "or contains(translate(@content-desc,'#{value.upcase}', '#{value}'), '#{value}')" + r_id + ']'
end
string_visible_exact(class_name, value) click to toggle source

@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]

# File lib/appium_lib/android/common/helper.rb, line 301
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
string_visible_exact_xpath(class_name, value) click to toggle source

@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]

# File lib/appium_lib/android/common/helper.rb, line 288
def string_visible_exact_xpath(class_name, value)
  r_id = resource_id(value, " or @resource-id='#{value}'")

  return "//*[@text='#{value}' or @content-desc='#{value}'" + r_id + ']' if class_name == '*'

  "//#{class_name}[@text='#{value}' or @content-desc='#{value}'" + r_id + ']'
end
tag(class_name) click to toggle source

Find the first element of type class_name

@param class_name [String] the class_name to search for @return [Element]

# File lib/appium_lib/android/common/helper.rb, line 181
def tag(class_name)
  find_element :class, class_name
end
tags(class_name) click to toggle source

Find all elements of type class_name

@param class_name [String] the class_name to search for @return [Element]

# File lib/appium_lib/android/common/helper.rb, line 189
def tags(class_name)
  find_elements :class, class_name
end
text(value) click to toggle source

Find the first TextView that contains value or by index. @param value [String, Integer] the value to find. If int then the TextView at that index is returned. @return [TextView]

# File lib/appium_lib/android/element/text.rb, line 25
def text(value)
  return ele_index TEXT_VIEW, value if value.is_a? Numeric

  complex_find_contains TEXT_VIEW, value
end
text_exact(value) click to toggle source

Find the first TextView that exactly matches value. @param value [String] the value to match exactly @return [TEXT_VIEW]

# File lib/appium_lib/android/element/text.rb, line 56
def text_exact(value)
  complex_find_exact TEXT_VIEW, value
end
textfield(value) click to toggle source

Find the first EditText that contains value or by index. @param value [String, Integer] the text to match exactly. If int then the EditText at that index is returned. @return [EDIT_TEXT]

# File lib/appium_lib/android/element/textfield.rb, line 24
def textfield(value)
  return ele_index EDIT_TEXT, value if value.is_a? Numeric

  complex_find_contains EDIT_TEXT, value
end
textfield_exact(value) click to toggle source

Find the first EditText that exactly matches value. @param value [String] the value to match exactly @return [EDIT_TEXT]

# File lib/appium_lib/android/element/textfield.rb, line 55
def textfield_exact(value)
  complex_find_exact EDIT_TEXT, value
end
textfields(value = false) click to toggle source

Find all EditTexts containing value. If value is omitted, all EditTexts are returned. @param value [String] the value to search for @return [Array<EDIT_TEXT>]

# File lib/appium_lib/android/element/textfield.rb, line 34
def textfields(value = false)
  return tags EDIT_TEXT unless value

  complex_finds_contains EDIT_TEXT, value
end
textfields_exact(value) click to toggle source

Find all EditTexts that exactly match value. @param value [String] the value to match exactly @return [Array<EDIT_TEXT>]

# File lib/appium_lib/android/element/textfield.rb, line 62
def textfields_exact(value)
  complex_finds_exact EDIT_TEXT, value
end
texts(value = false) click to toggle source

Find all TextViews containing value. If value is omitted, all texts are returned. @param value [String] the value to search for @return [Array<TEXT_VIEW>]

# File lib/appium_lib/android/element/text.rb, line 35
def texts(value = false)
  return tags TEXT_VIEW unless value

  complex_finds_contains TEXT_VIEW, value
end
texts_exact(value) click to toggle source

Find all TextViews that exactly match value. @param value [String] the value to match exactly @return [Array<TEXT_VIEW>]

# File lib/appium_lib/android/element/text.rb, line 63
def texts_exact(value)
  complex_finds_exact TEXT_VIEW, value
end

Private Instance Methods

_button_contains_string(value) click to toggle source
# File lib/appium_lib/android/element/button.rb, line 114
def _button_contains_string(value)
  button       = string_visible_contains BUTTON, value
  image_button = string_visible_contains IMAGE_BUTTON, value
  button + image_button
end
_button_exact_string(value) click to toggle source
# File lib/appium_lib/android/element/button.rb, line 108
def _button_exact_string(value)
  button       = string_visible_exact BUTTON, value
  image_button = string_visible_exact IMAGE_BUTTON, value
  button + image_button
end
_button_visible_selectors(opts = {}) click to toggle source
# File lib/appium_lib/android/element/button.rb, line 95
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(#{IMAGE_BUTTON}).instance(#{image_button_index});"
  else
    "new UiSelector().className(#{BUTTON});" \
      "new UiSelector().className(#{IMAGE_BUTTON});"
  end
end
raise_no_such_element_if_empty(elements) click to toggle source

@private

# File lib/appium_lib/android/element/button.rb, line 89
def raise_no_such_element_if_empty(elements)
  raise _no_such_element if elements.empty?

  elements.first
end