testcentricity_apps 4.0.10

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