appium_lib 6.0.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +28 -0
- data/.travis.yml +10 -0
- data/Rakefile +9 -1
- data/android_tests/Gemfile +1 -1
- data/android_tests/Rakefile +20 -13
- data/android_tests/lib/android/specs/android/element/alert.rb +1 -1
- data/android_tests/lib/android/specs/android/element/button.rb +2 -2
- data/android_tests/lib/android/specs/android/element/generic.rb +1 -2
- data/android_tests/lib/android/specs/android/element/text.rb +2 -3
- data/android_tests/lib/android/specs/android/element/textfield.rb +2 -2
- data/android_tests/lib/android/specs/android/helper.rb +5 -3
- data/android_tests/lib/android/specs/android/patch.rb +2 -2
- data/android_tests/lib/android/specs/common/device.rb +16 -9
- data/android_tests/lib/android/specs/common/device_touchaction.rb +5 -2
- data/android_tests/lib/android/specs/common/element/window.rb +1 -1
- data/android_tests/lib/android/specs/common/helper.rb +14 -15
- data/android_tests/lib/android/specs/common/patch.rb +11 -9
- data/android_tests/lib/android/specs/common/version.rb +3 -3
- data/android_tests/lib/android/specs/common/web_context.rb +2 -3
- data/android_tests/lib/android/specs/driver.rb +38 -29
- data/android_tests/lib/android/specs/install.rb +3 -3
- data/android_tests/lib/format.rb +6 -8
- data/android_tests/lib/run.rb +25 -17
- data/android_tests/readme.md +4 -2
- data/appium_lib.gemspec +13 -11
- data/contributing.md +1 -1
- data/docs/android_docs.md +358 -274
- data/docs/ios_docs.md +333 -270
- data/docs/migration.md +10 -0
- data/docs_gen/make_docs.rb +3 -1
- data/ios_tests/Gemfile +1 -1
- data/ios_tests/Rakefile +17 -10
- data/ios_tests/appium.txt +1 -1
- data/ios_tests/lib/common.rb +8 -4
- data/ios_tests/lib/format.rb +5 -7
- data/ios_tests/lib/ios/specs/common/element/window.rb +1 -1
- data/ios_tests/lib/ios/specs/common/helper.rb +40 -39
- data/ios_tests/lib/ios/specs/common/patch.rb +15 -11
- data/ios_tests/lib/ios/specs/common/version.rb +3 -3
- data/ios_tests/lib/ios/specs/common/web_context.rb +1 -2
- data/ios_tests/lib/ios/specs/device/device.rb +7 -7
- data/ios_tests/lib/ios/specs/device/multi_touch.rb +6 -8
- data/ios_tests/lib/ios/specs/device/touch_actions.rb +12 -12
- data/ios_tests/lib/ios/specs/driver.rb +23 -22
- data/ios_tests/lib/ios/specs/ios/element/alert.rb +6 -2
- data/ios_tests/lib/ios/specs/ios/element/button.rb +2 -2
- data/ios_tests/lib/ios/specs/ios/element/generic.rb +1 -1
- data/ios_tests/lib/ios/specs/ios/element/text.rb +4 -1
- data/ios_tests/lib/ios/specs/ios/element/textfield.rb +6 -6
- data/ios_tests/lib/ios/specs/ios/helper.rb +5 -5
- data/ios_tests/lib/ios/specs/ios/patch.rb +2 -2
- data/ios_tests/lib/run.rb +1 -1
- data/ios_tests/readme.md +3 -3
- data/ios_tests/upload/sauce_storage.rb +8 -8
- data/ios_tests/upload/upload.rb +1 -1
- data/lib/appium_lib/android/client_xpath.rb +7 -7
- data/lib/appium_lib/android/element/alert.rb +2 -2
- data/lib/appium_lib/android/element/button.rb +16 -16
- data/lib/appium_lib/android/element/generic.rb +12 -13
- data/lib/appium_lib/android/element/text.rb +5 -5
- data/lib/appium_lib/android/element/textfield.rb +5 -5
- data/lib/appium_lib/android/helper.rb +82 -52
- data/lib/appium_lib/android/mobile_methods.rb +2 -2
- data/lib/appium_lib/android/patch.rb +3 -3
- data/lib/appium_lib/common/element/window.rb +1 -1
- data/lib/appium_lib/common/helper.rb +30 -35
- data/lib/appium_lib/common/patch.rb +22 -20
- data/lib/appium_lib/common/version.rb +3 -3
- data/lib/appium_lib/common/wait.rb +9 -10
- data/lib/appium_lib/device/device.rb +39 -33
- data/lib/appium_lib/device/multi_touch.rb +5 -7
- data/lib/appium_lib/device/touch_actions.rb +14 -15
- data/lib/appium_lib/driver.rb +97 -76
- data/lib/appium_lib/ios/element/alert.rb +1 -1
- data/lib/appium_lib/ios/element/button.rb +5 -5
- data/lib/appium_lib/ios/element/generic.rb +5 -6
- data/lib/appium_lib/ios/element/text.rb +5 -5
- data/lib/appium_lib/ios/element/textfield.rb +15 -15
- data/lib/appium_lib/ios/helper.rb +103 -90
- data/lib/appium_lib/ios/mobile_methods.rb +2 -2
- data/lib/appium_lib/ios/patch.rb +4 -4
- data/lib/appium_lib/logger.rb +7 -5
- data/lib/appium_lib/rails/duplicable.rb +3 -1
- data/readme.md +7 -1
- data/release_notes.md +152 -0
- metadata +28 -54
@@ -8,7 +8,7 @@ describe 'driver' do
|
|
8
8
|
before_first
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
11
|
+
def sauce?
|
12
12
|
ENV['UPLOAD_FILE'] && ENV['SAUCE_USERNAME']
|
13
13
|
end
|
14
14
|
|
@@ -20,7 +20,7 @@ describe 'driver' do
|
|
20
20
|
t 'load_appium_txt' do
|
21
21
|
# skip this test if we're using Sauce
|
22
22
|
# the storage API doesn't have an on disk file
|
23
|
-
skip if
|
23
|
+
skip if sauce?
|
24
24
|
appium_txt = File.expand_path(File.join(Dir.pwd, 'lib'))
|
25
25
|
opts = Appium.load_appium_txt file: appium_txt, verbose: true
|
26
26
|
|
@@ -36,7 +36,7 @@ describe 'driver' do
|
|
36
36
|
actual = driver_attributes
|
37
37
|
actual[:caps][:app] = File.basename actual[:caps][:app]
|
38
38
|
expected = { caps: { platformName: 'ios',
|
39
|
-
platformVersion: '8.
|
39
|
+
platformVersion: '8.3',
|
40
40
|
deviceName: 'iPhone Simulator',
|
41
41
|
app: 'UICatalog.app' },
|
42
42
|
custom_url: false,
|
@@ -82,7 +82,7 @@ describe 'driver' do
|
|
82
82
|
t 'app_path attr' do
|
83
83
|
apk_name = File.basename driver_attributes[:caps][:app]
|
84
84
|
|
85
|
-
if
|
85
|
+
if sauce?
|
86
86
|
apk_name.must_equal 'sauce-storage:UICatalog6.1.app.zip'
|
87
87
|
else
|
88
88
|
apk_name.must_equal 'UICatalog.app'
|
@@ -92,7 +92,7 @@ describe 'driver' do
|
|
92
92
|
# Only used for Sauce Labs
|
93
93
|
t 'app_name attr' do
|
94
94
|
name_attr = driver_attributes[:caps][:name]
|
95
|
-
if
|
95
|
+
if sauce?
|
96
96
|
name_attr.must_equal 'appium_lib_ios'
|
97
97
|
else
|
98
98
|
name_attr.must_be_nil
|
@@ -101,7 +101,7 @@ describe 'driver' do
|
|
101
101
|
|
102
102
|
t 'sauce_username attr' do
|
103
103
|
sauce_username = driver_attributes[:sauce_username]
|
104
|
-
if
|
104
|
+
if sauce?
|
105
105
|
sauce_username.must_equal 'appiumci'
|
106
106
|
else
|
107
107
|
sauce_username.must_be_nil
|
@@ -110,8 +110,8 @@ describe 'driver' do
|
|
110
110
|
|
111
111
|
t 'sauce_access_key attr' do
|
112
112
|
sauce_access_key = driver_attributes[:sauce_access_key]
|
113
|
-
if
|
114
|
-
sauce_access_key.must_match
|
113
|
+
if sauce?
|
114
|
+
sauce_access_key.must_match(/\h{8}-\h{4}-\h{4}-\h{4}-\h{12}/)
|
115
115
|
else
|
116
116
|
sauce_access_key.must_be_nil
|
117
117
|
end
|
@@ -119,11 +119,6 @@ describe 'driver' do
|
|
119
119
|
end
|
120
120
|
|
121
121
|
describe 'Appium::Driver' do
|
122
|
-
t '@@loaded' do
|
123
|
-
loaded = $driver.class.class_variable_get :@@loaded
|
124
|
-
loaded.must_equal true
|
125
|
-
end
|
126
|
-
|
127
122
|
t '$driver.class' do
|
128
123
|
$driver.class.must_equal Appium::Driver
|
129
124
|
end
|
@@ -136,10 +131,10 @@ describe 'driver' do
|
|
136
131
|
|
137
132
|
t 'server_version' do
|
138
133
|
server_version = appium_server_version['build']['version']
|
139
|
-
if
|
134
|
+
if sauce?
|
140
135
|
server_version.must_match 'Sauce OnDemand'
|
141
136
|
else
|
142
|
-
server_version.must_match
|
137
|
+
server_version.must_match(/(\d+)\.(\d+).(\d+)/)
|
143
138
|
end
|
144
139
|
end
|
145
140
|
|
@@ -152,12 +147,13 @@ describe 'driver' do
|
|
152
147
|
driver.browser.must_equal :iOS
|
153
148
|
end
|
154
149
|
|
155
|
-
|
156
|
-
|
157
|
-
screenshot # this is slow and already tested by Appium
|
158
|
-
driver_quit # tested by restart
|
159
|
-
start_driver # tested by restart
|
160
|
-
|
150
|
+
#
|
151
|
+
# Skip:
|
152
|
+
# screenshot # this is slow and already tested by Appium
|
153
|
+
# driver_quit # tested by restart
|
154
|
+
# start_driver # tested by restart
|
155
|
+
#
|
156
|
+
|
161
157
|
t 'set_wait' do
|
162
158
|
# fill the @last_waits array with: [30, 30]
|
163
159
|
set_wait(30).must_equal(30)
|
@@ -186,7 +182,12 @@ describe 'driver' do
|
|
186
182
|
# returns true unless an error is raised
|
187
183
|
t 'exists' do
|
188
184
|
exists(0, 0) { true }.must_equal true
|
189
|
-
exists(0, 0) {
|
185
|
+
exists(0, 0) { fail 'error' }.must_equal false
|
186
|
+
end
|
187
|
+
|
188
|
+
# simple integration sanity test to check for unexpected exceptions
|
189
|
+
t 'set_location' do
|
190
|
+
set_location latitude: 55, longitude: -72, altitude: 33
|
190
191
|
end
|
191
192
|
|
192
193
|
# any script
|
@@ -2,7 +2,11 @@
|
|
2
2
|
describe 'ios/element/alert' do
|
3
3
|
def nav_once
|
4
4
|
screen.must_equal catalog
|
5
|
-
wait_true
|
5
|
+
wait_true do
|
6
|
+
text('alerts').click
|
7
|
+
tag('UIANavigationBar').name == 'Alerts' # wait for true
|
8
|
+
end
|
9
|
+
|
6
10
|
tag('UIANavigationBar').name.must_equal 'Alerts'
|
7
11
|
|
8
12
|
# redefine method as no-op after it's invoked once
|
@@ -40,4 +44,4 @@ describe 'ios/element/alert' do
|
|
40
44
|
t 'after_last' do
|
41
45
|
after_last
|
42
46
|
end
|
43
|
-
end
|
47
|
+
end
|
@@ -30,7 +30,7 @@ describe 'ios/element/button' do
|
|
30
30
|
t 'buttons' do
|
31
31
|
exp = ['Back', 'Back', 'Gray', 'Right pointing arrow']
|
32
32
|
target_buttons = buttons('a')
|
33
|
-
target_buttons.map
|
33
|
+
target_buttons.map(&:name).must_equal exp
|
34
34
|
target_buttons.length.must_equal exp.length
|
35
35
|
end
|
36
36
|
|
@@ -53,4 +53,4 @@ describe 'ios/element/button' do
|
|
53
53
|
t 'after_last' do
|
54
54
|
after_last
|
55
55
|
end
|
56
|
-
end
|
56
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# rubocop:disable Lint/HandleExceptions
|
2
|
+
|
1
3
|
# rake ios['ios/element/text']
|
2
4
|
describe 'ios/element/text' do
|
3
5
|
def ui_catalog
|
@@ -34,7 +36,7 @@ describe 'ios/element/text' do
|
|
34
36
|
t 'texts' do
|
35
37
|
exp = ['Controls', 'Various uses of UIControl', 'Various uses of UISegmentedControl']
|
36
38
|
texts.length.must_equal 24
|
37
|
-
texts('trol').map
|
39
|
+
texts('trol').map(&:name).must_equal exp
|
38
40
|
texts('uses').length.must_equal 7
|
39
41
|
end
|
40
42
|
|
@@ -44,6 +46,7 @@ describe 'ios/element/text' do
|
|
44
46
|
act = begin
|
45
47
|
text_exact 'mos'
|
46
48
|
rescue
|
49
|
+
# nop
|
47
50
|
end
|
48
51
|
act.must_be_nil
|
49
52
|
set_wait
|
@@ -27,14 +27,14 @@ describe 'ios/element/textfield' do
|
|
27
27
|
end
|
28
28
|
|
29
29
|
t 'textfields' do
|
30
|
-
values = textfields('enter').map
|
30
|
+
values = textfields('enter').map(&:value)
|
31
31
|
values.include?('<enter text>').must_equal true
|
32
32
|
values.include?('<enter password>').must_equal true
|
33
33
|
textfields.length.must_equal 4
|
34
34
|
end
|
35
35
|
|
36
36
|
t 'predicate textfields' do
|
37
|
-
textfield_count = execute_script(%
|
37
|
+
textfield_count = execute_script(%(au.mainApp().getAllWithPredicate("type contains[c] 'textfield'", true))).length
|
38
38
|
textfield_count.must_equal 4
|
39
39
|
end
|
40
40
|
|
@@ -72,14 +72,14 @@ describe 'ios/element/textfield' do
|
|
72
72
|
textfield(1).send_keys 'ok'
|
73
73
|
keyboard_must_exist
|
74
74
|
|
75
|
-
# type
|
75
|
+
# type should not dismiss the keyboard
|
76
76
|
message = 'type test type'
|
77
77
|
textfield(1).type message
|
78
|
-
|
78
|
+
keyboard_must_exist
|
79
79
|
textfield(1).text.must_equal message
|
80
80
|
end
|
81
81
|
|
82
|
-
def must_raise_no_element
|
82
|
+
def must_raise_no_element(&block)
|
83
83
|
proc { block.call }.must_raise Selenium::WebDriver::Error::NoSuchElementError
|
84
84
|
end
|
85
85
|
|
@@ -123,4 +123,4 @@ describe 'ios/element/textfield' do
|
|
123
123
|
t 'after_last' do
|
124
124
|
after_last
|
125
125
|
end
|
126
|
-
end
|
126
|
+
end
|
@@ -13,7 +13,7 @@ describe 'ios/helper' do
|
|
13
13
|
ios_password(2).must_equal 8226.chr('UTF-8') * 2
|
14
14
|
end
|
15
15
|
|
16
|
-
#
|
16
|
+
# TODO: t 'get_page' do
|
17
17
|
|
18
18
|
# t 'page' do # writes to std out
|
19
19
|
|
@@ -21,7 +21,7 @@ describe 'ios/helper' do
|
|
21
21
|
source_window.length.must_equal 11
|
22
22
|
end
|
23
23
|
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
end
|
24
|
+
# TODO: t 'page_window' do
|
25
|
+
# TODO: t 'id' do
|
26
|
+
# TODO: t 'ios_version' do
|
27
|
+
end
|
data/ios_tests/lib/run.rb
CHANGED
data/ios_tests/readme.md
CHANGED
@@ -12,7 +12,7 @@ ruby_lib's iOS tests. Requires `Ruby 1.9.3` or better.
|
|
12
12
|
|
13
13
|
`UICatalog6.1` is from [appium/appium](https://github.com/appium/appium/blob/master/assets/UICatalog6.1.app.zip)
|
14
14
|
|
15
|
-
The tests are now run against `iPhone Simulator
|
15
|
+
The tests are now run against `iPhone 6 Simulator 8.3 (12F69)`
|
16
16
|
|
17
17
|
#### Documentation
|
18
18
|
|
@@ -24,7 +24,7 @@ The tests are now run against `iPhone Simulator 7.0.3 (11B508)`
|
|
24
24
|
--
|
25
25
|
|
26
26
|
```java
|
27
|
-
Finished in 1 min
|
27
|
+
Finished in 1 min 57 secs
|
28
28
|
|
29
|
-
|
29
|
+
123 runs, 164 assertions, 0 failures, 0 errors, 0 skips
|
30
30
|
```
|
@@ -6,13 +6,13 @@ s = SauceStorage.new username: 'my_user_name', key: '00', debug: true
|
|
6
6
|
# or if you have SAUCE_USERNAME and SAUCE_ACCESS_KEY in env already
|
7
7
|
|
8
8
|
s = SauceStorage.new debug: true
|
9
|
-
|
9
|
+
|
10
10
|
# list all files
|
11
11
|
s.files
|
12
|
-
|
12
|
+
|
13
13
|
# upload a file
|
14
14
|
s.upload '/tmp/sauce/test.zip'
|
15
|
-
|
15
|
+
|
16
16
|
> s.files
|
17
17
|
=> [{"size"=>8,
|
18
18
|
"mtime"=>1367700857.1011374,
|
@@ -30,20 +30,20 @@ require 'json'
|
|
30
30
|
class SauceStorage
|
31
31
|
attr_reader :username, :key, :url, :debug
|
32
32
|
|
33
|
-
def initialize
|
33
|
+
def initialize(opts)
|
34
34
|
@username = opts.fetch :username, ENV['SAUCE_USERNAME']
|
35
35
|
@key = opts.fetch :key, ENV['SAUCE_ACCESS_KEY']
|
36
36
|
@url = "https://#{@username}:#{@key}@saucelabs.com/rest/v1/storage/#{@username}"
|
37
37
|
@debug = opts.fetch :debug, false
|
38
38
|
end
|
39
39
|
|
40
|
-
def upload
|
40
|
+
def upload(file_path)
|
41
41
|
file_name = File.basename file_path
|
42
42
|
file = File.new file_path
|
43
43
|
local_md5 = Digest::MD5.hexdigest File.read file_path
|
44
44
|
|
45
|
-
|
46
|
-
if
|
45
|
+
files.each do |f|
|
46
|
+
if f['md5'] == local_md5
|
47
47
|
puts 'File already uploaded' if @debug
|
48
48
|
return true
|
49
49
|
end
|
@@ -62,4 +62,4 @@ class SauceStorage
|
|
62
62
|
def files
|
63
63
|
JSON.parse(RestClient.get @url)['files']
|
64
64
|
end
|
65
|
-
end
|
65
|
+
end
|
data/ios_tests/upload/upload.rb
CHANGED
@@ -2,7 +2,7 @@ require 'nokogiri'
|
|
2
2
|
|
3
3
|
module Appium
|
4
4
|
module Android
|
5
|
-
def _nodeset_to_uiselector
|
5
|
+
def _nodeset_to_uiselector(opts = {})
|
6
6
|
results = ''
|
7
7
|
|
8
8
|
nodes = opts[:nodes]
|
@@ -11,16 +11,16 @@ module Appium
|
|
11
11
|
nodes = [nodes[0]] if first
|
12
12
|
|
13
13
|
nodes.each do |node|
|
14
|
-
results += %
|
14
|
+
results += %(new UiSelector().className("#{node.name}").instance(#{node.attr('instance')});)
|
15
15
|
end
|
16
16
|
|
17
17
|
results.strip
|
18
18
|
end
|
19
19
|
|
20
|
-
def _client_xpath
|
20
|
+
def _client_xpath(opts = {})
|
21
21
|
root_node = Nokogiri::XML(get_source).children.first
|
22
22
|
|
23
|
-
instance = Hash.new
|
23
|
+
instance = Hash.new(-1)
|
24
24
|
|
25
25
|
root_node.traverse do |node|
|
26
26
|
number = instance[node.name] += 1
|
@@ -33,15 +33,15 @@ module Appium
|
|
33
33
|
_nodeset_to_uiselector nodes: nodes, first: first
|
34
34
|
end
|
35
35
|
|
36
|
-
def client_xpath
|
36
|
+
def client_xpath(xpath)
|
37
37
|
find_element :uiautomator, _client_xpath(xpath: xpath, first: true)
|
38
38
|
end
|
39
39
|
|
40
|
-
def client_xpaths
|
40
|
+
def client_xpaths(xpath)
|
41
41
|
find_elements :uiautomator, _client_xpath(xpath: xpath, first: false)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
46
|
# http://stackoverflow.com/questions/9199415/getting-first-node-in-xpath-result-set
|
47
|
-
# '(//android.widget.TextView)[1]' not '//android.widget.TextView[1]'
|
47
|
+
# '(//android.widget.TextView)[1]' not '//android.widget.TextView[1]'
|
@@ -3,7 +3,7 @@ module Appium
|
|
3
3
|
# Click the first alert button that contains value or by index.
|
4
4
|
# @param value [Integer, String] either an integer index of the button or the button's name
|
5
5
|
# @return [void]
|
6
|
-
def alert_click
|
6
|
+
def alert_click(value)
|
7
7
|
button(value).click
|
8
8
|
end
|
9
9
|
|
@@ -35,4 +35,4 @@ module Appium
|
|
35
35
|
first_button.text
|
36
36
|
end
|
37
37
|
end # module Android
|
38
|
-
end # module Appium
|
38
|
+
end # module Appium
|
@@ -7,28 +7,28 @@ module Appium
|
|
7
7
|
private
|
8
8
|
|
9
9
|
# @private
|
10
|
-
def _button_visible_selectors
|
10
|
+
def _button_visible_selectors(opts = {})
|
11
11
|
button_index = opts.fetch :button_index, false
|
12
12
|
image_button_index = opts.fetch :image_button_index, false
|
13
13
|
|
14
14
|
if button_index && image_button_index
|
15
|
-
"new UiSelector().className(#{Button}).instance(#{button_index});"
|
16
|
-
|
15
|
+
"new UiSelector().className(#{Button}).instance(#{button_index});" \
|
16
|
+
"new UiSelector().className(#{ImageButton}).instance(#{image_button_index});"
|
17
17
|
else
|
18
|
-
"new UiSelector().className(#{Button});"
|
19
|
-
|
18
|
+
"new UiSelector().className(#{Button});" \
|
19
|
+
"new UiSelector().className(#{ImageButton});"
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
# @private
|
24
|
-
def _button_exact_string
|
24
|
+
def _button_exact_string(value)
|
25
25
|
button = string_visible_exact Button, value
|
26
26
|
image_button = string_visible_exact ImageButton, value
|
27
27
|
button + image_button
|
28
28
|
end
|
29
29
|
|
30
30
|
# @private
|
31
|
-
def _button_contains_string
|
31
|
+
def _button_contains_string(value)
|
32
32
|
button = string_visible_contains Button, value
|
33
33
|
image_button = string_visible_contains ImageButton, value
|
34
34
|
button + image_button
|
@@ -40,12 +40,12 @@ module Appium
|
|
40
40
|
# @param value [String, Integer] the value to exactly match.
|
41
41
|
# If int then the button at that index is returned.
|
42
42
|
# @return [Button]
|
43
|
-
def button
|
43
|
+
def button(value)
|
44
44
|
# Don't use ele_index because that only works on one element type.
|
45
45
|
# Android needs to combine button and image button to match iOS.
|
46
46
|
if value.is_a? Numeric
|
47
47
|
index = value
|
48
|
-
|
48
|
+
fail "#{index} is not a valid index. Must be >= 1" if index <= 0
|
49
49
|
|
50
50
|
return find_element :uiautomator, _button_visible_selectors(index: index)
|
51
51
|
end
|
@@ -57,7 +57,7 @@ module Appium
|
|
57
57
|
# If value is omitted, all buttons are returned.
|
58
58
|
# @param value [String] the value to search for
|
59
59
|
# @return [Array<Button>]
|
60
|
-
def buttons
|
60
|
+
def buttons(value = false)
|
61
61
|
return find_elements :uiautomator, _button_visible_selectors unless value
|
62
62
|
find_elements :uiautomator, _button_contains_string(value)
|
63
63
|
end
|
@@ -73,28 +73,28 @@ module Appium
|
|
73
73
|
def last_button
|
74
74
|
# uiautomator index doesn't support last
|
75
75
|
# and it's 0 indexed
|
76
|
-
button_index
|
77
|
-
button_index
|
76
|
+
button_index = tags(Button).length
|
77
|
+
button_index -= 1 if button_index > 0
|
78
78
|
image_button_index = tags(ImageButton).length
|
79
79
|
image_button_index -= 1 if image_button_index > 0
|
80
80
|
|
81
81
|
find_element :uiautomator,
|
82
82
|
_button_visible_selectors(button_index: button_index,
|
83
|
-
|
83
|
+
image_button_index: image_button_index)
|
84
84
|
end
|
85
85
|
|
86
86
|
# Find the first button that exactly matches value.
|
87
87
|
# @param value [String] the value to match exactly
|
88
88
|
# @return [Button]
|
89
|
-
def button_exact
|
89
|
+
def button_exact(value)
|
90
90
|
find_element :uiautomator, _button_exact_string(value)
|
91
91
|
end
|
92
92
|
|
93
93
|
# Find all buttons that exactly match value.
|
94
94
|
# @param value [String] the value to match exactly
|
95
95
|
# @return [Array<Button>]
|
96
|
-
def buttons_exact
|
96
|
+
def buttons_exact(value)
|
97
97
|
find_elements :uiautomator, _button_exact_string(value)
|
98
98
|
end
|
99
99
|
end # module Android
|
100
|
-
end # module Appium
|
100
|
+
end # module Appium
|