haya_select_helpers 0.0.11 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/haya_select.rb +144 -52
- data/lib/haya_select_helpers/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7f84d8a6672eb46f35aa0949b1b1bbbf702e7fca854541d7fcb7e2152d890caa
|
|
4
|
+
data.tar.gz: e5e2e100bc9e5697c4cd93c0d747026d94d249cbc1793ee4e7e4967be6ac19eb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6ed9d67b118f6ec2ffa66789a44b258f542a2e331e3401b9b5ccd6263d26dacd4be1b8ef3d7fcad2bc6c5ddc0a6e8444a0c7c6ea98542bbdb287f4b243184469
|
|
7
|
+
data.tar.gz: 9751a4a39bb5304733df0a7e783a67adb6182bb7e63f486308b96ec7b6b63df86c5268d136eca26058e69228ac70c9eadb0bafebfa9a62b12b17cea368d8f0d5
|
data/lib/haya_select.rb
CHANGED
|
@@ -37,7 +37,7 @@ class HayaSelect
|
|
|
37
37
|
attempts = 0
|
|
38
38
|
|
|
39
39
|
begin
|
|
40
|
-
|
|
40
|
+
click_open_target_element
|
|
41
41
|
wait_for_open
|
|
42
42
|
self
|
|
43
43
|
rescue WaitUtil::TimeoutError, Selenium::WebDriver::Error::StaleElementReferenceError
|
|
@@ -75,7 +75,9 @@ class HayaSelect
|
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
def search(value)
|
|
78
|
-
wait_for_and_find("#{base_selector} [data-class='search-text-input']")
|
|
78
|
+
search_input = wait_for_and_find("#{base_selector} [data-class='search-text-input']")
|
|
79
|
+
search_input.set("")
|
|
80
|
+
search_input.send_keys(value)
|
|
79
81
|
self
|
|
80
82
|
rescue Selenium::WebDriver::Error::StaleElementReferenceError
|
|
81
83
|
retry
|
|
@@ -90,8 +92,8 @@ class HayaSelect
|
|
|
90
92
|
selected_value = select_option_value(label:, value:)
|
|
91
93
|
selected_value = "" if selected_value.nil? && value.nil?
|
|
92
94
|
allow_blank = previous_value == selected_value
|
|
93
|
-
wait_for_selected_value_or_label(label, value || selected_value, allow_blank:)
|
|
94
95
|
close_if_open
|
|
96
|
+
wait_for_selected_value_or_label(label, value || selected_value, allow_blank:)
|
|
95
97
|
self
|
|
96
98
|
rescue WaitUtil::TimeoutError, Selenium::WebDriver::Error::StaleElementReferenceError
|
|
97
99
|
attempts += 1
|
|
@@ -117,15 +119,8 @@ class HayaSelect
|
|
|
117
119
|
raise "The '#{label}'-option is disabled" if option['data-disabled'] == 'true'
|
|
118
120
|
|
|
119
121
|
option_value = option['data-value']
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
else
|
|
123
|
-
scope.page.execute_script(
|
|
124
|
-
"arguments[0].scrollIntoView({block: 'center', inline: 'center'})",
|
|
125
|
-
option
|
|
126
|
-
)
|
|
127
|
-
scope.page.execute_script("arguments[0].click()", option)
|
|
128
|
-
end
|
|
122
|
+
perform_option_selection(option, label, option_value)
|
|
123
|
+
|
|
129
124
|
option_value
|
|
130
125
|
rescue Selenium::WebDriver::Error::StaleElementReferenceError
|
|
131
126
|
retry
|
|
@@ -201,14 +196,21 @@ private
|
|
|
201
196
|
|
|
202
197
|
return if option_present?(selector, label)
|
|
203
198
|
|
|
204
|
-
|
|
199
|
+
if scope.page.has_selector?(options_selector, visible: :all)
|
|
205
200
|
wait_for_browser do
|
|
206
|
-
|
|
201
|
+
scope.page.has_selector?("#{options_selector} [data-class='select-option']", visible: :all) ||
|
|
202
|
+
scope.page.has_selector?(no_options_selector, visible: :all)
|
|
207
203
|
end
|
|
204
|
+
end
|
|
208
205
|
|
|
209
|
-
|
|
206
|
+
wait_for_browser do
|
|
207
|
+
option_present?(selector, label)
|
|
210
208
|
end
|
|
211
209
|
|
|
210
|
+
return if option_present?(selector, label)
|
|
211
|
+
|
|
212
|
+
return unless scope.page.has_selector?(search_input_selector)
|
|
213
|
+
|
|
212
214
|
search_terms_for(label).each do |search_term|
|
|
213
215
|
current_options_text = options_container_text
|
|
214
216
|
search_for_option(search_term)
|
|
@@ -228,11 +230,20 @@ private
|
|
|
228
230
|
|
|
229
231
|
def wait_for_selected_value_or_label(label, value, allow_blank: false)
|
|
230
232
|
wait_for_expect do
|
|
233
|
+
value_input_selector = "#{base_selector} [data-class='current-selected'] input[type='hidden']"
|
|
234
|
+
has_value_input = scope.page.has_selector?(value_input_selector, visible: false)
|
|
231
235
|
label_matches = label && label_matches?(label)
|
|
232
236
|
value_matches = value && scope.page.has_selector?(current_value_selector(value), visible: false)
|
|
233
237
|
blank_matches = allow_blank && scope.page.has_selector?(current_value_selector(""), visible: false)
|
|
234
238
|
|
|
235
|
-
|
|
239
|
+
matches =
|
|
240
|
+
if has_value_input
|
|
241
|
+
value_matches || blank_matches
|
|
242
|
+
else
|
|
243
|
+
label_matches || value_matches || blank_matches
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
expect(matches).to eq true
|
|
236
247
|
end
|
|
237
248
|
end
|
|
238
249
|
|
|
@@ -280,26 +291,36 @@ private
|
|
|
280
291
|
end
|
|
281
292
|
|
|
282
293
|
def close_if_open
|
|
283
|
-
return if scope.page.has_no_selector?(options_selector)
|
|
294
|
+
return if scope.page.has_no_selector?(options_selector, visible: :all)
|
|
284
295
|
|
|
285
296
|
close_attempts = 0
|
|
286
297
|
|
|
287
|
-
while scope.page.has_selector?(options_selector) && close_attempts < 3
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
else
|
|
291
|
-
wait_for_and_find("body").click
|
|
292
|
-
end
|
|
298
|
+
while scope.page.has_selector?(options_selector, visible: :all) && close_attempts < 3
|
|
299
|
+
close_attempt
|
|
300
|
+
break if wait_for_close?
|
|
293
301
|
|
|
294
302
|
close_attempts += 1
|
|
295
303
|
end
|
|
304
|
+
|
|
305
|
+
return if scope.page.has_no_selector?(options_selector, visible: :all)
|
|
306
|
+
|
|
307
|
+
body = wait_for_and_find("body")
|
|
308
|
+
body.send_keys(:escape)
|
|
309
|
+
return if wait_for_close?
|
|
310
|
+
|
|
311
|
+
click_element_safely(body)
|
|
312
|
+
wait_for_close?
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def wait_for_close?
|
|
316
|
+
scope.page.has_no_selector?(options_selector, visible: :all, wait: 1)
|
|
296
317
|
end
|
|
297
318
|
|
|
298
319
|
def search_input_selector
|
|
299
320
|
"#{base_selector} [data-class='search-text-input']"
|
|
300
321
|
end
|
|
301
322
|
|
|
302
|
-
def
|
|
323
|
+
def click_open_target_element
|
|
303
324
|
target_selector =
|
|
304
325
|
if scope.page.has_selector?(select_container_selector)
|
|
305
326
|
select_container_selector
|
|
@@ -310,16 +331,11 @@ private
|
|
|
310
331
|
end
|
|
311
332
|
|
|
312
333
|
element = wait_for_and_find(target_selector)
|
|
313
|
-
scope.page.execute_script("arguments[0].focus()", element)
|
|
314
334
|
scope.page.execute_script(
|
|
315
335
|
"arguments[0].scrollIntoView({block: 'center', inline: 'center'})",
|
|
316
336
|
element
|
|
317
337
|
)
|
|
318
338
|
click_element_safely(element)
|
|
319
|
-
|
|
320
|
-
return if scope.page.has_selector?(opened_current_selected_selector)
|
|
321
|
-
|
|
322
|
-
dispatch_open_events(element)
|
|
323
339
|
end
|
|
324
340
|
|
|
325
341
|
def current_selected_selector
|
|
@@ -335,7 +351,47 @@ private
|
|
|
335
351
|
def click_element_safely(element)
|
|
336
352
|
element.click
|
|
337
353
|
rescue Selenium::WebDriver::Error::ElementClickInterceptedError
|
|
338
|
-
scope.page.
|
|
354
|
+
scope.page.driver.browser.action.move_to(element.native).click.perform
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
def close_attempt
|
|
358
|
+
close_search_input
|
|
359
|
+
send_close_escape
|
|
360
|
+
click_close_target
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
def send_escape
|
|
364
|
+
scope.page.driver.browser.action.send_keys(:escape).perform
|
|
365
|
+
rescue Selenium::WebDriver::Error::InvalidElementStateError
|
|
366
|
+
scope.page.find("body").send_keys(:escape)
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
def close_search_input
|
|
370
|
+
return unless scope.page.has_selector?(search_input_selector)
|
|
371
|
+
|
|
372
|
+
search_input = wait_for_and_find(search_input_selector)
|
|
373
|
+
click_element_safely(search_input)
|
|
374
|
+
search_input.send_keys(:escape)
|
|
375
|
+
search_input.send_keys(:tab)
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
def send_close_escape
|
|
379
|
+
select_container = scope.page.first(select_container_selector, minimum: 0)
|
|
380
|
+
return select_container.send_keys(:escape) if select_container
|
|
381
|
+
|
|
382
|
+
send_escape
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
def click_close_target
|
|
386
|
+
close_target = scope.page.first(
|
|
387
|
+
"[data-component='super-admin--layout'], " \
|
|
388
|
+
"[data-component='admin/layout'], " \
|
|
389
|
+
"[data-component='layout/base'], " \
|
|
390
|
+
".react-root > *",
|
|
391
|
+
minimum: 0
|
|
392
|
+
)
|
|
393
|
+
close_target ||= wait_for_and_find("body")
|
|
394
|
+
scope.page.driver.browser.action.move_to(close_target.native).click.perform
|
|
339
395
|
end
|
|
340
396
|
|
|
341
397
|
def send_open_key
|
|
@@ -346,24 +402,6 @@ private
|
|
|
346
402
|
select_container.send_keys(:space)
|
|
347
403
|
end
|
|
348
404
|
|
|
349
|
-
def dispatch_open_events(element)
|
|
350
|
-
scope.page.execute_script(
|
|
351
|
-
<<~JS,
|
|
352
|
-
const target = arguments[0]
|
|
353
|
-
const events = [
|
|
354
|
-
new PointerEvent('pointerdown', {bubbles: true, cancelable: true}),
|
|
355
|
-
new MouseEvent('mousedown', {bubbles: true, cancelable: true}),
|
|
356
|
-
new PointerEvent('pointerup', {bubbles: true, cancelable: true}),
|
|
357
|
-
new MouseEvent('mouseup', {bubbles: true, cancelable: true}),
|
|
358
|
-
new MouseEvent('click', {bubbles: true, cancelable: true})
|
|
359
|
-
]
|
|
360
|
-
|
|
361
|
-
for (const event of events) target.dispatchEvent(event)
|
|
362
|
-
JS
|
|
363
|
-
element
|
|
364
|
-
)
|
|
365
|
-
end
|
|
366
|
-
|
|
367
405
|
def current_option_label_selectors
|
|
368
406
|
[
|
|
369
407
|
"#{base_selector} [data-class='current-selected'] [data-testid='option-presentation-text']",
|
|
@@ -399,18 +437,72 @@ private
|
|
|
399
437
|
end
|
|
400
438
|
|
|
401
439
|
def find_option_element(selector, label)
|
|
402
|
-
return wait_for_and_find(selector
|
|
440
|
+
return wait_for_and_find(selector) unless label
|
|
441
|
+
|
|
442
|
+
return wait_for_and_find(selector) if selector.start_with?(select_option_container_selector)
|
|
403
443
|
|
|
404
|
-
|
|
444
|
+
if selector.include?("option-presentation")
|
|
445
|
+
option_presentation = wait_for_and_find(selector)
|
|
446
|
+
return option_presentation.find(:xpath, "./ancestor::*[@data-class='select-option']")
|
|
447
|
+
end
|
|
405
448
|
|
|
406
|
-
return wait_for_and_find(selector
|
|
449
|
+
return wait_for_and_find(selector) if scope.page.has_selector?(selector)
|
|
407
450
|
|
|
408
|
-
option_text = wait_for_and_find(option_label_selector, text: label
|
|
451
|
+
option_text = wait_for_and_find(option_label_selector, text: label)
|
|
409
452
|
option_text.find(:xpath, "./ancestor::*[@data-class='select-option']")
|
|
410
453
|
rescue Selenium::WebDriver::Error::StaleElementReferenceError
|
|
411
454
|
retry
|
|
412
455
|
end
|
|
413
456
|
|
|
457
|
+
def click_target_element(click_target)
|
|
458
|
+
unless click_target.visible?
|
|
459
|
+
scope.page.execute_script(
|
|
460
|
+
"arguments[0].scrollIntoView({block: 'center', inline: 'center'})",
|
|
461
|
+
click_target
|
|
462
|
+
)
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
click_element_safely(click_target)
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
def click_option_element(element)
|
|
469
|
+
raise ArgumentError, "Expected a clickable option element, got nil" if element.nil?
|
|
470
|
+
|
|
471
|
+
element.native.location_once_scrolled_into_view
|
|
472
|
+
element.click
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
def perform_option_selection(option, label, option_value)
|
|
476
|
+
click_option_element(option)
|
|
477
|
+
return if selected?(label, option_value)
|
|
478
|
+
|
|
479
|
+
if scope.page.has_selector?(current_value_selector(option_value), visible: false, wait: 1) ||
|
|
480
|
+
(label && label_matches?(label))
|
|
481
|
+
return
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
option_text = option.first("[data-testid='option-presentation-text']", minimum: 0)
|
|
485
|
+
click_option_element(option_text) if option_text
|
|
486
|
+
return if selected?(label, option_value)
|
|
487
|
+
|
|
488
|
+
click_option_presentation(option, label, option_value)
|
|
489
|
+
send_option_keys(option, label, option_value)
|
|
490
|
+
click_option_element(option) unless selected?(label, option_value)
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
def click_option_presentation(option, label, option_value)
|
|
494
|
+
return if selected?(label, option_value)
|
|
495
|
+
|
|
496
|
+
option_presentation = option.all("[data-testid='option-presentation']", minimum: 0).first
|
|
497
|
+
click_option_element(option_presentation) if option_presentation
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
def send_option_keys(option, label, option_value)
|
|
501
|
+
return if selected?(label, option_value)
|
|
502
|
+
|
|
503
|
+
option.click
|
|
504
|
+
end
|
|
505
|
+
|
|
414
506
|
def select_option_container_selector
|
|
415
507
|
"#{options_selector} [data-class='select-option']"
|
|
416
508
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: haya_select_helpers
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.13
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- kaspernj
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-02-
|
|
11
|
+
date: 2026-02-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|