appium_lib 0.24.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|