appium_lib_core 4.1.0 → 5.0.0.beta2

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