testcentricity_apps 4.0.10

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 (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