Module: Appium::Android

Defined in:
lib/appium_lib/android/android.rb,
lib/appium_lib/android/espresso.rb,
lib/appium_lib/android/element/text.rb,
lib/appium_lib/android/uiautomator2.rb,
lib/appium_lib/android/common/helper.rb,
lib/appium_lib/android/element/alert.rb,
lib/appium_lib/android/element/button.rb,
lib/appium_lib/android/element/generic.rb,
lib/appium_lib/android/espresso/bridge.rb,
lib/appium_lib/android/espresso/helper.rb,
lib/appium_lib/android/espresso/element.rb,
lib/appium_lib/android/element/textfield.rb,
lib/appium_lib/android/uiautomator2/bridge.rb,
lib/appium_lib/android/uiautomator2/helper.rb,
lib/appium_lib/android/uiautomator2/element.rb,
lib/appium_lib/android/common/command/command.rb,
lib/appium_lib/android/espresso/element/button.rb,
lib/appium_lib/android/espresso/element/generic.rb,
lib/appium_lib/android/uiautomator2/element/button.rb

Defined Under Namespace

Modules: Command, Espresso, Uiautomator2 Classes: AndroidElements, Bridge

Constant Summary collapse

TEXT_VIEW =
'android.widget.TextView'
TextView =
TEXT_VIEW
BUTTON =
'android.widget.Button'
Button =

backward compatibility

BUTTON
IMAGE_BUTTON =
'android.widget.ImageButton'
ImageButton =

backward compatibility

IMAGE_BUTTON
EDIT_TEXT =
'android.widget.EditText'
EditText =
EDIT_TEXT

Instance Method Summary collapse

Instance Method Details

#alert_acceptvoid

This method returns an undefined value.

Accept the alert. The last button is considered “accept.”



27
28
29
# File 'lib/appium_lib/android/element/alert.rb', line 27

def alert_accept
  last_button.click
end

#alert_accept_textString

Get the text of the alert’s accept button. The last button is considered “accept.”



34
35
36
# File 'lib/appium_lib/android/element/alert.rb', line 34

def alert_accept_text
  last_button.text
end

#alert_click(value) ⇒ void

This method returns an undefined value.

Click the first alert button that contains value or by index.



20
21
22
# File 'lib/appium_lib/android/element/alert.rb', line 20

def alert_click(value)
  button(value).click
end

#alert_dismissvoid

This method returns an undefined value.

Dismiss the alert. The first button is considered “dismiss.”



41
42
43
# File 'lib/appium_lib/android/element/alert.rb', line 41

def alert_dismiss
  first_button.click
end

#alert_dismiss_textString

Get the text of the alert’s dismiss button. The first button is considered “dismiss.”



48
49
50
# File 'lib/appium_lib/android/element/alert.rb', line 48

def alert_dismiss_text
  first_button.text
end

#button(value) ⇒ BUTTON

Find the first button that contains value or by index. If int then the button at that index is returned.



27
28
29
30
31
32
33
34
35
36
37
38
39
# 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) ⇒ BUTTON

Find the first button that exactly matches value.



75
76
77
# 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) ⇒ Array<BUTTON>

Find all buttons containing value. If value is omitted, all buttons are returned.



45
46
47
48
49
# 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) ⇒ Array<BUTTON>

Find all buttons that exactly match value.



82
83
84
# 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) ⇒ Element

Find the first element that contains value



270
271
272
# 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) ⇒ Element

Find the first element exactly matching value



320
321
322
# 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) ⇒ Array<Element>

Find all elements containing value



278
279
280
# 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) ⇒ Element

Find all elements exactly matching value



328
329
330
# 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) ⇒ Element

Find the element of type class_name at matching index.



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# 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) ⇒ Element

Find the first element containing value



20
21
22
# File 'lib/appium_lib/android/element/generic.rb', line 20

def find(value)
  complex_find_contains '*', value
end

#find_exact(value) ⇒ Element

Find the first element exactly matching value



34
35
36
# File 'lib/appium_lib/android/element/generic.rb', line 34

def find_exact(value)
  complex_find_exact '*', value
end

#finds(value) ⇒ Array<Element>

Find all elements containing value



27
28
29
# File 'lib/appium_lib/android/element/generic.rb', line 27

def finds(value)
  complex_finds_contains '*', value
end

#finds_exact(value) ⇒ Array<Element>

Find all elements exactly matching value



41
42
43
# File 'lib/appium_lib/android/element/generic.rb', line 41

def finds_exact(value)
  complex_finds_exact '*', value
end

#first_buttonBUTTON

Find the first button.



53
54
55
# 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) ⇒ Element

Find the first element that matches class_name



166
167
168
# File 'lib/appium_lib/android/common/helper.rb', line 166

def first_ele(class_name)
  tag(class_name)
end

#first_textTEXT_VIEW

Find the first TextView.



43
44
45
# File 'lib/appium_lib/android/element/text.rb', line 43

def first_text
  first_ele TEXT_VIEW
end

#first_textfieldEDIT_TEXT

Find the first EditText.



42
43
44
# File 'lib/appium_lib/android/element/textfield.rb', line 42

def first_textfield
  first_ele EDIT_TEXT
end

#get_android_inspect(class_name = false) ⇒ String

Android only. Returns a string containing interesting elements. The text, content description, and id are returned. if false (default) then all classes will be inspected



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# 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) ⇒ Element

Find the first matching element by id



130
131
132
133
# 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) ⇒ Element

Find all matching elements by id



138
139
140
141
# 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_buttonBUTTON

Find the last button.



59
60
61
62
63
64
65
66
67
68
69
70
# 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) ⇒ Element

Find the last element that matches class_name



173
174
175
# File 'lib/appium_lib/android/common/helper.rb', line 173

def last_ele(class_name)
  ele_index class_name, 'last()'
end

#last_textTEXT_VIEW

Find the last TextView.



49
50
51
# File 'lib/appium_lib/android/element/text.rb', line 49

def last_text
  last_ele TEXT_VIEW
end

#last_textfieldEDIT_TEXT

Find the last EditText.



48
49
50
# File 'lib/appium_lib/android/element/textfield.rb', line 48

def last_textfield
  last_ele EDIT_TEXT
end

#page(opts = {}) ⇒ void

This method returns an undefined value.

Intended for use with console. Inspects and prints the current page. Will return XHTML for Web contexts because of a quirk with Nokogiri. if nil (default) then all classes will be inspected



121
122
123
124
125
# 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) ⇒ String

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



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# 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) ⇒ Element

Scroll to the first element containing target text or description.



54
55
56
57
58
59
60
61
62
63
64
# 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) ⇒ Element

Scroll to the first element with the exact target text or description.



70
71
72
73
74
75
76
77
78
79
80
# 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) ⇒ Object



46
47
48
# 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) ⇒ String

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



252
253
254
255
256
257
258
259
260
261
262
263
264
# 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) ⇒ String

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



232
233
234
235
236
237
238
239
240
241
242
# 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) ⇒ String

Create an string to exactly match the first element with target value



301
302
303
304
305
306
307
308
309
310
311
312
313
314
# 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) ⇒ String

Create an string to exactly match the first element with target value For automationName is uiautomator2



288
289
290
291
292
293
294
# 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) ⇒ Element

Find the first element of type class_name



181
182
183
# File 'lib/appium_lib/android/common/helper.rb', line 181

def tag(class_name)
  find_element :class, class_name
end

#tags(class_name) ⇒ Element

Find all elements of type class_name



189
190
191
# File 'lib/appium_lib/android/common/helper.rb', line 189

def tags(class_name)
  find_elements :class, class_name
end

#text(value) ⇒ TextView

Find the first TextView that contains value or by index. If int then the TextView at that index is returned.



25
26
27
28
29
# 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) ⇒ TEXT_VIEW

Find the first TextView that exactly matches value.



56
57
58
# File 'lib/appium_lib/android/element/text.rb', line 56

def text_exact(value)
  complex_find_exact TEXT_VIEW, value
end

#textfield(value) ⇒ EDIT_TEXT

Find the first EditText that contains value or by index. If int then the EditText at that index is returned.



24
25
26
27
28
# 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) ⇒ EDIT_TEXT

Find the first EditText that exactly matches value.



55
56
57
# File 'lib/appium_lib/android/element/textfield.rb', line 55

def textfield_exact(value)
  complex_find_exact EDIT_TEXT, value
end

#textfields(value = false) ⇒ Array<EDIT_TEXT>

Find all EditTexts containing value. If value is omitted, all EditTexts are returned.



34
35
36
37
38
# 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) ⇒ Array<EDIT_TEXT>

Find all EditTexts that exactly match value.



62
63
64
# File 'lib/appium_lib/android/element/textfield.rb', line 62

def textfields_exact(value)
  complex_finds_exact EDIT_TEXT, value
end

#texts(value = false) ⇒ Array<TEXT_VIEW>

Find all TextViews containing value. If value is omitted, all texts are returned.



35
36
37
38
39
# 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) ⇒ Array<TEXT_VIEW>

Find all TextViews that exactly match value.



63
64
65
# File 'lib/appium_lib/android/element/text.rb', line 63

def texts_exact(value)
  complex_finds_exact TEXT_VIEW, value
end