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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9756954e876e2e6afc78872b90101b188977b26a82a589e653c2103119062b0b
4
- data.tar.gz: ac41d31b10a7b81871445a581cfd071074ef600cb458fd4b80865f4ada7baf4d
3
+ metadata.gz: 7f84d8a6672eb46f35aa0949b1b1bbbf702e7fca854541d7fcb7e2152d890caa
4
+ data.tar.gz: e5e2e100bc9e5697c4cd93c0d747026d94d249cbc1793ee4e7e4967be6ac19eb
5
5
  SHA512:
6
- metadata.gz: dea740fc972e837eb124d7fb517813931a11d4a2a10a594c0d6a47282df17b450e6ebaec5c1b3d74e70c1d60e52182a08bd9c968d43f785610f68a888eedd61d
7
- data.tar.gz: 667adf2ee18c752efc6f5eac4739ce360c76f71c47c614c99e8d3a89a1cc6760c028a23249bcb4747531ba98315adbac2aacee841519b65bc6af628df2115450
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
- click_open_target
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']").set(value)
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
- if option.visible?
121
- option.click
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
- unless scope.page.has_selector?(search_input_selector)
199
+ if scope.page.has_selector?(options_selector, visible: :all)
205
200
  wait_for_browser do
206
- option_present?(selector, label)
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
- return
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
- expect(label_matches || value_matches || blank_matches).to eq true
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
- if scope.page.has_selector?(select_container_selector)
289
- wait_for_and_find(select_container_selector).click
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 click_open_target
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.execute_script("arguments[0].click()", element)
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, visible: :all) unless label
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
- return wait_for_and_find(selector, visible: :all) if selector.start_with?(select_option_container_selector)
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, visible: :all) if scope.page.has_selector?(selector, visible: :all)
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, visible: :all)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HayaSelectHelpers
4
- VERSION = '0.0.11'
4
+ VERSION = "0.0.13"
5
5
  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.11
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-09 00:00:00.000000000 Z
11
+ date: 2026-02-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails