appium_lib 6.0.0 → 7.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/docs/migration.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
### Breaking Changes in 7.0
|
2
|
+
|
3
|
+
Requires appium 1.4.0-beta or newer for iOS helper methods. appium_lib no longer automatically promotes methods on minispec. To restore the old behavior use: `Appium.promote_appium_methods ::Minitest::Spec`
|
4
|
+
|
5
|
+
The implicit wait now defaults to zero. To restore the old behavior, use `set_wait 30`.
|
6
|
+
|
7
|
+
Old | New
|
8
|
+
:--|:--
|
9
|
+
`installed?` | `app_installed?`
|
10
|
+
|
1
11
|
### Breaking Changes in 5.0
|
2
12
|
|
3
13
|
Old | New
|
data/docs_gen/make_docs.rb
CHANGED
@@ -30,13 +30,15 @@ def mobj_to_md obj
|
|
30
30
|
out += "> #{obj.signature}\n\n"
|
31
31
|
out += "#{obj.docstring}\n\n"
|
32
32
|
|
33
|
+
# puts "Processing: #{obj.name} #{method_path}"
|
33
34
|
|
34
35
|
indent = space 5
|
35
36
|
params = obj.tags.select { |tag| tag.tag_name == 'param' }
|
36
37
|
if !params.empty?
|
37
38
|
out += "__Parameters:__\n\n"
|
38
39
|
params.each do |param|
|
39
|
-
|
40
|
+
param_types = param.types ? "[#{param.types.join ', '}] " : ''
|
41
|
+
out += indent + param_types
|
40
42
|
out += "#{param.name} - #{param.text}\n\n"
|
41
43
|
end
|
42
44
|
end
|
data/ios_tests/Gemfile
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
|
-
gemspec path: File.expand_path('../../', __FILE__) # __dir__ fails on 1.9
|
2
|
+
gemspec path: File.expand_path('../../', __FILE__) # __dir__ fails on 1.9
|
data/ios_tests/Rakefile
CHANGED
@@ -1,22 +1,22 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
|
+
require 'rubocop/rake_task'
|
3
4
|
|
4
|
-
task :
|
5
|
+
task default: :ios
|
5
6
|
|
6
7
|
# Run sh and ignore exception
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
8
|
+
# rubocop:disable Lint/HandleExceptions
|
9
|
+
def run_sh(cmd)
|
10
|
+
sh cmd
|
11
|
+
rescue
|
12
12
|
end
|
13
13
|
|
14
14
|
# Run cmd. On failure run install and try again.
|
15
|
-
def bash
|
15
|
+
def bash(cmd)
|
16
16
|
sh cmd do |successful, result|
|
17
17
|
# exitstatus 7 means bundle install failed
|
18
18
|
# exitstatus 1 means the test failed
|
19
|
-
if !successful && result.exitstatus
|
19
|
+
if !successful && result.exitstatus == 7
|
20
20
|
Rake::Task['install'].execute
|
21
21
|
run_sh cmd
|
22
22
|
end
|
@@ -31,13 +31,13 @@ end
|
|
31
31
|
# Run all tests with:
|
32
32
|
# rake ios
|
33
33
|
desc 'Run the iOS tests'
|
34
|
-
task :ios, :args, :test_file do |
|
34
|
+
task :ios, :args, :test_file do |_args, test_file|
|
35
35
|
# rake android['ok']
|
36
36
|
# args = android
|
37
37
|
# test_file = {:args=>"ok"}
|
38
38
|
test_file = test_file[:args]
|
39
39
|
cmd = 'bundle exec ruby ./lib/run.rb ios'
|
40
|
-
cmd += %
|
40
|
+
cmd += %( "#{test_file}") if test_file
|
41
41
|
bash cmd
|
42
42
|
end
|
43
43
|
|
@@ -45,3 +45,10 @@ desc 'Run bundle install'
|
|
45
45
|
task :install do
|
46
46
|
sh 'bundle install'
|
47
47
|
end
|
48
|
+
|
49
|
+
desc 'Execute RuboCop static code analysis'
|
50
|
+
RuboCop::RakeTask.new(:rubocop) do |t|
|
51
|
+
t.patterns = %w(**/*.rb)
|
52
|
+
t.options = %w(-D)
|
53
|
+
t.fail_on_error = false
|
54
|
+
end
|
data/ios_tests/appium.txt
CHANGED
data/ios_tests/lib/common.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
# common methods
|
3
|
-
def back_click(opts={})
|
4
|
-
opts
|
3
|
+
def back_click(opts = {})
|
4
|
+
opts ||= {}
|
5
5
|
search_wait = opts.fetch(:wait, 60 * 1.7)
|
6
6
|
# iOS may have multiple 'back' buttons
|
7
7
|
# select the first displayed? back button.
|
@@ -17,7 +17,11 @@ end
|
|
17
17
|
|
18
18
|
def go_to_textfields
|
19
19
|
screen.must_equal catalog
|
20
|
-
wait_true
|
20
|
+
wait_true do
|
21
|
+
text('textfield').click
|
22
|
+
screen == 'TextFields' # wait for screen transition
|
23
|
+
end
|
24
|
+
|
21
25
|
screen.must_equal 'TextFields'
|
22
26
|
end
|
23
27
|
|
@@ -27,4 +31,4 @@ end
|
|
27
31
|
|
28
32
|
def catalog
|
29
33
|
'UICatalog'
|
30
|
-
end
|
34
|
+
end
|
data/ios_tests/lib/format.rb
CHANGED
@@ -15,11 +15,9 @@ list.split("\n").each do |method|
|
|
15
15
|
puts
|
16
16
|
end
|
17
17
|
|
18
|
-
=begin
|
19
18
|
# for Pry
|
20
|
-
class Object
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
25
|
-
=end
|
19
|
+
# class Object
|
20
|
+
# def must_equal b
|
21
|
+
# raise 'not equal' unless self == b
|
22
|
+
# end
|
23
|
+
# end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# rake ios[common/helper]
|
2
2
|
describe 'common/helper.rb' do
|
3
|
-
|
4
3
|
def before_first
|
5
4
|
screen.must_equal catalog
|
6
5
|
end
|
@@ -11,12 +10,10 @@ describe 'common/helper.rb' do
|
|
11
10
|
|
12
11
|
wait_opts = { timeout: 0.2, interval: 0.2 } # max_wait, interval
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
must_not_raise is a no-op.
|
19
|
-
=end
|
13
|
+
# There's no `must_not_raise` as the opposite of must_raise
|
14
|
+
#
|
15
|
+
# By default code is expected to not raise exceptions.
|
16
|
+
# must_not_raise is a no-op.
|
20
17
|
|
21
18
|
# wait is a success unless an error is raised
|
22
19
|
# max_wait=0 is infinity to use 0.1
|
@@ -27,12 +24,12 @@ must_not_raise is a no-op.
|
|
27
24
|
wait(wait_opts) { nil }
|
28
25
|
|
29
26
|
# failed wait should error
|
30
|
-
proc { wait(wait_opts) {
|
27
|
+
proc { wait(wait_opts) { fail } }.must_raise Selenium::WebDriver::Error::TimeOutError
|
31
28
|
|
32
29
|
# regular rescue will not handle exceptions outside of StandardError hierarchy
|
33
30
|
# must rescue Exception explicitly to rescue everything
|
34
|
-
proc { wait(wait_opts) {
|
35
|
-
proc { wait(timeout: 0.2, interval: 0.0) {
|
31
|
+
proc { wait(wait_opts) { fail NoMemoryError } }.must_raise Selenium::WebDriver::Error::TimeOutError
|
32
|
+
proc { wait(timeout: 0.2, interval: 0.0) { fail NoMemoryError } }.must_raise Selenium::WebDriver::Error::TimeOutError
|
36
33
|
|
37
34
|
# invalid keys are rejected
|
38
35
|
proc { wait(invalidkey: 2) { true } }.must_raise RuntimeError
|
@@ -43,8 +40,8 @@ must_not_raise is a no-op.
|
|
43
40
|
ignore { true }
|
44
41
|
ignore { false }
|
45
42
|
ignore { nil }
|
46
|
-
ignore {
|
47
|
-
ignore {
|
43
|
+
ignore { fail }
|
44
|
+
ignore { fail NoMemoryError }
|
48
45
|
end
|
49
46
|
|
50
47
|
# wait_true is a success unless the value is not true
|
@@ -57,12 +54,13 @@ must_not_raise is a no-op.
|
|
57
54
|
proc { wait_true(wait_opts) { nil } }.must_raise Selenium::WebDriver::Error::TimeOutError
|
58
55
|
|
59
56
|
# raise should error
|
60
|
-
proc { wait_true(wait_opts) {
|
57
|
+
proc { wait_true(wait_opts) { fail } }.must_raise Selenium::WebDriver::Error::TimeOutError
|
61
58
|
|
62
59
|
# regular rescue will not handle exceptions outside of StandardError hierarchy
|
63
60
|
# must rescue Exception explicitly to rescue everything
|
64
|
-
proc { wait_true(wait_opts) {
|
65
|
-
proc { wait_true(timeout: 0.2, interval: 0.0) {
|
61
|
+
proc { wait_true(wait_opts) { fail NoMemoryError } }.must_raise Selenium::WebDriver::Error::TimeOutError
|
62
|
+
proc { wait_true(timeout: 0.2, interval: 0.0) { fail NoMemoryError } }
|
63
|
+
.must_raise Selenium::WebDriver::Error::TimeOutError
|
66
64
|
|
67
65
|
# invalid keys are rejected
|
68
66
|
proc { wait_true(invalidkey: 2) { true } }.must_raise RuntimeError
|
@@ -74,7 +72,11 @@ must_not_raise is a no-op.
|
|
74
72
|
# start page
|
75
73
|
tag('UIANavigationBar').name.must_equal 'UICatalog'
|
76
74
|
# nav to new page.
|
77
|
-
wait_true
|
75
|
+
wait_true do
|
76
|
+
text('buttons').click
|
77
|
+
tag('UIANavigationBar').name == 'Buttons'
|
78
|
+
end
|
79
|
+
|
78
80
|
tag('UIANavigationBar').name.must_equal 'Buttons'
|
79
81
|
# go back
|
80
82
|
back_click
|
@@ -84,7 +86,7 @@ must_not_raise is a no-op.
|
|
84
86
|
|
85
87
|
t 'session_id' do
|
86
88
|
# Sauce doesn't return '-' so make them optional.
|
87
|
-
session_id.must_match
|
89
|
+
session_id.must_match(/\h{8}-?\h{4}-?\h{4}-?\h{4}-?\h{12}/)
|
88
90
|
end
|
89
91
|
|
90
92
|
t 'xpath' do
|
@@ -103,11 +105,11 @@ must_not_raise is a no-op.
|
|
103
105
|
ele_index('UIAStaticText', 2).name.must_equal uibutton_text
|
104
106
|
end
|
105
107
|
|
106
|
-
#
|
108
|
+
# TODO: 'string_attr_exact'
|
107
109
|
|
108
110
|
t 'find_ele_by_attr' do
|
109
111
|
el_id = find_ele_by_attr('UIAStaticText', 'name', uibutton_text).instance_variable_get :@id
|
110
|
-
el_id.must_match
|
112
|
+
el_id.must_match(/\d+/)
|
111
113
|
end
|
112
114
|
|
113
115
|
t 'find_eles_by_attr' do
|
@@ -123,7 +125,7 @@ must_not_raise is a no-op.
|
|
123
125
|
set_wait
|
124
126
|
end
|
125
127
|
|
126
|
-
#
|
128
|
+
# TODO: 'string_attr_include'
|
127
129
|
|
128
130
|
t 'find_ele_by_attr_include' do
|
129
131
|
el_text = find_ele_by_attr_include('UIAStaticText', :name, 'button').text
|
@@ -181,23 +183,22 @@ must_not_raise is a no-op.
|
|
181
183
|
# 8 local. 9 on sauce.
|
182
184
|
get_page_class.split("\n").length.must_be :>=, 8
|
183
185
|
end
|
184
|
-
|
185
|
-
|
186
|
-
get_page_class
|
187
|
-
page_class
|
188
|
-
tag
|
189
|
-
tags
|
190
|
-
px_to_window_rel
|
191
|
-
lazy_load_strings
|
192
|
-
xml_keys
|
193
|
-
xml_values
|
194
|
-
resolve_id
|
195
|
-
string_visible_contains
|
196
|
-
xpath_visible_contains
|
197
|
-
xpaths_visible_contains
|
198
|
-
string_visible_exact
|
199
|
-
xpath_visible_exact
|
200
|
-
xpaths_visible_exact
|
201
|
-
raise_no_element_error
|
202
|
-
=end
|
186
|
+
|
187
|
+
# TODO: write tests
|
188
|
+
# get_page_class
|
189
|
+
# page_class
|
190
|
+
# tag
|
191
|
+
# tags
|
192
|
+
# px_to_window_rel
|
193
|
+
# lazy_load_strings
|
194
|
+
# xml_keys
|
195
|
+
# xml_values
|
196
|
+
# resolve_id
|
197
|
+
# string_visible_contains
|
198
|
+
# xpath_visible_contains
|
199
|
+
# xpaths_visible_contains
|
200
|
+
# string_visible_exact
|
201
|
+
# xpath_visible_exact
|
202
|
+
# xpaths_visible_exact
|
203
|
+
# raise_no_element_error
|
203
204
|
end
|
@@ -1,8 +1,12 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
# rubocop:disable Lint/RescueException
|
2
|
+
# rubocop:disable Metrics/LineLength
|
3
|
+
|
4
|
+
#
|
5
|
+
# Skip:
|
6
|
+
# status # status patches are already tested in driver.rb
|
7
|
+
# raw_execute # debug output for Pry
|
8
|
+
#
|
9
|
+
|
6
10
|
# rake ios[common/patch]
|
7
11
|
describe 'common/patch.rb' do
|
8
12
|
def before_first
|
@@ -13,10 +17,10 @@ describe 'common/patch.rb' do
|
|
13
17
|
before_first
|
14
18
|
end
|
15
19
|
|
16
|
-
# Attributes are busted in Android.
|
17
|
-
# Blocked on https://github.com/appium/appium/issues/628
|
20
|
+
# Attributes are busted in Android.
|
21
|
+
# Blocked on https://github.com/appium/appium/issues/628
|
18
22
|
describe 'Selenium::WebDriver::Element methods' do
|
19
|
-
#
|
23
|
+
# TODO: t 'value' do; end
|
20
24
|
|
21
25
|
t 'name' do
|
22
26
|
first_text.name.must_equal 'UICatalog'
|
@@ -39,12 +43,12 @@ describe 'common/patch.rb' do
|
|
39
43
|
begin
|
40
44
|
set_wait 0
|
41
45
|
find_element(:css, 'ok')
|
42
|
-
rescue Exception => e
|
46
|
+
rescue Exception => e
|
43
47
|
value = e.message
|
44
48
|
ensure
|
45
49
|
set_wait
|
46
50
|
end
|
47
|
-
value.must_equal
|
51
|
+
value.must_equal 'Invalid locator strategy: css selector'
|
48
52
|
end
|
49
53
|
end
|
50
|
-
end
|
54
|
+
end
|
@@ -8,10 +8,10 @@ describe 'version.rb' do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
t '::Appium::VERSION' do
|
11
|
-
::Appium::VERSION.must_match
|
11
|
+
::Appium::VERSION.must_match(/(\d+)\.(\d+).(\d+)/)
|
12
12
|
end
|
13
13
|
|
14
14
|
t '::Appium::DATE' do
|
15
|
-
::Appium::DATE.must_match
|
15
|
+
::Appium::DATE.must_match(/(\d+)\-(\d+)\-(\d+)/)
|
16
16
|
end
|
17
|
-
end
|
17
|
+
end
|
@@ -1,11 +1,10 @@
|
|
1
1
|
# Tests specifically for areas where the web_context differs in behaviour
|
2
2
|
describe 'the web context' do
|
3
|
-
|
4
3
|
t 'get_android_inspect' do
|
5
4
|
text('Web').click
|
6
5
|
set_context 'WEBVIEW'
|
7
6
|
current_context.must_equal 'WEBVIEW_1'
|
8
|
-
sleep 1 #Give a chance to load
|
7
|
+
sleep 1 # Give a chance to load
|
9
8
|
page.start_with?("\nhtml\n").must_equal true
|
10
9
|
end
|
11
10
|
|
@@ -6,7 +6,7 @@ describe 'device/device' do
|
|
6
6
|
# go back to the main page
|
7
7
|
def go_back
|
8
8
|
back
|
9
|
-
wait { !
|
9
|
+
wait { !exists { id 'ArrowButton' } } # successfully transitioned back
|
10
10
|
end
|
11
11
|
|
12
12
|
t 'before_first' do
|
@@ -27,8 +27,8 @@ describe 'device/device' do
|
|
27
27
|
screen.must_equal catalog
|
28
28
|
end
|
29
29
|
|
30
|
-
t '
|
31
|
-
installed =
|
30
|
+
t 'app_installed' do
|
31
|
+
installed = app_installed? 'Derrp'
|
32
32
|
installed.must_equal false
|
33
33
|
end
|
34
34
|
|
@@ -47,7 +47,7 @@ describe 'device/device' do
|
|
47
47
|
end
|
48
48
|
|
49
49
|
t 'available_contexts' do
|
50
|
-
available_contexts.must_equal [
|
50
|
+
available_contexts.must_equal ['NATIVE_APP']
|
51
51
|
end
|
52
52
|
|
53
53
|
t 'current_context' do
|
@@ -60,8 +60,8 @@ describe 'device/device' do
|
|
60
60
|
end
|
61
61
|
|
62
62
|
t 'app_strings' do
|
63
|
-
app_strings.must_include
|
64
|
-
app_strings('en').must_include
|
63
|
+
app_strings.must_include 'SearchBarExplain'
|
64
|
+
app_strings('en').must_include 'SearchBarExplain'
|
65
65
|
end
|
66
66
|
|
67
67
|
t 'action_chain' do
|
@@ -91,4 +91,4 @@ describe 'device/device' do
|
|
91
91
|
data = pull_folder 'Library/AddressBook'
|
92
92
|
data.length.must_be :>, 1
|
93
93
|
end
|
94
|
-
end
|
94
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
describe 'device/touch_actions' do
|
2
2
|
t {} # place holder test
|
3
3
|
end
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
4
|
+
|
5
|
+
# TODO: write tests
|
6
|
+
#
|
7
|
+
# move_to
|
8
|
+
# long_press
|
9
|
+
# press
|
10
|
+
# release
|
11
|
+
# tap
|
12
|
+
# wait
|
13
|
+
# swipe
|
14
|
+
# perform
|
15
|
+
# cancel
|