appium_lib 9.5.0 → 9.6.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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -0
  3. data/docs/android_docs.md +512 -287
  4. data/docs/ios_docs.md +906 -315
  5. data/docs/ios_xcuitest.md +4 -0
  6. data/lib/appium_lib/android/device.rb +39 -0
  7. data/lib/appium_lib/android/element/button.rb +36 -65
  8. data/lib/appium_lib/android/element/generic.rb +20 -12
  9. data/lib/appium_lib/android/helper.rb +4 -16
  10. data/lib/appium_lib/android/uiautomator2/element/button.rb +110 -0
  11. data/lib/appium_lib/android/uiautomator2/helper.rb +85 -0
  12. data/lib/appium_lib/common/command.rb +9 -1
  13. data/lib/appium_lib/common/helper.rb +5 -4
  14. data/lib/appium_lib/common/patch.rb +21 -5
  15. data/lib/appium_lib/common/version.rb +2 -2
  16. data/lib/appium_lib/common/wait.rb +1 -0
  17. data/lib/appium_lib/device/device.rb +13 -23
  18. data/lib/appium_lib/device/multi_touch.rb +60 -20
  19. data/lib/appium_lib/device/touch_actions.rb +17 -8
  20. data/lib/appium_lib/driver.rb +79 -19
  21. data/lib/appium_lib/ios/element/button.rb +5 -25
  22. data/lib/appium_lib/ios/element/generic.rb +4 -22
  23. data/lib/appium_lib/ios/element/text.rb +5 -25
  24. data/lib/appium_lib/ios/element/textfield.rb +31 -78
  25. data/lib/appium_lib/ios/helper.rb +11 -74
  26. data/lib/appium_lib/ios/mobile_methods.rb +0 -20
  27. data/lib/appium_lib/ios/patch.rb +2 -6
  28. data/lib/appium_lib/ios/xcuitest/device.rb +59 -0
  29. data/lib/appium_lib/ios/xcuitest/element.rb +24 -0
  30. data/lib/appium_lib/ios/xcuitest/element/button.rb +64 -0
  31. data/lib/appium_lib/ios/xcuitest/element/generic.rb +50 -0
  32. data/lib/appium_lib/ios/xcuitest/element/text.rb +61 -0
  33. data/lib/appium_lib/ios/xcuitest/element/textfield.rb +94 -0
  34. data/lib/appium_lib/ios/{xcuitest_gestures.rb → xcuitest/gestures.rb} +10 -23
  35. data/lib/appium_lib/ios/xcuitest/helper.rb +103 -0
  36. data/lib/appium_lib/ios/xcuitest/mobile_methods.rb +23 -0
  37. data/release_notes.md +6 -0
  38. metadata +14 -3
@@ -52,11 +52,19 @@ module Appium
52
52
  end_coverage: [:post, 'session/:session_id/appium/app/end_test_coverage'.freeze],
53
53
  set_network_connection: [:post, 'session/:session_id/network_connection'.freeze],
54
54
  get_performance_data: [:post, 'session/:session_id/appium/getPerformanceData'.freeze],
55
+ get_ime_available_engines: [:get, 'session/:session_id/ime/available_engines'.freeze],
56
+ get_ime_active_engine: [:get, 'session/:session_id/ime/active_engine'.freeze],
57
+ get_ime_activated: [:get, 'session/:session_id/ime/activated'.freeze],
58
+ ime_deactivate: [:post, 'session/:session_id/ime/deactivate'.freeze],
59
+ ime_activate: [:post, 'session/:session_id/ime/activate'.freeze],
55
60
 
56
61
  # iOS
57
62
  touch_id: [:post, 'session/:session_id/appium/simulator/touch_id'.freeze],
58
63
  toggle_touch_id_enrollment: [:post, 'session/:session_id/appium/simulator/toggle_touch_id_enrollment'.freeze]
59
- }.merge(COMMAND_NO_ARG).merge(::Selenium::WebDriver::Remote::OSS::Bridge::COMMANDS).freeze
64
+ }.merge(COMMAND_NO_ARG).freeze
65
+
66
+ COMMANDS_EXTEND_OSS = COMMAND.merge(::Selenium::WebDriver::Remote::OSS::Bridge::COMMANDS).freeze
67
+ COMMANDS_EXTEND_W3C = COMMAND.merge(::Selenium::WebDriver::Remote::W3C::Bridge::COMMANDS).freeze
60
68
  end
61
69
  end
62
70
  end
@@ -77,9 +77,9 @@ module Appium
77
77
  end
78
78
 
79
79
  # http://nokogiri.org/Nokogiri/XML/SAX/Document.html
80
- def start_element(name, attrs = [])
80
+ def start_element(name, attrs = [], driver = $driver)
81
81
  # Count only visible elements. Android is always visible
82
- element_visible = $driver.device_is_android? ? true : Hash[attrs]['visible'] == 'true'
82
+ element_visible = driver.device_is_android? ? true : Hash[attrs]['visible'] == 'true'
83
83
  @result[name] += 1 if element_visible
84
84
  end
85
85
 
@@ -115,8 +115,8 @@ module Appium
115
115
  # ```ruby
116
116
  # px_to_window_rel x: 50, y: 150
117
117
  # ```
118
- def px_to_window_rel(opts = {})
119
- w = $driver.window_size
118
+ def px_to_window_rel(opts = {}, driver = $driver)
119
+ w = driver.window_size
120
120
  x = opts.fetch :x, 0
121
121
  y = opts.fetch :y, 0
122
122
 
@@ -214,6 +214,7 @@ module Appium
214
214
  end
215
215
  end
216
216
 
217
+ # @private
217
218
  def _no_such_element
218
219
  error_message = 'An element could not be located on the page using the given search parameters.'
219
220
  raise Selenium::WebDriver::Error::NoSuchElementError, error_message
@@ -27,7 +27,7 @@ module Appium
27
27
  # ```
28
28
  #
29
29
  # @return [OpenStruct] the relative x, y in a struct. ex: { x: 0.50, y: 0.20 }
30
- def location_rel
30
+ def location_rel(driver = $driver)
31
31
  # TODO: Remove with 'refine Appium ruby binding'
32
32
  # https://github.com/appium/ruby_lib/issues/602
33
33
  if ::Appium.selenium_webdriver_version_more?('3.4.0')
@@ -50,7 +50,7 @@ module Appium
50
50
  center_x = location_x + (size_width / 2.0)
51
51
  center_y = location_y + (size_height / 2.0)
52
52
 
53
- w = $driver.window_size
53
+ w = driver.window_size
54
54
  OpenStruct.new(x: "#{center_x} / #{w.width.to_f}",
55
55
  y: "#{center_y} / #{w.height.to_f}")
56
56
  end
@@ -129,8 +129,13 @@ def patch_webdriver_bridge
129
129
  # for example invalid JSON will not be a Hash
130
130
  Appium::Logger.ap_info command_hash
131
131
  end
132
- delay = $driver.global_webdriver_http_sleep
133
- sleep delay if !delay.nil? && delay > 0
132
+
133
+ if !$driver.nil? && $driver.global_webdriver_http_sleep
134
+ warn '[DEPRECATION] global_webdriver_http_sleep will be removed. Please arrange with timeout.'
135
+
136
+ delay = $driver.global_webdriver_http_sleep
137
+ sleep delay if delay > 0
138
+ end
134
139
  # Appium::Logger.info "verb: #{verb}, path #{path}, command_hash #{command_hash.to_json}"
135
140
  http.call(verb, path, command_hash)
136
141
  end # def
@@ -168,7 +173,18 @@ end
168
173
  def patch_remote_driver_commands
169
174
  Selenium::WebDriver::Remote::OSS::Bridge.class_eval do
170
175
  def commands(command)
171
- ::Appium::Driver::Commands::COMMAND[command]
176
+ ::Appium::Driver::Commands::COMMANDS_EXTEND_OSS[command]
177
+ end
178
+ end
179
+
180
+ Selenium::WebDriver::Remote::W3C::Bridge.class_eval do
181
+ def commands(command)
182
+ case command
183
+ when :status, :is_element_displayed
184
+ ::Appium::Driver::Commands::COMMANDS_EXTEND_OSS[command]
185
+ else
186
+ ::Appium::Driver::Commands::COMMANDS_EXTEND_W3C[command]
187
+ end
172
188
  end
173
189
  end
174
190
  end
@@ -1,5 +1,5 @@
1
1
  module Appium
2
2
  # Version and Date are defined on the 'Appium' module, not 'Appium::Common'
3
- VERSION = '9.5.0'.freeze unless defined? ::Appium::VERSION
4
- DATE = '2017-08-05'.freeze unless defined? ::Appium::DATE
3
+ VERSION = '9.6.0'.freeze unless defined? ::Appium::VERSION
4
+ DATE = '2017-08-19'.freeze unless defined? ::Appium::DATE
5
5
  end
@@ -48,6 +48,7 @@ module Appium
48
48
  end
49
49
 
50
50
  # process opts before calling _generic_wait
51
+ # @private
51
52
  def _process_wait_opts(opts)
52
53
  opts = { timeout: opts } if opts.is_a?(Numeric)
53
54
  raise 'opts must be a hash' unless opts.is_a? Hash
@@ -254,14 +254,7 @@ module Appium
254
254
 
255
255
  add_endpoint_method(:background_app) do
256
256
  def background_app(duration = 0)
257
- # https://github.com/appium/ruby_lib/issues/500, https://github.com/appium/appium/issues/7741
258
- # `execute :background_app, {}, seconds: { timeout: duration_milli_sec }` works over Appium 1.6.4
259
- if $driver.automation_name_is_xcuitest?
260
- duration_milli_sec = duration.nil? ? nil : duration * 1000
261
- execute :background_app, {}, seconds: { timeout: duration_milli_sec }
262
- else
263
- execute :background_app, {}, seconds: duration
264
- end
257
+ execute :background_app, {}, seconds: duration
265
258
  end
266
259
  end
267
260
 
@@ -295,16 +288,9 @@ module Appium
295
288
  def hide_keyboard(close_key = nil, strategy = nil)
296
289
  option = {}
297
290
 
298
- if $driver.device_is_android? # Android can only tapOutside.
299
- option[:key] = close_key if close_key
300
- option[:strategy] = strategy || :tapOutside # default to pressKey
301
- elsif $driver.automation_name_is_xcuitest?
302
- option[:key] = close_key if close_key
303
- option[:strategy] = strategy if strategy
304
- else
305
- option[:key] = close_key || 'Done' # default to Done key.
306
- option[:strategy] = strategy || :pressKey # default to pressKey
307
- end
291
+ option[:key] = close_key || 'Done' # default to Done key.
292
+ option[:strategy] = strategy || :pressKey # default to pressKey
293
+
308
294
  execute :hide_keyboard, {}, option
309
295
  end
310
296
  end
@@ -440,6 +426,10 @@ module Appium
440
426
  Selenium::WebDriver::Remote::OSS::Bridge.class_eval do
441
427
  block_given? ? class_eval(&Proc.new) : define_method(method) { execute method }
442
428
  end
429
+
430
+ Selenium::WebDriver::Remote::W3C::Bridge.class_eval do
431
+ block_given? ? class_eval(&Proc.new) : define_method(method) { execute method }
432
+ end
443
433
  end
444
434
 
445
435
  # @!method find_element_with_appium
@@ -520,7 +510,7 @@ module Appium
520
510
  # ```
521
511
  add_endpoint_method(:ime_activate) do
522
512
  def ime_activate(ime_name)
523
- execute :imeActivateEngine, {}, engine: ime_name
513
+ execute :ime_activate, {}, engine: ime_name
524
514
  end
525
515
  end
526
516
 
@@ -533,7 +523,7 @@ module Appium
533
523
  # ```
534
524
  add_endpoint_method(:ime_available_engines) do
535
525
  def ime_available_engines
536
- execute :imeGetAvailableEngines
526
+ execute :get_ime_available_engines
537
527
  end
538
528
  end
539
529
 
@@ -546,7 +536,7 @@ module Appium
546
536
  # ```
547
537
  add_endpoint_method(:ime_active_engine) do
548
538
  def ime_active_engine
549
- execute :imeGetActiveEngine
539
+ execute :get_ime_active_engine
550
540
  end
551
541
  end
552
542
 
@@ -559,7 +549,7 @@ module Appium
559
549
  # ```
560
550
  add_endpoint_method(:ime_activated) do
561
551
  def ime_activated
562
- execute :imeIsActivated
552
+ execute :get_ime_activated
563
553
  end
564
554
  end
565
555
 
@@ -573,7 +563,7 @@ module Appium
573
563
  # ```
574
564
  add_endpoint_method(:ime_deactivate) do
575
565
  def ime_deactivate
576
- execute :imeDeactivate, {}
566
+ execute :ime_deactivate, {}
577
567
  end
578
568
  end
579
569
  end
@@ -14,31 +14,56 @@ module Appium
14
14
  # multi_touch_action.add action_1
15
15
  # multi_touch_action.add action_2
16
16
  # multi_touch_action.perform
17
+ # ```
18
+ #
19
+ # ```
20
+ # # with an arbitrary driver
21
+ # driver = Appium::Driver.new(opts, false).start_driver
22
+ # multi_touch_action = MultiTouch.new(driver)
23
+ # multi_touch_action.add action_1
24
+ # multi_touch_action.add action_2
25
+ # multi_touch_action.perform
26
+ # ```
27
+
17
28
  class MultiTouch
18
29
  class << self
19
30
  # Convenience method for pinching the screen.
20
31
  # Places two fingers at the edges of the screen and brings them together.
21
32
  # @param percentage (int) The percent size by which to shrink the screen when pinched.
22
33
  # @param auto_perform (boolean) Whether to perform the action immediately (default true)
34
+ # @param driver (Driver) Set a driver to conduct the action. DEfault is global driver($driver)
23
35
  #
24
36
  # ```ruby
25
- # action = pinch 75 #=> Pinch the screen from the top right and bottom left corners
37
+ # pinch 75 #=> Pinch the screen from the top right and bottom left corners
38
+ # ```
39
+ #
40
+ # Without auto_perform
41
+ #
42
+ # ```ruby
43
+ # action = pinch 75, false #=> Pinch the screen from the top right and bottom left corners
26
44
  # action.perform #=> to 25% of its size.
27
45
  # ```
28
- def pinch(percentage = 25, auto_perform = true)
46
+ #
47
+ # With driver
48
+ #
49
+ # ```ruby
50
+ # driver = Appium::Driver.new(opts, false).start_driver
51
+ # pinch 75, true, driver #=> Pinch the screen from the top right and bottom left corners
52
+ # ```
53
+ def pinch(percentage = 25, auto_perform = true, driver = $driver)
29
54
  raise ArgumentError("Can't pinch to greater than screen size.") if percentage > 100
30
55
 
31
56
  rate = Float(percentage) / 100
57
+ pinch = MultiTouch.new(driver)
32
58
 
33
- if $driver.automation_name_is_xcuitest?
34
- top, bottom = pinch_for_xcuitest(rate)
35
- elsif $driver.device_is_android?
59
+ if pinch.driver.automation_name_is_xcuitest?
60
+ top, bottom = pinch_for_xcuitest(rate, pinch.driver)
61
+ elsif pinch.driver.device_is_android?
36
62
  top, bottom = pinch_android(rate)
37
63
  else
38
64
  top, bottom = pinch_ios(rate)
39
65
  end
40
66
 
41
- pinch = MultiTouch.new
42
67
  pinch.add top
43
68
  pinch.add bottom
44
69
  return pinch unless auto_perform
@@ -49,25 +74,39 @@ module Appium
49
74
  # Places two fingers at the edges of the screen and brings them together.
50
75
  # @param percentage (int) The percent size by which to shrink the screen when pinched.
51
76
  # @param auto_perform (boolean) Whether to perform the action immediately (default true)
77
+ # @param driver (Driver) Set a driver to conduct the action. DEfault is global driver($driver)
52
78
  #
53
79
  # ```ruby
54
80
  # action = zoom 200 #=> Zoom in the screen from the center until it doubles in size.
55
- # action.perform
56
81
  # ```
57
- def zoom(percentage = 200, auto_perform = true)
82
+ #
83
+ # Without auto_perform
84
+ #
85
+ # ```ruby
86
+ # action = zoom 200, false #=> Zoom in the screen from the center until it doubles in size.
87
+ # action.perform #=> to 25% of its size.
88
+ # ```
89
+ #
90
+ # With driver
91
+ #
92
+ # ```ruby
93
+ # driver = Appium::Driver.new(opts, false).start_driver
94
+ # pinch 200, true, driver #=> Zoom in the screen from the center until it doubles in size.
95
+ # ```
96
+ def zoom(percentage = 200, auto_perform = true, driver = $driver)
58
97
  raise ArgumentError("Can't zoom to smaller then screen size.") if percentage < 100
59
98
 
60
99
  rate = 100 / Float(percentage)
100
+ zoom = MultiTouch.new(driver)
61
101
 
62
- if $driver.automation_name_is_xcuitest?
63
- top, bottom = zoom_for_xcuitest(rate)
64
- elsif $driver.device_is_android?
102
+ if zoom.driver.automation_name_is_xcuitest?
103
+ top, bottom = zoom_for_xcuitest(rate, zoom.driver)
104
+ elsif zoom.driver.device_is_android?
65
105
  top, bottom = zoom_android(rate)
66
106
  else
67
107
  top, bottom = zoom_ios(rate)
68
108
  end
69
109
 
70
- zoom = MultiTouch.new
71
110
  zoom.add top
72
111
  zoom.add bottom
73
112
  return zoom unless auto_perform
@@ -76,10 +115,10 @@ module Appium
76
115
 
77
116
  private
78
117
 
79
- def pinch_for_xcuitest(rate)
118
+ def pinch_for_xcuitest(rate, driver)
80
119
  height = 100
81
120
 
82
- ele = $driver.find_element :class, 'XCUIElementTypeApplication'
121
+ ele = driver.find_element :class, 'XCUIElementTypeApplication'
83
122
  top = TouchAction.new
84
123
  top.swipe({ start_x: 0.5, start_y: 0.0,
85
124
  offset_x: 0.0, offset_y: (1 - rate) * height }, ele)
@@ -119,10 +158,10 @@ module Appium
119
158
  [top, bottom]
120
159
  end
121
160
 
122
- def zoom_for_xcuitest(rate)
161
+ def zoom_for_xcuitest(rate, driver)
123
162
  height = 100
124
163
 
125
- ele = $driver.find_element :class, 'XCUIElementTypeApplication'
164
+ ele = driver.find_element :class, 'XCUIElementTypeApplication'
126
165
  top = TouchAction.new
127
166
  top.swipe({ start_x: 0.5, start_y: (1 - rate) * height,
128
167
  offset_x: 0.0, offset_y: - (1 - rate) * height }, ele)
@@ -163,11 +202,12 @@ module Appium
163
202
  end
164
203
  end # self
165
204
 
166
- attr_reader :actions
205
+ attr_reader :actions, :driver
167
206
 
168
- # Create a new multi-action
169
- def initialize
207
+ # Create a new multi-action with Driver
208
+ def initialize(driver = $driver)
170
209
  @actions = []
210
+ @driver = driver
171
211
  end
172
212
 
173
213
  # Add a touch_action to be performed
@@ -178,7 +218,7 @@ module Appium
178
218
 
179
219
  # Ask Appium to perform the actions
180
220
  def perform
181
- $driver.multi_touch @actions
221
+ @driver.multi_touch @actions
182
222
  @actions.clear
183
223
  end
184
224
  end # class MultiTouch
@@ -1,6 +1,6 @@
1
1
  module Appium
2
2
  # Perform a series of gestures, one after another. Gestures are chained
3
- # together and only performed when `perform()` is called.
3
+ # together and only performed when `perform()` is called. Default is conducted by global driver.
4
4
  #
5
5
  # Each method returns the object itself, so calls can be chained.
6
6
  #
@@ -17,7 +17,15 @@ module Appium
17
17
  # # called `swipe(...).perform` in this method.
18
18
  # swipe(start_x: 75, start_y: 500, offset_x: 75, offset_y: 20, duration: 500)
19
19
  # ```
20
-
20
+ #
21
+ # If you'd like to perform the chain with an arbitrary driver:
22
+ # ```ruby
23
+ # driver = Appium::Driver.new(opts, false).start_driver
24
+ # action = TouchAction.new.press(x: 45, y: 100).wait(5).release
25
+ # action.perform(@driver)
26
+ # action = TouchAction.new.swipe(....)
27
+ # action.perform(@driver)
28
+ # ```
21
29
  class TouchAction
22
30
  ACTIONS = [:move_to, :long_press, :double_tap, :two_finger_tap, :press, :release, :tap, :wait, :perform].freeze
23
31
  COMPLEX_ACTIONS = [:swipe].freeze
@@ -176,21 +184,22 @@ module Appium
176
184
  end
177
185
 
178
186
  # Ask the driver to perform all actions in this action chain.
179
- def perform
180
- $driver.touch_actions @actions
187
+ def perform(driver = $driver)
188
+ driver.touch_actions @actions
181
189
  @actions.clear
182
190
  self
183
191
  end
184
192
 
185
193
  # Does nothing, currently.
186
- def cancel
194
+ def cancel(driver = $driver)
187
195
  @actions << { action: cancel }
188
- $driver.touch_actions @actions
196
+ driver.touch_actions @actions
189
197
  self
190
198
  end
191
199
 
192
- def swipe_coordinates(end_x: nil, end_y: nil, offset_x: nil, offset_y: nil)
193
- if $driver.device_is_android?
200
+ # Visible for testing
201
+ def swipe_coordinates(end_x: nil, end_y: nil, offset_x: nil, offset_y: nil, driver: $driver)
202
+ if driver.device_is_android?
194
203
  puts 'end_x and end_y are used for Android. Not offset_x and offset_y.' if end_x.nil? || end_y.nil?
195
204
  end_x ||= 0
196
205
  end_y ||= 0
@@ -24,7 +24,17 @@ require_relative 'ios/element/generic'
24
24
  require_relative 'ios/element/textfield'
25
25
  require_relative 'ios/element/text'
26
26
  require_relative 'ios/mobile_methods'
27
- require_relative 'ios/xcuitest_gestures'
27
+
28
+ # ios - xcuitest
29
+ require_relative 'ios/xcuitest/element'
30
+ require_relative 'ios/xcuitest/gestures'
31
+ require_relative 'ios/xcuitest/mobile_methods'
32
+ require_relative 'ios/xcuitest/device'
33
+ require_relative 'ios/xcuitest/helper'
34
+ require_relative 'ios/xcuitest/element/text'
35
+ require_relative 'ios/xcuitest/element/textfield'
36
+ require_relative 'ios/xcuitest/element/generic'
37
+ require_relative 'ios/xcuitest/element/button'
28
38
 
29
39
  # android
30
40
  require_relative 'android/helper'
@@ -37,6 +47,11 @@ require_relative 'android/element/textfield'
37
47
  require_relative 'android/element/text'
38
48
  require_relative 'android/mobile_methods'
39
49
 
50
+ require_relative 'android/device'
51
+
52
+ # android - uiautomator2
53
+ require_relative 'android/uiautomator2/helper.rb'
54
+
40
55
  # device methods
41
56
  require_relative 'device/device'
42
57
  require_relative 'device/touch_actions'
@@ -168,8 +183,8 @@ module Appium
168
183
  # if modules is a module instead of an array, then the constants of
169
184
  # that module are promoted on.
170
185
  # otherwise, the array of modules will be used as the promotion target.
171
- def self.promote_singleton_appium_methods(modules)
172
- raise 'Driver is nil' if $driver.nil?
186
+ def self.promote_singleton_appium_methods(modules, driver = $driver)
187
+ raise 'Global $driver is nil' if driver.nil?
173
188
 
174
189
  target_modules = []
175
190
 
@@ -185,15 +200,15 @@ module Appium
185
200
  target_modules.each do |const|
186
201
  # noinspection RubyResolve
187
202
  # rubocop:disable Style/MultilineIfModifier
188
- $driver.public_methods(false).each do |m|
203
+ driver.public_methods(false).each do |m|
189
204
  const.send(:define_singleton_method, m) do |*args, &block|
190
205
  begin
191
206
  super(*args, &block) # promote.rb
192
207
  rescue NoMethodError, ArgumentError
193
- $driver.send m, *args, &block if $driver.respond_to?(m)
208
+ driver.send m, *args, &block if driver.respond_to?(m)
194
209
  end
195
210
  # override unless there's an existing method with matching arity
196
- end unless const.respond_to?(m) && const.method(m).arity == $driver.method(m).arity
211
+ end unless const.respond_to?(m) && const.method(m).arity == driver.method(m).arity
197
212
  end
198
213
  # rubocop:enable Style/MultilineIfModifier
199
214
  end
@@ -221,13 +236,13 @@ module Appium
221
236
  # # promote on minispec
222
237
  # Appium.promote_appium_methods Minitest::Spec
223
238
  # ```
224
- def self.promote_appium_methods(class_array)
225
- raise 'Driver is nil' if $driver.nil?
239
+ def self.promote_appium_methods(class_array, driver = $driver)
240
+ raise 'Driver is nil' if driver.nil?
226
241
  # Wrap single class into an array
227
242
  class_array = [class_array] unless class_array.class == Array
228
243
  # Promote Appium driver methods to class instance methods.
229
244
  class_array.each do |klass|
230
- $driver.public_methods(false).each do |m|
245
+ driver.public_methods(false).each do |m|
231
246
  klass.class_eval do
232
247
  define_method m do |*args, &block|
233
248
  begin
@@ -239,7 +254,7 @@ module Appium
239
254
  # so rescue argument error
240
255
  # and call the name method on $driver
241
256
  rescue NoMethodError, ArgumentError
242
- $driver.send m, *args, &block if $driver.respond_to?(m)
257
+ driver.send m, *args, &block if driver.respond_to?(m)
243
258
  end
244
259
  end
245
260
  end
@@ -320,7 +335,8 @@ module Appium
320
335
  # @return [Integer]
321
336
  attr_reader :appium_wait_interval
322
337
 
323
- # Creates a new driver
338
+ # Creates a new driver. The driver is defined as global scope by default.
339
+ # We can avoid defining global driver.
324
340
  #
325
341
  # @example
326
342
  #
@@ -330,7 +346,7 @@ module Appium
330
346
  #
331
347
  # # platformName takes a string or a symbol.
332
348
  #
333
- # # Start iOS driver
349
+ # # Start iOS driver with global scope
334
350
  # opts = {
335
351
  # caps: {
336
352
  # platformName: :ios,
@@ -342,7 +358,7 @@ module Appium
342
358
  # }
343
359
  # Appium::Driver.new(opts).start_driver
344
360
  #
345
- # # Start Android driver
361
+ # # Start Android driver with global scope
346
362
  # opts = {
347
363
  # caps: {
348
364
  # platformName: :android,
@@ -354,13 +370,30 @@ module Appium
354
370
  # }
355
371
  # }
356
372
  # Appium::Driver.new(opts).start_driver
373
+ #
374
+ # # Start iOS driver without global scope
375
+ # opts = {
376
+ # caps: {
377
+ # platformName: :ios,
378
+ # app: '/path/to/MyiOS.app'
379
+ # },
380
+ # appium_lib: {
381
+ # wait_timeout: 30
382
+ # }
383
+ # }
384
+ # Appium::Driver.new(opts, false).start_driver
357
385
  # ```
358
386
  #
359
387
  # @param opts [Object] A hash containing various options.
388
+ # @param global_driver [Bool] A bool require global driver before initialize.
360
389
  # @return [Driver]
361
- def initialize(opts = {})
362
- # quit last driver
363
- $driver.driver_quit if $driver
390
+ def initialize(opts = {}, global_driver = true)
391
+ if global_driver
392
+ warn '[DEPRECATION] Appium::Driver.new(opts) will not generate global driver by default.' \
393
+ 'If you would like to generate the global driver dy default, ' \
394
+ 'please initialise driver with Appium::Driver.new(opts, true)'
395
+ $driver.driver_quit if $driver
396
+ end
364
397
  raise 'opts must be a hash' unless opts.is_a? Hash
365
398
 
366
399
  opts = Appium.symbolize_keys opts
@@ -391,11 +424,19 @@ module Appium
391
424
 
392
425
  if device_is_android?
393
426
  extend Appium::Android
427
+ extend Appium::Android::Device
428
+ if automation_name_is_uiautomator2?
429
+ extend Appium::Android::Uiautomator2::Helper
430
+ end
394
431
  else
395
432
  extend Appium::Ios
396
- if automation_name_is_xcuitest? # Override touch actions
433
+ if automation_name_is_xcuitest?
434
+ # Override touch actions and patch_webdriver_element
397
435
  extend Appium::Ios::Xcuitest
436
+ extend Appium::Ios::Xcuitest::Helper
398
437
  extend Appium::Ios::Xcuitest::Gesture
438
+ extend Appium::Ios::Xcuitest::Device
439
+ extend Appium::Ios::Xcuitest::Element
399
440
  end
400
441
  end
401
442
 
@@ -417,7 +458,7 @@ module Appium
417
458
  end
418
459
 
419
460
  # Save global reference to last created Appium driver for top level methods.
420
- $driver = self
461
+ $driver = self if global_driver
421
462
 
422
463
  self # return newly created driver
423
464
  end
@@ -485,6 +526,12 @@ module Appium
485
526
  !@automation_name.nil? && @automation_name == :uiautomator2
486
527
  end
487
528
 
529
+ # Return true if automationName is 'Espresso'
530
+ # @return [Boolean]
531
+ def automation_name_is_espresso?
532
+ !@automation_name.nil? && @automation_name == :espresso
533
+ end
534
+
488
535
  # Return true if the target Appium server is over REQUIRED_VERSION_XCUITEST.
489
536
  # If the Appium server is under REQUIRED_VERSION_XCUITEST, then error is raised.
490
537
  # @return [Boolean]
@@ -617,6 +664,9 @@ module Appium
617
664
  nil
618
665
  end
619
666
 
667
+ # Alias for driver_quit
668
+ alias_method :quit_driver, :driver_quit
669
+
620
670
  # Creates a new global driver and quits the old one if it exists.
621
671
  # You can customise http_client as the following
622
672
  #
@@ -677,11 +727,21 @@ module Appium
677
727
  check_server_version_xcuitest
678
728
  set_automation_name_if_nil
679
729
 
680
- @driver.manage.timeouts.implicit_wait = @default_wait
730
+ set_implicit_wait(@default_wait)
681
731
 
682
732
  @driver
683
733
  end
684
734
 
735
+ # To ignore error for Espresso Driver
736
+ def set_implicit_wait(wait)
737
+ @driver.manage.timeouts.implicit_wait = wait
738
+ rescue Selenium::WebDriver::Error::UnknownError => e
739
+ unless e.message.include?('The operation requested is not yet implemented by Espresso driver')
740
+ raise ::Appium::Error::ServerError
741
+ end
742
+ {}
743
+ end
744
+
685
745
  # Set implicit wait to zero.
686
746
  def no_wait
687
747
  @driver.manage.timeouts.implicit_wait = 0