appium_lib_core 5.0.0.beta1 → 5.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -6
- data/README.md +2 -1
- data/Rakefile +4 -0
- data/appium_lib_core.gemspec +3 -3
- data/ci-jobs/functional_test.yml +1 -1
- data/docs/mobile_command.md +3 -2
- data/lib/appium_lib_core/android/device/auth_finger_print.rb +2 -1
- data/lib/appium_lib_core/common/base/bridge.rb +303 -7
- data/lib/appium_lib_core/common/base/device_ime.rb +49 -0
- data/lib/appium_lib_core/common/base/driver.rb +101 -105
- data/lib/appium_lib_core/common/base/driver_settings.rb +51 -0
- data/lib/appium_lib_core/common/base/has_location.rb +11 -4
- data/lib/appium_lib_core/common/base/has_network_connection.rb +1 -1
- data/lib/appium_lib_core/common/base/rotable.rb +1 -1
- data/lib/appium_lib_core/common/base/screenshot.rb +4 -3
- data/lib/appium_lib_core/common/base/search_context.rb +9 -4
- data/lib/appium_lib_core/common/base.rb +0 -2
- data/lib/appium_lib_core/common/command.rb +259 -3
- data/lib/appium_lib_core/common/device/keyevent.rb +4 -4
- data/lib/appium_lib_core/common/device/value.rb +4 -4
- data/lib/appium_lib_core/common/error.rb +4 -1
- data/lib/appium_lib_core/common/log.rb +4 -1
- data/lib/appium_lib_core/common/touch_action/touch_actions.rb +4 -1
- data/lib/appium_lib_core/device.rb +1 -1
- data/lib/appium_lib_core/driver.rb +3 -4
- data/lib/appium_lib_core/{patch.rb → element.rb} +9 -14
- data/lib/appium_lib_core/ios/uiautomation/patch.rb +1 -1
- data/lib/appium_lib_core/version.rb +2 -2
- data/lib/appium_lib_core.rb +2 -5
- data/release_notes.md +23 -0
- data/script/commands.rb +1 -12
- metadata +15 -17
- data/lib/appium_lib_core/common/base/bridge/w3c.rb +0 -348
- data/lib/appium_lib_core/common/base/command.rb +0 -145
- data/lib/appium_lib_core/common/command/common.rb +0 -110
- data/lib/appium_lib_core/common/command/w3c.rb +0 -56
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module Appium
|
16
|
+
module Core
|
17
|
+
class Base
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
#
|
21
|
+
class DeviceIME
|
22
|
+
# @private this class is private
|
23
|
+
def initialize(bridge)
|
24
|
+
@bridge = bridge
|
25
|
+
end
|
26
|
+
|
27
|
+
def activate(ime_name)
|
28
|
+
@bridge.ime_activate(ime_name)
|
29
|
+
end
|
30
|
+
|
31
|
+
def available_engines
|
32
|
+
@bridge.ime_available_engines
|
33
|
+
end
|
34
|
+
|
35
|
+
def active_engine
|
36
|
+
@bridge.ime_active_engine
|
37
|
+
end
|
38
|
+
|
39
|
+
def activated?
|
40
|
+
@bridge.ime_activated
|
41
|
+
end
|
42
|
+
|
43
|
+
def deactivate
|
44
|
+
@bridge.ime_deactivate
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -13,6 +13,8 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
15
|
require 'base64'
|
16
|
+
require_relative 'device_ime'
|
17
|
+
require_relative 'driver_settings'
|
16
18
|
require_relative 'search_context'
|
17
19
|
require_relative 'screenshot'
|
18
20
|
require_relative 'rotable'
|
@@ -36,23 +38,25 @@ module Appium
|
|
36
38
|
include ::Appium::Core::Base::HasLocation
|
37
39
|
include ::Appium::Core::Base::HasNetworkConnection
|
38
40
|
|
41
|
+
private
|
42
|
+
|
39
43
|
# Private API.
|
40
44
|
# Do not use this for general use. Used by flutter driver to get bridge for creating a new element
|
41
45
|
attr_reader :bridge
|
42
46
|
|
43
|
-
|
44
|
-
|
47
|
+
def initialize(bridge: nil, listener: nil, **opts)
|
48
|
+
super
|
49
|
+
end
|
50
|
+
|
45
51
|
# Implements protocol handshake which:
|
46
52
|
#
|
47
53
|
# 1. Creates session with driver.
|
48
54
|
# 2. Sniffs response.
|
49
55
|
# 3. Based on the response, understands which dialect we should use.
|
50
56
|
#
|
51
|
-
# @return [Bridge
|
57
|
+
# @return [::Appium::Core::Base::Bridge]
|
52
58
|
#
|
53
|
-
# TODO: Fixme
|
54
59
|
def create_bridge(**opts)
|
55
|
-
opts[:url] ||= service_url(opts)
|
56
60
|
caps = opts.delete(:capabilities)
|
57
61
|
# NOTE: This is deprecated
|
58
62
|
cap_array = caps.is_a?(Hash) ? [caps] : Array(caps)
|
@@ -71,19 +75,15 @@ module Appium
|
|
71
75
|
capabilities = generate_capabilities(cap_array)
|
72
76
|
|
73
77
|
bridge_opts = { http_client: opts.delete(:http_client), url: opts.delete(:url) }
|
74
|
-
raise ArgumentError, "Unable to create a driver with parameters: #{opts}" unless opts.empty?
|
78
|
+
raise ::Appium::Core::Error::ArgumentError, "Unable to create a driver with parameters: #{opts}" unless opts.empty?
|
75
79
|
|
76
|
-
bridge = ::Appium::Core::Base::Bridge
|
80
|
+
bridge = ::Appium::Core::Base::Bridge.new(**bridge_opts)
|
77
81
|
|
78
82
|
bridge.create_session(capabilities)
|
79
83
|
bridge
|
80
84
|
end
|
81
85
|
|
82
|
-
|
83
|
-
# @return [:oss|:w3c]
|
84
|
-
def dialect
|
85
|
-
@bridge.dialect
|
86
|
-
end
|
86
|
+
public
|
87
87
|
|
88
88
|
# Update +server_url+ and HTTP clients following this arguments, protocol, host, port and path.
|
89
89
|
# After this method, +@bridge.http+ will be a new instance following them instead of +server_url+ which is
|
@@ -109,6 +109,86 @@ module Appium
|
|
109
109
|
path: path)
|
110
110
|
end
|
111
111
|
|
112
|
+
AVAILABLE_METHODS = [
|
113
|
+
:get, :head, :post, :put, :delete,
|
114
|
+
:connect, :options, :trace, :patch
|
115
|
+
].freeze
|
116
|
+
# Define a new custom method to the driver so that you can define your own method for
|
117
|
+
# drivers/plugins in Appium 2.0. Appium 2.0 and its custom drivers/plugins allow you
|
118
|
+
# to define custom commands that are not part of W3C spec.
|
119
|
+
#
|
120
|
+
# @param [Symbol] method HTTP request method as https://www.w3.org/TR/webdriver/#endpoints
|
121
|
+
# @param [string] url The url to URL template as https://www.w3.org/TR/webdriver/#endpoints.
|
122
|
+
# +:session_id+ is the placeholder of 'session id'.
|
123
|
+
# Other place holders can be specified with +:+ prefix like +:id+.
|
124
|
+
# Then, the +:id+ will be replaced with a given value as the seconds argument of +execute+
|
125
|
+
# @param [Symbol] name The name of method that is called as the driver instance method.
|
126
|
+
# @param [Proc] block The block to involve as the method.
|
127
|
+
# Please define a method that has the same +name+ with arguments you want.
|
128
|
+
# The method must has +execute+ method. tHe +execute+ is calls the +url+
|
129
|
+
# with the given parameters.
|
130
|
+
# The first argument should be +name+ as symbol.
|
131
|
+
# The second argument should be hash. If keys in the hash matches +:+ prefix
|
132
|
+
# string in the given url, the matched string in the given url will be
|
133
|
+
# values in the hash.
|
134
|
+
# The third argument should be hash. The hash will be the request body.
|
135
|
+
# Please read examples below for more details.
|
136
|
+
# @raise [ArgumentError] If the given +method+ is invalid value.
|
137
|
+
#
|
138
|
+
# @example
|
139
|
+
#
|
140
|
+
# @driver.add_command(
|
141
|
+
# method: :get,
|
142
|
+
# url: 'session/:session_id/path/to/custom/url',
|
143
|
+
# name: :test_command
|
144
|
+
# )
|
145
|
+
# # Send a GET request to 'session/<session id>/path/to/custom/url'
|
146
|
+
# @driver.test_command
|
147
|
+
#
|
148
|
+
#
|
149
|
+
# @driver.add_command(
|
150
|
+
# method: :post,
|
151
|
+
# url: 'session/:session_id/path/to/custom/url',
|
152
|
+
# name: :test_command
|
153
|
+
# ) do
|
154
|
+
# def test_command(argument)
|
155
|
+
# execute(:test_command, {}, { dummy: argument })
|
156
|
+
# end
|
157
|
+
# end
|
158
|
+
# # Send a POST request to 'session/<session id>/path/to/custom/url'
|
159
|
+
# # with body "{ dummy: 1 }" as JSON object. "1" is the argument.
|
160
|
+
# # ':session_id' in the given 'url' is replaced with current 'session id'.
|
161
|
+
# @driver.test_command(1)
|
162
|
+
#
|
163
|
+
#
|
164
|
+
# @driver.add_command(
|
165
|
+
# method: :post,
|
166
|
+
# url: 'session/:session_id/element/:id/custom/action',
|
167
|
+
# name: :test_action_command
|
168
|
+
# ) do
|
169
|
+
# def test_action_command(element_id, action)
|
170
|
+
# execute(:test_action_command, {id: element_id}, { dummy_action: action })
|
171
|
+
# end
|
172
|
+
# end
|
173
|
+
# # Send a POST request to 'session/<session id>/element/<element id>/custom/action'
|
174
|
+
# # with body "{ dummy_action: #{action} }" as JSON object. "action" is the seconds argument.
|
175
|
+
# # ':session_id' in the given url is replaced with current 'session id'.
|
176
|
+
# # ':id' in the given url is replaced with the given 'element_id'.
|
177
|
+
# e = @driver.find_element :accessibility_id, 'an element'
|
178
|
+
# _, element_id = e.ref
|
179
|
+
# @driver.test_action_command(element_id, 'action')
|
180
|
+
#
|
181
|
+
def add_command(method:, url:, name:, &block)
|
182
|
+
unless AVAILABLE_METHODS.include? method
|
183
|
+
raise ::Appium::Core::Error::ArgumentError, "Available method is either #{AVAILABLE_METHODS}"
|
184
|
+
end
|
185
|
+
|
186
|
+
# TODO: Remove this logger before Appium 2.0 release
|
187
|
+
::Appium::Logger.info '[Experimental] this method is experimental for Appium 2.0. This interface may change.'
|
188
|
+
|
189
|
+
@bridge.add_command method: method, url: url, name: name, &block
|
190
|
+
end
|
191
|
+
|
112
192
|
### Methods for Appium
|
113
193
|
|
114
194
|
# Lock the device
|
@@ -191,36 +271,6 @@ module Appium
|
|
191
271
|
end
|
192
272
|
alias type send_keys
|
193
273
|
|
194
|
-
class DriverSettings
|
195
|
-
# @private this class is private
|
196
|
-
def initialize(bridge)
|
197
|
-
@bridge = bridge
|
198
|
-
end
|
199
|
-
|
200
|
-
# Get appium Settings for current test session.
|
201
|
-
#
|
202
|
-
# @example
|
203
|
-
#
|
204
|
-
# @driver.settings.get
|
205
|
-
#
|
206
|
-
def get
|
207
|
-
@bridge.get_settings
|
208
|
-
end
|
209
|
-
|
210
|
-
# Update Appium Settings for current test session
|
211
|
-
#
|
212
|
-
# @param [Hash] settings Settings to update, keys are settings, values to value to set each setting to
|
213
|
-
#
|
214
|
-
# @example
|
215
|
-
#
|
216
|
-
# @driver.settings.update({'allowInvisibleElements': true})
|
217
|
-
#
|
218
|
-
def update(settings)
|
219
|
-
@bridge.update_settings(settings)
|
220
|
-
end
|
221
|
-
end
|
222
|
-
private_constant :DriverSettings
|
223
|
-
|
224
274
|
# Returns an instance of DriverSettings to call get/update.
|
225
275
|
#
|
226
276
|
# @example
|
@@ -229,7 +279,7 @@ module Appium
|
|
229
279
|
# @driver.settings.update('allowInvisibleElements': true)
|
230
280
|
#
|
231
281
|
def settings
|
232
|
-
@
|
282
|
+
@settings ||= DriverSettings.new(@bridge)
|
233
283
|
end
|
234
284
|
|
235
285
|
# Get appium Settings for current test session.
|
@@ -260,34 +310,6 @@ module Appium
|
|
260
310
|
end
|
261
311
|
alias update_settings settings=
|
262
312
|
|
263
|
-
class DeviceIME
|
264
|
-
# @private this class is private
|
265
|
-
def initialize(bridge)
|
266
|
-
@bridge = bridge
|
267
|
-
end
|
268
|
-
|
269
|
-
def activate(ime_name)
|
270
|
-
@bridge.ime_activate(ime_name)
|
271
|
-
end
|
272
|
-
|
273
|
-
def available_engines
|
274
|
-
@bridge.ime_available_engines
|
275
|
-
end
|
276
|
-
|
277
|
-
def active_engine
|
278
|
-
@bridge.ime_active_engine
|
279
|
-
end
|
280
|
-
|
281
|
-
def activated?
|
282
|
-
@bridge.ime_activated
|
283
|
-
end
|
284
|
-
|
285
|
-
def deactivate
|
286
|
-
@bridge.ime_deactivate
|
287
|
-
end
|
288
|
-
end
|
289
|
-
private_constant :DeviceIME
|
290
|
-
|
291
313
|
# Returns an instance of DeviceIME
|
292
314
|
#
|
293
315
|
# @return [Appium::Core::Base::Driver::DeviceIME]
|
@@ -301,7 +323,7 @@ module Appium
|
|
301
323
|
# @driver.ime.deactivate #=> Deactivate current IME engine
|
302
324
|
#
|
303
325
|
def ime
|
304
|
-
@
|
326
|
+
@ime ||= DeviceIME.new(@bridge)
|
305
327
|
end
|
306
328
|
|
307
329
|
# Android only. Make an engine that is available active.
|
@@ -421,30 +443,6 @@ module Appium
|
|
421
443
|
end
|
422
444
|
alias set_context context=
|
423
445
|
|
424
|
-
# Set the value to element directly
|
425
|
-
#
|
426
|
-
# @example
|
427
|
-
#
|
428
|
-
# @driver.set_immediate_value element, 'hello'
|
429
|
-
#
|
430
|
-
def set_immediate_value(element, *value)
|
431
|
-
::Appium::Logger.warn '[DEPRECATION] driver#set_immediate_value(element, *value) is deprecated. ' \
|
432
|
-
'Use Element#immediate_value(*value) instead'
|
433
|
-
@bridge.set_immediate_value(element, *value)
|
434
|
-
end
|
435
|
-
|
436
|
-
# Replace the value to element directly
|
437
|
-
#
|
438
|
-
# @example
|
439
|
-
#
|
440
|
-
# @driver.replace_value element, 'hello'
|
441
|
-
#
|
442
|
-
def replace_value(element, *value)
|
443
|
-
::Appium::Logger.warn '[DEPRECATION] driver#replace_value(element, *value) is deprecated. ' \
|
444
|
-
'Use Element#replace_value(*value) instead'
|
445
|
-
@bridge.replace_value(element, *value)
|
446
|
-
end
|
447
|
-
|
448
446
|
# Place a file in a specific location on the device.
|
449
447
|
# On iOS, the server should have ifuse libraries installed and configured properly for this feature to work on
|
450
448
|
# real devices.
|
@@ -864,7 +862,7 @@ module Appium
|
|
864
862
|
# @driver.perform_actions [f1, f2] #=> 'nil' if the action succeed
|
865
863
|
#
|
866
864
|
def perform_actions(data)
|
867
|
-
raise ArgumentError, "'#{data}' must be Array" unless data.is_a? Array
|
865
|
+
raise ::Appium::Core::Error::ArgumentError, "'#{data}' must be Array" unless data.is_a? Array
|
868
866
|
|
869
867
|
@bridge.send_actions data.map(&:encode).compact
|
870
868
|
data.each(&:clear_actions)
|
@@ -942,8 +940,7 @@ module Appium
|
|
942
940
|
# #=> uiautomator2
|
943
941
|
# # <Selenium::WebDriver::Remote::Capabilities:0x007fa38dae1360
|
944
942
|
# # @capabilities=
|
945
|
-
# # {:
|
946
|
-
# # :browser_name=>nil,
|
943
|
+
# # {:browser_name=>nil,
|
947
944
|
# # :browser_version=>nil,
|
948
945
|
# # :platform_name=>"android",
|
949
946
|
# # :page_load_strategy=>nil,
|
@@ -992,8 +989,7 @@ module Appium
|
|
992
989
|
# #=> XCUITest
|
993
990
|
# # <Selenium::WebDriver::Remote::Capabilities:0x007fb15dc01370
|
994
991
|
# # @capabilities=
|
995
|
-
# # {:
|
996
|
-
# # :browser_name=>"UICatalog",
|
992
|
+
# # {:browser_name=>"UICatalog",
|
997
993
|
# # :browser_version=>nil,
|
998
994
|
# # :platform_name=>"ios",
|
999
995
|
# # :page_load_strategy=>nil,
|
@@ -1074,7 +1070,7 @@ module Appium
|
|
1074
1070
|
#
|
1075
1071
|
# @param [String] img_path A path to a partial image you'd like to find
|
1076
1072
|
#
|
1077
|
-
# @return [::
|
1073
|
+
# @return [::Appium::Core::Element]
|
1078
1074
|
#
|
1079
1075
|
# @example
|
1080
1076
|
#
|
@@ -1144,14 +1140,14 @@ module Appium
|
|
1144
1140
|
@bridge.execute_driver(script: script, type: type, timeout_ms: timeout_ms)
|
1145
1141
|
end
|
1146
1142
|
|
1147
|
-
# Convert vanilla element response to ::
|
1143
|
+
# Convert vanilla element response to ::Appium::Core::Element
|
1148
1144
|
#
|
1149
1145
|
# @param [Hash] id The id which can get as a response from server
|
1150
|
-
# @return [::
|
1146
|
+
# @return [::Appium::Core::Element]
|
1151
1147
|
#
|
1152
1148
|
# @example
|
1153
1149
|
# response = {"element-6066-11e4-a52e-4f735466cecf"=>"xxxx", "ELEMENT"=>"xxxx"}
|
1154
|
-
# ele = @driver.convert_to_element(response) #=> ::
|
1150
|
+
# ele = @driver.convert_to_element(response) #=> ::Appium::Core::Element
|
1155
1151
|
# ele.rect #=> Can get the rect of the element
|
1156
1152
|
#
|
1157
1153
|
def convert_to_element(id)
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module Appium
|
16
|
+
module Core
|
17
|
+
class Base
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
#
|
21
|
+
class DriverSettings
|
22
|
+
# @private this class is private
|
23
|
+
def initialize(bridge)
|
24
|
+
@bridge = bridge
|
25
|
+
end
|
26
|
+
|
27
|
+
# Get appium Settings for current test session.
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
#
|
31
|
+
# @driver.settings.get
|
32
|
+
#
|
33
|
+
def get
|
34
|
+
@bridge.get_settings
|
35
|
+
end
|
36
|
+
|
37
|
+
# Update Appium Settings for current test session
|
38
|
+
#
|
39
|
+
# @param [Hash] settings Settings to update, keys are settings, values to value to set each setting to
|
40
|
+
#
|
41
|
+
# @example
|
42
|
+
#
|
43
|
+
# @driver.settings.update({'allowInvisibleElements': true})
|
44
|
+
#
|
45
|
+
def update(settings)
|
46
|
+
@bridge.update_settings(settings)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -52,19 +52,26 @@ module Appium
|
|
52
52
|
# @param [String, Number] latitude Set the latitude.
|
53
53
|
# @param [String, Number] longitude Set the longitude.
|
54
54
|
# @param [String, Number] altitude Set the altitude.
|
55
|
-
# @param [String, Number] speed Set the speed to apply the location on Android real devices
|
55
|
+
# @param [String, Number] speed Set the speed to apply the location on Android real devices
|
56
|
+
# in meters/second @since Appium 1.21.0 and in knots for emulators @since Appium 1.22.0.
|
57
|
+
# @param [String, Number] satellites Sets the count of geo satellites being tracked in range 1..12 @since Appium 1.22.0.
|
58
|
+
# This number is respected on Emulators.
|
56
59
|
# @param [::Selenium::WebDriver::Location]
|
57
60
|
#
|
58
61
|
# @example
|
59
62
|
#
|
60
63
|
# driver.location = ::Selenium::WebDriver::Location.new(10, 10, 10)
|
61
64
|
#
|
62
|
-
def set_location(latitude, longitude, altitude, speed: nil)
|
63
|
-
if speed.nil?
|
65
|
+
def set_location(latitude, longitude, altitude, speed: nil, satellites: nil)
|
66
|
+
if speed.nil? && satellites.nil?
|
64
67
|
self.location = ::Selenium::WebDriver::Location.new(Float(latitude), Float(longitude), Float(altitude))
|
65
68
|
else
|
66
69
|
loc = ::Selenium::WebDriver::Location.new(Float(latitude), Float(longitude), Float(altitude))
|
67
|
-
|
70
|
+
|
71
|
+
speed = Float(speed) unless speed.nil?
|
72
|
+
satellites = Integer(satellites) unless satellites.nil?
|
73
|
+
|
74
|
+
@bridge.set_location loc.latitude, loc.longitude, loc.altitude, speed: speed, satellites: satellites
|
68
75
|
end
|
69
76
|
end
|
70
77
|
end
|