appium_lib 9.5.0 → 9.6.0

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