testcentricity_mobile 4.0.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.
- checksums.yaml +7 -0
- data/.yardopts +3 -0
- data/CHANGELOG.md +105 -0
- data/LICENSE.md +27 -0
- data/README.md +1795 -0
- data/lib/testcentricity_mobile/app_core/appium_connect_helper.rb +634 -0
- data/lib/testcentricity_mobile/app_core/screen_object.rb +413 -0
- data/lib/testcentricity_mobile/app_core/screen_objects_helper.rb +183 -0
- data/lib/testcentricity_mobile/app_core/screen_section.rb +607 -0
- data/lib/testcentricity_mobile/app_elements/alert.rb +152 -0
- data/lib/testcentricity_mobile/app_elements/app_element.rb +692 -0
- data/lib/testcentricity_mobile/app_elements/button.rb +10 -0
- data/lib/testcentricity_mobile/app_elements/checkbox.rb +56 -0
- data/lib/testcentricity_mobile/app_elements/image.rb +10 -0
- data/lib/testcentricity_mobile/app_elements/label.rb +10 -0
- data/lib/testcentricity_mobile/app_elements/list.rb +175 -0
- data/lib/testcentricity_mobile/app_elements/switch.rb +66 -0
- data/lib/testcentricity_mobile/app_elements/textfield.rb +51 -0
- data/lib/testcentricity_mobile/appium_server.rb +71 -0
- data/lib/testcentricity_mobile/data_objects/data_objects_helper.rb +100 -0
- data/lib/testcentricity_mobile/data_objects/environment.rb +416 -0
- data/lib/testcentricity_mobile/exception_queue_helper.rb +160 -0
- data/lib/testcentricity_mobile/utility_helpers.rb +48 -0
- data/lib/testcentricity_mobile/version.rb +3 -0
- data/lib/testcentricity_mobile/world_extensions.rb +61 -0
- data/lib/testcentricity_mobile.rb +99 -0
- metadata +317 -0
@@ -0,0 +1,692 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
module TestCentricity
|
4
|
+
module AppElements
|
5
|
+
class AppUIElement
|
6
|
+
include Test::Unit::Assertions
|
7
|
+
|
8
|
+
attr_reader :parent, :locator, :context, :type, :name
|
9
|
+
attr_accessor :mru_object, :mru_locator, :mru_parent, :mru_app_session
|
10
|
+
|
11
|
+
def initialize(name, parent, locator, context)
|
12
|
+
@name = name
|
13
|
+
@parent = parent
|
14
|
+
@locator = locator
|
15
|
+
@context = context
|
16
|
+
@type = nil
|
17
|
+
reset_mru_cache
|
18
|
+
end
|
19
|
+
|
20
|
+
def reset_mru_cache
|
21
|
+
@mru_object = nil
|
22
|
+
@mru_locator = nil
|
23
|
+
@mru_parent = nil
|
24
|
+
@mru_app_session = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_object_type
|
28
|
+
@type
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_locator
|
32
|
+
@locator
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_name
|
36
|
+
@name
|
37
|
+
end
|
38
|
+
|
39
|
+
def set(value)
|
40
|
+
obj = element
|
41
|
+
object_not_found_exception(obj)
|
42
|
+
if value.is_a?(Array)
|
43
|
+
obj.send_keys(value[0])
|
44
|
+
if value[1].is_a?(Integer)
|
45
|
+
press_keycode(value[1])
|
46
|
+
else
|
47
|
+
obj.send_keys(value[1])
|
48
|
+
end
|
49
|
+
elsif value.is_a?(String)
|
50
|
+
obj.send_keys(value)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Send keystrokes to this UI element.
|
55
|
+
#
|
56
|
+
# @param value [String] keys
|
57
|
+
# @example
|
58
|
+
# color_picker_wheel.send_keys('Lime green')
|
59
|
+
#
|
60
|
+
def send_keys(value)
|
61
|
+
obj = element
|
62
|
+
object_not_found_exception(obj)
|
63
|
+
obj.send_keys(value)
|
64
|
+
end
|
65
|
+
|
66
|
+
def clear
|
67
|
+
obj = element
|
68
|
+
object_not_found_exception(obj)
|
69
|
+
obj.clear
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_value
|
73
|
+
obj = element
|
74
|
+
object_not_found_exception(obj)
|
75
|
+
if AppiumConnect.is_webview?
|
76
|
+
case obj.tag_name.downcase
|
77
|
+
when 'input', 'select', 'textarea'
|
78
|
+
obj.value
|
79
|
+
else
|
80
|
+
obj.text
|
81
|
+
end
|
82
|
+
else
|
83
|
+
obj.text
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
alias value get_value
|
88
|
+
|
89
|
+
def get_caption
|
90
|
+
obj = element
|
91
|
+
object_not_found_exception(obj)
|
92
|
+
if AppiumConnect.is_webview?
|
93
|
+
case obj.tag_name.downcase
|
94
|
+
when 'input', 'select', 'textarea'
|
95
|
+
obj.value
|
96
|
+
else
|
97
|
+
obj.text
|
98
|
+
end
|
99
|
+
elsif Environ.is_ios?
|
100
|
+
caption = case obj.tag_name
|
101
|
+
when 'XCUIElementTypeNavigationBar'
|
102
|
+
obj.attribute(:name)
|
103
|
+
else
|
104
|
+
obj.attribute(:label)
|
105
|
+
end
|
106
|
+
caption = '' if caption.nil?
|
107
|
+
else
|
108
|
+
caption = obj.text
|
109
|
+
if caption.blank?
|
110
|
+
case obj.attribute(:class)
|
111
|
+
when 'android.view.ViewGroup'
|
112
|
+
caption_obj = obj.find_element(:xpath, '//android.widget.TextView')
|
113
|
+
caption = caption_obj.text
|
114
|
+
when 'android.widget.Button'
|
115
|
+
caption_obj = obj.find_element(:xpath, '//android.widget.TextView')
|
116
|
+
caption = caption_obj.text
|
117
|
+
if caption.blank?
|
118
|
+
caption_obj = obj.find_element(:xpath, '//android.widget.ViewGroup/android.widget.TextView')
|
119
|
+
caption = caption_obj.text
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
caption
|
125
|
+
end
|
126
|
+
|
127
|
+
alias caption get_caption
|
128
|
+
|
129
|
+
# Does UI object exists?
|
130
|
+
#
|
131
|
+
# @return [Boolean]
|
132
|
+
# @example
|
133
|
+
# empty_cart_image.exists?
|
134
|
+
#
|
135
|
+
def exists?
|
136
|
+
obj = element
|
137
|
+
!obj.nil?
|
138
|
+
end
|
139
|
+
|
140
|
+
# Is UI object visible?
|
141
|
+
#
|
142
|
+
# @return [Boolean]
|
143
|
+
# @example
|
144
|
+
# remember_me_checkbox.visible?
|
145
|
+
#
|
146
|
+
def visible?
|
147
|
+
obj = element
|
148
|
+
return false if obj.nil?
|
149
|
+
begin
|
150
|
+
obj.displayed?
|
151
|
+
rescue
|
152
|
+
reset_mru_cache
|
153
|
+
obj = element
|
154
|
+
return false if obj.nil?
|
155
|
+
obj.displayed?
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Is UI object hidden (not visible)?
|
160
|
+
#
|
161
|
+
# @return [Boolean]
|
162
|
+
# @example
|
163
|
+
# remember_me_checkbox.hidden?
|
164
|
+
#
|
165
|
+
def hidden?
|
166
|
+
!visible?
|
167
|
+
end
|
168
|
+
|
169
|
+
# Is UI object enabled?
|
170
|
+
#
|
171
|
+
# @return [Boolean]
|
172
|
+
# @example
|
173
|
+
# login_button.enabled?
|
174
|
+
#
|
175
|
+
def enabled?
|
176
|
+
obj = element
|
177
|
+
object_not_found_exception(obj)
|
178
|
+
obj.enabled?
|
179
|
+
end
|
180
|
+
|
181
|
+
# Is UI object disabled (not enabled)?
|
182
|
+
#
|
183
|
+
# @return [Boolean]
|
184
|
+
# @example
|
185
|
+
# refresh_button.disabled?
|
186
|
+
#
|
187
|
+
def disabled?
|
188
|
+
!enabled?
|
189
|
+
end
|
190
|
+
|
191
|
+
def selected?
|
192
|
+
obj = element
|
193
|
+
object_not_found_exception(obj)
|
194
|
+
obj.selected?
|
195
|
+
end
|
196
|
+
|
197
|
+
def get_attribute(attrib)
|
198
|
+
obj = element
|
199
|
+
object_not_found_exception(obj)
|
200
|
+
obj.attribute(attrib)
|
201
|
+
end
|
202
|
+
|
203
|
+
# Wait until the object exists, or until the specified wait time has expired. If the wait time is nil, then the wait
|
204
|
+
# time will be Environ.default_max_wait_time.
|
205
|
+
#
|
206
|
+
# @param seconds [Integer or Float] wait time in seconds
|
207
|
+
# @example
|
208
|
+
# run_button.wait_until_exists(0.5)
|
209
|
+
#
|
210
|
+
def wait_until_exists(seconds = nil, post_exception = true)
|
211
|
+
timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
|
212
|
+
wait = Selenium::WebDriver::Wait.new(timeout: timeout)
|
213
|
+
wait.until do
|
214
|
+
reset_mru_cache
|
215
|
+
exists?
|
216
|
+
end
|
217
|
+
rescue
|
218
|
+
if post_exception
|
219
|
+
raise "Could not find UI #{object_ref_message} after #{timeout} seconds" unless exists?
|
220
|
+
else
|
221
|
+
exists?
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# Wait until the object no longer exists, or until the specified wait time has expired. If the wait time is nil, then
|
226
|
+
# the wait time will be Environ.default_max_wait_time.
|
227
|
+
#
|
228
|
+
# @param seconds [Integer or Float] wait time in seconds
|
229
|
+
# @example
|
230
|
+
# logout_button.wait_until_gone(5)
|
231
|
+
#
|
232
|
+
def wait_until_gone(seconds = nil, post_exception = true)
|
233
|
+
timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
|
234
|
+
wait = Selenium::WebDriver::Wait.new(timeout: timeout)
|
235
|
+
wait.until do
|
236
|
+
reset_mru_cache
|
237
|
+
!exists?
|
238
|
+
end
|
239
|
+
rescue
|
240
|
+
if post_exception
|
241
|
+
raise "UI #{object_ref_message} remained visible after #{timeout} seconds" if exists?
|
242
|
+
else
|
243
|
+
exists?
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# Wait until the object is visible, or until the specified wait time has expired. If the wait time is nil, then the
|
248
|
+
# wait time will be Environ.default_max_wait_time.
|
249
|
+
#
|
250
|
+
# @param seconds [Integer or Float] wait time in seconds
|
251
|
+
# @example
|
252
|
+
# run_button.wait_until_visible(0.5)
|
253
|
+
#
|
254
|
+
def wait_until_visible(seconds = nil, post_exception = true)
|
255
|
+
timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
|
256
|
+
wait = Selenium::WebDriver::Wait.new(timeout: timeout)
|
257
|
+
wait.until do
|
258
|
+
reset_mru_cache
|
259
|
+
visible?
|
260
|
+
end
|
261
|
+
rescue
|
262
|
+
if post_exception
|
263
|
+
raise "Could not find UI #{object_ref_message} after #{timeout} seconds" unless visible?
|
264
|
+
else
|
265
|
+
visible?
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
# Wait until the object is hidden, or until the specified wait time has expired. If the wait time is nil, then the
|
270
|
+
# wait time will be Environ.default_max_wait_time.
|
271
|
+
#
|
272
|
+
# @param seconds [Integer or Float] wait time in seconds
|
273
|
+
# @example
|
274
|
+
# run_button.wait_until_hidden(10)
|
275
|
+
#
|
276
|
+
def wait_until_hidden(seconds = nil, post_exception = true)
|
277
|
+
timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
|
278
|
+
wait = Selenium::WebDriver::Wait.new(timeout: timeout)
|
279
|
+
wait.until do
|
280
|
+
reset_mru_cache
|
281
|
+
hidden?
|
282
|
+
end
|
283
|
+
rescue
|
284
|
+
if post_exception
|
285
|
+
raise "UI #{object_ref_message} remained visible after #{timeout} seconds" if visible?
|
286
|
+
else
|
287
|
+
hidden?
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
# Wait until the object is enabled, or until the specified wait time has expired. If the wait time is nil, then the
|
292
|
+
# wait time will be Environ.default_max_wait_time.
|
293
|
+
#
|
294
|
+
# @param seconds [Integer or Float] wait time in seconds
|
295
|
+
# @example
|
296
|
+
# run_button.wait_until_enabled(10)
|
297
|
+
#
|
298
|
+
def wait_until_enabled(seconds = nil, post_exception = true)
|
299
|
+
timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
|
300
|
+
wait = Selenium::WebDriver::Wait.new(timeout: timeout)
|
301
|
+
wait.until do
|
302
|
+
reset_mru_cache
|
303
|
+
enabled?
|
304
|
+
end
|
305
|
+
rescue
|
306
|
+
if post_exception
|
307
|
+
raise "UI #{object_ref_message} remained disabled after #{timeout} seconds" unless enabled?
|
308
|
+
else
|
309
|
+
enabled?
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# Wait until the object's value equals the specified value, or until the specified wait time has expired. If the wait
|
314
|
+
# time is nil, then the wait time will be Environ.default_max_wait_time.
|
315
|
+
#
|
316
|
+
# @param value [String or Hash] value expected or comparison hash
|
317
|
+
# @param seconds [Integer or Float] wait time in seconds
|
318
|
+
# @example
|
319
|
+
# card_authorized_label.wait_until_value_is('Card authorized', 5)
|
320
|
+
# or
|
321
|
+
# total_weight_field.wait_until_value_is({ :greater_than => '250' }, 5)
|
322
|
+
#
|
323
|
+
def wait_until_value_is(value, seconds = nil, post_exception = true)
|
324
|
+
timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
|
325
|
+
wait = Selenium::WebDriver::Wait.new(timeout: timeout)
|
326
|
+
wait.until do
|
327
|
+
reset_mru_cache
|
328
|
+
compare(value, get_value)
|
329
|
+
end
|
330
|
+
rescue
|
331
|
+
if post_exception
|
332
|
+
raise "Value of UI #{object_ref_message} failed to equal '#{value}' after #{timeout} seconds" unless get_value == value
|
333
|
+
else
|
334
|
+
get_value == value
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
# Wait until the object's value changes to a different value, or until the specified wait time has expired. If the
|
339
|
+
# wait time is nil, then the wait time will be Environ.default_max_wait_time.
|
340
|
+
#
|
341
|
+
# @param seconds [Integer or Float] wait time in seconds
|
342
|
+
# @example
|
343
|
+
# basket_grand_total_label.wait_until_value_changes(5)
|
344
|
+
#
|
345
|
+
def wait_until_value_changes(seconds = nil, post_exception = true)
|
346
|
+
value = get_value
|
347
|
+
timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
|
348
|
+
wait = Selenium::WebDriver::Wait.new(timeout: timeout)
|
349
|
+
wait.until do
|
350
|
+
reset_mru_cache
|
351
|
+
get_value != value
|
352
|
+
end
|
353
|
+
rescue
|
354
|
+
if post_exception
|
355
|
+
raise "Value of UI #{object_ref_message} failed to change from '#{value}' after #{timeout} seconds" if get_value == value
|
356
|
+
else
|
357
|
+
get_value == value
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
# Return width of object.
|
362
|
+
#
|
363
|
+
# @return [Integer]
|
364
|
+
# @example
|
365
|
+
# button_width = my_button.width
|
366
|
+
#
|
367
|
+
def width
|
368
|
+
obj = element
|
369
|
+
object_not_found_exception(obj)
|
370
|
+
obj.size.width
|
371
|
+
end
|
372
|
+
|
373
|
+
# Return height of object.
|
374
|
+
#
|
375
|
+
# @return [Integer]
|
376
|
+
# @example
|
377
|
+
# button_height = my_button.height
|
378
|
+
#
|
379
|
+
def height
|
380
|
+
obj = element
|
381
|
+
object_not_found_exception(obj)
|
382
|
+
obj.size.height
|
383
|
+
end
|
384
|
+
|
385
|
+
# Return x coordinate of object's location.
|
386
|
+
#
|
387
|
+
# @return [Integer]
|
388
|
+
# @example
|
389
|
+
# button_x = my_button.x_loc
|
390
|
+
#
|
391
|
+
def x_loc
|
392
|
+
obj = element
|
393
|
+
object_not_found_exception(obj)
|
394
|
+
obj.location.x
|
395
|
+
end
|
396
|
+
|
397
|
+
# Return y coordinate of object's location.
|
398
|
+
#
|
399
|
+
# @return [Integer]
|
400
|
+
# @example
|
401
|
+
# button_y = my_button.y_loc
|
402
|
+
#
|
403
|
+
def y_loc
|
404
|
+
obj = element
|
405
|
+
object_not_found_exception(obj)
|
406
|
+
obj.location.y
|
407
|
+
end
|
408
|
+
|
409
|
+
# Return the number of occurrences of an object with an ambiguous locator that evaluates to multiple UI elements.
|
410
|
+
#
|
411
|
+
# @return [Integer]
|
412
|
+
# @example
|
413
|
+
# num_items = store_item.count
|
414
|
+
#
|
415
|
+
def count
|
416
|
+
objs = find_elements(@locator.keys[0], @locator.values[0])
|
417
|
+
objs.count
|
418
|
+
end
|
419
|
+
|
420
|
+
# Click on a UI element
|
421
|
+
#
|
422
|
+
# @example
|
423
|
+
# login_button.click
|
424
|
+
#
|
425
|
+
def click
|
426
|
+
obj = element
|
427
|
+
object_not_found_exception(obj)
|
428
|
+
obj.click
|
429
|
+
end
|
430
|
+
|
431
|
+
# Tap on a UI element
|
432
|
+
#
|
433
|
+
# @example
|
434
|
+
# bar_chart_close.tap
|
435
|
+
#
|
436
|
+
def tap
|
437
|
+
obj = element
|
438
|
+
object_not_found_exception(obj)
|
439
|
+
driver.action
|
440
|
+
.click_and_hold(obj)
|
441
|
+
.release
|
442
|
+
.perform
|
443
|
+
end
|
444
|
+
|
445
|
+
# Double-tap on a UI element
|
446
|
+
#
|
447
|
+
# @example
|
448
|
+
# refresh_chart_button.double_tap
|
449
|
+
#
|
450
|
+
def double_tap
|
451
|
+
obj = element
|
452
|
+
object_not_found_exception(obj)
|
453
|
+
driver.action
|
454
|
+
.click_and_hold(obj)
|
455
|
+
.release
|
456
|
+
.pause(duration: 0.2)
|
457
|
+
.click_and_hold(obj)
|
458
|
+
.release
|
459
|
+
.perform
|
460
|
+
end
|
461
|
+
|
462
|
+
# Long press on a UI element
|
463
|
+
#
|
464
|
+
# @param duration [Float] duration of long press in seconds
|
465
|
+
# @example
|
466
|
+
# header_image.long_press(1.5)
|
467
|
+
#
|
468
|
+
def long_press(duration = 1)
|
469
|
+
obj = element
|
470
|
+
object_not_found_exception(obj)
|
471
|
+
if Environ.is_ios?
|
472
|
+
begin
|
473
|
+
Environ.appium_driver.execute_script('mobile: touchAndHold', { elementId: obj.id, duration: duration })
|
474
|
+
rescue => err
|
475
|
+
puts "Retrying longpress due to error: #{err}"
|
476
|
+
else
|
477
|
+
return
|
478
|
+
end
|
479
|
+
end
|
480
|
+
driver.action
|
481
|
+
.click_and_hold(obj)
|
482
|
+
.pause(duration: duration)
|
483
|
+
.release
|
484
|
+
.perform
|
485
|
+
end
|
486
|
+
|
487
|
+
# Drag the UI object by the specified offset. If the optional duration parameter is not specified, the duration
|
488
|
+
# defaults to 0.3 seconds (300 milliseconds).
|
489
|
+
#
|
490
|
+
# @param right_offset [Integer] x coordinate offset
|
491
|
+
# @param down_offset [Integer] y coordinate offset
|
492
|
+
# @param duration [Float] OPTIONAL duration of drag in seconds
|
493
|
+
# @example
|
494
|
+
# puzzle_21_piece.drag_by(-100, -300)
|
495
|
+
#
|
496
|
+
def drag_by(right_offset, down_offset, duration = 0.3)
|
497
|
+
obj = element
|
498
|
+
object_not_found_exception(obj)
|
499
|
+
driver.action
|
500
|
+
.click_and_hold(obj)
|
501
|
+
.move_by(right_offset, down_offset, duration: duration)
|
502
|
+
.release
|
503
|
+
.perform
|
504
|
+
end
|
505
|
+
|
506
|
+
# Drag the UI object to the specified target object. If the optional duration parameter is not specified, the
|
507
|
+
# duration defaults to 0.3 seconds (300 milliseconds).
|
508
|
+
#
|
509
|
+
# @param target [String] target object to drag to
|
510
|
+
# @param duration [Float] OPTIONAL duration of drag in seconds
|
511
|
+
# @example
|
512
|
+
# puzzle_21_piece.drag_and_drop(puzzle_21_slot)
|
513
|
+
#
|
514
|
+
def drag_and_drop(target, duration = 0.3)
|
515
|
+
drag = element
|
516
|
+
object_not_found_exception(drag)
|
517
|
+
drop = target.element
|
518
|
+
drag_x = drag.location.x
|
519
|
+
drag_y = drag.location.y
|
520
|
+
drop_x = drop.location.x
|
521
|
+
drop_y = drop.location.y
|
522
|
+
driver.action
|
523
|
+
.click_and_hold(drag)
|
524
|
+
.move_by(drop_x - drag_x, drop_y - drag_y, duration: duration)
|
525
|
+
.release
|
526
|
+
.perform
|
527
|
+
end
|
528
|
+
|
529
|
+
# Scroll the UI object until it is visible. If scroll_mode is not specified, then vertical scrolling will be used.
|
530
|
+
#
|
531
|
+
# @param scroll_mode [Symbol] :vertical (default) or :horizontal
|
532
|
+
# @example
|
533
|
+
# place_order_button.scroll_into_view(scroll_mode = :horizontal)
|
534
|
+
#
|
535
|
+
def scroll_into_view(scroll_mode = :vertical)
|
536
|
+
return if visible?
|
537
|
+
case scroll_mode
|
538
|
+
when :vertical
|
539
|
+
start_direction = :down
|
540
|
+
end_direction = :up
|
541
|
+
when :horizontal
|
542
|
+
start_direction = :right
|
543
|
+
end_direction = :left
|
544
|
+
else
|
545
|
+
raise "#{scroll_mode} is not a valid selector"
|
546
|
+
end
|
547
|
+
try_count = 8
|
548
|
+
direction = start_direction
|
549
|
+
while hidden?
|
550
|
+
ScreenManager.current_screen.swipe_gesture(direction, distance = 0.1)
|
551
|
+
try_count -= 1
|
552
|
+
if try_count.zero?
|
553
|
+
if direction == end_direction
|
554
|
+
break
|
555
|
+
else
|
556
|
+
direction = end_direction
|
557
|
+
try_count = 8
|
558
|
+
end
|
559
|
+
end
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
# Perform a swipe gesture on the UI object in the specified direction. The swipe start point is the center of the
|
564
|
+
# UI object, and the swipe end point is the distance specified.
|
565
|
+
#
|
566
|
+
# A distance of 1 specifies a swipe gesture with a distance that is the full screen height (vertical swipe), or full
|
567
|
+
# screen width (horizontal swipe). A distance of 0.5 specifies a swipe gesture with a distance that is half the screen
|
568
|
+
# width or height.
|
569
|
+
#
|
570
|
+
# If distance is a value less than zero, then the distance of the swipe gesture will be half the height (vertical)
|
571
|
+
# or width (horizontal) of the UI element being swiped. This is useful for preforming swipes/scrolls in vertical
|
572
|
+
# or horizontal list objects.
|
573
|
+
#
|
574
|
+
# @param direction [Symbol] :up, :down, :left, or :right
|
575
|
+
# @param distance [Float] scroll distance relative to the screen height or width
|
576
|
+
# @example
|
577
|
+
# carousel_list.swipe_gesture(direction = :right, distance = 1)
|
578
|
+
#
|
579
|
+
def swipe_gesture(direction, distance = 0.5)
|
580
|
+
raise 'Scroll distance must be less than 1' if distance > 1
|
581
|
+
obj = element
|
582
|
+
object_not_found_exception(obj)
|
583
|
+
start_pt = [(obj.location.x + (obj.size.width * 0.5)).to_i, (obj.location.y + (obj.size.height * 0.5)).to_i]
|
584
|
+
|
585
|
+
if distance < 0
|
586
|
+
top = (start_pt[1] - obj.size.height).to_i
|
587
|
+
bottom = (start_pt[1] + obj.size.height).to_i
|
588
|
+
left = (start_pt[0] - obj.size.width).to_i
|
589
|
+
right = (start_pt[0] + obj.size.width).to_i
|
590
|
+
else
|
591
|
+
screen_size = window_size
|
592
|
+
top = (start_pt[1] - ((screen_size.height * distance) * 0.5)).to_i
|
593
|
+
bottom = (start_pt[1] + ((screen_size.height * distance) * 0.5)).to_i
|
594
|
+
left = (start_pt[0] - ((screen_size.width * distance) * 0.5)).to_i
|
595
|
+
right = (start_pt[0] + ((screen_size.width * distance) * 0.5)).to_i
|
596
|
+
end
|
597
|
+
|
598
|
+
end_pt = case direction
|
599
|
+
when :up
|
600
|
+
[start_pt[0], bottom]
|
601
|
+
when :down
|
602
|
+
[start_pt[0], top]
|
603
|
+
when :left
|
604
|
+
[right, start_pt[1]]
|
605
|
+
when :right
|
606
|
+
[left, start_pt[1]]
|
607
|
+
end
|
608
|
+
|
609
|
+
puts "Swipe start_pt = #{start_pt} / end_pt = #{end_pt}" if ENV['DEBUG']
|
610
|
+
driver.action
|
611
|
+
.click_and_hold(obj)
|
612
|
+
.move_to_location(end_pt[0], end_pt[1], duration: 0.25)
|
613
|
+
.pointer_up
|
614
|
+
.perform
|
615
|
+
end
|
616
|
+
|
617
|
+
def element
|
618
|
+
reset_mru_cache if @mru_app_session != Environ.app_session_id
|
619
|
+
obj = if @context == :section
|
620
|
+
parent_obj = nil
|
621
|
+
parent_locator = @parent.get_locator
|
622
|
+
|
623
|
+
if @mru_locator == @locator && @mru_parent == parent_locator && !@mru_object.nil?
|
624
|
+
return @mru_object
|
625
|
+
end
|
626
|
+
|
627
|
+
parent_locator.each do |locators|
|
628
|
+
|
629
|
+
if locators.keys[0] == :object
|
630
|
+
parent_obj = locators.values[0]
|
631
|
+
break
|
632
|
+
end
|
633
|
+
|
634
|
+
parent_obj = if parent_obj.nil?
|
635
|
+
find_element(locators.keys[0], locators.values[0])
|
636
|
+
else
|
637
|
+
parent_obj.find_element(locators.keys[0], locators.values[0])
|
638
|
+
end
|
639
|
+
end
|
640
|
+
puts "Found parent object '#{@parent.get_name}' - #{@parent.get_locator}" if ENV['DEBUG']
|
641
|
+
parent_obj.find_element(@locator.keys[0], @locator.values[0])
|
642
|
+
else
|
643
|
+
return @mru_object if @mru_locator == @locator && !@mru_object.nil?
|
644
|
+
find_element(@locator.keys[0], @locator.values[0])
|
645
|
+
end
|
646
|
+
puts "Found object '#{@name}' - #{@locator}" if ENV['DEBUG']
|
647
|
+
@mru_object = obj
|
648
|
+
@mru_locator = @locator
|
649
|
+
@mru_parent = parent_locator
|
650
|
+
@mru_app_session = Environ.app_session_id
|
651
|
+
obj
|
652
|
+
rescue
|
653
|
+
puts "Did not find object '#{@name}' - #{@locator}" if ENV['DEBUG']
|
654
|
+
nil
|
655
|
+
end
|
656
|
+
|
657
|
+
private
|
658
|
+
|
659
|
+
def object_not_found_exception(obj)
|
660
|
+
@type.nil? ? object_type = 'Object' : object_type = @type
|
661
|
+
raise ObjectNotFoundError.new("#{object_type} named '#{@name}' (#{get_locator}) not found") unless obj
|
662
|
+
end
|
663
|
+
|
664
|
+
def object_ref_message
|
665
|
+
"object '#{@name}' (#{get_locator})"
|
666
|
+
end
|
667
|
+
|
668
|
+
def compare(expected, actual)
|
669
|
+
if expected.is_a?(Hash)
|
670
|
+
result = false
|
671
|
+
expected.each do |key, value|
|
672
|
+
case key
|
673
|
+
when :lt, :less_than
|
674
|
+
result = actual < value
|
675
|
+
when :lt_eq, :less_than_or_equal
|
676
|
+
result = actual <= value
|
677
|
+
when :gt, :greater_than
|
678
|
+
result = actual > value
|
679
|
+
when :gt_eq, :greater_than_or_equal
|
680
|
+
result = actual >= value
|
681
|
+
when :not_equal
|
682
|
+
result = actual != value
|
683
|
+
end
|
684
|
+
end
|
685
|
+
else
|
686
|
+
result = expected == actual
|
687
|
+
end
|
688
|
+
result
|
689
|
+
end
|
690
|
+
end
|
691
|
+
end
|
692
|
+
end
|