appium_lib 0.24.1 → 1.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/Rakefile +17 -8
- data/android_tests/Gemfile +1 -0
- data/android_tests/LICENSE-2.0.txt +202 -0
- data/android_tests/Rakefile +61 -0
- data/android_tests/api.apk +0 -0
- data/android_tests/appium.txt +3 -0
- data/android_tests/flaky.txt +1 -0
- data/android_tests/lib/android/specs/android/dynamic.rb +5 -0
- data/android_tests/lib/android/specs/android/element/alert.rb +41 -0
- data/android_tests/lib/android/specs/android/element/button.rb +55 -0
- data/android_tests/lib/android/specs/android/element/generic.rb +48 -0
- data/android_tests/lib/android/specs/android/element/text.rb +39 -0
- data/android_tests/lib/android/specs/android/element/textfield.rb +60 -0
- data/android_tests/lib/android/specs/android/helper.rb +80 -0
- data/android_tests/lib/android/specs/android/patch.rb +14 -0
- data/android_tests/lib/android/specs/common/device.rb +117 -0
- data/android_tests/lib/android/specs/common/element/window.rb +9 -0
- data/android_tests/lib/android/specs/common/helper.rb +112 -0
- data/android_tests/lib/android/specs/common/patch.rb +69 -0
- data/android_tests/lib/android/specs/common/version.rb +9 -0
- data/android_tests/lib/android/specs/driver.rb +174 -0
- data/android_tests/lib/format.rb +49 -0
- data/android_tests/lib/run.rb +72 -0
- data/android_tests/readme.md +27 -0
- data/appium_lib.gemspec +8 -5
- data/docs/android_docs.md +1052 -716
- data/docs/ios_docs.md +657 -834
- data/docs_gen/make_docs.rb +1 -3
- data/ios_tests/Gemfile +1 -0
- data/ios_tests/LICENSE-2.0.txt +202 -0
- data/ios_tests/Rakefile +47 -0
- data/ios_tests/UICatalog.app.zip +0 -0
- data/ios_tests/UICatalog.app/12-6AM.png +0 -0
- data/ios_tests/UICatalog.app/12-6PM.png +0 -0
- data/ios_tests/UICatalog.app/6-12AM.png +0 -0
- data/ios_tests/UICatalog.app/6-12PM.png +0 -0
- data/ios_tests/UICatalog.app/Default-568h@2x.png +0 -0
- data/ios_tests/UICatalog.app/Default@2x.png +0 -0
- data/ios_tests/UICatalog.app/Info.plist +0 -0
- data/ios_tests/UICatalog.app/PkgInfo +1 -0
- data/ios_tests/UICatalog.app/UIButton_custom.png +0 -0
- data/ios_tests/UICatalog.app/UICatalog +0 -0
- data/ios_tests/UICatalog.app/blueButton.png +0 -0
- data/ios_tests/UICatalog.app/bookmarkImage.png +0 -0
- data/ios_tests/UICatalog.app/bookmarkImageHighlighted.png +0 -0
- data/ios_tests/UICatalog.app/divider.png +0 -0
- data/ios_tests/UICatalog.app/en.lproj/AlertsViewController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/ButtonsViewController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/ControlsViewController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/ImagesViewController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/Localizable.strings +0 -0
- data/ios_tests/UICatalog.app/en.lproj/MainWindow.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/PickerViewController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/SearchBarController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/SegmentViewController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/TextFieldController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/TextViewController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/ToolbarViewController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/TransitionViewController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/WebViewController.nib +0 -0
- data/ios_tests/UICatalog.app/orangeslide.png +0 -0
- data/ios_tests/UICatalog.app/scene1.jpg +0 -0
- data/ios_tests/UICatalog.app/scene2.jpg +0 -0
- data/ios_tests/UICatalog.app/scene3.jpg +0 -0
- data/ios_tests/UICatalog.app/scene4.jpg +0 -0
- data/ios_tests/UICatalog.app/scene5.jpg +0 -0
- data/ios_tests/UICatalog.app/searchBarBackground.png +0 -0
- data/ios_tests/UICatalog.app/segment_check.png +0 -0
- data/ios_tests/UICatalog.app/segment_search.png +0 -0
- data/ios_tests/UICatalog.app/segment_tools.png +0 -0
- data/ios_tests/UICatalog.app/segmentedBackground.png +0 -0
- data/ios_tests/UICatalog.app/slider_ball.png +0 -0
- data/ios_tests/UICatalog.app/toolbarBackground.png +0 -0
- data/ios_tests/UICatalog.app/whiteButton.png +0 -0
- data/ios_tests/UICatalog.app/yellowslide.png +0 -0
- data/ios_tests/appium.txt +3 -0
- data/ios_tests/flaky.txt +1 -0
- data/ios_tests/lib/format.rb +25 -0
- data/ios_tests/lib/ios/specs/common/element/window.rb +15 -0
- data/ios_tests/lib/ios/specs/common/helper.rb +204 -0
- data/ios_tests/lib/ios/specs/common/patch.rb +50 -0
- data/ios_tests/lib/ios/specs/common/version.rb +17 -0
- data/ios_tests/lib/ios/specs/device/device.rb +82 -0
- data/ios_tests/lib/ios/specs/device/multi_touch.rb +12 -0
- data/ios_tests/lib/ios/specs/device/touch_actions.rb +15 -0
- data/ios_tests/lib/ios/specs/driver.rb +203 -0
- data/ios_tests/lib/ios/specs/ios/element/alert.rb +48 -0
- data/ios_tests/lib/ios/specs/ios/element/button.rb +58 -0
- data/ios_tests/lib/ios/specs/ios/element/generic.rb +35 -0
- data/ios_tests/lib/ios/specs/ios/element/text.rb +54 -0
- data/ios_tests/lib/ios/specs/ios/element/textfield.rb +123 -0
- data/ios_tests/lib/ios/specs/ios/helper.rb +27 -0
- data/ios_tests/lib/ios/specs/ios/patch.rb +30 -0
- data/ios_tests/lib/run.rb +106 -0
- data/ios_tests/readme.md +30 -0
- data/ios_tests/upload/sauce_storage.rb +64 -0
- data/ios_tests/upload/upload.rb +6 -0
- data/lib/appium_lib.rb +4 -14
- data/lib/appium_lib/android/dynamic.rb +30 -32
- data/lib/appium_lib/android/element/alert.rb +34 -33
- data/lib/appium_lib/android/element/button.rb +91 -0
- data/lib/appium_lib/android/element/generic.rb +51 -146
- data/lib/appium_lib/android/element/text.rb +54 -0
- data/lib/appium_lib/android/element/textfield.rb +46 -41
- data/lib/appium_lib/android/helper.rb +248 -417
- data/lib/appium_lib/android/mobile_methods.rb +17 -0
- data/lib/appium_lib/android/patch.rb +9 -8
- data/lib/appium_lib/awesome_print/ostruct.rb +33 -0
- data/lib/appium_lib/common/element/window.rb +9 -8
- data/lib/appium_lib/common/helper.rb +182 -243
- data/lib/appium_lib/common/patch.rb +65 -79
- data/lib/appium_lib/common/version.rb +2 -3
- data/lib/appium_lib/device/device.rb +339 -0
- data/lib/appium_lib/device/multi_touch.rb +94 -0
- data/lib/appium_lib/device/touch_actions.rb +142 -0
- data/lib/appium_lib/driver.rb +217 -306
- data/lib/appium_lib/ios/element/alert.rb +16 -92
- data/lib/appium_lib/ios/element/button.rb +55 -0
- data/lib/appium_lib/ios/element/generic.rb +27 -160
- data/lib/appium_lib/ios/element/text.rb +54 -0
- data/lib/appium_lib/ios/element/textfield.rb +78 -65
- data/lib/appium_lib/ios/helper.rb +300 -190
- data/lib/appium_lib/ios/mobile_methods.rb +17 -0
- data/lib/appium_lib/ios/patch.rb +55 -41
- data/lib/appium_lib/logger.rb +13 -0
- data/lib/appium_lib/rails/duplicable.rb +116 -0
- data/readme.md +6 -1
- data/release_notes.md +118 -0
- metadata +170 -12
- data/lib/appium_lib/common/element/button.rb +0 -83
- data/lib/appium_lib/common/element/text.rb +0 -61
|
@@ -1,71 +1,50 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
#
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
# @private
|
|
14
|
-
def status
|
|
15
|
-
raw_execute :status
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
class Selenium::WebDriver::Remote::Bridge
|
|
20
|
-
command :status, :get, 'status'
|
|
21
|
-
end
|
|
22
|
-
# end Add status to WebDriver
|
|
23
|
-
|
|
24
|
-
module Appium::Common
|
|
25
|
-
# Implement useful features for element.
|
|
26
|
-
class Selenium::WebDriver::Element
|
|
27
|
-
# Note: For testing .text should be used over value, and name.
|
|
28
|
-
|
|
29
|
-
# Returns the value attribute
|
|
30
|
-
#
|
|
31
|
-
# Fixes NoMethodError: undefined method `value' for Selenium::WebDriver::Element
|
|
32
|
-
def value
|
|
33
|
-
self.attribute :value
|
|
34
|
-
end
|
|
1
|
+
module Appium
|
|
2
|
+
module Common
|
|
3
|
+
# Implement useful features for element.
|
|
4
|
+
class Selenium::WebDriver::Element
|
|
5
|
+
# Note: For testing .text should be used over value, and name.
|
|
6
|
+
|
|
7
|
+
# Returns the value attribute
|
|
8
|
+
#
|
|
9
|
+
# Fixes NoMethodError: undefined method `value' for Selenium::WebDriver::Element
|
|
10
|
+
def value
|
|
11
|
+
self.attribute :value
|
|
12
|
+
end
|
|
35
13
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
14
|
+
# Returns the name attribute
|
|
15
|
+
#
|
|
16
|
+
# Fixes NoMethodError: undefined method `name' for Selenium::WebDriver::Element
|
|
17
|
+
def name
|
|
18
|
+
self.attribute :name
|
|
19
|
+
end
|
|
42
20
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
21
|
+
# For use with mobile tap.
|
|
22
|
+
#
|
|
23
|
+
# ```ruby
|
|
24
|
+
# execute_script 'mobile: tap', :x => 0.0, :y => 0.98
|
|
25
|
+
# ```
|
|
26
|
+
#
|
|
27
|
+
# https://github.com/appium/appium/wiki/Automating-mobile-gestures
|
|
28
|
+
# @return [OpenStruct] the relative x, y in a struct. ex: { x: 0.50, y: 0.20 }
|
|
29
|
+
def location_rel
|
|
30
|
+
location = self.location
|
|
31
|
+
location_x = location.x.to_f
|
|
32
|
+
location_y = location.y.to_f
|
|
33
|
+
|
|
34
|
+
size = self.size
|
|
35
|
+
size_width = size.width.to_f
|
|
36
|
+
size_height = size.height.to_f
|
|
37
|
+
|
|
38
|
+
center_x = location_x + (size_width / 2.0)
|
|
39
|
+
center_y = location_y + (size_height / 2.0)
|
|
40
|
+
|
|
41
|
+
w = $driver.window_size
|
|
42
|
+
OpenStruct.new(x: "#{center_x} / #{w.width.to_f}",
|
|
43
|
+
y: "#{center_y} / #{w.height.to_f}")
|
|
44
|
+
end
|
|
66
45
|
end
|
|
67
|
-
end
|
|
68
|
-
end # module Appium
|
|
46
|
+
end # module Common
|
|
47
|
+
end # module Appium
|
|
69
48
|
|
|
70
49
|
# Print JSON posted to Appium. Not scoped to an Appium module.
|
|
71
50
|
#
|
|
@@ -86,14 +65,14 @@ def patch_webdriver_bridge
|
|
|
86
65
|
Selenium::WebDriver::Remote::Bridge.class_eval do
|
|
87
66
|
# Code from lib/selenium/webdriver/remote/bridge.rb
|
|
88
67
|
def raw_execute(command, opts = {}, command_hash = nil)
|
|
89
|
-
verb, path
|
|
90
|
-
path
|
|
68
|
+
verb, path = Selenium::WebDriver::Remote::COMMANDS[command] || raise(ArgumentError, "unknown command: #{command.inspect}")
|
|
69
|
+
path = path.dup
|
|
91
70
|
|
|
92
71
|
path[':session_id'] = @session_id if path.include?(':session_id')
|
|
93
72
|
|
|
94
73
|
begin
|
|
95
74
|
opts.each { |key, value| path[key.inspect] = escaper.escape(value.to_s) }
|
|
96
|
-
|
|
75
|
+
rescue IndexError
|
|
97
76
|
raise ArgumentError, "#{opts.inspect} invalid for #{command.inspect}"
|
|
98
77
|
end
|
|
99
78
|
|
|
@@ -103,39 +82,46 @@ def patch_webdriver_bridge
|
|
|
103
82
|
# change path from session/efac972c-941a-499c-803c-d7d008749/execute
|
|
104
83
|
# to /execute
|
|
105
84
|
# path may be nil, session, or not have anything after the session_id.
|
|
106
|
-
path_str
|
|
107
|
-
path_str
|
|
85
|
+
path_str = path
|
|
86
|
+
path_str = '/' + path_str unless path_str.nil? ||
|
|
108
87
|
path_str.length <= 0 || path_str[0] == '/'
|
|
109
88
|
path_match = path.match /.*\h{8}-?\h{4}-?\h{4}-?\h{4}-?\h{12}/
|
|
110
|
-
path_str
|
|
89
|
+
path_str = path.sub(path_match[0], '') unless path_match.nil?
|
|
111
90
|
|
|
112
91
|
puts "#{verb} #{path_str}"
|
|
113
92
|
unless command_hash.nil? || command_hash.length == 0
|
|
114
|
-
print_command =
|
|
93
|
+
print_command = {}
|
|
94
|
+
# For complex_find, we pass a whole array
|
|
95
|
+
if command_hash.kind_of? Array
|
|
96
|
+
print_command[:args] = [command_hash.clone]
|
|
97
|
+
print_command[:script] = 'mobile: find' if command == :complex_find
|
|
98
|
+
else
|
|
99
|
+
print_command = command_hash.clone
|
|
100
|
+
end
|
|
115
101
|
print_command.delete :args if print_command[:args] == []
|
|
116
102
|
|
|
117
103
|
mobile_find = 'mobile: find'
|
|
118
104
|
if print_command[:script] == mobile_find
|
|
119
105
|
args = print_command[:args]
|
|
120
|
-
puts "#{mobile_find}"#" #{args}"
|
|
106
|
+
puts "#{mobile_find}" #" #{args}"
|
|
121
107
|
|
|
122
108
|
# [[[[3, "sign"]]]] => [[[3, "sign"]]]
|
|
123
109
|
#
|
|
124
110
|
# [[[[4, "android.widget.EditText"], [7, "z"]], [[4, "android.widget.EditText"], [3, "z"]]]]
|
|
125
111
|
# => [[[4, "android.widget.EditText"], [7, "z"]], [[4, "android.widget.EditText"], [3, "z"]]]
|
|
126
|
-
args
|
|
127
|
-
option
|
|
128
|
-
has_option = !
|
|
112
|
+
args = args[0]
|
|
113
|
+
option = args[0].to_s.downcase
|
|
114
|
+
has_option = !option.match(/all|scroll/).nil?
|
|
129
115
|
puts option if has_option
|
|
130
116
|
|
|
131
117
|
start = has_option ? 1 : 0
|
|
132
118
|
|
|
133
119
|
start.upto(args.length-1) do |selector_index|
|
|
134
|
-
selectors
|
|
120
|
+
selectors = args[selector_index]
|
|
135
121
|
selectors_size = selectors.length
|
|
136
122
|
selectors.each_index do |pair_index|
|
|
137
123
|
pair = selectors[pair_index]
|
|
138
|
-
res
|
|
124
|
+
res = $driver.dynamic_code_to_string pair[0], pair[1]
|
|
139
125
|
|
|
140
126
|
if selectors_size == 1 || pair_index >= selectors_size - 1
|
|
141
127
|
puts res
|
|
@@ -154,7 +140,7 @@ def patch_webdriver_bridge
|
|
|
154
140
|
http.call verb, path, command_hash
|
|
155
141
|
end # def
|
|
156
142
|
end # class
|
|
157
|
-
end
|
|
143
|
+
end
|
|
158
144
|
|
|
159
145
|
# Print Appium's origValue error messages.
|
|
160
146
|
class Selenium::WebDriver::Remote::Response
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
1
|
module Appium
|
|
3
2
|
# Version and Date are defined on the 'Appium' module, not 'Appium::Common'
|
|
4
|
-
VERSION = '0.
|
|
5
|
-
DATE
|
|
3
|
+
VERSION = '1.0.0' unless defined? ::Appium::VERSION
|
|
4
|
+
DATE = '2014-04-29' unless defined? ::Appium::DATE
|
|
6
5
|
end
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
require 'base64'
|
|
2
|
+
|
|
3
|
+
module Appium
|
|
4
|
+
module Device
|
|
5
|
+
extend Forwardable
|
|
6
|
+
|
|
7
|
+
NoArgMethods = {
|
|
8
|
+
post: {
|
|
9
|
+
shake: 'session/:session_id/appium/device/shake',
|
|
10
|
+
launch: 'session/:session_id/appium/app/launch',
|
|
11
|
+
close_app: 'session/:session_id/appium/app/close',
|
|
12
|
+
reset: 'session/:session_id/appium/app/reset',
|
|
13
|
+
toggle_airplane_mode: 'session/:session_id/appium/device/toggle_airplane_mode'
|
|
14
|
+
},
|
|
15
|
+
get: {
|
|
16
|
+
current_activity: 'session/:session_id/appium/device/current_activity',
|
|
17
|
+
current_context: 'session/:session_id/context',
|
|
18
|
+
app_strings: 'session/:session_id/appium/app/strings',
|
|
19
|
+
available_contexts: 'session/:session_id/contexts',
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
# @!method app_strings
|
|
24
|
+
# Return the hash of all localization strings.
|
|
25
|
+
# ```ruby
|
|
26
|
+
# app_strings #=> "TransitionsTitle"=>"Transitions", "WebTitle"=>"Web"
|
|
27
|
+
# ```
|
|
28
|
+
|
|
29
|
+
# @!method background_app
|
|
30
|
+
# Backgrounds the app for a set number of seconds.
|
|
31
|
+
# This is a blocking application
|
|
32
|
+
# @param seconds (int) How many seconds to background the app for.
|
|
33
|
+
|
|
34
|
+
# @!method current_activity
|
|
35
|
+
|
|
36
|
+
# @!method launch
|
|
37
|
+
# Start the simulator and applicaton configured with desired capabilities
|
|
38
|
+
|
|
39
|
+
# @!method reset
|
|
40
|
+
# Reset the device, relaunching the application.
|
|
41
|
+
|
|
42
|
+
# @!method shake
|
|
43
|
+
# Cause the device to shake
|
|
44
|
+
|
|
45
|
+
# @!method toggle_flight_mode
|
|
46
|
+
# toggle flight mode on or off
|
|
47
|
+
|
|
48
|
+
#@!method complex_find
|
|
49
|
+
# Find an element by a complex array of criteria. Available criteria
|
|
50
|
+
# are listed in [link here]. Criteria are formed by creating an array
|
|
51
|
+
# of arrays, each containing a selector and that selector's value.
|
|
52
|
+
#
|
|
53
|
+
# ```ruby
|
|
54
|
+
# complex_find [[[2, 'Sau'], [14, true]]] # => Find a clickable element
|
|
55
|
+
# # whose names starts with 'Sau'
|
|
56
|
+
# ```
|
|
57
|
+
# @param mod (Symbol) If present, will be the 0th element in the selector array.
|
|
58
|
+
# @param selectors (Array<Object>) The selectors to find elements with.
|
|
59
|
+
|
|
60
|
+
# @!method hide_keyboard
|
|
61
|
+
# Hide the onscreen keyboard
|
|
62
|
+
# @param close_key (String) the name of the key which closes the keyboard.
|
|
63
|
+
# Defaults to 'Done'.
|
|
64
|
+
# ```ruby
|
|
65
|
+
# hide_keyboard # Close a keyboard with the 'Done' button
|
|
66
|
+
# hide_keyboard('Finished') # Close a keyboard with the 'Finished' button
|
|
67
|
+
# ```
|
|
68
|
+
|
|
69
|
+
# @!method key_event
|
|
70
|
+
# Send a key event to the device.
|
|
71
|
+
# @param key (integer) The key to send.
|
|
72
|
+
# @param metastate (String) The state the metakeys should be in when sending the key.
|
|
73
|
+
|
|
74
|
+
# @!method push_file
|
|
75
|
+
# Place a file in a specific location on the device.
|
|
76
|
+
# @param path (String) The absolute path on the device to store data at.
|
|
77
|
+
# @param data (String) Raw file data to be sent to the device.
|
|
78
|
+
|
|
79
|
+
# @!method pull_file
|
|
80
|
+
# Retrieve a file from the device. This can retrieve an absolute path or
|
|
81
|
+
# a path relative to the installed app (iOS only).
|
|
82
|
+
# @param path (String) Either an absolute path OR, for iOS devices, a path relative to the app, as described.
|
|
83
|
+
#
|
|
84
|
+
# ```ruby
|
|
85
|
+
# pull_file '/local/data/some/path' #=> Get the file at that path
|
|
86
|
+
# pull_file 'Shenanigans.app/some/file' #=> Get 'some/file' from the install location of Shenanigans.app
|
|
87
|
+
# ```
|
|
88
|
+
|
|
89
|
+
# @!method end_coverage
|
|
90
|
+
# Android only; Ends the test coverage and writes the results to the given path on device.
|
|
91
|
+
# @param path (String) Path on the device to write too.
|
|
92
|
+
# @param intent (String) Intent to broadcast when ending coverage.
|
|
93
|
+
class << self
|
|
94
|
+
def extended(mod)
|
|
95
|
+
extend_webdriver_with_forwardable
|
|
96
|
+
|
|
97
|
+
NoArgMethods.each_pair do |verb, pair|
|
|
98
|
+
pair.each_pair { |command, path| add_endpoint_method command, path, verb }
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
add_endpoint_method(:lock, 'session/:session_id/appium/device/lock') do
|
|
102
|
+
def lock(duration)
|
|
103
|
+
execute :lock, {}, :seconds => duration
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
add_endpoint_method(:install, 'session/:session_id/appium/device/install_app') do
|
|
108
|
+
def install(path)
|
|
109
|
+
execute :install, {}, :appPath => path
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
add_endpoint_method(:remove, 'session/:session_id/appium/device/remove_app') do
|
|
114
|
+
def remove(id)
|
|
115
|
+
execute :remove, {}, :appId => id
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
add_endpoint_method(:is_installed?, 'session/:session_id/appium/device/app_installed') do
|
|
120
|
+
def is_installed?(app_id)
|
|
121
|
+
execute :is_installed?, {}, :bundleId => app_id
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
add_endpoint_method(:background_app, 'session/:session_id/appium/app/background') do
|
|
126
|
+
def background_app(duration)
|
|
127
|
+
execute :background_app, {}, :seconds => duration
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
add_endpoint_method(:current_context=, 'session/:session_id/context') do
|
|
132
|
+
def current_context=(context=null)
|
|
133
|
+
execute :current_context=, {}, :context => context
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
add_endpoint_method(:hide_keyboard, 'session/:session_id/appium/device/hide_keyboard') do
|
|
138
|
+
def hide_keyboard(close_key='Done')
|
|
139
|
+
execute :hide_keyboard, {}, keyName: close_key
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
add_endpoint_method(:key_event, 'session/:session_id/appium/device/keyevent') do
|
|
144
|
+
def key_event(key, metastate=nil)
|
|
145
|
+
args = {keycode: key}
|
|
146
|
+
args[:metastate] = metastate if metastate
|
|
147
|
+
execute :key_event, {}, args
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# TODO TEST ME
|
|
152
|
+
add_endpoint_method(:set_immediate_value, 'session/:session_id/appium/element/:id/value') do
|
|
153
|
+
def set_immediate_value(element, value)
|
|
154
|
+
execute :set_immediate_value, { :id => element.ref }, value
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
add_endpoint_method(:complex_find, 'session/:session_id/appium/app/complex_find') do
|
|
159
|
+
def complex_find(opts)
|
|
160
|
+
mode = opts.fetch :mode, false
|
|
161
|
+
selectors = opts.fetch :selectors, false
|
|
162
|
+
raise 'Complex find must have selectors' unless selectors
|
|
163
|
+
selectors.insert(0, mode) if mode
|
|
164
|
+
|
|
165
|
+
ids = execute :complex_find, {}, selectors
|
|
166
|
+
|
|
167
|
+
if mode == 'all' && ids.length > 1
|
|
168
|
+
return ids.map { |id| Selenium::WebDriver::Element.new self, element_id_from(id) }
|
|
169
|
+
else
|
|
170
|
+
return Selenium::WebDriver::Element.new self, element_id_from(ids)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
add_endpoint_method(:push_file,'session/:session_id/appium/device/push_file') do
|
|
176
|
+
def push_file(path, filedata)
|
|
177
|
+
encoded_data = Base64.encode64 filedata
|
|
178
|
+
execute :push_file, {}, path: path, data: encoded_data
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
add_endpoint_method(:pull_file, 'session/:session_id/appium/device/pull_file') do
|
|
183
|
+
def pull_file(path)
|
|
184
|
+
data = execute :pull_file, {}, path: path
|
|
185
|
+
Base64.decode64 data
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# TODO TEST ME
|
|
190
|
+
add_endpoint_method(:end_coverage, 'session/:session_id/appium/app/end_test_coverage') do
|
|
191
|
+
def end_coverage(path, intent)
|
|
192
|
+
execute :end_coverage, {}, path: path, intent: intent
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
add_touch_actions
|
|
197
|
+
extend_search_contexts
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# def extended
|
|
201
|
+
|
|
202
|
+
# @private
|
|
203
|
+
def add_endpoint_method(method, path, verb=:post)
|
|
204
|
+
if block_given?
|
|
205
|
+
# &Proc.new with no args passes the passed_in block
|
|
206
|
+
# Because creating Procs from blocks is slow
|
|
207
|
+
create_bridge_command method, verb, path, &Proc.new
|
|
208
|
+
else
|
|
209
|
+
create_bridge_command method, verb, path
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
delegate_driver_method method
|
|
213
|
+
delegate_from_appium_driver method
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# @private
|
|
217
|
+
def extend_webdriver_with_forwardable
|
|
218
|
+
return if Selenium::WebDriver::Driver.kind_of? Forwardable
|
|
219
|
+
Selenium::WebDriver::Driver.class_eval do
|
|
220
|
+
extend Forwardable
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# @private
|
|
225
|
+
def delegate_driver_method(method)
|
|
226
|
+
return if Selenium::WebDriver::Driver.method_defined? method
|
|
227
|
+
Selenium::WebDriver::Driver.class_eval { def_delegator :@bridge, method }
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# @private
|
|
231
|
+
def delegate_from_appium_driver(method, delegation_target=:driver)
|
|
232
|
+
def_delegator delegation_target, method
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# @private
|
|
236
|
+
def create_bridge_command(method, verb, path)
|
|
237
|
+
# Don't clobber methods that are moved into Selenium
|
|
238
|
+
if selenium_has method
|
|
239
|
+
log_reimplemented_warning(method, path)
|
|
240
|
+
return
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
Selenium::WebDriver::Remote::Bridge.class_eval do
|
|
244
|
+
command method, verb, path
|
|
245
|
+
if block_given?
|
|
246
|
+
class_eval &Proc.new
|
|
247
|
+
else
|
|
248
|
+
define_method(method) { execute method }
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# @private
|
|
254
|
+
def selenium_has(method)
|
|
255
|
+
Selenium::WebDriver::Remote::Bridge.method_defined? method
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# @private
|
|
259
|
+
def log_reimplemented_warning(method, path)
|
|
260
|
+
msg = "Selenium::WebDriver has now implemented the `#{method}` method."
|
|
261
|
+
if Selenium::WebDriver::Remote::COMMANDS[method][1] == path
|
|
262
|
+
msg << " It may no longer function as expected"
|
|
263
|
+
else
|
|
264
|
+
msg << " It no longer uses the same endpoint,"
|
|
265
|
+
msg << " so it probably won't do what you expect anymore."
|
|
266
|
+
end
|
|
267
|
+
msg << " Raise an issue at http://www.github.com/appium/ruby_lib if so."
|
|
268
|
+
Appium::Logger.warn msg
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# @!method accessiblity_id_find
|
|
272
|
+
# find_element/s with their accessibility_id
|
|
273
|
+
#
|
|
274
|
+
# ```ruby
|
|
275
|
+
# find_elements :accessibility_id, 'Animation'
|
|
276
|
+
# ```
|
|
277
|
+
def extend_search_contexts
|
|
278
|
+
Selenium::WebDriver::SearchContext.class_eval do
|
|
279
|
+
Selenium::WebDriver::SearchContext::FINDERS[:accessibility_id] = 'accessibility id'
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def add_touch_actions
|
|
284
|
+
add_endpoint_method(:touch_actions, 'session/:session_id/touch/perform') do
|
|
285
|
+
def touch_actions(actions)
|
|
286
|
+
actions = [actions].flatten
|
|
287
|
+
execute :touch_actions, {}, actions
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
add_endpoint_method(:multi_touch, 'session/:session_id/touch/multi/perform') do
|
|
292
|
+
def multi_touch(actions)
|
|
293
|
+
execute :multi_touch, {}, actions: actions
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
actions = Appium::TouchAction::COMPLEX_ACTIONS
|
|
298
|
+
actions.each do |method|
|
|
299
|
+
delegate_from_appium_driver(method, Appium::TouchAction)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
delegate_from_appium_driver(:pinch, Appium::MultiTouch)
|
|
303
|
+
delegate_from_appium_driver(:zoom, Appium::MultiTouch)
|
|
304
|
+
end
|
|
305
|
+
end # class << self
|
|
306
|
+
|
|
307
|
+
# @!method current_context=
|
|
308
|
+
# Change the context to the given context.
|
|
309
|
+
# @param [String] The context to change to
|
|
310
|
+
#
|
|
311
|
+
# ```ruby
|
|
312
|
+
# current_context= "NATIVE_APP"
|
|
313
|
+
# ```
|
|
314
|
+
|
|
315
|
+
# @!method current_context
|
|
316
|
+
# @return [String] The context currently being used.
|
|
317
|
+
|
|
318
|
+
# @!method available_contexts
|
|
319
|
+
# @return [Array<String>] All usable contexts, as an array of strings.
|
|
320
|
+
|
|
321
|
+
# Perform a block within the given context, then switch back to the starting context.
|
|
322
|
+
# @param context (String) The context to switch to for the duration of the block.
|
|
323
|
+
#
|
|
324
|
+
# ```ruby
|
|
325
|
+
# within_context('NATIVE_APP') do
|
|
326
|
+
# find_element [:tag, "button"]
|
|
327
|
+
# ```
|
|
328
|
+
def within_context(context)
|
|
329
|
+
existing_context = current_context
|
|
330
|
+
yield if block_given?
|
|
331
|
+
current_context = existing_context
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
# Change to the default context. This is equivalent to `current_context= nil`.
|
|
335
|
+
def switch_to_default_context
|
|
336
|
+
current_context = nil
|
|
337
|
+
end
|
|
338
|
+
end # module Device
|
|
339
|
+
end # module Appium
|