testcentricity_web 4.3.0 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +46 -11
  3. data/LICENSE.md +1 -1
  4. data/README.md +1931 -801
  5. data/lib/devices/devices.yml +144 -216
  6. data/lib/testcentricity_web/browser_helper.rb +33 -4
  7. data/lib/testcentricity_web/data_objects/environment.rb +96 -15
  8. data/lib/testcentricity_web/exception_queue_helper.rb +5 -6
  9. data/lib/testcentricity_web/version.rb +1 -1
  10. data/lib/testcentricity_web/web_core/page_object.rb +53 -49
  11. data/lib/testcentricity_web/web_core/page_objects_helper.rb +20 -11
  12. data/lib/testcentricity_web/web_core/page_section.rb +31 -34
  13. data/lib/testcentricity_web/web_core/webdriver_helper.rb +416 -288
  14. data/lib/testcentricity_web/web_elements/audio.rb +6 -4
  15. data/lib/testcentricity_web/web_elements/button.rb +7 -4
  16. data/lib/testcentricity_web/web_elements/checkbox.rb +149 -147
  17. data/lib/testcentricity_web/web_elements/file_field.rb +38 -36
  18. data/lib/testcentricity_web/web_elements/image.rb +75 -70
  19. data/lib/testcentricity_web/web_elements/label.rb +6 -4
  20. data/lib/testcentricity_web/web_elements/link.rb +15 -13
  21. data/lib/testcentricity_web/web_elements/list.rb +171 -169
  22. data/lib/testcentricity_web/web_elements/media.rb +384 -379
  23. data/lib/testcentricity_web/web_elements/radio.rb +135 -133
  24. data/lib/testcentricity_web/web_elements/range.rb +16 -29
  25. data/lib/testcentricity_web/web_elements/select_list.rb +247 -245
  26. data/lib/testcentricity_web/web_elements/table.rb +575 -573
  27. data/lib/testcentricity_web/web_elements/textfield.rb +143 -139
  28. data/lib/testcentricity_web/web_elements/ui_element.rb +1171 -0
  29. data/lib/testcentricity_web/web_elements/video.rb +39 -37
  30. data/lib/testcentricity_web/world_extensions.rb +37 -4
  31. data/lib/testcentricity_web.rb +4 -23
  32. metadata +27 -79
  33. data/lib/testcentricity_web/web_elements/ui_elements_helper.rb +0 -1148
@@ -1,1148 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test/unit'
4
-
5
- Capybara::Node::Element.class_eval do
6
- def click_at(x, y)
7
- right = x - (native.size.width / 2)
8
- top = y - (native.size.height / 2)
9
- driver.browser.action.move_to(native).move_by(right.to_i, top.to_i).click.perform
10
- end
11
-
12
- def hover_at(x, y)
13
- right = x - (native.size.width / 2)
14
- top = y - (native.size.height / 2)
15
- driver.browser.action.move_to(native).move_by(right.to_i, top.to_i).perform
16
- end
17
-
18
- def get_width
19
- native.size.width
20
- end
21
-
22
- def get_height
23
- native.size.height
24
- end
25
-
26
- def get_x
27
- native.location.x
28
- end
29
-
30
- def get_y
31
- native.location.y
32
- end
33
-
34
- def displayed?
35
- native.displayed?
36
- end
37
- end
38
-
39
-
40
- module TestCentricity
41
- class UIElement
42
- include Capybara::DSL
43
- include Test::Unit::Assertions
44
-
45
- attr_reader :parent, :locator, :context, :type, :name
46
- attr_accessor :alt_locator, :locator_type, :original_style
47
- attr_accessor :base_object
48
-
49
- XPATH_SELECTORS = ['//', '[@', '[contains(']
50
- CSS_SELECTORS = %w[# :nth-child( :first-child :last-child :nth-of-type( :first-of-type :last-of-type ^= $= *= :contains(]
51
-
52
- def initialize(name, parent, locator, context)
53
- @name = name
54
- @parent = parent
55
- @locator = locator
56
- @context = context
57
- @type = nil
58
- @alt_locator = nil
59
- @original_style = nil
60
- set_locator_type
61
- end
62
-
63
- def set_locator_type(locator = nil)
64
- locator = @locator if locator.nil?
65
- is_xpath = XPATH_SELECTORS.any? { |selector| locator.include?(selector) }
66
- is_css = CSS_SELECTORS.any? { |selector| locator.include?(selector) }
67
- @locator_type = if is_xpath && !is_css
68
- :xpath
69
- elsif is_css && !is_xpath
70
- :css
71
- elsif !is_css && !is_xpath
72
- :css
73
- else
74
- :css
75
- end
76
- end
77
-
78
- def get_locator_type
79
- @locator_type
80
- end
81
-
82
- def get_object_type
83
- if @type
84
- @type
85
- else
86
- obj, type = find_element
87
- object_not_found_exception(obj, type)
88
- if obj.tag_name
89
- obj.tag_name
90
- elsif obj.native.attribute('type')
91
- obj.native.attribute('type')
92
- end
93
- end
94
- end
95
-
96
- def get_locator
97
- @locator
98
- end
99
-
100
- def get_name
101
- @name
102
- end
103
-
104
- def set_alt_locator(temp_locator)
105
- @alt_locator = temp_locator
106
- end
107
-
108
- def clear_alt_locator
109
- @alt_locator = nil
110
- end
111
-
112
- # Click on an object
113
- #
114
- # @example
115
- # basket_link.click
116
- #
117
- def click
118
- obj, type = find_element
119
- object_not_found_exception(obj, type)
120
- begin
121
- obj.click
122
- rescue StandardError
123
- obj.click_at(10, 10)
124
- end
125
- end
126
-
127
- # Double-click on an object
128
- #
129
- # @example
130
- # file_image.double_click
131
- #
132
- def double_click
133
- obj, type = find_element
134
- object_not_found_exception(obj, type)
135
- page.driver.browser.action.double_click(obj.native).perform
136
- end
137
-
138
- # Right-click on an object
139
- #
140
- # @example
141
- # basket_item_image.right_click
142
- #
143
- def right_click
144
- obj, type = find_element
145
- object_not_found_exception(obj, type)
146
- page.driver.browser.action.context_click(obj.native).perform
147
- end
148
-
149
- # Click at a specific location within an object
150
- #
151
- # @param x [Integer] X offset
152
- # @param y [Integer] Y offset
153
- # @example
154
- # basket_item_image.click_at(10, 10)
155
- #
156
- def click_at(x, y)
157
- obj, = find_element
158
- raise "UI #{object_ref_message} not found" unless obj
159
- obj.click_at(x, y)
160
- end
161
-
162
- # Scroll the object to its top, middle, or bottom
163
- #
164
- # @param position [Symbol] :top, :bottom, :center
165
- # @example
166
- # cue_list.scroll_to(:bottom)
167
- #
168
- def scroll_to(position)
169
- obj, type = find_element
170
- object_not_found_exception(obj, type)
171
- page.scroll_to(obj, align: position)
172
- end
173
-
174
- def set(value)
175
- obj, type = find_element
176
- object_not_found_exception(obj, type)
177
- obj.set(value)
178
- end
179
-
180
- # Send keystrokes to this object.
181
- #
182
- # @param keys [String] keys
183
- # @example
184
- # comment_field.send_keys(:enter)
185
- #
186
- def send_keys(*keys)
187
- obj, type = find_element
188
- object_not_found_exception(obj, type)
189
- obj.send_keys(*keys)
190
- end
191
-
192
- # Does UI object exists?
193
- #
194
- # @return [Boolean]
195
- # @example
196
- # basket_link.exists?
197
- #
198
- def exists?(visible = true)
199
- obj, = find_object(visible)
200
- !obj.nil?
201
- end
202
-
203
- # Is UI object visible?
204
- #
205
- # @return [Boolean]
206
- # @example
207
- # remember_me_checkbox.visible?
208
- #
209
- def visible?
210
- obj, type = find_element
211
- exists = obj
212
- invisible = false
213
- if type == :css
214
- Capybara.using_wait_time 0.1 do
215
- # is object itself hidden with .ui-helper-hidden class?
216
- self_hidden = page.has_css?("#{@locator}.ui-helper-hidden")
217
- # is parent of object hidden, thus hiding the object?
218
- parent_hidden = page.has_css?(".ui-helper-hidden > #{@locator}")
219
- # is grandparent of object, or any other ancestor, hidden?
220
- other_ancestor_hidden = page.has_css?(".ui-helper-hidden * #{@locator}")
221
- # if any of the above conditions are true, then object is invisible
222
- invisible = self_hidden || parent_hidden || other_ancestor_hidden
223
- end
224
- else
225
- invisible = !obj.visible? if exists
226
- end
227
- # the object is visible if it exists and it is not invisible
228
- if exists && !invisible
229
- true
230
- else
231
- false
232
- end
233
- end
234
-
235
- # Is UI object hidden (not visible)?
236
- #
237
- # @return [Boolean]
238
- # @example
239
- # remember_me_checkbox.hidden?
240
- #
241
- def hidden?
242
- !visible?
243
- end
244
-
245
- # Is UI object enabled?
246
- #
247
- # @return [Boolean]
248
- # @example
249
- # login_button.enabled?
250
- #
251
- def enabled?
252
- !disabled?
253
- end
254
-
255
- # Is UI object disabled (not enabled)?
256
- #
257
- # @return [Boolean]
258
- # @example
259
- # login_button.disabled?
260
- #
261
- def disabled?
262
- obj, type = find_element
263
- object_not_found_exception(obj, type)
264
- obj.disabled?
265
- end
266
-
267
- # Is UI object's required attribute set?
268
- #
269
- # @return [Boolean]
270
- # @example
271
- # first_name_field.required?
272
- #
273
- def required?
274
- obj, type = find_element
275
- object_not_found_exception(obj, type)
276
- state = get_attribute(:required)
277
- state.boolean? ? state : state == 'true'
278
- end
279
-
280
- # Is UI object obscured (not currently in viewport and not clickable)?
281
- #
282
- # @return [Boolean]
283
- # @example
284
- # buy_now_button.obscured?
285
- #
286
- def obscured?
287
- obj, type = find_element
288
- object_not_found_exception(obj, type)
289
- obj.obscured?
290
- end
291
-
292
- # Does UI object have the current focus?
293
- #
294
- # @return [Boolean]
295
- # @example
296
- # first_name_field.focused?
297
- #
298
- def focused?
299
- obj, type = find_element(visible = :all)
300
- object_not_found_exception(obj, type)
301
- focused_obj = page.driver.browser.switch_to.active_element
302
- focused_obj == obj.native
303
- end
304
-
305
- # Return a human readable representation of the UI element
306
- #
307
- # @return [String]
308
- # @example
309
- # buy_now_button.inspect
310
- #
311
- def inspect
312
- obj, type = find_element
313
- object_not_found_exception(obj, type)
314
- obj.inspect
315
- end
316
-
317
- # Wait until the object exists, or until the specified wait time has expired. If the wait time is nil, then the wait
318
- # time will be Capybara.default_max_wait_time.
319
- #
320
- # @param seconds [Integer or Float] wait time in seconds
321
- # @example
322
- # run_button.wait_until_exists(0.5)
323
- #
324
- def wait_until_exists(seconds = nil, post_exception = true)
325
- timeout = seconds.nil? ? Capybara.default_max_wait_time : seconds
326
- wait = Selenium::WebDriver::Wait.new(timeout: timeout)
327
- wait.until { exists? }
328
- rescue StandardError
329
- if post_exception
330
- raise "Could not find UI #{object_ref_message} after #{timeout} seconds" unless exists?
331
- else
332
- exists?
333
- end
334
- end
335
-
336
- # Wait until the object no longer exists, or until the specified wait time has expired. If the wait time is nil, then
337
- # the wait time will be Capybara.default_max_wait_time.
338
- #
339
- # @param seconds [Integer or Float] wait time in seconds
340
- # @example
341
- # logout_button.wait_until_gone(5)
342
- #
343
- def wait_until_gone(seconds = nil, post_exception = true)
344
- timeout = seconds.nil? ? Capybara.default_max_wait_time : seconds
345
- wait = Selenium::WebDriver::Wait.new(timeout: timeout)
346
- wait.until { !exists? }
347
- rescue StandardError
348
- if post_exception
349
- raise "UI #{object_ref_message} remained visible after #{timeout} seconds" if exists?
350
- else
351
- exists?
352
- end
353
- end
354
-
355
- # Wait until the object is visible, or until the specified wait time has expired. If the wait time is nil, then the
356
- # wait time will be Capybara.default_max_wait_time.
357
- #
358
- # @param seconds [Integer or Float] wait time in seconds
359
- # @example
360
- # run_button.wait_until_visible(0.5)
361
- #
362
- def wait_until_visible(seconds = nil, post_exception = true)
363
- timeout = seconds.nil? ? Capybara.default_max_wait_time : seconds
364
- wait = Selenium::WebDriver::Wait.new(timeout: timeout)
365
- wait.until { visible? }
366
- rescue StandardError
367
- if post_exception
368
- raise "Could not find UI #{object_ref_message} after #{timeout} seconds" unless visible?
369
- else
370
- visible?
371
- end
372
- end
373
-
374
- # Wait until the object is hidden, or until the specified wait time has expired. If the wait time is nil, then the
375
- # wait time will be Capybara.default_max_wait_time.
376
- #
377
- # @param seconds [Integer or Float] wait time in seconds
378
- # @example
379
- # run_button.wait_until_hidden(10)
380
- #
381
- def wait_until_hidden(seconds = nil, post_exception = true)
382
- timeout = seconds.nil? ? Capybara.default_max_wait_time : seconds
383
- wait = Selenium::WebDriver::Wait.new(timeout: timeout)
384
- wait.until { hidden? }
385
- rescue StandardError
386
- if post_exception
387
- raise "UI #{object_ref_message} remained visible after #{timeout} seconds" if visible?
388
- else
389
- visible?
390
- end
391
- end
392
-
393
- # Wait until the object is enabled, or until the specified wait time has expired. If the wait time is nil, then the
394
- # wait time will be Capybara.default_max_wait_time.
395
- #
396
- # @param seconds [Integer or Float] wait time in seconds
397
- # @example
398
- # run_button.wait_until_enabled(10)
399
- #
400
- def wait_until_enabled(seconds = nil, post_exception = true)
401
- timeout = seconds.nil? ? Capybara.default_max_wait_time : seconds
402
- wait = Selenium::WebDriver::Wait.new(timeout: timeout)
403
- wait.until { enabled? }
404
- rescue StandardError
405
- if post_exception
406
- raise "UI #{object_ref_message} remained disabled after #{timeout} seconds" unless enabled?
407
- else
408
- enabled?
409
- end
410
- end
411
-
412
- # Wait until the object is no longer in a busy state, or until the specified wait time has expired. If the wait time
413
- # is nil, then the wait time will be Capybara.default_max_wait_time.
414
- #
415
- # @param seconds [Integer or Float] wait time in seconds
416
- # @example
417
- # login_button.wait_while_busy(10)
418
- #
419
- def wait_while_busy(seconds = nil, post_exception = true)
420
- timeout = seconds.nil? ? Capybara.default_max_wait_time : seconds
421
- wait = Selenium::WebDriver::Wait.new(timeout: timeout)
422
- wait.until { aria_busy? }
423
- rescue StandardError
424
- if post_exception
425
- raise "UI #{object_ref_message} remained in busy state after #{timeout} seconds" if aria_busy?
426
- else
427
- aria_busy?
428
- end
429
- end
430
-
431
- # Wait until the object's value equals the specified value, or until the specified wait time has expired. If the wait
432
- # time is nil, then the wait time will be Capybara.default_max_wait_time.
433
- #
434
- # @param value [String or Hash] value expected or comparison hash
435
- # @param seconds [Integer or Float] wait time in seconds
436
- # @example
437
- # card_authorized_label.wait_until_value_is('Card authorized', 5)
438
- # or
439
- # total_weight_field.wait_until_value_is({ greater_than: '250' }, 5)
440
- #
441
- def wait_until_value_is(value, seconds = nil, post_exception = true)
442
- timeout = seconds.nil? ? Capybara.default_max_wait_time : seconds
443
- wait = Selenium::WebDriver::Wait.new(timeout: timeout)
444
- wait.until { compare(value, get_value) }
445
- rescue StandardError
446
- if post_exception
447
- raise "Value of UI #{object_ref_message} failed to equal '#{value}' after #{timeout} seconds" unless get_value == value
448
- else
449
- get_value == value
450
- end
451
- end
452
-
453
- # Wait until the object's value changes to a different value, or until the specified wait time has expired. If the
454
- # wait time is nil, then the wait time will be Capybara.default_max_wait_time.
455
- #
456
- # @param seconds [Integer or Float] wait time in seconds
457
- # @example
458
- # basket_grand_total_label.wait_until_value_changes(5)
459
- #
460
- def wait_until_value_changes(seconds = nil, post_exception = true)
461
- value = get_value
462
- timeout = seconds.nil? ? Capybara.default_max_wait_time : seconds
463
- wait = Selenium::WebDriver::Wait.new(timeout: timeout)
464
- wait.until { get_value != value }
465
- rescue StandardError
466
- if post_exception
467
- raise "Value of UI #{object_ref_message} failed to change from '#{value}' after #{timeout} seconds" if get_value == value
468
- else
469
- get_value == value
470
- end
471
- end
472
-
473
- # Return the number of occurrences of an object with an ambiguous locator that evaluates to multiple UI elements.
474
- #
475
- # @param visible [Boolean, Symbol] Only find elements with the specified visibility:
476
- # * true - only finds visible elements.
477
- # * false - finds invisible _and_ visible elements.
478
- # * :all - same as false; finds visible and invisible elements.
479
- # * :hidden - only finds invisible elements.
480
- # * :visible - same as true; only finds visible elements.
481
- # @example
482
- # num_uploads = upload_progress_bars.count(:all)
483
- #
484
- def count(visible = true)
485
- obj_locator = @alt_locator.nil? ? @locator : @alt_locator
486
- page.all(@locator_type, obj_locator, wait: 0.01, visible: visible, minimum: 0).count
487
- end
488
-
489
- # Return width of object.
490
- #
491
- # @return [Integer]
492
- # @example
493
- # button_width = my_button.width
494
- #
495
- def width
496
- obj, type = find_element(visible = false)
497
- object_not_found_exception(obj, type)
498
- obj.get_width
499
- end
500
-
501
- # Return height of object.
502
- #
503
- # @return [Integer]
504
- # @example
505
- # button_height = my_button.height
506
- #
507
- def height
508
- obj, type = find_element(visible = false)
509
- object_not_found_exception(obj, type)
510
- obj.get_height
511
- end
512
-
513
- # Return x coordinate of object's location.
514
- #
515
- # @return [Integer]
516
- # @example
517
- # button_x = my_button.x
518
- #
519
- def x
520
- obj, type = find_element(visible = false)
521
- object_not_found_exception(obj, type)
522
- obj.get_x
523
- end
524
-
525
- # Return y coordinate of object's location.
526
- #
527
- # @return [Integer]
528
- # @example
529
- # button_y = my_button.y
530
- #
531
- def y
532
- obj, type = find_element(visible = false)
533
- object_not_found_exception(obj, type)
534
- obj.get_y
535
- end
536
-
537
- # Return UI object's title property
538
- #
539
- # @return [String]
540
- # @example
541
- # buy_now_button.title
542
- #
543
- def title
544
- get_attribute(:title)
545
- end
546
-
547
- # Is UI object displayed in browser window?
548
- #
549
- # @return [Boolean]
550
- # @example
551
- # basket_link.displayed??
552
- #
553
- def displayed?
554
- obj, type = find_element(visible = false)
555
- object_not_found_exception(obj, type)
556
- obj.displayed?
557
- end
558
-
559
- def get_value(visible = true)
560
- obj, type = find_element(visible)
561
- object_not_found_exception(obj, type)
562
- text = case obj.tag_name.downcase
563
- when 'input', 'select', 'textarea'
564
- obj.value
565
- else
566
- obj.text
567
- end
568
- text.gsub(/[[:space:]]+/, ' ').strip unless text.nil?
569
- end
570
-
571
- alias get_caption get_value
572
- alias caption get_value
573
- alias value get_value
574
-
575
- def verify_value(expected, enqueue = false)
576
- actual = get_value
577
- enqueue ?
578
- ExceptionQueue.enqueue_assert_equal(expected.strip, actual.strip, "Expected UI #{object_ref_message}") :
579
- assert_equal(expected.strip, actual.strip, "Expected UI #{object_ref_message} to display '#{expected}' but found '#{actual}'")
580
- end
581
-
582
- alias verify_caption verify_value
583
-
584
- # Hover the cursor over an object
585
- #
586
- # @param visible [Boolean, Symbol] Only find elements with the specified visibility:
587
- # * true - only finds visible elements.
588
- # * false - finds invisible _and_ visible elements.
589
- # * :all - same as false; finds visible and invisible elements.
590
- # * :hidden - only finds invisible elements.
591
- # * :visible - same as true; only finds visible elements.
592
- # @example
593
- # basket_link.hover
594
- #
595
- def hover(visible = true)
596
- obj, type = find_element(visible)
597
- object_not_found_exception(obj, type)
598
- obj.hover
599
- end
600
-
601
- # Hover at a specific location within an object
602
- #
603
- # @param x [Integer] X offset
604
- # @param y [Integer] Y offset
605
- # @param visible [Boolean, Symbol] Only find elements with the specified visibility:
606
- # * true - only finds visible elements.
607
- # * false - finds invisible _and_ visible elements.
608
- # * :all - same as false; finds visible and invisible elements.
609
- # * :hidden - only finds invisible elements.
610
- # * :visible - same as true; only finds visible elements.
611
- # @example
612
- # timeline_bar.hover_at(100, 5)
613
- #
614
- def hover_at(x, y, visible = true)
615
- obj, = find_element(visible)
616
- raise "UI #{object_ref_message} not found" unless obj
617
- obj.hover_at(x, y)
618
- end
619
-
620
- def drag_by(right_offset, down_offset)
621
- obj, type = find_element
622
- object_not_found_exception(obj, type)
623
- page.driver.browser.action.click_and_hold(obj.native).perform
624
- sleep(1)
625
- obj.drag_by(right_offset, down_offset)
626
- end
627
-
628
- def drag_and_drop(target, right_offset = nil, down_offset = nil)
629
- source, type = find_element
630
- object_not_found_exception(source, type)
631
- page.driver.browser.action.click_and_hold(source.native).perform
632
- sleep(1)
633
- target_drop, = target.find_element
634
- page.driver.browser.action.move_to(target_drop.native, right_offset.to_i, down_offset.to_i).release.perform
635
- end
636
-
637
- # Highlight an object with a 3 pixel wide, red dashed border for the specified wait time.
638
- # If wait time is zero, then the highlight will remain until the page is refreshed
639
- #
640
- # @param duration [Integer or Float] wait time in seconds
641
- # @example
642
- # error_message.highlight(3)
643
- #
644
- def highlight(duration = 1)
645
- obj, type = find_element
646
- object_not_found_exception(obj, type)
647
- # store original style so it can be reset later
648
- @original_style = obj.native.attribute('style')
649
- # style element with red border
650
- page.execute_script(
651
- 'arguments[0].setAttribute(arguments[1], arguments[2])',
652
- obj,
653
- 'style',
654
- 'border: 3px solid red; border-style: dashed;'
655
- )
656
- # keep element highlighted for duration and then revert to original style
657
- if duration.positive?
658
- sleep duration
659
- page.execute_script(
660
- 'arguments[0].setAttribute(arguments[1], arguments[2])',
661
- obj,
662
- 'style',
663
- @original_style
664
- )
665
- end
666
- end
667
-
668
- # Restore a highlighted object's original style
669
- #
670
- # @example
671
- # store_link.unhighlight
672
- #
673
- def unhighlight
674
- obj, type = find_element
675
- object_not_found_exception(obj, type)
676
- return if @original_style.nil?
677
- page.execute_script(
678
- 'arguments[0].setAttribute(arguments[1], arguments[2])',
679
- obj,
680
- 'style',
681
- @original_style
682
- )
683
- end
684
-
685
- # Return UI object's style property
686
- #
687
- # @return [String]
688
- # @example
689
- # buy_now_button.style
690
- #
691
- def style
692
- get_attribute('style')
693
- end
694
-
695
- # Return state of UI object's role property
696
- #
697
- # @return [String]
698
- # @example
699
- # buy_now_button.role
700
- #
701
- def role
702
- get_attribute('role')
703
- end
704
-
705
- # Return state of UI object's tabindex property
706
- #
707
- # @return [String]
708
- # @example
709
- # buy_now_button.tabindex
710
- #
711
- def tabindex
712
- get_attribute('tabindex')
713
- end
714
-
715
- # Return state of UI object's aria-label property
716
- #
717
- # @return [String]
718
- # @example
719
- # buy_now_button.aria_label
720
- #
721
- def aria_label
722
- get_attribute('aria-label')
723
- end
724
-
725
- # Return state of UI object's aria-labelledby property
726
- #
727
- # @return [String]
728
- # @example
729
- # buy_now_button.aria_labelledby
730
- #
731
- def aria_labelledby
732
- get_attribute('aria-labelledby')
733
- end
734
-
735
- # Return state of UI object's aria-describedby property
736
- #
737
- # @return [String]
738
- # @example
739
- # buy_now_button.aria_describedby
740
- #
741
- def aria_describedby
742
- get_attribute('aria-describedby')
743
- end
744
-
745
- # Return state of UI object's aria-live property
746
- #
747
- # @return [String]
748
- # @example
749
- # properties_list.aria_live
750
- #
751
- def aria_live
752
- get_attribute('aria-live')
753
- end
754
-
755
- # Return state of UI object's aria-sort property
756
- #
757
- # @return [String]
758
- # @example
759
- # name_column.aria_sort
760
- #
761
- def aria_sort
762
- get_attribute('aria-sort')
763
- end
764
-
765
- # Return state of UI object's aria-rowcount property
766
- #
767
- # @return [Integer]
768
- # @example
769
- # user_grid.aria_rowcount
770
- #
771
- def aria_rowcount
772
- get_attribute('aria-rowcount')
773
- end
774
-
775
- # Return state of UI object's aria-colcount property
776
- #
777
- # @return [Integer]
778
- # @example
779
- # user_grid.aria_colcount
780
- #
781
- def aria_colcount
782
- get_attribute('aria-colcount')
783
- end
784
-
785
- # Return state of UI object's aria-valuemax property
786
- #
787
- # @return [Integer]
788
- # @example
789
- # volume_slider.aria_valuemax
790
- #
791
- def aria_valuemax
792
- get_attribute('aria-valuemax')
793
- end
794
-
795
- # Return state of UI object's aria-valuemin property
796
- #
797
- # @return [Integer]
798
- # @example
799
- # volume_slider.aria_valuemin
800
- #
801
- def aria_valuemin
802
- get_attribute('aria-valuemin')
803
- end
804
-
805
- # Return state of UI object's aria-valuenow property
806
- #
807
- # @return [Integer]
808
- # @example
809
- # volume_slider.aria_valuenow
810
- #
811
- def aria_valuenow
812
- get_attribute('aria-valuenow')
813
- end
814
-
815
- # Return state of UI object's aria-valuetext property
816
- #
817
- # @return [Integer]
818
- # @example
819
- # volume_slider.aria_valuetext
820
- #
821
- def aria_valuetext
822
- get_attribute('aria-valuetext')
823
- end
824
-
825
- # Return state of UI object's aria-orientation property
826
- #
827
- # @return [Integer]
828
- # @example
829
- # volume_slider.aria_orientation
830
- #
831
- def aria_orientation
832
- get_attribute('aria-orientation')
833
- end
834
-
835
- # Return state of UI object's aria-keyshortcuts property
836
- #
837
- # @return [Integer]
838
- # @example
839
- # play_button.aria_keyshortcuts
840
- #
841
- def aria_keyshortcuts
842
- get_attribute('aria-keyshortcuts')
843
- end
844
-
845
- # Return state of UI object's aria-roledescription property
846
- #
847
- # @return [Integer]
848
- # @example
849
- # editor_button.aria_roledescription
850
- #
851
- def aria_roledescription
852
- get_attribute('aria-roledescription')
853
- end
854
-
855
- # Return state of UI object's aria-autocomplete property
856
- #
857
- # @return [Integer]
858
- # @example
859
- # email_field.aria_autocomplete
860
- #
861
- def aria_autocomplete
862
- get_attribute('aria-autocomplete')
863
- end
864
-
865
- # Return state of UI object's aria-controls property
866
- #
867
- # @return [Integer]
868
- # @example
869
- # video_menu.aria_controls
870
- #
871
- def aria_controls
872
- get_attribute('aria-controls')
873
- end
874
-
875
- # Return state of UI object's aria-disabled property
876
- #
877
- # @return [Boolean]
878
- # @example
879
- # buy_now_button.aria_disabled?
880
- #
881
- def aria_disabled?
882
- state = get_attribute('aria-disabled')
883
- state.boolean? ? state : state == 'true'
884
- end
885
-
886
- # Return state of UI object's aria-selected property
887
- #
888
- # @return [Boolean]
889
- # @example
890
- # nutrition_info_tab.aria_selected?
891
- #
892
- def aria_selected?
893
- state = get_attribute('aria-selected')
894
- state.boolean? ? state : state == 'true'
895
- end
896
-
897
- # Return state of UI object's aria-hidden property
898
- #
899
- # @return [Boolean]
900
- # @example
901
- # nutrition_info_tab.aria_hidden?
902
- #
903
- def aria_hidden?
904
- state = get_attribute('aria-hidden')
905
- state.boolean? ? state : state == 'true'
906
- end
907
-
908
- # Return state of UI object's aria-expanded property
909
- #
910
- # @return [Boolean]
911
- # @example
912
- # catalog_tree.aria_expanded?
913
- #
914
- def aria_expanded?
915
- state = get_attribute('aria-expanded')
916
- state.boolean? ? state : state == 'true'
917
- end
918
-
919
- # Return state of UI object's aria-required property
920
- #
921
- # @return [Boolean]
922
- # @example
923
- # home_phone_field.aria_required?
924
- #
925
- def aria_required?
926
- state = get_attribute('aria-required')
927
- state.boolean? ? state : state == 'true'
928
- end
929
-
930
- # Return state of UI object's aria-invalid property
931
- #
932
- # @return [Boolean]
933
- # @example
934
- # home_phone_field.aria_invalid?
935
- #
936
- def aria_invalid?
937
- state = get_attribute('aria-invalid')
938
- state.boolean? ? state : state == 'true'
939
- end
940
-
941
- # Return state of UI object's aria-checked property
942
- #
943
- # @return [Boolean]
944
- # @example
945
- # allow_new_users_checkbox.aria_checked?
946
- #
947
- def aria_checked?
948
- state = get_attribute('aria-checked')
949
- state.boolean? ? state : state == 'true'
950
- end
951
-
952
- # Return state of UI object's aria-haspopup property
953
- #
954
- # @return [Boolean]
955
- # @example
956
- # user_avatar.aria_haspopup?
957
- #
958
- def aria_haspopup?
959
- state = get_attribute('aria-haspopup')
960
- state.boolean? ? state : state == 'true'
961
- end
962
-
963
- # Return state of UI object's aria-pressed property
964
- #
965
- # @return [Boolean]
966
- # @example
967
- # option1_button.aria_pressed?
968
- #
969
- def aria_pressed?
970
- state = get_attribute('aria-pressed')
971
- state.boolean? ? state : state == 'true'
972
- end
973
-
974
- # Return state of UI object's aria-readonly property
975
- #
976
- # @return [Boolean]
977
- # @example
978
- # home_phone_field.aria_readonly?
979
- #
980
- def aria_readonly?
981
- state = get_attribute('aria-readonly')
982
- state.boolean? ? state : state == 'true'
983
- end
984
-
985
- # Return state of UI object's aria-busy property
986
- #
987
- # @return [Boolean]
988
- # @example
989
- # home_phone_field.aria_busy?
990
- #
991
- def aria_busy?
992
- state = get_attribute('aria-busy')
993
- state.boolean? ? state : state == 'true'
994
- end
995
-
996
- # Return state of UI object's aria-modal property
997
- #
998
- # @return [Boolean]
999
- # @example
1000
- # add_user_modal.aria_modal?
1001
- #
1002
- def aria_modal?
1003
- state = get_attribute('aria-modal')
1004
- state.boolean? ? state : state == 'true'
1005
- end
1006
-
1007
- # Return state of UI object's aria-multiline property
1008
- #
1009
- # @return [Boolean]
1010
- # @example
1011
- # description_field.aria_multiline?
1012
- #
1013
- def aria_multiline?
1014
- state = get_attribute('aria-multiline')
1015
- state.boolean? ? state : state == 'true'
1016
- end
1017
-
1018
- # Return state of UI object's aria-multiselectable property
1019
- #
1020
- # @return [Boolean]
1021
- # @example
1022
- # channels_select.aria_multiselectable?
1023
- #
1024
- def aria_multiselectable?
1025
- state = get_attribute('aria-multiselectable')
1026
- state.boolean? ? state : state == 'true'
1027
- end
1028
-
1029
- # Return state of UI object's contenteditable property
1030
- #
1031
- # @return [Boolean]
1032
- # @example
1033
- # description_field.content_editable?
1034
- #
1035
- def content_editable?
1036
- state = get_attribute('contenteditable')
1037
- state.boolean? ? state : state == 'true'
1038
- end
1039
-
1040
- # Return crossorigin property
1041
- #
1042
- # @return crossorigin value
1043
- # @example
1044
- # with_creds = media_player.crossorigin == 'use-credentials'
1045
- #
1046
- def crossorigin
1047
- obj, = find_element
1048
- object_not_found_exception(obj, @type)
1049
- obj.native.attribute('crossorigin')
1050
- end
1051
-
1052
- def get_attribute(attrib)
1053
- obj, type = find_element(visible = false)
1054
- object_not_found_exception(obj, type)
1055
- obj[attrib]
1056
- end
1057
-
1058
- def get_native_attribute(attrib)
1059
- obj, type = find_element(visible = false)
1060
- object_not_found_exception(obj, type)
1061
- obj.native.attribute(attrib)
1062
- end
1063
-
1064
- def find_element(visible = true)
1065
- wait = Selenium::WebDriver::Wait.new(timeout: Capybara.default_max_wait_time)
1066
- wait.until { find_object(visible) }
1067
- end
1068
-
1069
- private
1070
-
1071
- def find_object(visible = true)
1072
- obj_locator = @alt_locator.nil? ? @locator : @alt_locator
1073
- parent_section = @context == :section && !@parent.get_locator.nil?
1074
- tries ||= parent_section ? 2 : 1
1075
- if parent_section && tries == 2
1076
- parent_locator = @parent.get_locator
1077
- parent_locator = parent_locator.tr('|', ' ')
1078
- parent_locator_type = @parent.get_locator_type
1079
- obj = page.find(parent_locator_type, parent_locator, visible: :all, wait: 0.01).find(@locator_type, obj_locator, wait: 0.01, visible: visible)
1080
- else
1081
- obj = page.find(@locator_type, obj_locator, wait: 0.01, visible: visible)
1082
- end
1083
- [obj, @locator_type]
1084
- rescue StandardError
1085
- retry if (tries -= 1).positive?
1086
- [nil, nil]
1087
- end
1088
-
1089
- def object_not_found_exception(obj, obj_type)
1090
- locator = @alt_locator.nil? ? @locator : @alt_locator
1091
- object_type = obj_type.nil? ? 'Object' : obj_type
1092
- raise ObjectNotFoundError, "#{object_type} named '#{@name}' (#{locator}) not found" unless obj
1093
- end
1094
-
1095
- def invalid_object_type_exception(obj, obj_type)
1096
- unless obj.tag_name == obj_type || obj.native.attribute('type') == obj_type
1097
- locator = @alt_locator.nil? ? @locator : @alt_locator
1098
- raise "#{locator} is not a #{obj_type} element"
1099
- end
1100
- end
1101
-
1102
- def object_ref_message
1103
- "object '#{get_name}' (#{get_locator})"
1104
- end
1105
-
1106
- def compare(expected, actual)
1107
- if expected.is_a?(Hash) && expected.length == 1
1108
- expected.each do |key, value|
1109
- case key
1110
- when :lt, :less_than
1111
- actual < value
1112
- when :lt_eq, :less_than_or_equal
1113
- actual <= value
1114
- when :gt, :greater_than
1115
- actual > value
1116
- when :gt_eq, :greater_than_or_equal
1117
- actual >= value
1118
- when :starts_with
1119
- actual.start_with?(value)
1120
- when :ends_with
1121
- actual.end_with?(value)
1122
- when :contains
1123
- actual.include?(value)
1124
- when :not_contains, :does_not_contain
1125
- !actual.include?(value)
1126
- when :not_equal
1127
- actual != value
1128
- end
1129
- end
1130
- else
1131
- expected == actual
1132
- end
1133
- end
1134
-
1135
- def find_component(component, component_name)
1136
- begin
1137
- element = @base_object.find(:css, component, visible: :all, minimum: 0, wait: 1)
1138
- rescue
1139
- begin
1140
- element = page.find(:css, component, visible: :all, minimum: 0, wait: 2)
1141
- rescue
1142
- raise "Component #{component_name} (#{component}) for #{@type} named '#{@name}' (#{locator}) not found"
1143
- end
1144
- end
1145
- element
1146
- end
1147
- end
1148
- end