appium_lib_core 4.1.0 → 5.0.0.beta2

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +8 -0
  3. data/.github/workflows/unittest.yml +2 -2
  4. data/CHANGELOG.md +40 -275
  5. data/appium_lib_core.gemspec +4 -4
  6. data/ci-jobs/functional/run_appium.yml +2 -2
  7. data/ci-jobs/functional_test.yml +1 -1
  8. data/lib/appium_lib_core/android/device.rb +4 -4
  9. data/lib/appium_lib_core/common/base/bridge.rb +263 -88
  10. data/lib/appium_lib_core/common/base/capabilities.rb +3 -3
  11. data/lib/appium_lib_core/common/base/driver.rb +92 -37
  12. data/lib/appium_lib_core/common/base/has_location.rb +73 -0
  13. data/lib/appium_lib_core/common/base/has_network_connection.rb +56 -0
  14. data/lib/appium_lib_core/common/base/http_default.rb +1 -3
  15. data/lib/appium_lib_core/common/base/remote_status.rb +31 -0
  16. data/lib/appium_lib_core/common/base/rotable.rb +54 -0
  17. data/lib/appium_lib_core/common/base/screenshot.rb +1 -1
  18. data/lib/appium_lib_core/common/base/search_context.rb +2 -0
  19. data/lib/appium_lib_core/common/base.rb +1 -3
  20. data/lib/appium_lib_core/common/command.rb +259 -4
  21. data/lib/appium_lib_core/common/device/image_comparison.rb +12 -4
  22. data/lib/appium_lib_core/common/{command/mjsonwp.rb → device/orientation.rb} +14 -11
  23. data/lib/appium_lib_core/device.rb +1 -5
  24. data/lib/appium_lib_core/driver.rb +18 -13
  25. data/lib/appium_lib_core/{patch.rb → element.rb} +53 -5
  26. data/lib/appium_lib_core/ios/uiautomation/patch.rb +1 -1
  27. data/lib/appium_lib_core/{common/base/command.rb → mac2/bridge.rb} +9 -8
  28. data/lib/appium_lib_core/mac2/device/screen.rb +48 -0
  29. data/lib/appium_lib_core/mac2/device.rb +92 -0
  30. data/lib/appium_lib_core/mac2.rb +17 -0
  31. data/lib/appium_lib_core/version.rb +2 -2
  32. data/lib/appium_lib_core.rb +1 -4
  33. data/release_notes.md +59 -0
  34. data/script/commands.rb +3 -37
  35. metadata +24 -26
  36. data/lib/appium_lib_core/common/base/bridge/mjsonwp.rb +0 -81
  37. data/lib/appium_lib_core/common/base/bridge/w3c.rb +0 -252
  38. data/lib/appium_lib_core/common/command/common.rb +0 -110
  39. data/lib/appium_lib_core/common/command/w3c.rb +0 -56
@@ -15,6 +15,10 @@
15
15
  require 'base64'
16
16
  require_relative 'search_context'
17
17
  require_relative 'screenshot'
18
+ require_relative 'rotable'
19
+ require_relative 'remote_status'
20
+ require_relative 'has_location'
21
+ require_relative 'has_network_connection'
18
22
 
19
23
  module Appium
20
24
  module Core
@@ -22,42 +26,66 @@ module Appium
22
26
  class Driver < ::Selenium::WebDriver::Driver
23
27
  include ::Selenium::WebDriver::DriverExtensions::UploadsFiles
24
28
  include ::Selenium::WebDriver::DriverExtensions::HasSessionId
25
- include ::Selenium::WebDriver::DriverExtensions::Rotatable
26
29
  include ::Selenium::WebDriver::DriverExtensions::HasRemoteStatus
27
30
  include ::Selenium::WebDriver::DriverExtensions::HasWebStorage
28
31
 
32
+ include ::Appium::Core::Base::Rotatable
29
33
  include ::Appium::Core::Base::SearchContext
30
- include ::Appium::Core::Base::TakeScreenshot
34
+ include ::Appium::Core::Base::TakesScreenshot
35
+ include ::Appium::Core::Base::HasRemoteStatus
36
+ include ::Appium::Core::Base::HasLocation
37
+ include ::Appium::Core::Base::HasNetworkConnection
38
+
39
+ private
31
40
 
32
41
  # Private API.
33
42
  # Do not use this for general use. Used by flutter driver to get bridge for creating a new element
34
43
  attr_reader :bridge
35
44
 
36
- def initialize(opts = {})
37
- listener = opts.delete(:listener)
38
- @bridge = ::Appium::Core::Base::Bridge.handshake(**opts)
39
- if @bridge.dialect == :oss # MJSONWP
40
- extend ::Selenium::WebDriver::DriverExtensions::HasTouchScreen
41
- extend ::Selenium::WebDriver::DriverExtensions::HasLocation
42
- extend ::Selenium::WebDriver::DriverExtensions::HasNetworkConnection
43
- elsif @bridge.dialect == :w3c
44
- # TODO: Only for Appium. Ideally, we'd like to remove the below like selenium-webdriver
45
- extend ::Selenium::WebDriver::DriverExtensions::HasTouchScreen
46
- extend ::Selenium::WebDriver::DriverExtensions::HasLocation
47
- extend ::Selenium::WebDriver::DriverExtensions::HasNetworkConnection
45
+ # Almost same as self.handshake in ::Selenium::WebDriver::Remote::Bridge
46
+ #
47
+ # Implements protocol handshake which:
48
+ #
49
+ # 1. Creates session with driver.
50
+ # 2. Sniffs response.
51
+ # 3. Based on the response, understands which dialect we should use.
52
+ #
53
+ # @return [::Appium::Core::Base::Bridge]
54
+ #
55
+ def create_bridge(**opts)
56
+ opts[:url] ||= service_url(opts)
57
+ caps = opts.delete(:capabilities)
58
+ # NOTE: This is deprecated
59
+ cap_array = caps.is_a?(Hash) ? [caps] : Array(caps)
60
+
61
+ desired_capabilities = opts.delete(:desired_capabilities)
62
+ if desired_capabilities
63
+ if desired_capabilities.is_a?(Hash)
64
+ desired_capabilities = ::Selenium::WebDriver::Remote::Capabilities(desired_capabilities)
65
+ end
66
+ cap_array << desired_capabilities
48
67
  end
49
- super(@bridge, listener: listener)
50
- end
51
68
 
52
- # Get the dialect value
53
- # @return [:oss|:w3c]
54
- def dialect
55
- @bridge.dialect
69
+ options = opts.delete(:options)
70
+ cap_array << options if options
71
+
72
+ capabilities = generate_capabilities(cap_array)
73
+
74
+ bridge_opts = { http_client: opts.delete(:http_client), url: opts.delete(:url) }
75
+ raise ArgumentError, "Unable to create a driver with parameters: #{opts}" unless opts.empty?
76
+
77
+ bridge = ::Appium::Core::Base::Bridge.new(**bridge_opts)
78
+
79
+ bridge.create_session(capabilities)
80
+ bridge
56
81
  end
57
82
 
83
+ public
84
+
58
85
  # Update +server_url+ and HTTP clients following this arguments, protocol, host, port and path.
59
86
  # After this method, +@bridge.http+ will be a new instance following them instead of +server_url+ which is
60
87
  # set before creating session.
88
+ # If +@bridge.http+ did not have +update_sending_request_to+ method, this method returns immediately.
61
89
  #
62
90
  # @example
63
91
  #
@@ -66,10 +94,16 @@ module Appium
66
94
  # driver.manage.timeouts.implicit_wait = 10 # @bridge.http is for 'https://example2.com:9000/wd/hub/'
67
95
  #
68
96
  def update_sending_request_to(protocol:, host:, port:, path:)
69
- @bridge.http.update_sending_request_to(scheme: protocol,
70
- host: host,
71
- port: port,
72
- path: path)
97
+ unless @bridge.http&.class&.method_defined? :update_sending_request_to
98
+ ::Appium::Logger.warn "#{@bridge.http&.class} has no 'update_sending_request_to'. " \
99
+ 'It keeps current connection target.'
100
+ return
101
+ end
102
+
103
+ @bridge.http&.update_sending_request_to(scheme: protocol,
104
+ host: host,
105
+ port: port,
106
+ path: path)
73
107
  end
74
108
 
75
109
  ### Methods for Appium
@@ -160,10 +194,24 @@ module Appium
160
194
  @bridge = bridge
161
195
  end
162
196
 
197
+ # Get appium Settings for current test session.
198
+ #
199
+ # @example
200
+ #
201
+ # @driver.settings.get
202
+ #
163
203
  def get
164
204
  @bridge.get_settings
165
205
  end
166
206
 
207
+ # Update Appium Settings for current test session
208
+ #
209
+ # @param [Hash] settings Settings to update, keys are settings, values to value to set each setting to
210
+ #
211
+ # @example
212
+ #
213
+ # @driver.settings.update({'allowInvisibleElements': true})
214
+ #
167
215
  def update(settings)
168
216
  @bridge.update_settings(settings)
169
217
  end
@@ -200,8 +248,8 @@ module Appium
200
248
  #
201
249
  # @example
202
250
  #
203
- # @driver.update_settings('allowInvisibleElements': true)
204
- # @driver.settings.update('allowInvisibleElements': true)
251
+ # @driver.update_settings({ 'allowInvisibleElements': true })
252
+ # @driver.settings.update({ 'allowInvisibleElements': true })
205
253
  # @driver.settings = { 'allowInvisibleElements': true }
206
254
  #
207
255
  def settings=(value)
@@ -239,6 +287,8 @@ module Appium
239
287
 
240
288
  # Returns an instance of DeviceIME
241
289
  #
290
+ # @return [Appium::Core::Base::Driver::DeviceIME]
291
+ #
242
292
  # @example
243
293
  #
244
294
  # @driver.ime.activate engine: 'com.android.inputmethod.latin/.LatinIME'
@@ -289,6 +339,8 @@ module Appium
289
339
  # @!method ime_activated
290
340
  # Android only. Indicates whether IME input is active at the moment (not if it is available).
291
341
  #
342
+ # @return [Boolean]
343
+ #
292
344
  # @example
293
345
  #
294
346
  # @driver.ime_activated #=> True if IME is activated
@@ -853,7 +905,7 @@ module Appium
853
905
  end
854
906
 
855
907
  # Get the device window's logs.
856
- # @return [String]
908
+ # @return [Appium::Core::Logs]
857
909
  #
858
910
  # @example
859
911
  #
@@ -879,13 +931,13 @@ module Appium
879
931
  # Retrieve the capabilities of the specified session.
880
932
  # It's almost same as +@driver.capabilities+ but you can get more details.
881
933
  #
882
- # @return [Selenium::WebDriver::Remote::Capabilities]
934
+ # @return [Selenium::WebDriver::Remote::Capabilities, Selenium::WebDriver::Remote::Capabilities]
883
935
  #
884
936
  # @example
885
937
  # @driver.session_capabilities
886
938
  #
887
939
  # #=> uiautomator2
888
- # # <Selenium::WebDriver::Remote::W3C::Capabilities:0x007fa38dae1360
940
+ # # <Selenium::WebDriver::Remote::Capabilities:0x007fa38dae1360
889
941
  # # @capabilities=
890
942
  # # {:proxy=>nil,
891
943
  # # :browser_name=>nil,
@@ -935,7 +987,7 @@ module Appium
935
987
  # # "viewportRect"=>{"left"=>0, "top"=>63, "width"=>1080, "height"=>1731}}>
936
988
  # #
937
989
  # #=> XCUITest
938
- # # <Selenium::WebDriver::Remote::W3C::Capabilities:0x007fb15dc01370
990
+ # # <Selenium::WebDriver::Remote::Capabilities:0x007fb15dc01370
939
991
  # # @capabilities=
940
992
  # # {:proxy=>nil,
941
993
  # # :browser_name=>"UICatalog",
@@ -992,11 +1044,14 @@ module Appium
992
1044
  visualize: visualize)
993
1045
  end
994
1046
 
995
- def find_image_occurrence(full_image:, partial_image:, visualize: false, threshold: nil)
1047
+ def find_image_occurrence(full_image:, partial_image:, visualize: false, threshold: nil,
1048
+ multiple: nil, match_neighbour_threshold: nil)
996
1049
  @bridge.find_image_occurrence(full_image: full_image,
997
1050
  partial_image: partial_image,
998
1051
  visualize: visualize,
999
- threshold: threshold)
1052
+ threshold: threshold,
1053
+ multiple: multiple,
1054
+ match_neighbour_threshold: match_neighbour_threshold)
1000
1055
  end
1001
1056
 
1002
1057
  def get_images_similarity(first_image:, second_image:, visualize: false)
@@ -1016,7 +1071,7 @@ module Appium
1016
1071
  #
1017
1072
  # @param [String] img_path A path to a partial image you'd like to find
1018
1073
  #
1019
- # @return [::Selenium::WebDriver::Element]
1074
+ # @return [::Appium::Core::Element]
1020
1075
  #
1021
1076
  # @example
1022
1077
  #
@@ -1038,7 +1093,7 @@ module Appium
1038
1093
  #
1039
1094
  # @param [String] img_path A path to a partial image you'd like to find
1040
1095
  #
1041
- # @return [::Selenium::WebDriver::Element]
1096
+ # @return [Array<Selenium::WebDriver::Element>]
1042
1097
  #
1043
1098
  # @example
1044
1099
  #
@@ -1086,14 +1141,14 @@ module Appium
1086
1141
  @bridge.execute_driver(script: script, type: type, timeout_ms: timeout_ms)
1087
1142
  end
1088
1143
 
1089
- # Convert vanilla element response to ::Selenium::WebDriver::Element
1144
+ # Convert vanilla element response to ::Appium::Core::Element
1090
1145
  #
1091
1146
  # @param [Hash] id The id which can get as a response from server
1092
- # @return [::Selenium::WebDriver::Element]
1147
+ # @return [::Appium::Core::Element]
1093
1148
  #
1094
1149
  # @example
1095
1150
  # response = {"element-6066-11e4-a52e-4f735466cecf"=>"xxxx", "ELEMENT"=>"xxxx"}
1096
- # ele = @driver.convert_to_element(response) #=> ::Selenium::WebDriver::Element
1151
+ # ele = @driver.convert_to_element(response) #=> ::Appium::Core::Element
1097
1152
  # ele.rect #=> Can get the rect of the element
1098
1153
  #
1099
1154
  def convert_to_element(id)
@@ -0,0 +1,73 @@
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
+ module HasLocation
22
+ # Get the location of the device.
23
+ #
24
+ # @return [::Selenium::WebDriver::Location]
25
+ #
26
+ # @example
27
+ #
28
+ # driver.location #=> ::Selenium::WebDriver::Location.new(10, 10, 10)
29
+ #
30
+ def location
31
+ @bridge.location
32
+ end
33
+
34
+ # Set the location of the device.
35
+ #
36
+ # @param [::Selenium::WebDriver::Location] location Set the location.
37
+ #
38
+ # @example
39
+ #
40
+ # driver.location = ::Selenium::WebDriver::Location.new(10, 10, 10)
41
+ #
42
+ def location=(location)
43
+ unless location.is_a?(::Selenium::WebDriver::Location)
44
+ raise TypeError, "expected #{::Selenium::WebDriver::Location}, got #{location.inspect}:#{location.class}"
45
+ end
46
+
47
+ @bridge.set_location location.latitude, location.longitude, location.altitude
48
+ end
49
+
50
+ # Set the location of the device.
51
+ #
52
+ # @param [String, Number] latitude Set the latitude.
53
+ # @param [String, Number] longitude Set the longitude.
54
+ # @param [String, Number] altitude Set the altitude.
55
+ # @param [String, Number] speed Set the speed to apply the location on Android real devices @since Appium 1.21.0.
56
+ # @param [::Selenium::WebDriver::Location]
57
+ #
58
+ # @example
59
+ #
60
+ # driver.location = ::Selenium::WebDriver::Location.new(10, 10, 10)
61
+ #
62
+ def set_location(latitude, longitude, altitude, speed: nil)
63
+ if speed.nil?
64
+ self.location = ::Selenium::WebDriver::Location.new(Float(latitude), Float(longitude), Float(altitude))
65
+ else
66
+ loc = ::Selenium::WebDriver::Location.new(Float(latitude), Float(longitude), Float(altitude))
67
+ @bridge.set_location loc.latitude, loc.longitude, loc.altitude, speed: Float(speed)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,56 @@
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
+ module HasNetworkConnection
22
+ def network_connection_type
23
+ connection_value = @bridge.network_connection
24
+
25
+ connection_type = values_to_type[connection_value]
26
+
27
+ # In case the connection type is not recognized return the
28
+ # connection value.
29
+ connection_type || connection_value
30
+ end
31
+
32
+ def network_connection_type=(connection_type)
33
+ raise ArgumentError, 'Invalid connection type' unless valid_type? connection_type
34
+
35
+ connection_value = type_to_values[connection_type]
36
+
37
+ @bridge.network_connection = connection_value
38
+ end
39
+
40
+ private
41
+
42
+ def type_to_values
43
+ { airplane_mode: 1, wifi: 2, data: 4, all: 6, none: 0 }
44
+ end
45
+
46
+ def values_to_type
47
+ type_to_values.invert
48
+ end
49
+
50
+ def valid_type?(type)
51
+ type_to_values.keys.include? type
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -55,8 +55,6 @@ module Appium
55
55
  def update_sending_request_to(scheme:, host:, port:, path:)
56
56
  return @server_url unless validate_url_param(scheme, host, port, path)
57
57
 
58
- ::Appium::Logger.debug("[experimental] This feature, #{__method__}, is an experimental")
59
-
60
58
  # Add / if 'path' does not have it
61
59
  path = path.start_with?('/') ? path : "/#{path}"
62
60
  path = path.end_with?('/') ? path : "#{path}/"
@@ -71,7 +69,7 @@ module Appium
71
69
  return true unless [scheme, host, port, path].include?(nil)
72
70
 
73
71
  message = "Given parameters are scheme: '#{scheme}', host: '#{host}', port: '#{port}', path: '#{path}'"
74
- ::Appium::Logger.warn(message)
72
+ ::Appium::Logger.debug(message)
75
73
  false
76
74
  end
77
75
 
@@ -0,0 +1,31 @@
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
+
22
+ module HasRemoteStatus
23
+ # Selenium binding has this ability only in Remote Binding,
24
+ # so this library has this method by own for safe.
25
+ def remote_status
26
+ bridge.status
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,54 @@
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
+
22
+ module Rotatable
23
+ ORIENTATIONS = %i[landscape portrait].freeze
24
+
25
+ #
26
+ # Change the screen orientation
27
+ #
28
+ # @param [:landscape, :portrait] orientation
29
+ #
30
+ #
31
+ def rotation=(orientation)
32
+ unless ORIENTATIONS.include?(orientation)
33
+ raise ArgumentError, "expected #{ORIENTATIONS.inspect}, got #{orientation.inspect}"
34
+ end
35
+
36
+ bridge.screen_orientation = orientation.to_s.upcase
37
+ end
38
+ alias rotate rotation=
39
+
40
+ #
41
+ # Get the current screen orientation
42
+ #
43
+ # @return [:landscape, :portrait] orientation
44
+ #
45
+ # @api public
46
+ #
47
+
48
+ def orientation
49
+ bridge.screen_orientation.to_sym.downcase
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -15,7 +15,7 @@
15
15
  module Appium
16
16
  module Core
17
17
  class Base
18
- module TakeScreenshot
18
+ module TakesScreenshot
19
19
  #
20
20
  # Save a PNG screenshot to the given path
21
21
  #
@@ -141,6 +141,8 @@ module Appium
141
141
  #
142
142
  # Find all elements matching the given arguments
143
143
  #
144
+ # @return [Array<Selenium::WebDriver::Element>]
145
+ #
144
146
  # @see SearchContext#find_elements
145
147
  #
146
148
  def find_elements(*args)
@@ -29,14 +29,12 @@ require_relative 'device/clipboard_content_type'
29
29
  require_relative 'device/device'
30
30
  require_relative 'device/touch_actions'
31
31
  require_relative 'device/execute_driver'
32
+ require_relative 'device/orientation'
32
33
 
33
34
  # The following files have selenium-webdriver related stuff.
34
35
  require_relative 'base/driver'
35
36
  require_relative 'base/bridge'
36
- require_relative 'base/bridge/mjsonwp'
37
- require_relative 'base/bridge/w3c'
38
37
  require_relative 'base/capabilities'
39
38
  require_relative 'base/http_default'
40
39
  require_relative 'base/search_context'
41
- require_relative 'base/command'
42
40
  require_relative 'base/platform'