appium_lib 9.6.1 → 9.7.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 (84) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -2
  3. data/CHANGELOG.md +43 -0
  4. data/Rakefile +1 -1
  5. data/appium_lib.gemspec +1 -1
  6. data/docs/android_docs.md +440 -1295
  7. data/docs/docs.md +10 -103
  8. data/docs/index_paths.md +2 -0
  9. data/docs/ios_docs.md +725 -1674
  10. data/docs/migration.md +17 -0
  11. data/lib/appium_lib.rb +1 -2
  12. data/lib/appium_lib/android/android.rb +20 -0
  13. data/lib/appium_lib/android/{helper.rb → common/helper.rb} +1 -1
  14. data/lib/appium_lib/android/uiautomator2.rb +5 -4
  15. data/lib/appium_lib/android/uiautomator2/bridge.rb +16 -0
  16. data/lib/appium_lib/appium.rb +201 -0
  17. data/lib/appium_lib/common/helper.rb +18 -20
  18. data/lib/appium_lib/common/log.rb +24 -0
  19. data/lib/appium_lib/common/multi_touch.rb +89 -0
  20. data/lib/appium_lib/common/touch_actions.rb +48 -0
  21. data/lib/appium_lib/common/wait.rb +10 -49
  22. data/lib/appium_lib/core/android.rb +4 -0
  23. data/lib/appium_lib/core/android/device.rb +142 -0
  24. data/lib/appium_lib/core/android/search_context.rb +17 -0
  25. data/lib/appium_lib/core/android/uiautomator1/bridge.rb +16 -0
  26. data/lib/appium_lib/core/android/uiautomator2/bridge.rb +16 -0
  27. data/lib/appium_lib/core/android_uiautomator2.rb +4 -0
  28. data/lib/appium_lib/core/common.rb +6 -0
  29. data/lib/appium_lib/core/common/base.rb +8 -0
  30. data/lib/appium_lib/core/common/base/bridge.rb +47 -0
  31. data/lib/appium_lib/core/common/base/capabilities.rb +16 -0
  32. data/lib/appium_lib/core/common/base/command.rb +10 -0
  33. data/lib/appium_lib/core/common/base/driver.rb +40 -0
  34. data/lib/appium_lib/core/common/base/http_default.rb +12 -0
  35. data/lib/appium_lib/core/common/base/search_context.rb +89 -0
  36. data/lib/appium_lib/core/common/base/wait.rb +56 -0
  37. data/lib/appium_lib/{common → core/common}/command.rb +20 -16
  38. data/lib/appium_lib/core/common/device.rb +470 -0
  39. data/lib/appium_lib/core/common/error.rb +13 -0
  40. data/lib/appium_lib/core/common/log.rb +30 -0
  41. data/lib/appium_lib/{logger.rb → core/common/logger.rb} +2 -0
  42. data/lib/appium_lib/core/core.rb +38 -0
  43. data/lib/appium_lib/core/device/multi_touch.rb +213 -0
  44. data/lib/appium_lib/core/device/touch_actions.rb +206 -0
  45. data/lib/appium_lib/core/driver.rb +274 -0
  46. data/lib/appium_lib/core/ios.rb +6 -0
  47. data/lib/appium_lib/core/ios/device.rb +44 -0
  48. data/lib/appium_lib/core/ios/search_context.rb +27 -0
  49. data/lib/appium_lib/core/ios/uiautomation/bridge.rb +17 -0
  50. data/lib/appium_lib/core/ios/uiautomation/patch.rb +20 -0
  51. data/lib/appium_lib/core/ios/xcuitest/bridge.rb +18 -0
  52. data/lib/appium_lib/{ios → core/ios}/xcuitest/device.rb +5 -5
  53. data/lib/appium_lib/{ios → core/ios}/xcuitest/search_context.rb +13 -9
  54. data/lib/appium_lib/core/ios_xcuitest.rb +7 -0
  55. data/lib/appium_lib/core/patch.rb +56 -0
  56. data/lib/appium_lib/driver.rb +174 -446
  57. data/lib/appium_lib/ios/{errors.rb → common/errors.rb} +0 -0
  58. data/lib/appium_lib/ios/{helper.rb → common/helper.rb} +9 -110
  59. data/lib/appium_lib/ios/ios.rb +20 -0
  60. data/lib/appium_lib/ios/xcuitest.rb +1 -3
  61. data/lib/appium_lib/ios/xcuitest/bridge.rb +19 -0
  62. data/lib/appium_lib/ios/xcuitest/command.rb +4 -1
  63. data/lib/appium_lib/ios/xcuitest/{gestures.rb → command/gestures.rb} +1 -1
  64. data/lib/appium_lib/ios/xcuitest/element.rb +1 -18
  65. data/lib/appium_lib/ios/xcuitest/helper.rb +0 -6
  66. data/lib/appium_lib/sauce_labs.rb +29 -0
  67. data/lib/appium_lib/version.rb +5 -0
  68. data/release_notes.md +8 -0
  69. metadata +50 -25
  70. data/lib/appium_lib/android/client_xpath.rb +0 -51
  71. data/lib/appium_lib/android/device.rb +0 -39
  72. data/lib/appium_lib/android/mobile_methods.rb +0 -15
  73. data/lib/appium_lib/android/patch.rb +0 -16
  74. data/lib/appium_lib/capabilities.rb +0 -13
  75. data/lib/appium_lib/common/element/window.rb +0 -10
  76. data/lib/appium_lib/common/error.rb +0 -8
  77. data/lib/appium_lib/common/patch.rb +0 -190
  78. data/lib/appium_lib/common/search_context.rb +0 -10
  79. data/lib/appium_lib/common/version.rb +0 -5
  80. data/lib/appium_lib/device/device.rb +0 -611
  81. data/lib/appium_lib/device/multi_touch.rb +0 -225
  82. data/lib/appium_lib/device/touch_actions.rb +0 -230
  83. data/lib/appium_lib/ios/mobile_methods.rb +0 -25
  84. data/lib/appium_lib/ios/patch.rb +0 -22
@@ -1,225 +0,0 @@
1
- module Appium
2
- # MultiTouch actions allow for multiple touches to happen at the same time,
3
- # for instance, to simulate multiple finger swipes.
4
- #
5
- # Create a series of touch actions by themselves (without a `prepare()`), then
6
- # add to a new MultiTouch action. When ready, call `prepare()` and all
7
- # actions will be executed simultaneously.
8
- #
9
- # ```ruby
10
- # action_1 = TouchAction.new.press(x: 45, y: 100).wait(5).release
11
- # action_2 = TouchAction.new.tap(element: el, x: 50, y:5, count: 3)
12
- #
13
- # multi_touch_action = MultiTouch.new
14
- # multi_touch_action.add action_1
15
- # multi_touch_action.add action_2
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
-
28
- class MultiTouch
29
- class << self
30
- # Convenience method for pinching the screen.
31
- # Places two fingers at the edges of the screen and brings them together.
32
- # @param percentage (int) The percent size by which to shrink the screen when pinched.
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)
35
- #
36
- # ```ruby
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
44
- # action.perform #=> to 25% of its size.
45
- # ```
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)
54
- raise ArgumentError("Can't pinch to greater than screen size.") if percentage > 100
55
-
56
- rate = Float(percentage) / 100
57
- pinch = MultiTouch.new(driver)
58
-
59
- if pinch.driver.automation_name_is_xcuitest?
60
- top, bottom = pinch_for_xcuitest(rate, pinch.driver)
61
- elsif pinch.driver.device_is_android?
62
- top, bottom = pinch_android(rate)
63
- else
64
- top, bottom = pinch_ios(rate)
65
- end
66
-
67
- pinch.add top
68
- pinch.add bottom
69
- return pinch unless auto_perform
70
- pinch.perform
71
- end
72
-
73
- # Convenience method for zooming the screen.
74
- # Places two fingers at the edges of the screen and brings them together.
75
- # @param percentage (int) The percent size by which to shrink the screen when pinched.
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)
78
- #
79
- # ```ruby
80
- # action = zoom 200 #=> Zoom in the screen from the center until it doubles in size.
81
- # ```
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)
97
- raise ArgumentError("Can't zoom to smaller then screen size.") if percentage < 100
98
-
99
- rate = 100 / Float(percentage)
100
- zoom = MultiTouch.new(driver)
101
-
102
- if zoom.driver.automation_name_is_xcuitest?
103
- top, bottom = zoom_for_xcuitest(rate, zoom.driver)
104
- elsif zoom.driver.device_is_android?
105
- top, bottom = zoom_android(rate)
106
- else
107
- top, bottom = zoom_ios(rate)
108
- end
109
-
110
- zoom.add top
111
- zoom.add bottom
112
- return zoom unless auto_perform
113
- zoom.perform
114
- end
115
-
116
- private
117
-
118
- def pinch_for_xcuitest(rate, driver)
119
- height = 100
120
-
121
- ele = driver.find_element :class, 'XCUIElementTypeApplication'
122
- top = TouchAction.new
123
- top.swipe({ start_x: 0.5, start_y: 0.0,
124
- offset_x: 0.0, offset_y: (1 - rate) * height }, ele)
125
-
126
- bottom = TouchAction.new
127
- bottom.swipe({ start_x: 0.5, start_y: 1.0,
128
- offset_x: 0.0, offset_y: rate * height }, ele)
129
-
130
- [top, bottom]
131
- end
132
-
133
- def pinch_android(rate)
134
- height = 100
135
-
136
- top = TouchAction.new
137
- top.swipe start_x: 0.5, start_y: 1.0 * height,
138
- end_x: 0.5, end_y: rate * height, duration: 1_000
139
-
140
- bottom = TouchAction.new
141
- bottom.swipe start_x: 0.5, start_y: 0.0,
142
- end_x: 0.5, end_y: (1 - rate) * height, duration: 1_000
143
-
144
- [top, bottom]
145
- end
146
-
147
- def pinch_ios(rate)
148
- height = 100
149
-
150
- top = TouchAction.new
151
- top.swipe start_x: 0.5, start_y: 0.0,
152
- offset_x: 0.0, offset_y: (1 - rate) * height, duration: 1_000
153
-
154
- bottom = TouchAction.new
155
- bottom.swipe start_x: 0.5, start_y: 1.0,
156
- offset_x: 0.0, offset_y: rate * height, duration: 1_000
157
-
158
- [top, bottom]
159
- end
160
-
161
- def zoom_for_xcuitest(rate, driver)
162
- height = 100
163
-
164
- ele = driver.find_element :class, 'XCUIElementTypeApplication'
165
- top = TouchAction.new
166
- top.swipe({ start_x: 0.5, start_y: (1 - rate) * height,
167
- offset_x: 0.0, offset_y: - (1 - rate) * height }, ele)
168
-
169
- bottom = TouchAction.new
170
- bottom.swipe({ start_x: 0.5, start_y: rate * height,
171
- offset_x: 0.0, offset_y: (1 - rate) * height }, ele)
172
-
173
- [top, bottom]
174
- end
175
-
176
- def zoom_android(rate)
177
- height = 100
178
-
179
- top = TouchAction.new
180
- top.swipe start_x: 0.5, start_y: (1.0 - rate) * height,
181
- end_x: 0.5, end_y: 0.0, duration: 1_000
182
-
183
- bottom = TouchAction.new
184
- bottom.swipe start_x: 0.5, start_y: rate * height,
185
- end_x: 0.5, end_y: 1.0 * height, duration: 1_000
186
-
187
- [top, bottom]
188
- end
189
-
190
- def zoom_ios(rate)
191
- height = 100
192
-
193
- top = TouchAction.new
194
- top.swipe start_x: 0.5, start_y: (1 - rate) * height,
195
- offset_x: 0.0, offset_y: - (1 - rate) * height, duration: 1_000
196
-
197
- bottom = TouchAction.new
198
- bottom.swipe start_x: 0.5, start_y: rate * height,
199
- offset_x: 0.0, offset_y: (1 - rate) * height, duration: 1_000
200
-
201
- [top, bottom]
202
- end
203
- end # self
204
-
205
- attr_reader :actions, :driver
206
-
207
- # Create a new multi-action with Driver
208
- def initialize(driver = $driver)
209
- @actions = []
210
- @driver = driver
211
- end
212
-
213
- # Add a touch_action to be performed
214
- # @param chain (TouchAction) The action to add to the chain
215
- def add(chain)
216
- @actions << chain.actions
217
- end
218
-
219
- # Ask Appium to perform the actions
220
- def perform
221
- @driver.multi_touch @actions
222
- @actions.clear
223
- end
224
- end # class MultiTouch
225
- end # module Appium
@@ -1,230 +0,0 @@
1
- module Appium
2
- # Perform a series of gestures, one after another. Gestures are chained
3
- # together and only performed when `perform()` is called. Default is conducted by global driver.
4
- #
5
- # Each method returns the object itself, so calls can be chained.
6
- #
7
- # ```ruby
8
- # action = TouchAction.new.press(x: 45, y: 100).wait(5).release
9
- # action.perform
10
- # action = TouchAction.new.swipe(....)
11
- # action.perform
12
- # ```
13
- #
14
- # Or each methods can call without `TouchAction.new` as the following.
15
- # In this case, `perform` is called automatically.
16
- # ```ruby
17
- # # called `swipe(...).perform` in this method.
18
- # swipe(start_x: 75, start_y: 500, offset_x: 75, offset_y: 20, duration: 500)
19
- # ```
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
- # ```
29
- class TouchAction
30
- ACTIONS = [:move_to, :long_press, :double_tap, :two_finger_tap, :press, :release, :tap, :wait, :perform].freeze
31
- COMPLEX_ACTIONS = [:swipe].freeze
32
-
33
- class << self
34
- COMPLEX_ACTIONS.each do |action|
35
- define_method(action) do |opts|
36
- auto_perform = opts.delete(:auto_perform) { |_k| true }
37
- ta = TouchAction.new
38
- ta.send(action, opts)
39
- return ta unless auto_perform
40
- ta.perform
41
- end
42
- end
43
- end
44
-
45
- attr_reader :actions
46
-
47
- def initialize
48
- @actions = []
49
- end
50
-
51
- # Move to the given co-ordinates.
52
- #
53
- # `move_to`'s `x` and `y` have two case. One is working as coordinate, the other is working as offset.
54
- #
55
- # @option opts [integer] :x x co-ordinate to move to if element isn't set. Works as an offset if x is set with Element.
56
- # @option opts [integer] :y y co-ordinate to move to if element isn't set. Works as an offset if y is set with Element.
57
- # @option opts [WebDriver::Element] Element to scope this move within.
58
- def move_to(opts)
59
- opts = args_with_ele_ref(opts)
60
- chain_method(:moveTo, opts)
61
- end
62
-
63
- # Press down for a specific duration.
64
- # Alternatively, you can use `press(...).wait(...).release()` instead of `long_press` if duration doesn't work well.
65
- # https://github.com/appium/ruby_lib/issues/231#issuecomment-269895512
66
- # e.g. Appium::TouchAction.new.press(x: 280, y: 530).wait(2000).release.perform
67
- #
68
- # @option element [WebDriver::Element] the element to press.
69
- # @option x [integer] x co-ordinate to press on.
70
- # @option y [integer] y co-ordinate to press on.
71
- # @option duration [integer] Number of milliseconds to press.
72
- def long_press(opts)
73
- args = opts.select { |k, _v| [:element, :x, :y, :duration].include? k }
74
- args = args_with_ele_ref(args)
75
- chain_method(:longPress, args) # longPress is what the appium server expects
76
- end
77
-
78
- # Press a finger onto the screen. Finger will stay down until you call
79
- # `release`.
80
- #
81
- # @option opts [WebDriver::Element] :element (Optional) Element to press within.
82
- # @option opts [integer] :x x co-ordinate to press on
83
- # @option opts [integer] :y y co-ordinate to press on
84
- def press(opts)
85
- args = opts.select { |k, _v| [:element, :x, :y].include? k }
86
- args = args_with_ele_ref(args)
87
- chain_method(:press, args)
88
- end
89
-
90
- # Remove a finger from the screen.
91
- #
92
- # @option opts [WebDriver::Element] :element (Optional) Element to release from.
93
- # @option opts [integer] :x x co-ordinate to release from
94
- # @option opts [integer] :y y co-ordinate to release from
95
- def release(opts = nil)
96
- args = args_with_ele_ref(opts) if opts
97
- chain_method(:release, args)
98
- end
99
-
100
- # Touch a point on the screen.
101
- # Alternatively, you can use `press(...).release.perform` instead of `tap(...).perform`.
102
- #
103
- # @option opts [WebDriver::Element] :element (Optional) Element to restrict scope too.
104
- # @option opts [integer] :x x co-ordinate to tap
105
- # @option opts [integer] :y y co-ordinate to tap
106
- # @option opts [integer] :fingers how many fingers to tap with (Default 1)
107
- def tap(opts)
108
- opts[:count] = opts.delete(:fingers) if opts[:fingers]
109
- opts[:count] ||= 1
110
- args = args_with_ele_ref opts
111
- chain_method(:tap, args)
112
- end
113
-
114
- # Double tap an element on the screen
115
- #
116
- # @option opts [WebDriver::Element] :element (Optional) Element to restrict scope too.
117
- # @option opts [integer] :x x co-ordinate to tap
118
- # @option opts [integer] :y y co-ordinate to tap
119
-
120
- def double_tap(opts)
121
- args = opts.select { |k, _v| [:element, :x, :y].include? k }
122
- args = args_with_ele_ref(args)
123
- chain_method(:doubleTap, args) # doubleTap is what the appium server expects
124
- end
125
-
126
- # Two finger tap an element on the screen
127
- #
128
- # @option opts [WebDriver::Element] :element (Optional) Element to restrict scope too.
129
- # @option opts [integer] :x x co-ordinate to tap
130
- # @option opts [integer] :y y co-ordinate to tap
131
- def two_finger_tap(opts)
132
- args = opts.select { |k, _v| [:element, :x, :y].include? k }
133
- args = args_with_ele_ref(args)
134
- chain_method(:twoFingerTap, args) # twoFingerTap is what the appium server expects
135
- end
136
-
137
- # Pause for a number of milliseconds before the next action
138
- # @param milliseconds [integer] Number of milliseconds to pause for
139
- def wait(milliseconds)
140
- args = { ms: milliseconds }
141
- chain_method(:wait, args)
142
- end
143
-
144
- # Convenience method to peform a swipe.
145
- #
146
- # Note that iOS 7 simulators have broken swipe.
147
- #
148
- # For iOS: Use `offset_x` and `offset_y` to define the end point.
149
- #
150
- # For Android: Use `end_x` and `end_y` to define the end point.
151
- #
152
- # If you'd like more details, please read tests and its log samples in
153
- # `ios_tests/lib/ios/specs/device/touch_actions.rb` and `ios_tests/lib/ios/specs/device/touch_actions.rb`
154
- #
155
- # @option opts [int] :start_x Where to start swiping, on the x axis. Default 0.
156
- # @option opts [int] :start_y Where to start swiping, on the y axis. Default 0.
157
- # @option opts [int] :offset_x For iOS. Offset, on the x axis. Default 0.
158
- # @option opts [int] :offset_y For iOS. Offset, on the y axis. Default 0.
159
- # @option opts [int] :end_x For Android. Where to end swiping, on the x axis. Default 0.
160
- # @option opts [int] :end_y For Android. Where to end swiping, on the y axis. Default 0.
161
- # @option opts [int] :duration How long the actual swipe takes to complete in milliseconds. Default 200.
162
- def swipe(opts, ele = nil)
163
- start_x = opts.fetch :start_x, 0
164
- start_y = opts.fetch :start_y, 0
165
- offset_x = opts.fetch :offset_x, nil
166
- offset_y = opts.fetch :offset_y, nil
167
- end_x = opts.fetch :end_x, nil
168
- end_y = opts.fetch :end_y, nil
169
- duration = opts.fetch :duration, 200
170
-
171
- coordinates = swipe_coordinates(end_x: end_x, end_y: end_y, offset_x: offset_x, offset_y: offset_y)
172
-
173
- if ele # pinch/zoom for XCUITest
174
- press x: start_x, y: start_y, element: ele
175
- move_to x: coordinates[:offset_x], y: coordinates[:offset_y], element: ele
176
- else
177
- press x: start_x, y: start_y
178
- wait(duration) if duration
179
- move_to x: coordinates[:offset_x], y: coordinates[:offset_y]
180
- end
181
- release
182
-
183
- self
184
- end
185
-
186
- # Ask the driver to perform all actions in this action chain.
187
- def perform(driver = $driver)
188
- driver.touch_actions @actions
189
- @actions.clear
190
- self
191
- end
192
-
193
- # Does nothing, currently.
194
- def cancel(driver = $driver)
195
- @actions << { action: cancel }
196
- driver.touch_actions @actions
197
- self
198
- end
199
-
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?
203
- puts 'end_x and end_y are used for Android. Not offset_x and offset_y.' if end_x.nil? || end_y.nil?
204
- end_x ||= 0
205
- end_y ||= 0
206
- return { offset_x: end_x, offset_y: end_y }
207
- elsif offset_x.nil? || offset_y.nil?
208
- puts 'offset_x and offset_y are used for iOS. Not end_x and end_y point.'
209
- end
210
-
211
- offset_x ||= 0
212
- offset_y ||= 0
213
-
214
- { offset_x: offset_x, offset_y: offset_y }
215
- end
216
-
217
- private
218
-
219
- def chain_method(method, args = nil)
220
- action = args ? { action: method, options: args } : { action: method }
221
- @actions << action
222
- self
223
- end
224
-
225
- def args_with_ele_ref(args)
226
- args[:element] = args[:element].ref if args.key? :element
227
- args
228
- end
229
- end # class TouchAction
230
- end # module Appium