testa_appium_driver 0.1.21 → 0.1.24

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +23 -0
  3. data/.gitignore +17 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +6 -0
  6. data/Gemfile.lock +1 -1
  7. data/bin/console +17 -0
  8. data/bin/setup +8 -0
  9. data/lib/testa_appium_driver/android/class_selectors.rb +438 -0
  10. data/lib/testa_appium_driver/android/driver.rb +71 -0
  11. data/lib/testa_appium_driver/android/locator/attributes.rb +115 -0
  12. data/lib/testa_appium_driver/android/locator.rb +142 -0
  13. data/lib/testa_appium_driver/android/scroll_actions/uiautomator_scroll_actions.rb +62 -0
  14. data/lib/testa_appium_driver/android/selenium_element.rb +12 -0
  15. data/lib/testa_appium_driver/common/bounds.rb +150 -0
  16. data/lib/testa_appium_driver/common/constants.rb +38 -0
  17. data/lib/testa_appium_driver/common/exceptions/strategy_mix_exception.rb +12 -0
  18. data/lib/testa_appium_driver/common/helpers.rb +272 -0
  19. data/lib/testa_appium_driver/common/locator/scroll_actions.rb +390 -0
  20. data/lib/testa_appium_driver/common/locator.rb +640 -0
  21. data/lib/testa_appium_driver/common/scroll_actions/json_wire_scroll_actions.rb +4 -0
  22. data/lib/testa_appium_driver/common/scroll_actions/w3c_scroll_actions.rb +380 -0
  23. data/lib/testa_appium_driver/common/scroll_actions.rb +275 -0
  24. data/lib/testa_appium_driver/common/selenium_element.rb +19 -0
  25. data/lib/testa_appium_driver/driver.rb +338 -0
  26. data/lib/testa_appium_driver/ios/driver.rb +49 -0
  27. data/lib/testa_appium_driver/ios/locator/attributes.rb +89 -0
  28. data/lib/testa_appium_driver/ios/locator.rb +73 -0
  29. data/lib/testa_appium_driver/ios/selenium_element.rb +8 -0
  30. data/lib/testa_appium_driver/ios/type_selectors.rb +201 -0
  31. data/lib/testa_appium_driver.rb +4 -0
  32. data/testa_appium_driver.gemspec +6 -2
  33. metadata +39 -11
  34. data/appium-driver.iml +0 -79
@@ -0,0 +1,380 @@
1
+ module ::TestaAppiumDriver
2
+ module W3cScrollActions
3
+ # @return [Array]
4
+ def w3c_scroll_each(direction, &block)
5
+ default_deadzone!
6
+ if direction.nil?
7
+ scroll_to_start
8
+ if @scrollable.scroll_orientation == :vertical
9
+ direction = :down
10
+ else
11
+ direction = :right
12
+ end
13
+ end
14
+
15
+ case direction
16
+ when :up
17
+ align_with = :bottom
18
+ when :down
19
+ align_with = :top
20
+ when :right
21
+ align_with = :left
22
+ when :left
23
+ align_with = :right
24
+ else
25
+ align_with = :top
26
+ end
27
+
28
+ if @driver.ios?
29
+ # if true
30
+ w3c_scroll_each_ios(direction, align_with, &block)
31
+ else
32
+ w3c_scroll_each_android(direction, align_with, &block)
33
+ end
34
+ end
35
+
36
+ def w3c_scroll_each_android(direction, align_with, &block)
37
+ elements = []
38
+ begin
39
+
40
+ iterations = 0
41
+ ignore_element_ids = []
42
+ previous_element = nil
43
+
44
+ until is_end_of_scroll?
45
+ # # $__.puts "-- new iteration"
46
+ # # $__.puts "-------------"
47
+ aligned_items = 0
48
+ new_ignore_element_ids = []
49
+ matches = @locator.execute(skip_cache: true)
50
+ matches.each_with_index do |m, index|
51
+ # # $__.puts "Matches: #{matches.count}"
52
+ # # $__.puts "M: #{m.id}"
53
+ if ignore_element_ids.include?(m.id)
54
+ previous_element = m
55
+ next
56
+ end
57
+
58
+ sa = self.dup
59
+ sa.locator = m
60
+ sa.w3c_align(align_with, false, 1, speed_coef: 2.0)
61
+ is_aligned = sa.is_aligned?(align_with, m)
62
+
63
+ # add the previous to ignore if current is not aligned (probably means we cannot scroll any further)
64
+ new_ignore_element_ids << previous_element.id if !is_aligned && !previous_element.nil?
65
+
66
+ aligned_items += 1 if is_aligned
67
+
68
+ # add last element to ignore
69
+ new_ignore_element_ids << m.id if matches.count == index + 1
70
+
71
+ elements << m
72
+ if block_given? # block is given
73
+ @locator.driver.invalidate_cache
74
+ block.call(m) # use call to execute the block
75
+ else
76
+ # the value of block_argument becomes nil if you didn't give a block
77
+ # block was not given
78
+ end
79
+ previous_element = m
80
+ end
81
+
82
+ iterations += 1
83
+ break if !@max_scrolls.nil? && iterations == @max_scrolls
84
+
85
+ if aligned_items.zero?
86
+ self.send("page_#{direction}")
87
+ else
88
+ ignore_element_ids = new_ignore_element_ids.dup
89
+ end
90
+ end
91
+ rescue StandardError => e
92
+ raise e
93
+ end
94
+
95
+ elements
96
+ end
97
+
98
+ def w3c_scroll_each_ios(direction, align_with, &block)
99
+ elements = []
100
+ elements_in_current_iteration = []
101
+ begin
102
+ iterations = 0
103
+
104
+ loop do
105
+ elements_in_last_iteration = elements_in_current_iteration
106
+ elements_in_current_iteration = []
107
+ elements_count_before_iteration = elements.count
108
+
109
+ new_element_in_this_iteration_found = false
110
+ matches = @locator.execute(skip_cache: true)
111
+ matches.each do |m|
112
+ elements_in_current_iteration << m.id
113
+
114
+ element_found_in_last_iteration = elements_in_last_iteration.include?(m.id)
115
+
116
+ # ignore all elements from last iteration until first new element is found
117
+ if !new_element_in_this_iteration_found && element_found_in_last_iteration
118
+ next
119
+ end
120
+
121
+ # new element in this iteration is found,
122
+ # process all remaining elements regardless if it is found in last iteration or not
123
+ new_element_in_this_iteration_found = true
124
+
125
+ sa = self.dup
126
+ sa.locator = m
127
+ sa.w3c_align(align_with, false, 1, speed_coef: 2.0)
128
+
129
+ elements << m.id
130
+ if block_given? # block is given
131
+ @locator.driver.invalidate_cache
132
+ block.call(m) # use call to execute the block
133
+ else
134
+ # the value of block_argument becomes nil if you didn't give a block
135
+ # block was not given
136
+ end
137
+ end
138
+
139
+ iterations += 1
140
+ break if !@max_scrolls.nil? && iterations == @max_scrolls
141
+
142
+ if matches.count.positive?
143
+ # if there are elements on screen, but there are no new elements
144
+ # then we have reached the end of scrolling
145
+ if elements.count == elements_count_before_iteration
146
+ return elements
147
+ end
148
+ else
149
+ # there are no matching elements. to detect end of scroll,
150
+ # first and last leaf is compared before with first and last leaf of previous iteration
151
+ if is_end_of_scroll?
152
+ return elements
153
+ end
154
+ end
155
+
156
+ # if there are more than 1 match on screen,
157
+ # the page is scrolled by aligning elements 1 by one,
158
+ # but if there is only 1, or none elements.
159
+ # then scroll the page manually
160
+ self.send("page_#{direction}") if matches.count < 2
161
+ end
162
+ rescue Selenium::WebDriver::Error::StaleElementReferenceError
163
+ # if boundElementsByIndex is enabled, we can get stale element reference while doing scroll each
164
+ retry
165
+ rescue StandardError => e
166
+ raise e
167
+ end
168
+
169
+ elements
170
+ end
171
+
172
+ def w3c_align(with, scroll_to_find, max_attempts, speed_coef: 1.25)
173
+ default_deadzone!
174
+
175
+ @locator.scroll_to if scroll_to_find
176
+
177
+ if @locator.instance_of?(TestaAppiumDriver::Locator)
178
+ element = @locator.execute
179
+ else
180
+ element = @locator
181
+ end
182
+
183
+ max_attempts = 3 if max_attempts.nil? || max_attempts <= 0
184
+ # $ctx.puts("Is aligned: #{is_aligned?(with, element)}")
185
+ timeout = 0
186
+ stale_retries = 0
187
+ begin
188
+ until is_aligned?(with, element) || timeout == max_attempts
189
+ # $ctx.puts("align roudn: #{timeout}")
190
+ w3c_attempt_align(with, speed_coef)
191
+ timeout += 1
192
+ end
193
+ rescue Selenium::WebDriver::Error::StaleElementReferenceError
194
+ # if boundElementsByIndex is enabled, we can get stale element reference while doing scroll each
195
+ stale_retries += 1
196
+ element = @locator.execute if @locator.instance_of?(TestaAppiumDriver::Locator)
197
+ retry if stale_retries < 2
198
+ end
199
+ # $ctx.puts("end align")
200
+ end
201
+
202
+ def w3c_attempt_align(with, speed_coef)
203
+ case with
204
+ when :top
205
+ y0 = @bounds.bottom_right.y - @deadzone[:bottom]
206
+ y1 = y0 - @align_offset
207
+ x0 = @bounds.width / 2
208
+ x1 = x0
209
+ scroll_direction = :down
210
+ when :bottom
211
+ y0 = @bounds.top_left.y + @deadzone[:top]
212
+ y1 = y0 + @align_offset
213
+ x0 = @bounds.width / 2
214
+ x1 = x0
215
+ scroll_direction = :up
216
+ when :left
217
+ x0 = @bounds.bottom_right.x - @deadzone[:right]
218
+ x1 = x0 - @align_offset
219
+ y0 = @bounds.height / 2
220
+ y1 = y0
221
+ scroll_direction = :right
222
+ when :right
223
+ x0 = @bounds.top_left.x + @deadzone[:top]
224
+ x1 = x0 + @align_offset
225
+ y0 = @bounds.height / 2
226
+ y1 = y0
227
+ scroll_direction = :left
228
+ else
229
+ raise "Unsupported align with option: #{with}"
230
+ end
231
+
232
+ x1, y1 = apply_w3c_correction(x1, y1, scroll_direction) if @driver.device == :android
233
+ w3c_action(x0, y0, x1, y1, SCROLL_ACTION_TYPE_SCROLL, speed_coef: speed_coef)
234
+ end
235
+
236
+ def w3c_scroll_to(direction)
237
+ rounds = 0
238
+ max_scrolls_reached = false
239
+ end_of_scroll_reached = false
240
+ # $ctx.puts("starting scroll to")
241
+ until (@driver.android? && @locator.exists?) ||
242
+ (@driver.ios? && @locator.exists? && @locator.in_viewport?) || end_of_scroll_reached
243
+ # $ctx.puts("Scroll to round: #{rounds}")
244
+ end_of_scroll_reached = is_end_of_scroll?
245
+ case direction
246
+ when :down
247
+ page_down
248
+ when :right
249
+ page_right
250
+ when :left
251
+ page_left
252
+ when :up
253
+ page_up
254
+ else
255
+ scroll_to_start
256
+ @previous_elements = nil
257
+ if @scrollable.scroll_orientation == :vertical
258
+ direction = :down
259
+ else
260
+ direction = :right
261
+ end
262
+ end
263
+
264
+ rounds += 1
265
+
266
+ max_scrolls_reached = true if rounds == @max_scrolls
267
+ break if rounds == @max_scrolls
268
+ end
269
+ # $ctx.puts("end scroll to")
270
+ raise Selenium::WebDriver::Error::NoSuchElementError if max_scrolls_reached || end_of_scroll_reached
271
+ end
272
+
273
+ def w3c_scroll_to_start_or_end(type)
274
+ default_deadzone!
275
+
276
+ @previous_elements = nil
277
+
278
+ if type == :start
279
+ if @scrollable.scroll_orientation == :vertical
280
+ method = "fling_up"
281
+ else
282
+ method = "fling_left"
283
+ end
284
+ else
285
+ if @scrollable.scroll_orientation == :vertical
286
+ method = "fling_down"
287
+ else
288
+ method = "fling_right"
289
+ end
290
+ end
291
+
292
+ iterations = 0
293
+ until is_end_of_scroll? || iterations >= 3
294
+ self.send(method)
295
+ iterations += 1
296
+ end
297
+
298
+ # reset the flag for end of scroll elements
299
+ @previous_elements = nil
300
+ end
301
+
302
+ def w3c_page_or_fling(type, direction)
303
+ default_deadzone!
304
+
305
+ if direction == :down || direction == :up
306
+ if direction == :down
307
+ y0 = @bounds.bottom_right.y - @deadzone[:bottom].to_i
308
+ y1 = @bounds.top_left.y + @deadzone[:top].to_i
309
+ else
310
+ y0 = @bounds.top_left.y + @deadzone[:top].to_i
311
+ y1 = @bounds.bottom_right.y - @deadzone[:bottom].to_i
312
+ end
313
+ x0 = @bounds.top_left.x + (@bounds.width - @deadzone[:left].to_i - @deadzone[:right].to_i) / 2
314
+ x0 = @bounds.top_left.x if x0 < @bounds.top_left.x
315
+ x0 = @bounds.bottom_right.x if x0 > @bounds.bottom_right.x
316
+ x1 = x0
317
+ else
318
+ if direction == :right
319
+ x0 = @bounds.bottom_right.x - @deadzone[:right].to_i
320
+ x1 = @bounds.top_left.x + @deadzone[:left].to_i
321
+ else
322
+ x0 = @bounds.top_left.x + @deadzone[:left].to_i
323
+ x1 = @bounds.bottom_right.x - @deadzone[:right].to_i
324
+ end
325
+
326
+ y0 = @bounds.top_left.y + (@bounds.height - @deadzone[:top].to_i - @deadzone[:bottom].to_i) / 2
327
+ y0 = @bounds.top_left.y if y0 < @bounds.top_left.y
328
+ y0 = @bounds.bottom_right.y if y0 > @bounds.bottom_right.y
329
+ y1 = y0
330
+ end
331
+ x1, y1 = apply_w3c_correction(x1, y1, direction) if @driver.device == :android
332
+
333
+ speed_coef = 1
334
+ speed_coef = 1.5 if type == SCROLL_ACTION_TYPE_SCROLL
335
+
336
+ w3c_action(x0, y0, x1, y1, type, speed_coef: speed_coef)
337
+ end
338
+
339
+ def w3c_action(x0, y0, x1, y1, type, speed_coef: 1.0)
340
+ speed_coef = 1 / speed_coef
341
+ if type == SCROLL_ACTION_TYPE_SCROLL
342
+ duration = 1.8 * speed_coef
343
+ elsif type == SCROLL_ACTION_TYPE_FLING
344
+ duration = 0.1 * speed_coef
345
+ elsif type == SCROLL_ACTION_TYPE_DRAG
346
+ duration = 3.5 * speed_coef
347
+ else
348
+ raise "Unknown scroll action type #{type}"
349
+ end
350
+
351
+ action_builder = @driver.action
352
+ f1 = action_builder.add_pointer_input(:touch, "finger1")
353
+ f1.create_pointer_move(duration: 0, x: x0, y: y0, origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
354
+ f1.create_pointer_down(:left)
355
+
356
+ f1.create_pointer_move(duration: duration, x: x1, y: y1, origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
357
+ unless type == SCROLL_ACTION_TYPE_FLING
358
+ # with this move we prevent flinging/overscroll
359
+ overscroll_pause = @driver.ios? ? 1 : 0.5
360
+ f1.create_pointer_move(duration: overscroll_pause, x: x1, y: y1, origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
361
+ end
362
+ f1.create_pointer_up(:left)
363
+ puts "Scroll execute[w3c_action]: #{type}: {x0: #{x0}, y0: #{y0}} => (duration: #{duration}) => {x1: #{x1}, y1: #{y1}}"
364
+ # $ctx.puts "Scroll execute[w3c_action]: #{type}: {x0: #{x0}, y0: #{y0}} => (duration: #{duration}) => {x1: #{x1}, y1: #{y1}}"
365
+ @driver.perform_actions [f1]
366
+ end
367
+
368
+ def apply_w3c_correction(x1, y1, direction)
369
+ y1 -= SCROLL_CORRECTION_W3C if direction == :down
370
+ y1 += SCROLL_CORRECTION_W3C if direction == :up
371
+ x1 -= SCROLL_CORRECTION_W3C if direction == :right
372
+ x1 += SCROLL_CORRECTION_W3C if direction == :left
373
+ [x1, y1]
374
+ end
375
+
376
+ def w3c_drag_to(x0, y0, x1, y1)
377
+ w3c_action(x0, y0, x1, y1, SCROLL_ACTION_TYPE_DRAG)
378
+ end
379
+ end
380
+ end
@@ -0,0 +1,275 @@
1
+ require_relative 'scroll_actions/json_wire_scroll_actions'
2
+ require_relative 'scroll_actions/w3c_scroll_actions'
3
+
4
+ module ::TestaAppiumDriver
5
+
6
+ # Class for handling scroll actions
7
+ class ScrollActions
8
+ include W3cScrollActions
9
+ include JsonWireScrollActions
10
+
11
+ attr_accessor :locator
12
+ # @param [TestaAppiumDriver::Locator, nil] scrollable container that will be used to determine the bounds for scrolling
13
+ # @param [Hash] params
14
+ # acceptable params
15
+ # - locator - element that should be found with scrolling actions
16
+ # - deadzone - [Hash] that stores top, bottom, left and right deadzone values. If deadzone[:top] is 200 then 200px from top of the scrollable container will not be used for scrolling
17
+ # - max_scrolls - [Integer] maximum number of scrolls before exception is thrown
18
+ # - default_scroll_strategy - defines which scroll strategy will be used if a scroll action is valid for multiple strategies
19
+ def initialize(scrollable, params = {})
20
+ @scrollable = scrollable
21
+ @locator = params[:locator]
22
+ # TODO: raise error if locator is for multiple, but not for scroll each, chekc other cases aswell
23
+ @deadzone = params[:deadzone]
24
+ @max_scrolls = params[:max_scrolls]
25
+ @default_scroll_strategy = params[:default_scroll_strategy]
26
+ @driver = @locator.driver
27
+
28
+ if @scrollable.nil?
29
+ # if we dont have a scrollable element or if we do have it, but it is not compatible with uiautomator
30
+ # then find first scrollable in document
31
+ @scrollable = @driver.scrollable
32
+ end
33
+
34
+ @strategy = nil
35
+ if @scrollable.strategy == FIND_STRATEGY_XPATH || # uiautomator cannot resolve scrollable from a xpath locator
36
+ !@deadzone.nil? ||
37
+ !@scrollable.from_element.instance_of?(TestaAppiumDriver::Driver) # uiautomator cannot resolve nested scrollable
38
+ @strategy = SCROLL_STRATEGY_W3C
39
+ end
40
+
41
+ @bounds = @scrollable.bounds
42
+ end
43
+
44
+ def align(with, scroll_to_find, max_attempts)
45
+ w3c_align(with, scroll_to_find, max_attempts)
46
+ @locator
47
+ end
48
+
49
+ # @return [Array]
50
+ def scroll_each(&block)
51
+ w3c_scroll_each(nil, &block)
52
+ end
53
+
54
+ def scroll_each_down(&block)
55
+ w3c_scroll_each(:down, &block)
56
+ end
57
+
58
+ def scroll_each_up(&block)
59
+ w3c_scroll_each(:up, &block)
60
+ end
61
+
62
+ def scroll_each_right(&block)
63
+ w3c_scroll_each(:right, &block)
64
+ end
65
+
66
+ def scroll_each_left(&block)
67
+ w3c_scroll_each(:left, &block)
68
+ end
69
+
70
+ def resolve_strategy
71
+ if @strategy.nil?
72
+ @default_scroll_strategy
73
+ else
74
+ @strategy
75
+ end
76
+ end
77
+
78
+ def scroll_to
79
+ if @locator.strategy != FIND_STRATEGY_XPATH && resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
80
+ uiautomator_scroll_to
81
+ elsif resolve_strategy == SCROLL_STRATEGY_W3C
82
+ w3c_scroll_to(nil)
83
+ end
84
+ end
85
+
86
+ def scroll_down_to
87
+ w3c_scroll_to(:down)
88
+ end
89
+
90
+ def scroll_up_to
91
+ w3c_scroll_to(:up)
92
+ end
93
+
94
+ def scroll_right_to
95
+ w3c_scroll_to(:right)
96
+ end
97
+
98
+ def scroll_left_to
99
+ w3c_scroll_to(:left)
100
+ end
101
+
102
+ def page_next
103
+ if @scrollable.scroll_orientation == :vertical
104
+ page_down
105
+ else
106
+ page_left
107
+ end
108
+ end
109
+
110
+ def page_back
111
+ if @scrollable.scroll_orientation == :vertical
112
+ page_up
113
+ else
114
+ page_right
115
+ end
116
+ end
117
+
118
+ def page_down
119
+ if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
120
+ uiautomator_page_or_fling(SCROLL_ACTION_TYPE_SCROLL, :down)
121
+ elsif resolve_strategy == SCROLL_STRATEGY_W3C
122
+ w3c_page_or_fling(SCROLL_ACTION_TYPE_SCROLL, :down)
123
+ end
124
+ end
125
+
126
+ def page_right
127
+ if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
128
+ uiautomator_page_or_fling(SCROLL_ACTION_TYPE_SCROLL, :right)
129
+ elsif resolve_strategy == SCROLL_STRATEGY_W3C
130
+ w3c_page_or_fling(SCROLL_ACTION_TYPE_SCROLL, :right)
131
+ end
132
+ end
133
+
134
+ def page_up
135
+ if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
136
+ uiautomator_page_or_fling(SCROLL_ACTION_TYPE_SCROLL, :up)
137
+ elsif resolve_strategy == SCROLL_STRATEGY_W3C
138
+ w3c_page_or_fling(SCROLL_ACTION_TYPE_SCROLL, :up)
139
+ end
140
+ end
141
+
142
+ def page_left
143
+ if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
144
+ uiautomator_page_or_fling(SCROLL_ACTION_TYPE_SCROLL, :left)
145
+ elsif resolve_strategy == SCROLL_STRATEGY_W3C
146
+ w3c_page_or_fling(SCROLL_ACTION_TYPE_SCROLL, :left)
147
+ end
148
+ end
149
+
150
+ def scroll_to_start
151
+ if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
152
+ uiautomator_scroll_to_start_or_end(:start)
153
+
154
+ elsif resolve_strategy == SCROLL_STRATEGY_W3C
155
+ w3c_scroll_to_start_or_end(:start)
156
+ end
157
+ end
158
+
159
+ def scroll_to_end
160
+ if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
161
+ uiautomator_scroll_to_start_or_end(:end)
162
+ elsif resolve_strategy == SCROLL_STRATEGY_W3C
163
+ w3c_scroll_to_start_or_end(:end)
164
+ end
165
+ end
166
+
167
+ def fling_down
168
+ if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
169
+ uiautomator_page_or_fling(SCROLL_ACTION_TYPE_FLING, :down)
170
+ elsif resolve_strategy == SCROLL_STRATEGY_W3C
171
+ w3c_page_or_fling(SCROLL_ACTION_TYPE_FLING, :down)
172
+ end
173
+ end
174
+
175
+ def fling_right
176
+ if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
177
+ uiautomator_page_or_fling(SCROLL_ACTION_TYPE_FLING, :right)
178
+ elsif resolve_strategy == SCROLL_STRATEGY_W3C
179
+ w3c_page_or_fling(SCROLL_ACTION_TYPE_FLING, :right)
180
+ end
181
+ end
182
+
183
+ def fling_up
184
+ if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
185
+ uiautomator_page_or_fling(SCROLL_ACTION_TYPE_FLING, :up)
186
+ elsif resolve_strategy == SCROLL_STRATEGY_W3C
187
+ w3c_page_or_fling(SCROLL_ACTION_TYPE_FLING, :up)
188
+ end
189
+ end
190
+
191
+ def fling_left
192
+ if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
193
+ uiautomator_page_or_fling(SCROLL_ACTION_TYPE_FLING, :left)
194
+ elsif resolve_strategy == SCROLL_STRATEGY_W3C
195
+ w3c_page_or_fling(SCROLL_ACTION_TYPE_FLING, :left)
196
+ end
197
+ end
198
+
199
+ def drag_to(x, y)
200
+ b = @locator.bounds
201
+ coords = b.center
202
+ w3c_drag_to(coords.x, coords.y, x, y)
203
+ end
204
+
205
+
206
+
207
+
208
+ def is_aligned?(with, element)
209
+ align_bounds = @locator.bounds(force_cache_element: element)
210
+ case with
211
+ when :top
212
+ @align_offset = align_bounds.top_left.y - @bounds.top_left.y - @deadzone[:top]
213
+ when :bottom
214
+ @align_offset = @bounds.bottom_right.y - @deadzone[:bottom] - align_bounds.bottom_right.y
215
+ when :right
216
+ @align_offset = @bounds.bottom_right.x - @deadzone[:right] - align_bounds.bottom_right.x
217
+ when :left
218
+ @align_offset = align_bounds.top_left.x - @bounds.top_left.x - @deadzone[:left]
219
+ else
220
+ raise "Unsupported align with option: #{with}"
221
+ end
222
+ @align_offset < SCROLL_ALIGNMENT_THRESHOLD
223
+ end
224
+
225
+
226
+
227
+ def is_end_of_scroll?
228
+ # if @driver.device == :android
229
+
230
+ old_elements = @previous_elements
231
+ @previous_elements = @scrollable.first_and_last_leaf
232
+
233
+
234
+ # $__.puts "old: #{old_elements}"
235
+ # $__.puts "new: #{@previous_elements}"
236
+ # $__.puts "end_of_scroll? #{ old_elements == @previous_elements}"
237
+ old_elements == @previous_elements
238
+ # else
239
+ # # for ios, check location of first and last elements
240
+ # old_elements = @previous_elements
241
+ # @previous_elements = @scrollable.first_and_last_child&.map(&:location)
242
+ # # $__.puts "old:"
243
+ # # $__.puts old_elements
244
+ # # $__.puts "prev:"
245
+ # # $__.puts @previous_elements
246
+ # old_elements == @previous_elements
247
+ # end
248
+ end
249
+
250
+ def default_deadzone!
251
+ @deadzone = {} if @deadzone.nil?
252
+ if @deadzone[:top].nil?
253
+ @deadzone[:top] = 1
254
+ else
255
+ @deadzone[:top] = @deadzone[:top].to_f
256
+ end
257
+ if @deadzone[:bottom].nil?
258
+ @deadzone[:bottom] = 1
259
+ else
260
+ @deadzone[:bottom] = @deadzone[:bottom].to_f
261
+ end
262
+ if @deadzone[:right].nil?
263
+ @deadzone[:right] = 1
264
+ else
265
+ @deadzone[:right] = @deadzone[:right].to_f
266
+ end
267
+ if @deadzone[:left].nil?
268
+ @deadzone[:left] = 1
269
+ else
270
+ @deadzone[:left] = @deadzone[:left].to_f
271
+ end
272
+ end
273
+
274
+ end
275
+ end
@@ -0,0 +1,19 @@
1
+ module ::Appium
2
+ module Core
3
+ class Element
4
+ # sets the testa appium driver instance for the current phone
5
+ def self.set_driver(driver, udid)
6
+ udid = "unknown" if udid.nil?
7
+ @@drivers ||= {}
8
+ @@drivers[udid] = driver
9
+ end
10
+
11
+ # @return [TestaAppiumDriver::Driver] testa appium driver instance for the current phone
12
+ def get_driver
13
+ udid = @bridge.capabilities.instance_variable_get(:@capabilities)["udid"]
14
+ udid = "unknown" if udid.nil?
15
+ @@drivers[udid]
16
+ end
17
+ end
18
+ end
19
+ end