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.
@@ -0,0 +1,607 @@
1
+ require 'test/unit'
2
+
3
+ module TestCentricity
4
+ class ScreenSection < BaseScreenSectionObject
5
+ include Test::Unit::Assertions
6
+
7
+ attr_reader :context, :name
8
+ attr_accessor :locator
9
+ attr_accessor :parent
10
+ attr_accessor :parent_list
11
+ attr_accessor :list_index
12
+
13
+ def initialize(name, parent, locator, context)
14
+ @name = name
15
+ @parent = parent
16
+ @locator = locator
17
+ @context = context
18
+ @parent_list = nil
19
+ @list_index = nil
20
+ end
21
+
22
+ def get_locator
23
+ if @locator.zero? && defined?(section_locator)
24
+ my_locator = section_locator
25
+ else
26
+ my_locator = @locator
27
+ end
28
+ locators = []
29
+ if @context == :section && !@parent.nil?
30
+ locators.push(@parent.get_locator)
31
+ end
32
+
33
+ if @parent_list.nil?
34
+ locators.push(my_locator)
35
+ else
36
+ locators.push(@parent_list.get_locator)
37
+ if @list_index.nil?
38
+ locators.push(my_locator)
39
+ else
40
+ item_objects = @parent_list.item_refs
41
+ if item_objects.nil?
42
+ list_key = my_locator.keys[0]
43
+ list_value = "#{my_locator.values[0]}[#{@list_index}]"
44
+ else
45
+ list_key = :object
46
+ list_value = item_objects[@list_index - 1]
47
+ end
48
+ locators.push( { list_key => list_value } )
49
+ end
50
+ end
51
+ locators
52
+ end
53
+
54
+ def set_list_index(list, index = 1)
55
+ @parent_list = list unless list.nil?
56
+ @list_index = index
57
+ end
58
+
59
+ def get_item_count
60
+ raise 'No parent list defined' if @parent_list.nil?
61
+ @parent_list.get_item_count
62
+ end
63
+
64
+ def get_list_items
65
+ items = []
66
+ (1..get_item_count).each do |item|
67
+ set_list_index(nil, item)
68
+ begin
69
+ items.push(get_value)
70
+ rescue
71
+ scroll_into_view(@parent_list.scroll_mode)
72
+ items.push(get_value)
73
+ end
74
+ end
75
+ items
76
+ end
77
+
78
+ def get_object_type
79
+ :section
80
+ end
81
+
82
+ def get_name
83
+ @name
84
+ end
85
+
86
+ def set_parent(parent)
87
+ @parent = parent
88
+ end
89
+
90
+ # Declare and instantiate a single generic UI Element for this screen section object.
91
+ #
92
+ # @param element_name [Symbol] name of UI object (as a symbol)
93
+ # @param locator [Hash] { locator_strategy: locator_identifier }
94
+ # The locator_strategy (a Symbol) specifies the selector strategy that Appium will use to find the UI element. Valid
95
+ # selectors are accessibility_id:, id:, name:, class:, xpath:, predicate: (iOS only), class_chain: (iOS only), and
96
+ # css: (WebViews in hybrid apps only).
97
+ # * The locator_identifier (a String) is the value or attribute that uniquely and unambiguously identifies the UI element.
98
+ #
99
+ # @example
100
+ # element :video_player, { accessibility_id: 'YouTube Video Player' }
101
+ #
102
+ def self.element(element_name, locator)
103
+ define_section_element(element_name, TestCentricity::AppElements::AppUIElement, locator)
104
+ end
105
+
106
+ # Declare and instantiate a collection of generic UI Elements for this screen section object.
107
+ #
108
+ # @param element_hash [Hash] names of UI objects (as a Symbol) and locator Hash
109
+ # @example
110
+ # elements drop_down_field: { accessibility_id: 'drop_trigger' },
111
+ # settings_item: { accessibility_id: 'settings' },
112
+ # log_out_item: { accessibility_id: 'logout' }
113
+ #
114
+ def self.elements(element_hash)
115
+ element_hash.each_pair { |element_name, locator| element(element_name, locator) }
116
+ end
117
+
118
+ # Declare and instantiate a single button UI Element for this screen section object.
119
+ #
120
+ # @param element_name [Symbol] name of button object (as a symbol)
121
+ # @param locator [Hash] { locator_strategy: locator_identifier }
122
+ # @example
123
+ # button :video_play, { accessibility_id: 'video icon play' }
124
+ #
125
+ def self.button(element_name, locator)
126
+ define_section_element(element_name, TestCentricity::AppElements::AppButton, locator)
127
+ end
128
+
129
+ # Declare and instantiate a collection of buttons for this screen section object.
130
+ #
131
+ # @param element_hash [Hash] names of buttons (as symbol) and locator Hash
132
+ # @example
133
+ # buttons video_back: { accessibility_id: 'video icon backward' },
134
+ # video_play: { accessibility_id: 'video icon play' },
135
+ # video_pause: { accessibility_id: 'video icon stop' },
136
+ # video_forward: { accessibility_id: 'video icon forward' }
137
+ #
138
+ def self.buttons(element_hash)
139
+ element_hash.each_pair { |element_name, locator| button(element_name, locator) }
140
+ end
141
+
142
+ # Declare and instantiate a single textfield UI Element for this screen section object.
143
+ #
144
+ # @param element_name [Symbol] name of textfield object (as a symbol)
145
+ # @param locator [Hash] { locator_strategy: locator_identifier }
146
+ # @example
147
+ # textfield :payee_name_field, { xpath: '//android.widget.EditText[@content-desc="Full Name* input field"]' }
148
+ # textfield :payee_name_field, { xpath: '//XCUIElementTypeTextField[@name="Full Name* input field"]' }
149
+ #
150
+ def self.textfield(element_name, locator)
151
+ define_section_element(element_name, TestCentricity::AppElements::AppTextField, locator)
152
+ end
153
+
154
+ # Declare and instantiate a collection of textfields for this screen section object.
155
+ #
156
+ # @param element_hash [Hash] names of textfields (as symbol) and locator Hash
157
+ # @example
158
+ # textfields username_field: { accessibility_id: 'Username input field' },
159
+ # password_field: { accessibility_id: 'Password input field' }
160
+ #
161
+ def self.textfields(element_hash)
162
+ element_hash.each_pair { |element_name, locator| textfield(element_name, locator) }
163
+ end
164
+
165
+ # Declare and instantiate a single switch UI Element for this screen section object.
166
+ #
167
+ # @param element_name [Symbol] name of switch object (as a symbol)
168
+ # @param locator [Hash] { locator_strategy: locator_identifier }
169
+ # @example
170
+ # switch :debug_mode_switch, { accessibility_id: 'debug mode' }
171
+ #
172
+ def self.switch(element_name, locator)
173
+ define_section_element(element_name, TestCentricity::AppElements::AppSwitch, locator)
174
+ end
175
+
176
+ # Declare and instantiate a collection of switches for this screen section object.
177
+ #
178
+ # @param element_hash [Hash] names of switches (as symbol) and locator Hash
179
+ # @example
180
+ # switches debug_mode_switch: { accessibility_id: 'debug mode' },
181
+ # metrics_switch: { accessibility_id: 'metrics' }
182
+ #
183
+ def self.switches(element_hash)
184
+ element_hash.each_pair { |element_name, locator| switch(element_name, locator) }
185
+ end
186
+
187
+ # Declare and instantiate a single checkbox UI Element for this screen section object.
188
+ #
189
+ # @param element_name [Symbol] name of checkbox object (as a symbol)
190
+ # @param locator [Hash] { locator_strategy: locator_identifier }
191
+ # @example
192
+ # checkbox :bill_address_check, { xpath: '//XCUIElementTypeOther[contains(@name, "billing checkbox")]'}
193
+ #
194
+ def self.checkbox(element_name, locator)
195
+ define_section_element(element_name, TestCentricity::AppElements::AppCheckBox, locator)
196
+ end
197
+
198
+ # Declare and instantiate a collection of checkboxes for this screen section object.
199
+ #
200
+ # @param element_hash [Hash] names of checkboxes (as symbol) and locator Hash
201
+ # @example
202
+ # checkboxes bill_address_check: { xpath: '//XCUIElementTypeOther[contains(@name, "billing checkbox")]'},
203
+ # is_gift_check: { accessibility_id: 'is a gift' }
204
+ #
205
+ def self.checkboxes(element_hash)
206
+ element_hash.each_pair { |element_name, locator| checkbox(element_name, locator) }
207
+ end
208
+
209
+ # Declare and instantiate a single label UI Element for this screen section object.
210
+ #
211
+ # @param element_name [Symbol] name of label object (as a symbol)
212
+ # @param locator [Hash] { locator_strategy: locator_identifier }
213
+ # @example
214
+ # label :header_label, { accessibility_id: 'container header' }
215
+ #
216
+ def self.label(element_name, locator)
217
+ define_section_element(element_name, TestCentricity::AppElements::AppLabel, locator)
218
+ end
219
+
220
+ # Declare and instantiate a collection of labels for this screen section object.
221
+ #
222
+ # @param element_hash [Hash] names of labels (as symbol) and locator Hash
223
+ # @example
224
+ # labels total_qty_value: { accessibility_id: 'total number' },
225
+ # total_price_value: { accessibility_id: 'total price' }
226
+ #
227
+ def self.labels(element_hash)
228
+ element_hash.each_pair { |element_name, locator| label(element_name, locator) }
229
+ end
230
+
231
+ # Declare and instantiate a single list UI Element for this screen section object.
232
+ #
233
+ # @param element_name [Symbol] name of list object (as a symbol)
234
+ # @param locator [Hash] { locator_strategy: locator_identifier }
235
+ # @example
236
+ # list :carousel_list, { accessibility_id: 'Carousel' }
237
+ #
238
+ def self.list(element_name, locator)
239
+ define_section_element(element_name, TestCentricity::AppElements::AppList, locator)
240
+ end
241
+
242
+ # Declare and instantiate a collection of lists for this screen section object.
243
+ #
244
+ # @param element_hash [Hash] names of lists (as symbol) and locator Hash
245
+ # @example
246
+ # lists product_grid: { xpath: '//android.widget.ScrollView/android.view.ViewGroup' },
247
+ # cart_list: { xpath: '//android.widget.ScrollView[@content-desc="cart screen"]' }
248
+ #
249
+ def self.lists(element_hash)
250
+ element_hash.each_pair { |element_name, locator| list(element_name, locator) }
251
+ end
252
+
253
+ # Declare and instantiate a single image UI Element for this screen section object.
254
+ #
255
+ # @param element_name [Symbol] name of image object (as a symbol)
256
+ # @param locator [Hash] { locator_strategy: locator_identifier }
257
+ # @example
258
+ # image :product_image, { xpath: '//XCUIElementTypeImage' }
259
+ #
260
+ def self.image(element_name, locator)
261
+ define_section_element(element_name, TestCentricity::AppElements::AppImage, locator)
262
+ end
263
+
264
+ # Declare and instantiate a collection of images for this screen section object.
265
+ #
266
+ # @param element_hash [Hash] names of images (as symbol) and locator Hash
267
+ # @example
268
+ # images empty_cart_image: { accessibility_id: 'empty_cart' },
269
+ # logo_image: { accessibility_id: 'WebdriverIO logo' }
270
+ #
271
+ def self.images(element_hash)
272
+ element_hash.each_pair { |element_name, locator| image(element_name, locator) }
273
+ end
274
+
275
+ # Instantiate a single ScreenSection object within this ScreenSection object.
276
+ #
277
+ # @param section_name [Symbol] name of ScreenSection object (as a symbol)
278
+ # @param class_name [Class] Class name of ScreenSection object
279
+ # @example
280
+ # section :nav_menu, NavMenu
281
+ #
282
+ def self.section(section_name, obj, locator = 0)
283
+ define_section_element(section_name, obj, locator)
284
+ end
285
+
286
+ # Declare and instantiate a collection of ScreenSection objects for this ScreenSection object.
287
+ #
288
+ # @param element_hash [Hash] names of ScreenSections (as symbol) and class name
289
+ # @example
290
+ # sections product_grid_item: ProductGridItem,
291
+ # sort_by_menu: SortByMenu
292
+ #
293
+ def self.sections(section_hash)
294
+ section_hash.each_pair { |section_name, class_name| section(section_name, class_name) }
295
+ end
296
+
297
+ # Click on a screen Section object
298
+ #
299
+ # @example
300
+ # bar_chart_section.click
301
+ #
302
+ def click
303
+ section = find_section
304
+ section_not_found_exception(section)
305
+ section.click
306
+ end
307
+
308
+ # Tap on a screen Section object
309
+ #
310
+ # @example
311
+ # bar_chart_section.tap
312
+ #
313
+ def tap
314
+ section = find_section
315
+ section_not_found_exception(section)
316
+ driver.action
317
+ .click_and_hold(section)
318
+ .release
319
+ .perform
320
+ end
321
+
322
+ # Double-tap on a screen Section object
323
+ #
324
+ # @example
325
+ # bar_chart_section.double_tap
326
+ #
327
+ def double_tap
328
+ section = find_section
329
+ section_not_found_exception(section)
330
+ driver.action
331
+ .click_and_hold(section)
332
+ .release
333
+ .pause(duration: 0.2)
334
+ .click_and_hold(section)
335
+ .release
336
+ .perform
337
+ end
338
+
339
+ # Long press on a screen Section object
340
+ #
341
+ # @param duration [Float] duration of long press in seconds
342
+ # @example
343
+ # header_image.long_press(1.5)
344
+ #
345
+ def long_press(duration = 1)
346
+ section = find_section
347
+ section_not_found_exception(section)
348
+ driver.action
349
+ .click_and_hold(section)
350
+ .pause(duration: duration)
351
+ .release
352
+ .perform
353
+ end
354
+
355
+ # Scroll the screen Section object until it is visible. If scroll_mode is not specified, then vertical scrolling will
356
+ # be used.
357
+ #
358
+ # @param scroll_mode [Symbol] :vertical (default) or :horizontal
359
+ # @example
360
+ # carousel_item.scroll_into_view(scroll_mode = :horizontal)
361
+ #
362
+ def scroll_into_view(scroll_mode = :vertical)
363
+ return if visible?
364
+ obj = element
365
+ object_not_found_exception(obj)
366
+ driver.action.move_to(obj).perform
367
+ case scroll_mode
368
+ when :vertical
369
+ start_direction = :down
370
+ end_direction = :up
371
+ when :horizontal
372
+ start_direction = :right
373
+ end_direction = :left
374
+ else
375
+ raise "#{scroll_mode} is not a valid selector"
376
+ end
377
+ try_count = 8
378
+ direction = start_direction
379
+ while hidden?
380
+ swipe_gesture(direction, distance = 0.2)
381
+ try_count -= 1
382
+ if try_count.zero?
383
+ if direction == end_direction
384
+ break
385
+ else
386
+ direction = end_direction
387
+ try_count = 8
388
+ end
389
+ end
390
+ end
391
+ end
392
+
393
+ # Does screen Section object exists?
394
+ #
395
+ # @return [Boolean]
396
+ # @example
397
+ # navigation_toolbar.exists?
398
+ #
399
+ def exists?
400
+ section = find_section
401
+ section != nil
402
+ end
403
+
404
+ # Is screen Section object enabled?
405
+ #
406
+ # @return [Boolean]
407
+ # @example
408
+ # bar_chart_section.enabled?
409
+ #
410
+ def enabled?
411
+ section = find_section
412
+ section_not_found_exception(section)
413
+ section.enabled?
414
+ end
415
+
416
+ # Is screen Section object disabled (not enabled)?
417
+ #
418
+ # @return [Boolean]
419
+ # @example
420
+ # bar_chart_section.disabled?
421
+ #
422
+ def disabled?
423
+ section = find_section
424
+ section_not_found_exception(section)
425
+ section.enabled?
426
+ end
427
+
428
+ # Is screen Section object visible?
429
+ #
430
+ # @return [Boolean]
431
+ # @example
432
+ # navigation_toolbar.visible?
433
+ #
434
+ def visible?
435
+ section = find_section
436
+ return false if section.nil?
437
+
438
+ section.displayed?
439
+ end
440
+
441
+ # Is screen Section object hidden (not visible)?
442
+ #
443
+ # @return [Boolean]
444
+ # @example
445
+ # navigation_toolbar.hidden?
446
+ #
447
+ def hidden?
448
+ !visible?
449
+ end
450
+
451
+ # Wait until the screen Section object exists, or until the specified wait time has expired. If the wait time is nil,
452
+ # then the wait time will be Environ.default_max_wait_time.
453
+ #
454
+ # @param seconds [Integer or Float] wait time in seconds
455
+ # @example
456
+ # navigation_toolbar.wait_until_exists(1.5)
457
+ #
458
+ def wait_until_exists(seconds = nil, post_exception = true)
459
+ timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
460
+ wait = Selenium::WebDriver::Wait.new(timeout: timeout)
461
+ wait.until { exists? }
462
+ rescue
463
+ if post_exception
464
+ raise "Could not find Section object '#{get_name}' (#{get_locator}) after #{timeout} seconds" unless exists?
465
+ else
466
+ exists?
467
+ end
468
+ end
469
+
470
+ # Wait until the screen Section object no longer exists, or until the specified wait time has expired. If the wait
471
+ # time is nil, then the wait time will be Environ.default_max_wait_time.
472
+ #
473
+ # @param seconds [Integer or Float] wait time in seconds
474
+ # @example
475
+ # navigation_toolbar.wait_until_gone(5)
476
+ #
477
+ def wait_until_gone(seconds = nil, post_exception = true)
478
+ timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
479
+ wait = Selenium::WebDriver::Wait.new(timeout: timeout)
480
+ wait.until { !exists? }
481
+ rescue
482
+ if post_exception
483
+ raise "Section object '#{get_name}' (#{get_locator}) remained visible after #{timeout} seconds" if exists?
484
+ else
485
+ exists?
486
+ end
487
+ end
488
+
489
+ # Wait until the screen Section object is visible, or until the specified wait time has expired. If the wait time is nil,
490
+ # then the wait time will be Environ.default_max_wait_time.
491
+ #
492
+ # @param seconds [Integer or Float] wait time in seconds
493
+ # @example
494
+ # navigation_toolbar.wait_until_visible(1.5)
495
+ #
496
+ def wait_until_visible(seconds = nil, post_exception = true)
497
+ timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
498
+ wait = Selenium::WebDriver::Wait.new(timeout: timeout)
499
+ wait.until { visible? }
500
+ rescue
501
+ if post_exception
502
+ raise "Could not find Section object '#{get_name}' (#{get_locator}) after #{timeout} seconds" unless visible?
503
+ else
504
+ visible?
505
+ end
506
+ end
507
+
508
+ # Wait until the screen Section object is hidden, or until the specified wait time has expired. If the wait time is nil,
509
+ # then the wait time will be Environ.default_max_wait_time.
510
+ #
511
+ # @param seconds [Integer or Float] wait time in seconds
512
+ # @example
513
+ # navigation_toolbar.wait_until_hidden(2)
514
+ #
515
+ def wait_until_hidden(seconds = nil, post_exception = true)
516
+ timeout = seconds.nil? ? Environ.default_max_wait_time : seconds
517
+ wait = Selenium::WebDriver::Wait.new(timeout: timeout)
518
+ wait.until { hidden? }
519
+ rescue
520
+ if post_exception
521
+ raise "Section object '#{get_name}' (#{get_locator}) remained visible after #{timeout} seconds" if visible?
522
+ else
523
+ visible?
524
+ end
525
+ end
526
+
527
+ # Return width of screen Section object.
528
+ #
529
+ # @return [Integer]
530
+ # @example
531
+ # button_width = my_button.width
532
+ #
533
+ def width
534
+ section = find_section
535
+ section_not_found_exception(section)
536
+ section.size.width
537
+ end
538
+
539
+ # Return height of screen Section object.
540
+ #
541
+ # @return [Integer]
542
+ # @example
543
+ # button_height = my_button.height
544
+ #
545
+ def height
546
+ section = find_section
547
+ section_not_found_exception(section)
548
+ section.size.height
549
+ end
550
+
551
+ # Return x coordinate of screen Section object's location.
552
+ #
553
+ # @return [Integer]
554
+ # @example
555
+ # button_x = my_button.x_loc
556
+ #
557
+ def x_loc
558
+ section = find_section
559
+ section_not_found_exception(section)
560
+ section.location.x
561
+ end
562
+
563
+ # Return y coordinate of screen Section object's location.
564
+ #
565
+ # @return [Integer]
566
+ # @example
567
+ # button_x = my_button.x_loc
568
+ #
569
+ def y_loc
570
+ section = find_section
571
+ section_not_found_exception(section)
572
+ section.location.y
573
+ end
574
+
575
+ private
576
+
577
+ def find_section
578
+ obj = nil
579
+ locators = get_locator
580
+ locators.each do |loc|
581
+ if obj.nil?
582
+ obj = find_element(loc.keys[0], loc.values[0])
583
+ puts "Found object #{loc}" if ENV['DEBUG']
584
+ else
585
+ obj = obj.find_element(loc.keys[0], loc.values[0])
586
+ puts "Found object #{loc}" if ENV['DEBUG']
587
+ end
588
+ end
589
+ obj
590
+ rescue
591
+ nil
592
+ end
593
+
594
+ def section_not_found_exception(obj)
595
+ raise ObjectNotFoundError.new("Section object '#{get_name}' (#{get_locator}) not found") unless obj
596
+ end
597
+
598
+ def self.define_section_element(element_name, obj, locator)
599
+ define_method(element_name) do
600
+ ivar_name = "@#{element_name}"
601
+ ivar = instance_variable_get(ivar_name)
602
+ return ivar if ivar
603
+ instance_variable_set(ivar_name, obj.new(element_name, self, locator, :section))
604
+ end
605
+ end
606
+ end
607
+ end