Module: Appium::Android
- Defined in:
- lib/appium_lib/android/patch.rb,
lib/appium_lib/android/helper.rb,
lib/appium_lib/android/element/alert.rb,
lib/appium_lib/android/element/generic.rb,
lib/appium_lib/android/element/textfield.rb
Instance Method Summary collapse
-
#alert_accept ⇒ void
Accept the alert.
-
#alert_accept_text ⇒ String
Get the text of the alert’s accept button.
-
#alert_click(value) ⇒ void
Tap the alert button identified by value.
-
#alert_dismiss ⇒ void
Dismiss the alert.
-
#alert_dismiss_text ⇒ String
Get the text of the alert’s dismiss button.
-
#e_textfields ⇒ Array<Textfield>
Get an array of textfield elements.
-
#fast_duration ⇒ Object
JavaScript code from github.com/appium/appium/blob/master/app/android.js.
-
#find(val) ⇒ Element
Find the value contained in content description or text.
-
#find_eles_attr(tag_name, attribute = nil) ⇒ Element
Find all elements matching the attribute On android, assume the attr is name (which falls back to text).
-
#first_textfield ⇒ Textfield
Get the first textfield element.
-
#get_android_inspect ⇒ String
Android only.
-
#get_inspect ⇒ String
Automatically detects selendroid or android.
-
#get_selendroid_inspect ⇒ String
Selendroid only.
-
#last_textfield ⇒ Textfield
Get the last textfield element.
-
#name(name) ⇒ Element
Return the first element matching name.
-
#names(name) ⇒ Array<Element>
Return all elements matching name.
-
#page ⇒ Object
Intended for use with console.
-
#page_class ⇒ Object
Count all classes on screen and print to stdout.
-
#patch_webdriver_element ⇒ Object
class_eval inside a method because class Selenium::WebDriver::Element will trigger as soon as the file is required.
- #prefix(*tags) ⇒ Object
- #run(node) ⇒ Object
-
#scroll_to(text) ⇒ Element
Scroll to an element containing target text or description.
-
#tag_name_to_android(tag_name) ⇒ String
Returns an array of android classes that match the tag name.
-
#text(text) ⇒ Element
Return the first element matching text.
-
#textfield(text) ⇒ Textfield
Get the first textfield that includes text or name (content description).
-
#textfield_exact(text) ⇒ Textfield
Get the first textfield that matches text.
-
#textfields ⇒ Array<String>
Get an array of textfield texts.
-
#texts(text) ⇒ Array<Element>
Return all elements matching text.
Instance Method Details
#alert_accept ⇒ void
This method returns an undefined value.
Accept the alert. The last button is considered “accept.”
13 14 15 |
# File 'lib/appium_lib/android/element/alert.rb', line 13 def alert_accept .click end |
#alert_accept_text ⇒ String
Get the text of the alert’s accept button. The last button is considered “accept.”
20 21 22 |
# File 'lib/appium_lib/android/element/alert.rb', line 20 def alert_accept_text .text end |
#alert_click(value) ⇒ void
This method returns an undefined value.
Tap the alert button identified by value.
6 7 8 |
# File 'lib/appium_lib/android/element/alert.rb', line 6 def alert_click value (value).click end |
#alert_dismiss ⇒ void
This method returns an undefined value.
Dismiss the alert. The first button is considered “dismiss.”
27 28 29 |
# File 'lib/appium_lib/android/element/alert.rb', line 27 def alert_dismiss .click end |
#alert_dismiss_text ⇒ String
Get the text of the alert’s dismiss button. The first button is considered “dismiss.”
34 35 36 |
# File 'lib/appium_lib/android/element/alert.rb', line 34 def alert_dismiss_text .text end |
#e_textfields ⇒ Array<Textfield>
Get an array of textfield elements.
13 14 15 |
# File 'lib/appium_lib/android/element/textfield.rb', line 13 def e_textfields find_eles :textfield end |
#fast_duration ⇒ Object
JavaScript code from github.com/appium/appium/blob/master/app/android.js
“‘javascript Math.round((duration * 1000) / 200) (.20 * 1000) / 200 = 1 “`
We want steps to be exactly 1. If it’s zero then a tap is used instead of a swipe.
231 232 233 |
# File 'lib/appium_lib/android/helper.rb', line 231 def fast_duration 0.20 end |
#find(val) ⇒ Element
Find the value contained in content description or text. Search elements in this order: EditText, Button, ImageButton
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/appium_lib/android/element/generic.rb', line 44 def find val # s.className('android.widget.EditText').descriptionContains(value); args = [ [4, 'android.widget.EditText'], [7, val] ], # s.className('android.widget.EditText').textContains(value); [ [4, 'android.widget.EditText'], [3, val] ], # s.className('android.widget.Button').descriptionContains(value); [ [4, 'android.widget.Button'], [7, val] ], # s.className('android.widget.Button').textContains(value); [ [4, 'android.widget.Button'], [3, val] ], # s.className('android.widget.ImageButton').descriptionContains(value); [ [4, 'android.widget.ImageButton'], [7, val] ], # s.className('android.widget.ImageButton').textContains(value); [ [4, 'android.widget.ImageButton'], [3, val] ], # s.descriptionContains(value); [ [7, val] ], # s.textContains(value); [ [3, val] ] mobile :find, args end |
#find_eles_attr(tag_name, attribute = nil) ⇒ Element
Find all elements matching the attribute On android, assume the attr is name (which falls back to text).
“‘ruby
find_eles_attr :text
“‘
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/appium_lib/android/helper.rb', line 48 def find_eles_attr tag_name, attribute=nil =begin sel1 = [ [4, 'android.widget.Button'], [100] ] sel2 = [ [4, 'android.widget.ImageButton'], [100] ] args = [ 'all', sel1, sel2 ] mobile :find, args =end array = ['all'] tag_name_to_android(tag_name).each do |name| # sel.className(name).getStringAttribute("name") array.push [ [4, name], [100] ] end mobile :find, array end |
#first_textfield ⇒ Textfield
Get the first textfield element.
19 20 21 |
# File 'lib/appium_lib/android/element/textfield.rb', line 19 def first_textfield first_ele :textfield end |
#get_android_inspect ⇒ String
Android only. Returns a string containing interesting elements. If an element has no content desc or text, then it’s not returned by this method.
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
# File 'lib/appium_lib/android/helper.rb', line 163 def get_android_inspect # @private def run node r = [] run_internal = lambda do |node| if node.kind_of? Array node.each { |node| run_internal.call node } return end keys = node.keys return if keys.empty? obj = {} obj.merge!( { desc: node['@content-desc'] } ) if keys.include?('@content-desc') && !node['@content-desc'].empty? obj.merge!( { text: node['@text'] } ) if keys.include?('@text') && !node['@text'].empty? obj.merge!( { class: node['@class'] } ) if keys.include?('@class') && !obj.empty? r.push obj if !obj.empty? run_internal.call node['node'] if keys.include?('node') end run_internal.call node r end json = get_source node = json['hierarchy'] results = run node out = '' results.each { |e| out += e[:class].split('.').last + "\n" out += " class: #{e[:class]}\n" if e[:text] == e[:desc] out += " text, name: #{e[:text]}\n" unless e[:text].nil? else out += " text: #{e[:text]}\n" unless e[:text].nil? out += " name: #{e[:desc]}\n" unless e[:desc].nil? end } out end |
#get_inspect ⇒ String
Automatically detects selendroid or android. Returns a string containing interesting elements.
212 213 214 |
# File 'lib/appium_lib/android/helper.rb', line 212 def get_inspect @selendroid ? get_selendroid_inspect : get_android_inspect end |
#get_selendroid_inspect ⇒ String
Selendroid only. Returns a string containing interesting elements.
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/appium_lib/android/helper.rb', line 70 def get_selendroid_inspect # @private def run node r = [] run_internal = lambda do |node| if node.kind_of? Array node.each { |node| run_internal.call node } return end keys = node.keys return if keys.empty? obj = {} # name is id obj.merge!( { id: node['name'] } ) if keys.include?('name') && !node['name'].empty? obj.merge!( { text: node['value'] } ) if keys.include?('value') && !node['value'].empty? # label is name obj.merge!( { name: node['label'] } ) if keys.include?('label') && !node['label'].empty? obj.merge!( { class: node['type'] } ) if keys.include?('type') && !obj.empty? obj.merge!( { shown: node['shown'] } ) if keys.include?('shown') r.push obj if !obj.empty? run_internal.call node['children'] if keys.include?('children') end run_internal.call node r end json = get_source node = json['children'] results = run node out = '' results.each { |e| no_text = e[:text].nil? no_name = e[:name].nil? || e[:name] == 'null' next unless e[:shown] # skip invisible # Ignore elements with id only. next if no_text && no_name out += e[:class].split('.').last + "\n" # name is id when using selendroid. # remove id/ prefix e[:id].sub!(/^id\//, '') if e[:id] out += " class: #{e[:class]}\n" # id('back_button').click out += " id: #{e[:id]}\n" unless e[:id].nil? # find_element(:link_text, 'text') out += " text: #{e[:text]}\n" unless no_text # label is name. default is 'null' # find_element(:link_text, 'Facebook') out += " name: #{e[:name]}\n" unless no_name # out += " visible: #{e[:shown]}\n" unless e[:shown].nil? } out end |
#last_textfield ⇒ Textfield
Get the last textfield element.
25 26 27 |
# File 'lib/appium_lib/android/element/textfield.rb', line 25 def last_textfield last_ele :textfield end |
#name(name) ⇒ Element
Return the first element matching name. on Android name is content description on iOS name is the accessibility label or the text.
88 89 90 91 92 |
# File 'lib/appium_lib/android/element/generic.rb', line 88 def name name # work around https://github.com/appium/appium/issues/543 # @driver.find_element :name, name mobile :find, [ [ [7, name] ] ] end |
#names(name) ⇒ Array<Element>
Return all elements matching name. on Android name is content description on iOS name is the accessibility label or the text.
99 100 101 102 103 |
# File 'lib/appium_lib/android/element/generic.rb', line 99 def names name args = 'all', [ [7, name] ] mobile :find, args end |
#page ⇒ Object
Intended for use with console. Inspects and prints the current page.
218 219 220 221 |
# File 'lib/appium_lib/android/helper.rb', line 218 def page puts get_inspect nil end |
#page_class ⇒ Object
Count all classes on screen and print to stdout. Useful for appium_console.
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/appium_lib/android/helper.rb', line 134 def page_class r = [] run_internal = lambda do |node| if node.kind_of? Array node.each { |node| run_internal.call node } return end keys = node.keys return if keys.empty? r.push node['@class'] if keys.include?('@class') run_internal.call node['node'] if keys.include?('node') end json = get_source run_internal.call json['hierarchy'] r = r.sort r.uniq.each do |ele| print r.count(ele) puts "x #{ele}\n" end nil end |
#patch_webdriver_element ⇒ Object
class_eval inside a method because class Selenium::WebDriver::Element will trigger as soon as the file is required. in contrast a method will trigger only when invoked.
7 8 9 10 11 12 13 14 |
# File 'lib/appium_lib/android/patch.rb', line 7 def patch_webdriver_element Selenium::WebDriver::Element.class_eval do # Cross platform way of entering text into a textfield def type text self.send_keys text end end end |
#prefix(*tags) ⇒ Object
10 11 12 |
# File 'lib/appium_lib/android/helper.rb', line 10 def prefix * .map!{ |tag| "android.widget.#{tag}" } end |
#run(node) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/appium_lib/android/helper.rb', line 72 def run node r = [] run_internal = lambda do |node| if node.kind_of? Array node.each { |node| run_internal.call node } return end keys = node.keys return if keys.empty? obj = {} # name is id obj.merge!( { id: node['name'] } ) if keys.include?('name') && !node['name'].empty? obj.merge!( { text: node['value'] } ) if keys.include?('value') && !node['value'].empty? # label is name obj.merge!( { name: node['label'] } ) if keys.include?('label') && !node['label'].empty? obj.merge!( { class: node['type'] } ) if keys.include?('type') && !obj.empty? obj.merge!( { shown: node['shown'] } ) if keys.include?('shown') r.push obj if !obj.empty? run_internal.call node['children'] if keys.include?('children') end run_internal.call node r end |
#scroll_to(text) ⇒ Element
Scroll to an element containing target text or description.
108 109 110 111 112 113 114 115 116 |
# File 'lib/appium_lib/android/element/generic.rb', line 108 def scroll_to text args = 'scroll', # textContains(text) [ [3, text] ], # descriptionContains(text) [ [7, text] ] mobile :find, args end |
#tag_name_to_android(tag_name) ⇒ String
Returns an array of android classes that match the tag name
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/appium_lib/android/helper.rb', line 6 def tag_name_to_android tag_name tag_name = tag_name.to_s.downcase.strip # @private def prefix * .map!{ |tag| "android.widget.#{tag}" } end # note that 'secure' is not an allowed tag name on android # because android can't tell what a secure textfield is # they're all edittexts. # must match names in AndroidElementClassMap (Appium's Java server) case tag_name when 'button' prefix 'Button', 'ImageButton' when 'text' prefix 'TextView' when 'list' prefix 'ListView' when 'window', 'frame' prefix 'FrameLayout' when 'grid' prefix 'GridView' when 'relative' prefix 'RelativeLayout' when 'linear' prefix 'LinearLayout' when 'textfield' prefix 'EditText' else raise "Invalid tag name #{tag_name}" end # return result of case end |
#text(text) ⇒ Element
Return the first element matching text.
70 71 72 73 74 |
# File 'lib/appium_lib/android/element/generic.rb', line 70 def text text # Return the first element matching selector. # s.textContains(value) mobile :find, [ [ [3, text] ] ] end |
#textfield(text) ⇒ Textfield
Get the first textfield that includes text or name (content description).
32 33 34 35 36 37 38 39 40 |
# File 'lib/appium_lib/android/element/textfield.rb', line 32 def textfield text return ele_index :textfield, text if text.is_a? Numeric # s.className('android.widget.EditText').descriptionContains(value); args = [ [4, 'android.widget.EditText'], [7, text] ], # s.className('android.widget.EditText').textContains(value); [ [4, 'android.widget.EditText'], [3, text] ] mobile :find, args end |
#textfield_exact(text) ⇒ Textfield
Get the first textfield that matches text.
45 46 47 |
# File 'lib/appium_lib/android/element/textfield.rb', line 45 def textfield_exact text find_ele_by_text :textfield, text end |
#textfields ⇒ Array<String>
Get an array of textfield texts.
7 8 9 |
# File 'lib/appium_lib/android/element/textfield.rb', line 7 def textfields find_eles_attr :textfield, :text end |
#texts(text) ⇒ Array<Element>
Return all elements matching text.
79 80 81 |
# File 'lib/appium_lib/android/element/generic.rb', line 79 def texts text @driver.find_elements :xpath, "//*[contains(@text, '#{text}')]" end |