seleniumbase 4.32.9__py3-none-any.whl → 4.32.10a1__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- seleniumbase/__version__.py +1 -1
- seleniumbase/core/browser_launcher.py +57 -31
- seleniumbase/core/sb_cdp.py +360 -41
- seleniumbase/core/sb_driver.py +13 -0
- seleniumbase/fixtures/base_case.py +36 -3
- seleniumbase/fixtures/shared_utils.py +3 -3
- seleniumbase/undetected/cdp_driver/element.py +18 -2
- {seleniumbase-4.32.9.dist-info → seleniumbase-4.32.10a1.dist-info}/METADATA +4 -4
- {seleniumbase-4.32.9.dist-info → seleniumbase-4.32.10a1.dist-info}/RECORD +13 -13
- {seleniumbase-4.32.9.dist-info → seleniumbase-4.32.10a1.dist-info}/WHEEL +1 -1
- {seleniumbase-4.32.9.dist-info → seleniumbase-4.32.10a1.dist-info}/LICENSE +0 -0
- {seleniumbase-4.32.9.dist-info → seleniumbase-4.32.10a1.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.32.9.dist-info → seleniumbase-4.32.10a1.dist-info}/top_level.txt +0 -0
seleniumbase/__version__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
# seleniumbase package
|
2
|
-
__version__ = "4.32.
|
2
|
+
__version__ = "4.32.10a1"
|
@@ -603,6 +603,7 @@ def uc_open_with_cdp_mode(driver, url=None):
|
|
603
603
|
cdp.click = CDPM.click
|
604
604
|
cdp.click_active_element = CDPM.click_active_element
|
605
605
|
cdp.click_if_visible = CDPM.click_if_visible
|
606
|
+
cdp.click_visible_elements = CDPM.click_visible_elements
|
606
607
|
cdp.mouse_click = CDPM.mouse_click
|
607
608
|
cdp.remove_element = CDPM.remove_element
|
608
609
|
cdp.remove_from_dom = CDPM.remove_from_dom
|
@@ -611,6 +612,7 @@ def uc_open_with_cdp_mode(driver, url=None):
|
|
611
612
|
cdp.send_keys = CDPM.send_keys
|
612
613
|
cdp.press_keys = CDPM.press_keys
|
613
614
|
cdp.type = CDPM.type
|
615
|
+
cdp.set_value = CDPM.set_value
|
614
616
|
cdp.evaluate = CDPM.evaluate
|
615
617
|
cdp.js_dumps = CDPM.js_dumps
|
616
618
|
cdp.maximize = CDPM.maximize
|
@@ -625,6 +627,11 @@ def uc_open_with_cdp_mode(driver, url=None):
|
|
625
627
|
cdp.gui_write = CDPM.gui_write
|
626
628
|
cdp.gui_click_x_y = CDPM.gui_click_x_y
|
627
629
|
cdp.gui_click_element = CDPM.gui_click_element
|
630
|
+
cdp.gui_drag_drop_points = CDPM.gui_drag_drop_points
|
631
|
+
cdp.gui_drag_and_drop = CDPM.gui_drag_and_drop
|
632
|
+
cdp.gui_hover_x_y = CDPM.gui_hover_x_y
|
633
|
+
cdp.gui_hover_element = CDPM.gui_hover_element
|
634
|
+
cdp.gui_hover_and_click = CDPM.gui_hover_and_click
|
628
635
|
cdp.internalize_links = CDPM.internalize_links
|
629
636
|
cdp.get_window = CDPM.get_window
|
630
637
|
cdp.get_element_attributes = CDPM.get_element_attributes
|
@@ -651,7 +658,9 @@ def uc_open_with_cdp_mode(driver, url=None):
|
|
651
658
|
cdp.get_window_rect = CDPM.get_window_rect
|
652
659
|
cdp.get_window_size = CDPM.get_window_size
|
653
660
|
cdp.nested_click = CDPM.nested_click
|
661
|
+
cdp.select_option_by_text = CDPM.select_option_by_text
|
654
662
|
cdp.flash = CDPM.flash
|
663
|
+
cdp.highlight = CDPM.highlight
|
655
664
|
cdp.focus = CDPM.focus
|
656
665
|
cdp.highlight_overlay = CDPM.highlight_overlay
|
657
666
|
cdp.get_window_position = CDPM.get_window_position
|
@@ -663,8 +672,11 @@ def uc_open_with_cdp_mode(driver, url=None):
|
|
663
672
|
cdp.is_element_present = CDPM.is_element_present
|
664
673
|
cdp.is_element_visible = CDPM.is_element_visible
|
665
674
|
cdp.assert_element_present = CDPM.assert_element_present
|
675
|
+
cdp.assert_element_absent = CDPM.assert_element_absent
|
666
676
|
cdp.assert_element = CDPM.assert_element
|
667
677
|
cdp.assert_element_visible = CDPM.assert_element
|
678
|
+
cdp.assert_element_not_visible = CDPM.assert_element_not_visible
|
679
|
+
cdp.assert_title = CDPM.assert_title
|
668
680
|
cdp.assert_text = CDPM.assert_text
|
669
681
|
cdp.assert_exact_text = CDPM.assert_exact_text
|
670
682
|
cdp.scroll_down = CDPM.scroll_down
|
@@ -680,6 +692,7 @@ def uc_open_with_cdp_mode(driver, url=None):
|
|
680
692
|
core_items.tab = cdp.tab
|
681
693
|
core_items.util = cdp.util
|
682
694
|
cdp.core = core_items
|
695
|
+
cdp.loop = cdp.get_event_loop()
|
683
696
|
driver.cdp = cdp
|
684
697
|
driver._is_using_cdp = True
|
685
698
|
|
@@ -944,48 +957,46 @@ def uc_gui_click_x_y(driver, x, y, timeframe=0.25):
|
|
944
957
|
connected = True
|
945
958
|
width_ratio = 1.0
|
946
959
|
if IS_WINDOWS:
|
947
|
-
|
948
|
-
driver.window_handles
|
949
|
-
except Exception:
|
950
|
-
connected = False
|
960
|
+
connected = driver.is_connected()
|
951
961
|
if (
|
952
962
|
not connected
|
953
963
|
and (
|
954
964
|
not hasattr(sb_config, "_saved_width_ratio")
|
955
965
|
or not sb_config._saved_width_ratio
|
956
966
|
)
|
967
|
+
and not __is_cdp_swap_needed(driver)
|
957
968
|
):
|
958
969
|
driver.reconnect(0.1)
|
959
|
-
|
960
|
-
if IS_WINDOWS and connected:
|
970
|
+
if IS_WINDOWS and not __is_cdp_swap_needed(driver):
|
961
971
|
window_rect = driver.get_window_rect()
|
962
972
|
width = window_rect["width"]
|
963
973
|
height = window_rect["height"]
|
964
974
|
win_x = window_rect["x"]
|
965
975
|
win_y = window_rect["y"]
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
)
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
driver.maximize_window()
|
974
|
-
win_width = driver.get_window_size()["width"]
|
975
|
-
width_ratio = round(float(scr_width) / float(win_width), 2)
|
976
|
-
width_ratio += 0.01
|
977
|
-
if width_ratio < 0.45 or width_ratio > 2.55:
|
978
|
-
width_ratio = 1.01
|
979
|
-
sb_config._saved_width_ratio = width_ratio
|
976
|
+
scr_width = pyautogui.size().width
|
977
|
+
driver.maximize_window()
|
978
|
+
win_width = driver.get_window_size()["width"]
|
979
|
+
width_ratio = round(float(scr_width) / float(win_width), 2) + 0.01
|
980
|
+
if width_ratio < 0.45 or width_ratio > 2.55:
|
981
|
+
width_ratio = 1.01
|
982
|
+
sb_config._saved_width_ratio = width_ratio
|
980
983
|
driver.minimize_window()
|
981
984
|
driver.set_window_rect(win_x, win_y, width, height)
|
982
|
-
elif (
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
985
|
+
elif IS_WINDOWS and __is_cdp_swap_needed(driver):
|
986
|
+
window_rect = driver.cdp.get_window_rect()
|
987
|
+
width = window_rect["width"]
|
988
|
+
height = window_rect["height"]
|
989
|
+
win_x = window_rect["x"]
|
990
|
+
win_y = window_rect["y"]
|
991
|
+
scr_width = pyautogui.size().width
|
992
|
+
driver.cdp.maximize()
|
993
|
+
win_width = driver.cdp.get_window_size()["width"]
|
994
|
+
width_ratio = round(float(scr_width) / float(win_width), 2) + 0.01
|
995
|
+
if width_ratio < 0.45 or width_ratio > 2.55:
|
996
|
+
width_ratio = 1.01
|
997
|
+
sb_config._saved_width_ratio = width_ratio
|
998
|
+
driver.cdp.minimize()
|
999
|
+
driver.cdp.set_window_rect(win_x, win_y, width, height)
|
989
1000
|
if IS_WINDOWS:
|
990
1001
|
x = x * width_ratio
|
991
1002
|
y = y * width_ratio
|
@@ -1090,6 +1101,21 @@ def _uc_gui_click_captcha(
|
|
1090
1101
|
sb_config._saved_width_ratio = width_ratio
|
1091
1102
|
driver.minimize_window()
|
1092
1103
|
driver.set_window_rect(win_x, win_y, width, height)
|
1104
|
+
elif IS_WINDOWS and __is_cdp_swap_needed(driver):
|
1105
|
+
window_rect = driver.cdp.get_window_rect()
|
1106
|
+
width = window_rect["width"]
|
1107
|
+
height = window_rect["height"]
|
1108
|
+
win_x = window_rect["x"]
|
1109
|
+
win_y = window_rect["y"]
|
1110
|
+
scr_width = pyautogui.size().width
|
1111
|
+
driver.cdp.maximize()
|
1112
|
+
win_width = driver.cdp.get_window_size()["width"]
|
1113
|
+
width_ratio = round(float(scr_width) / float(win_width), 2) + 0.01
|
1114
|
+
if width_ratio < 0.45 or width_ratio > 2.55:
|
1115
|
+
width_ratio = 1.01
|
1116
|
+
sb_config._saved_width_ratio = width_ratio
|
1117
|
+
driver.cdp.minimize()
|
1118
|
+
driver.cdp.set_window_rect(win_x, win_y, width, height)
|
1093
1119
|
if ctype == "cf_t":
|
1094
1120
|
if (
|
1095
1121
|
driver.is_element_present(".cf-turnstile-wrapper iframe")
|
@@ -1201,10 +1227,10 @@ def _uc_gui_click_captcha(
|
|
1201
1227
|
element = driver.wait_for_element_present(
|
1202
1228
|
selector, timeout=2.5
|
1203
1229
|
)
|
1204
|
-
x = i_x + element.rect["x"] +
|
1205
|
-
x +=
|
1206
|
-
y = i_y + element.rect["y"] +
|
1207
|
-
y +=
|
1230
|
+
x = i_x + element.rect["x"] + (element.rect["width"] / 2.0)
|
1231
|
+
x += 0.5
|
1232
|
+
y = i_y + element.rect["y"] + (element.rect["height"] / 2.0)
|
1233
|
+
y += 0.5
|
1208
1234
|
else:
|
1209
1235
|
x = (i_x + 34) * width_ratio
|
1210
1236
|
y = (i_y + 34) * width_ratio
|
seleniumbase/core/sb_cdp.py
CHANGED
@@ -39,7 +39,9 @@ class CDPMethods():
|
|
39
39
|
return element
|
40
40
|
element.clear_input = lambda: self.__clear_input(element)
|
41
41
|
element.click = lambda: self.__click(element)
|
42
|
-
element.flash = lambda: self.__flash(
|
42
|
+
element.flash = lambda *args, **kwargs: self.__flash(
|
43
|
+
element, *args, **kwargs
|
44
|
+
)
|
43
45
|
element.focus = lambda: self.__focus(element)
|
44
46
|
element.highlight_overlay = lambda: self.__highlight_overlay(element)
|
45
47
|
element.mouse_click = lambda: self.__mouse_click(element)
|
@@ -258,9 +260,11 @@ class CDPMethods():
|
|
258
260
|
self.loop.run_until_complete(self.page.wait())
|
259
261
|
return result
|
260
262
|
|
261
|
-
def __flash(self, element):
|
263
|
+
def __flash(self, element, *args, **kwargs):
|
262
264
|
return (
|
263
|
-
self.loop.run_until_complete(
|
265
|
+
self.loop.run_until_complete(
|
266
|
+
element.flash_async(*args, **kwargs)
|
267
|
+
)
|
264
268
|
)
|
265
269
|
|
266
270
|
def __focus(self, element):
|
@@ -292,11 +296,11 @@ class CDPMethods():
|
|
292
296
|
|
293
297
|
def __query_selector(self, element, selector):
|
294
298
|
selector = self.__convert_to_css_if_xpath(selector)
|
295
|
-
|
299
|
+
element2 = self.loop.run_until_complete(
|
296
300
|
element.query_selector_async(selector)
|
297
301
|
)
|
298
|
-
|
299
|
-
return
|
302
|
+
element2 = self.__add_sync_methods(element2)
|
303
|
+
return element2
|
300
304
|
|
301
305
|
def __query_selector_all(self, element, selector):
|
302
306
|
selector = self.__convert_to_css_if_xpath(selector)
|
@@ -467,6 +471,19 @@ class CDPMethods():
|
|
467
471
|
self.__slow_mode_pause_if_set()
|
468
472
|
self.loop.run_until_complete(self.page.wait())
|
469
473
|
|
474
|
+
def click_visible_elements(self, selector):
|
475
|
+
elements = self.select_all(selector)
|
476
|
+
for element in elements:
|
477
|
+
try:
|
478
|
+
position = element.get_position()
|
479
|
+
if (position.width != 0 or position.height != 0):
|
480
|
+
element.click()
|
481
|
+
time.sleep(0.0375)
|
482
|
+
self.__slow_mode_pause_if_set()
|
483
|
+
self.loop.run_until_complete(self.page.wait())
|
484
|
+
except Exception:
|
485
|
+
pass
|
486
|
+
|
470
487
|
def mouse_click(self, selector, timeout=settings.SMALL_TIMEOUT):
|
471
488
|
"""(Attempt simulating a mouse click)"""
|
472
489
|
self.__slow_mode_pause_if_set()
|
@@ -491,9 +508,45 @@ class CDPMethods():
|
|
491
508
|
element = self.find_element(parent_selector)
|
492
509
|
return element.query_selector(selector)
|
493
510
|
|
494
|
-
def
|
511
|
+
def select_option_by_text(self, dropdown_selector, option):
|
512
|
+
element = self.find_element(dropdown_selector)
|
513
|
+
options = element.query_selector_all("option")
|
514
|
+
for found_option in options:
|
515
|
+
if found_option.text.strip() == option.strip():
|
516
|
+
found_option.select_option()
|
517
|
+
return
|
518
|
+
raise Exception(
|
519
|
+
"Unable to find text option {%s} in dropdown {%s}!"
|
520
|
+
% (dropdown_selector, option)
|
521
|
+
)
|
522
|
+
|
523
|
+
def flash(
|
524
|
+
self,
|
525
|
+
selector, # The CSS Selector to flash
|
526
|
+
duration=1, # (seconds) flash duration
|
527
|
+
color="44CC88", # RGB hex flash color
|
528
|
+
pause=0, # (seconds) If 0, the next action starts during flash
|
529
|
+
):
|
495
530
|
"""Paint a quickly-vanishing dot over an element."""
|
496
|
-
self.
|
531
|
+
selector = self.__convert_to_css_if_xpath(selector)
|
532
|
+
element = self.find_element(selector)
|
533
|
+
element.flash(duration=duration, color=color)
|
534
|
+
if pause and isinstance(pause, (int, float)):
|
535
|
+
time.sleep(pause)
|
536
|
+
|
537
|
+
def highlight(self, selector):
|
538
|
+
"""Highlight an element with multi-colors."""
|
539
|
+
selector = self.__convert_to_css_if_xpath(selector)
|
540
|
+
element = self.find_element(selector)
|
541
|
+
element = self.find_element(selector)
|
542
|
+
element.flash(0.46, "44CC88")
|
543
|
+
time.sleep(0.15)
|
544
|
+
element.flash(0.42, "8844CC")
|
545
|
+
time.sleep(0.15)
|
546
|
+
element.flash(0.38, "CC8844")
|
547
|
+
time.sleep(0.15)
|
548
|
+
element.flash(0.30, "44CC88")
|
549
|
+
time.sleep(0.30)
|
497
550
|
|
498
551
|
def focus(self, selector):
|
499
552
|
self.find_element(selector).focus()
|
@@ -526,8 +579,9 @@ class CDPMethods():
|
|
526
579
|
self.find_element(selector).scroll_into_view()
|
527
580
|
|
528
581
|
def send_keys(self, selector, text, timeout=settings.SMALL_TIMEOUT):
|
529
|
-
element = self.select(selector)
|
530
582
|
self.__slow_mode_pause_if_set()
|
583
|
+
element = self.select(selector, timeout=timeout)
|
584
|
+
self.__add_light_pause()
|
531
585
|
if text.endswith("\n") or text.endswith("\r"):
|
532
586
|
text = text[:-1] + "\r\n"
|
533
587
|
element.send_keys(text)
|
@@ -536,8 +590,9 @@ class CDPMethods():
|
|
536
590
|
|
537
591
|
def press_keys(self, selector, text, timeout=settings.SMALL_TIMEOUT):
|
538
592
|
"""Similar to send_keys(), but presses keys at human speed."""
|
539
|
-
element = self.select(selector)
|
540
593
|
self.__slow_mode_pause_if_set()
|
594
|
+
element = self.select(selector, timeout=timeout)
|
595
|
+
self.__add_light_pause()
|
541
596
|
submit = False
|
542
597
|
if text.endswith("\n") or text.endswith("\r"):
|
543
598
|
submit = True
|
@@ -553,8 +608,9 @@ class CDPMethods():
|
|
553
608
|
|
554
609
|
def type(self, selector, text, timeout=settings.SMALL_TIMEOUT):
|
555
610
|
"""Similar to send_keys(), but clears the text field first."""
|
556
|
-
element = self.select(selector)
|
557
611
|
self.__slow_mode_pause_if_set()
|
612
|
+
element = self.select(selector, timeout=timeout)
|
613
|
+
self.__add_light_pause()
|
558
614
|
with suppress(Exception):
|
559
615
|
element.clear_input()
|
560
616
|
if text.endswith("\n") or text.endswith("\r"):
|
@@ -563,6 +619,42 @@ class CDPMethods():
|
|
563
619
|
self.__slow_mode_pause_if_set()
|
564
620
|
self.loop.run_until_complete(self.page.wait())
|
565
621
|
|
622
|
+
def set_value(self, selector, text, timeout=settings.SMALL_TIMEOUT):
|
623
|
+
"""Similar to send_keys(), but clears the text field first."""
|
624
|
+
self.__slow_mode_pause_if_set()
|
625
|
+
selector = self.__convert_to_css_if_xpath(selector)
|
626
|
+
self.select(selector, timeout=timeout)
|
627
|
+
self.__add_light_pause()
|
628
|
+
press_enter = False
|
629
|
+
if text.endswith("\n"):
|
630
|
+
text = text[:-1]
|
631
|
+
press_enter = True
|
632
|
+
value = js_utils.escape_quotes_if_needed(re.escape(text))
|
633
|
+
css_selector = re.escape(selector)
|
634
|
+
css_selector = js_utils.escape_quotes_if_needed(css_selector)
|
635
|
+
set_value_script = (
|
636
|
+
"""m_elm = document.querySelector('%s');"""
|
637
|
+
"""m_elm.value = '%s';""" % (css_selector, value)
|
638
|
+
)
|
639
|
+
self.loop.run_until_complete(self.page.evaluate(set_value_script))
|
640
|
+
the_type = self.get_element_attribute(selector, "type")
|
641
|
+
if the_type == "range":
|
642
|
+
# Some input sliders need a mouse event to trigger listeners.
|
643
|
+
with suppress(Exception):
|
644
|
+
mouse_move_script = (
|
645
|
+
"""m_elm = document.querySelector('%s');"""
|
646
|
+
"""m_evt = new Event('mousemove');"""
|
647
|
+
"""m_elm.dispatchEvent(m_evt);""" % css_selector
|
648
|
+
)
|
649
|
+
self.loop.run_until_complete(
|
650
|
+
self.page.evaluate(mouse_move_script)
|
651
|
+
)
|
652
|
+
elif press_enter:
|
653
|
+
self.__add_light_pause()
|
654
|
+
self.send_keys(selector, "\n")
|
655
|
+
self.__slow_mode_pause_if_set()
|
656
|
+
self.loop.run_until_complete(self.page.wait())
|
657
|
+
|
566
658
|
def evaluate(self, expression):
|
567
659
|
"""Run a JavaScript expression and return the result."""
|
568
660
|
return self.loop.run_until_complete(
|
@@ -576,21 +668,30 @@ class CDPMethods():
|
|
576
668
|
)
|
577
669
|
|
578
670
|
def maximize(self):
|
579
|
-
|
580
|
-
|
581
|
-
)
|
671
|
+
if self.get_window()[1].window_state.value == "maximized":
|
672
|
+
return
|
673
|
+
elif self.get_window()[1].window_state.value == "minimized":
|
674
|
+
self.loop.run_until_complete(self.page.maximize())
|
675
|
+
time.sleep(0.0375)
|
676
|
+
return self.loop.run_until_complete(self.page.maximize())
|
582
677
|
|
583
678
|
def minimize(self):
|
584
|
-
|
585
|
-
self.page.minimize()
|
586
|
-
)
|
679
|
+
if self.get_window()[1].window_state.value != "minimized":
|
680
|
+
return self.loop.run_until_complete(self.page.minimize())
|
587
681
|
|
588
682
|
def medimize(self):
|
589
|
-
|
590
|
-
self.page.medimize()
|
591
|
-
|
683
|
+
if self.get_window()[1].window_state.value == "minimized":
|
684
|
+
self.loop.run_until_complete(self.page.medimize())
|
685
|
+
time.sleep(0.0375)
|
686
|
+
return self.loop.run_until_complete(self.page.medimize())
|
592
687
|
|
593
688
|
def set_window_rect(self, x, y, width, height):
|
689
|
+
if self.get_window()[1].window_state.value == "minimized":
|
690
|
+
self.loop.run_until_complete(
|
691
|
+
self.page.set_window_size(
|
692
|
+
left=x, top=y, width=width, height=height)
|
693
|
+
)
|
694
|
+
time.sleep(0.0375)
|
594
695
|
return self.loop.run_until_complete(
|
595
696
|
self.page.set_window_size(
|
596
697
|
left=x, top=y, width=width, height=height)
|
@@ -602,6 +703,7 @@ class CDPMethods():
|
|
602
703
|
width = settings.CHROME_START_WIDTH
|
603
704
|
height = settings.CHROME_START_HEIGHT
|
604
705
|
self.set_window_rect(x, y, width, height)
|
706
|
+
self.__add_light_pause()
|
605
707
|
|
606
708
|
def get_window(self):
|
607
709
|
return self.loop.run_until_complete(
|
@@ -785,7 +887,7 @@ class CDPMethods():
|
|
785
887
|
e_height = element_rect["height"]
|
786
888
|
e_x = element_rect["x"]
|
787
889
|
e_y = element_rect["y"]
|
788
|
-
return ((e_x + e_width / 2), (e_y + e_height / 2))
|
890
|
+
return ((e_x + e_width / 2.0) + 0.5, (e_y + e_height / 2.0) + 0.5)
|
789
891
|
|
790
892
|
def get_document(self):
|
791
893
|
return self.loop.run_until_complete(
|
@@ -798,6 +900,7 @@ class CDPMethods():
|
|
798
900
|
)
|
799
901
|
|
800
902
|
def get_element_attributes(self, selector):
|
903
|
+
selector = self.__convert_to_css_if_xpath(selector)
|
801
904
|
return self.loop.run_until_complete(
|
802
905
|
self.page.js_dumps(
|
803
906
|
"""document.querySelector('%s')"""
|
@@ -1013,6 +1116,156 @@ class CDPMethods():
|
|
1013
1116
|
pyautogui.click(x=x, y=y)
|
1014
1117
|
|
1015
1118
|
def gui_click_x_y(self, x, y, timeframe=0.25):
|
1119
|
+
gui_lock = fasteners.InterProcessLock(
|
1120
|
+
constants.MultiBrowser.PYAUTOGUILOCK
|
1121
|
+
)
|
1122
|
+
with gui_lock: # Prevent issues with multiple processes
|
1123
|
+
self.__install_pyautogui_if_missing()
|
1124
|
+
import pyautogui
|
1125
|
+
pyautogui = self.__get_configured_pyautogui(pyautogui)
|
1126
|
+
width_ratio = 1.0
|
1127
|
+
if shared_utils.is_windows():
|
1128
|
+
window_rect = self.get_window_rect()
|
1129
|
+
width = window_rect["width"]
|
1130
|
+
height = window_rect["height"]
|
1131
|
+
win_x = window_rect["x"]
|
1132
|
+
win_y = window_rect["y"]
|
1133
|
+
scr_width = pyautogui.size().width
|
1134
|
+
self.maximize()
|
1135
|
+
self.__add_light_pause()
|
1136
|
+
win_width = self.get_window_size()["width"]
|
1137
|
+
width_ratio = round(float(scr_width) / float(win_width), 2)
|
1138
|
+
width_ratio += 0.01
|
1139
|
+
if width_ratio < 0.45 or width_ratio > 2.55:
|
1140
|
+
width_ratio = 1.01
|
1141
|
+
sb_config._saved_width_ratio = width_ratio
|
1142
|
+
self.minimize()
|
1143
|
+
self.__add_light_pause()
|
1144
|
+
self.set_window_rect(win_x, win_y, width, height)
|
1145
|
+
self.__add_light_pause()
|
1146
|
+
x = x * width_ratio
|
1147
|
+
y = y * width_ratio
|
1148
|
+
self.bring_active_window_to_front()
|
1149
|
+
self.__gui_click_x_y(x, y, timeframe=timeframe, uc_lock=False)
|
1150
|
+
|
1151
|
+
def gui_click_element(self, selector, timeframe=0.25):
|
1152
|
+
self.__slow_mode_pause_if_set()
|
1153
|
+
x, y = self.get_gui_element_center(selector)
|
1154
|
+
self.__add_light_pause()
|
1155
|
+
self.gui_click_x_y(x, y, timeframe=timeframe)
|
1156
|
+
self.__slow_mode_pause_if_set()
|
1157
|
+
self.loop.run_until_complete(self.page.wait())
|
1158
|
+
|
1159
|
+
def __gui_drag_drop(self, x1, y1, x2, y2, timeframe=0.25, uc_lock=False):
|
1160
|
+
self.__install_pyautogui_if_missing()
|
1161
|
+
import pyautogui
|
1162
|
+
pyautogui = self.__get_configured_pyautogui(pyautogui)
|
1163
|
+
screen_width, screen_height = pyautogui.size()
|
1164
|
+
if x1 < 0 or y1 < 0 or x1 > screen_width or y1 > screen_height:
|
1165
|
+
raise Exception(
|
1166
|
+
"PyAutoGUI cannot drag-drop from point (%s, %s)"
|
1167
|
+
" outside screen. (Width: %s, Height: %s)"
|
1168
|
+
% (x1, y1, screen_width, screen_height)
|
1169
|
+
)
|
1170
|
+
if x2 < 0 or y2 < 0 or x2 > screen_width or y2 > screen_height:
|
1171
|
+
raise Exception(
|
1172
|
+
"PyAutoGUI cannot drag-drop to point (%s, %s)"
|
1173
|
+
" outside screen. (Width: %s, Height: %s)"
|
1174
|
+
% (x2, y2, screen_width, screen_height)
|
1175
|
+
)
|
1176
|
+
if uc_lock:
|
1177
|
+
gui_lock = fasteners.InterProcessLock(
|
1178
|
+
constants.MultiBrowser.PYAUTOGUILOCK
|
1179
|
+
)
|
1180
|
+
with gui_lock: # Prevent issues with multiple processes
|
1181
|
+
pyautogui.moveTo(x1, y1, 0.25, pyautogui.easeOutQuad)
|
1182
|
+
self.__add_light_pause()
|
1183
|
+
if "--debug" in sys.argv:
|
1184
|
+
print(" <DEBUG> pyautogui.moveTo(%s, %s)" % (x1, y1))
|
1185
|
+
pyautogui.dragTo(x2, y2, button="left", duration=timeframe)
|
1186
|
+
else:
|
1187
|
+
# Called from a method where the gui_lock is already active
|
1188
|
+
pyautogui.moveTo(x1, y1, 0.25, pyautogui.easeOutQuad)
|
1189
|
+
self.__add_light_pause()
|
1190
|
+
if "--debug" in sys.argv:
|
1191
|
+
print(" <DEBUG> pyautogui.dragTo(%s, %s)" % (x2, y2))
|
1192
|
+
pyautogui.dragTo(x2, y2, button="left", duration=timeframe)
|
1193
|
+
|
1194
|
+
def gui_drag_drop_points(self, x1, y1, x2, y2, timeframe=0.35):
|
1195
|
+
gui_lock = fasteners.InterProcessLock(
|
1196
|
+
constants.MultiBrowser.PYAUTOGUILOCK
|
1197
|
+
)
|
1198
|
+
with gui_lock: # Prevent issues with multiple processes
|
1199
|
+
self.__install_pyautogui_if_missing()
|
1200
|
+
import pyautogui
|
1201
|
+
pyautogui = self.__get_configured_pyautogui(pyautogui)
|
1202
|
+
width_ratio = 1.0
|
1203
|
+
if shared_utils.is_windows():
|
1204
|
+
window_rect = self.get_window_rect()
|
1205
|
+
width = window_rect["width"]
|
1206
|
+
height = window_rect["height"]
|
1207
|
+
win_x = window_rect["x"]
|
1208
|
+
win_y = window_rect["y"]
|
1209
|
+
scr_width = pyautogui.size().width
|
1210
|
+
self.maximize()
|
1211
|
+
self.__add_light_pause()
|
1212
|
+
win_width = self.get_window_size()["width"]
|
1213
|
+
width_ratio = round(float(scr_width) / float(win_width), 2)
|
1214
|
+
width_ratio += 0.01
|
1215
|
+
if width_ratio < 0.45 or width_ratio > 2.55:
|
1216
|
+
width_ratio = 1.01
|
1217
|
+
sb_config._saved_width_ratio = width_ratio
|
1218
|
+
self.minimize()
|
1219
|
+
self.__add_light_pause()
|
1220
|
+
self.set_window_rect(win_x, win_y, width, height)
|
1221
|
+
self.__add_light_pause()
|
1222
|
+
x1 = x1 * width_ratio
|
1223
|
+
y1 = y1 * width_ratio
|
1224
|
+
x2 = x2 * width_ratio
|
1225
|
+
y2 = y2 * width_ratio
|
1226
|
+
self.bring_active_window_to_front()
|
1227
|
+
self.__gui_drag_drop(
|
1228
|
+
x1, y1, x2, y2, timeframe=timeframe, uc_lock=False
|
1229
|
+
)
|
1230
|
+
self.__slow_mode_pause_if_set()
|
1231
|
+
self.loop.run_until_complete(self.page.wait())
|
1232
|
+
|
1233
|
+
def gui_drag_and_drop(self, drag_selector, drop_selector, timeframe=0.35):
|
1234
|
+
self.__slow_mode_pause_if_set()
|
1235
|
+
x1, y1 = self.get_gui_element_center(drag_selector)
|
1236
|
+
self.__add_light_pause()
|
1237
|
+
x2, y2 = self.get_gui_element_center(drop_selector)
|
1238
|
+
self.__add_light_pause()
|
1239
|
+
self.gui_drag_drop_points(x1, y1, x2, y2, timeframe=timeframe)
|
1240
|
+
|
1241
|
+
def __gui_hover_x_y(self, x, y, timeframe=0.25, uc_lock=False):
|
1242
|
+
self.__install_pyautogui_if_missing()
|
1243
|
+
import pyautogui
|
1244
|
+
pyautogui = self.__get_configured_pyautogui(pyautogui)
|
1245
|
+
screen_width, screen_height = pyautogui.size()
|
1246
|
+
if x < 0 or y < 0 or x > screen_width or y > screen_height:
|
1247
|
+
raise Exception(
|
1248
|
+
"PyAutoGUI cannot hover on point (%s, %s)"
|
1249
|
+
" outside screen. (Width: %s, Height: %s)"
|
1250
|
+
% (x, y, screen_width, screen_height)
|
1251
|
+
)
|
1252
|
+
if uc_lock:
|
1253
|
+
gui_lock = fasteners.InterProcessLock(
|
1254
|
+
constants.MultiBrowser.PYAUTOGUILOCK
|
1255
|
+
)
|
1256
|
+
with gui_lock: # Prevent issues with multiple processes
|
1257
|
+
pyautogui.moveTo(x, y, timeframe, pyautogui.easeOutQuad)
|
1258
|
+
time.sleep(0.056)
|
1259
|
+
if "--debug" in sys.argv:
|
1260
|
+
print(" <DEBUG> pyautogui.moveTo(%s, %s)" % (x, y))
|
1261
|
+
else:
|
1262
|
+
# Called from a method where the gui_lock is already active
|
1263
|
+
pyautogui.moveTo(x, y, timeframe, pyautogui.easeOutQuad)
|
1264
|
+
time.sleep(0.056)
|
1265
|
+
if "--debug" in sys.argv:
|
1266
|
+
print(" <DEBUG> pyautogui.moveTo(%s, %s)" % (x, y))
|
1267
|
+
|
1268
|
+
def gui_hover_x_y(self, x, y, timeframe=0.25):
|
1016
1269
|
gui_lock = fasteners.InterProcessLock(
|
1017
1270
|
constants.MultiBrowser.PYAUTOGUILOCK
|
1018
1271
|
)
|
@@ -1041,6 +1294,7 @@ class CDPMethods():
|
|
1041
1294
|
else:
|
1042
1295
|
scr_width = pyautogui.size().width
|
1043
1296
|
self.maximize()
|
1297
|
+
self.__add_light_pause()
|
1044
1298
|
win_width = self.get_window_size()["width"]
|
1045
1299
|
width_ratio = round(float(scr_width) / float(win_width), 2)
|
1046
1300
|
width_ratio += 0.01
|
@@ -1048,6 +1302,7 @@ class CDPMethods():
|
|
1048
1302
|
width_ratio = 1.01
|
1049
1303
|
sb_config._saved_width_ratio = width_ratio
|
1050
1304
|
self.set_window_rect(win_x, win_y, width, height)
|
1305
|
+
self.__add_light_pause()
|
1051
1306
|
self.bring_active_window_to_front()
|
1052
1307
|
elif (
|
1053
1308
|
shared_utils.is_windows()
|
@@ -1059,19 +1314,29 @@ class CDPMethods():
|
|
1059
1314
|
if shared_utils.is_windows():
|
1060
1315
|
x = x * width_ratio
|
1061
1316
|
y = y * width_ratio
|
1062
|
-
self.
|
1317
|
+
self.__gui_hover_x_y(x, y, timeframe=timeframe, uc_lock=False)
|
1063
1318
|
return
|
1064
1319
|
self.bring_active_window_to_front()
|
1065
|
-
self.
|
1320
|
+
self.__gui_hover_x_y(x, y, timeframe=timeframe, uc_lock=False)
|
1066
1321
|
|
1067
|
-
def
|
1322
|
+
def gui_hover_element(self, selector, timeframe=0.25):
|
1068
1323
|
self.__slow_mode_pause_if_set()
|
1069
1324
|
x, y = self.get_gui_element_center(selector)
|
1070
1325
|
self.__add_light_pause()
|
1071
|
-
self.
|
1326
|
+
self.__gui_hover_x_y(x, y, timeframe=timeframe)
|
1072
1327
|
self.__slow_mode_pause_if_set()
|
1073
1328
|
self.loop.run_until_complete(self.page.wait())
|
1074
1329
|
|
1330
|
+
def gui_hover_and_click(self, hover_selector, click_selector):
|
1331
|
+
gui_lock = fasteners.InterProcessLock(
|
1332
|
+
constants.MultiBrowser.PYAUTOGUILOCK
|
1333
|
+
)
|
1334
|
+
with gui_lock:
|
1335
|
+
self.gui_hover_element(hover_selector)
|
1336
|
+
time.sleep(0.15)
|
1337
|
+
self.gui_hover_element(click_selector)
|
1338
|
+
self.click(click_selector)
|
1339
|
+
|
1075
1340
|
def internalize_links(self):
|
1076
1341
|
"""All `target="_blank"` links become `target="_self"`.
|
1077
1342
|
This prevents those links from opening in a new tab."""
|
@@ -1079,24 +1344,30 @@ class CDPMethods():
|
|
1079
1344
|
|
1080
1345
|
def is_checked(self, selector):
|
1081
1346
|
"""Return True if checkbox (or radio button) is checked."""
|
1347
|
+
selector = self.__convert_to_css_if_xpath(selector)
|
1082
1348
|
self.find_element(selector, timeout=settings.SMALL_TIMEOUT)
|
1083
1349
|
return self.get_element_attribute(selector, "checked")
|
1084
1350
|
|
1085
1351
|
def is_selected(self, selector):
|
1352
|
+
selector = self.__convert_to_css_if_xpath(selector)
|
1086
1353
|
return self.is_checked(selector)
|
1087
1354
|
|
1088
1355
|
def check_if_unchecked(self, selector):
|
1356
|
+
selector = self.__convert_to_css_if_xpath(selector)
|
1089
1357
|
if not self.is_checked(selector):
|
1090
1358
|
self.click(selector)
|
1091
1359
|
|
1092
1360
|
def select_if_unselected(self, selector):
|
1361
|
+
selector = self.__convert_to_css_if_xpath(selector)
|
1093
1362
|
self.check_if_unchecked(selector)
|
1094
1363
|
|
1095
1364
|
def uncheck_if_checked(self, selector):
|
1365
|
+
selector = self.__convert_to_css_if_xpath(selector)
|
1096
1366
|
if self.is_checked(selector):
|
1097
1367
|
self.click(selector)
|
1098
1368
|
|
1099
1369
|
def unselect_if_selected(self, selector):
|
1370
|
+
selector = self.__convert_to_css_if_xpath(selector)
|
1100
1371
|
self.uncheck_if_checked(selector)
|
1101
1372
|
|
1102
1373
|
def is_element_present(self, selector):
|
@@ -1105,32 +1376,22 @@ class CDPMethods():
|
|
1105
1376
|
return True
|
1106
1377
|
except Exception:
|
1107
1378
|
return False
|
1108
|
-
selector = self.__convert_to_css_if_xpath(selector)
|
1109
|
-
element = self.loop.run_until_complete(
|
1110
|
-
self.page.js_dumps(
|
1111
|
-
"""document.querySelector('%s')"""
|
1112
|
-
% js_utils.escape_quotes_if_needed(re.escape(selector))
|
1113
|
-
)
|
1114
|
-
)
|
1115
|
-
return element is not None
|
1116
1379
|
|
1117
1380
|
def is_element_visible(self, selector):
|
1118
1381
|
selector = self.__convert_to_css_if_xpath(selector)
|
1119
1382
|
element = None
|
1120
1383
|
if ":contains(" not in selector:
|
1121
1384
|
try:
|
1122
|
-
element = self.
|
1123
|
-
self.page.js_dumps(
|
1124
|
-
"""window.getComputedStyle(document.querySelector"""
|
1125
|
-
"""('%s'))"""
|
1126
|
-
% js_utils.escape_quotes_if_needed(re.escape(selector))
|
1127
|
-
)
|
1128
|
-
)
|
1385
|
+
element = self.select(selector, timeout=0.01)
|
1129
1386
|
except Exception:
|
1130
1387
|
return False
|
1131
1388
|
if not element:
|
1132
1389
|
return False
|
1133
|
-
|
1390
|
+
try:
|
1391
|
+
position = element.get_position()
|
1392
|
+
return (position.width != 0 or position.height != 0)
|
1393
|
+
except Exception:
|
1394
|
+
return False
|
1134
1395
|
else:
|
1135
1396
|
with suppress(Exception):
|
1136
1397
|
tag_name = selector.split(":contains(")[0].split(" ")[-1]
|
@@ -1160,9 +1421,66 @@ class CDPMethods():
|
|
1160
1421
|
raise Exception("Element {%s} not found!" % selector)
|
1161
1422
|
return True
|
1162
1423
|
|
1424
|
+
def assert_element_absent(self, selector, timeout=settings.SMALL_TIMEOUT):
|
1425
|
+
start_ms = time.time() * 1000.0
|
1426
|
+
stop_ms = start_ms + (timeout * 1000.0)
|
1427
|
+
for i in range(int(timeout * 10)):
|
1428
|
+
if not self.is_element_present(selector):
|
1429
|
+
return True
|
1430
|
+
now_ms = time.time() * 1000.0
|
1431
|
+
if now_ms >= stop_ms:
|
1432
|
+
break
|
1433
|
+
time.sleep(0.1)
|
1434
|
+
plural = "s"
|
1435
|
+
if timeout == 1:
|
1436
|
+
plural = ""
|
1437
|
+
raise Exception(
|
1438
|
+
"Element {%s} was still present after %s second%s!"
|
1439
|
+
% (selector, timeout, plural)
|
1440
|
+
)
|
1441
|
+
|
1442
|
+
def assert_element_not_visible(
|
1443
|
+
self, selector, timeout=settings.SMALL_TIMEOUT
|
1444
|
+
):
|
1445
|
+
start_ms = time.time() * 1000.0
|
1446
|
+
stop_ms = start_ms + (timeout * 1000.0)
|
1447
|
+
for i in range(int(timeout * 10)):
|
1448
|
+
if not self.is_element_present(selector):
|
1449
|
+
return True
|
1450
|
+
elif not self.is_element_visible(selector):
|
1451
|
+
return True
|
1452
|
+
now_ms = time.time() * 1000.0
|
1453
|
+
if now_ms >= stop_ms:
|
1454
|
+
break
|
1455
|
+
time.sleep(0.1)
|
1456
|
+
plural = "s"
|
1457
|
+
if timeout == 1:
|
1458
|
+
plural = ""
|
1459
|
+
raise Exception(
|
1460
|
+
"Element {%s} was still visible after %s second%s!"
|
1461
|
+
% (selector, timeout, plural)
|
1462
|
+
)
|
1463
|
+
|
1464
|
+
def assert_title(self, title):
|
1465
|
+
expected = title.strip()
|
1466
|
+
actual = self.get_title().strip()
|
1467
|
+
error = (
|
1468
|
+
"Expected page title [%s] does not match the actual title [%s]!"
|
1469
|
+
)
|
1470
|
+
try:
|
1471
|
+
if expected != actual:
|
1472
|
+
raise Exception(error % (expected, actual))
|
1473
|
+
except Exception:
|
1474
|
+
time.sleep(2)
|
1475
|
+
expected = title.strip()
|
1476
|
+
actual = self.get_title().strip()
|
1477
|
+
if expected != actual:
|
1478
|
+
raise Exception(error % (expected, actual))
|
1479
|
+
|
1163
1480
|
def assert_text(
|
1164
1481
|
self, text, selector="html", timeout=settings.SMALL_TIMEOUT
|
1165
1482
|
):
|
1483
|
+
text = text.strip()
|
1166
1484
|
element = None
|
1167
1485
|
try:
|
1168
1486
|
element = self.select(selector, timeout=timeout)
|
@@ -1180,6 +1498,7 @@ class CDPMethods():
|
|
1180
1498
|
def assert_exact_text(
|
1181
1499
|
self, text, selector="html", timeout=settings.SMALL_TIMEOUT
|
1182
1500
|
):
|
1501
|
+
text = text.strip()
|
1183
1502
|
element = None
|
1184
1503
|
try:
|
1185
1504
|
element = self.select(selector, timeout=timeout)
|
seleniumbase/core/sb_driver.py
CHANGED
@@ -198,6 +198,11 @@ class DriverMethods():
|
|
198
198
|
In CDP Mode, the CDP-Driver controls the web browser.
|
199
199
|
The CDP-Driver can be connected while WebDriver isn't.
|
200
200
|
"""
|
201
|
+
if shared_utils.is_windows():
|
202
|
+
return (
|
203
|
+
not hasattr(self.driver, "_is_connected")
|
204
|
+
or self.driver._is_connected
|
205
|
+
)
|
201
206
|
try:
|
202
207
|
self.driver.window_handles
|
203
208
|
return True
|
@@ -238,6 +243,14 @@ class DriverMethods():
|
|
238
243
|
return js_utils.get_user_agent(self.driver, *args, **kwargs)
|
239
244
|
|
240
245
|
def highlight(self, *args, **kwargs):
|
246
|
+
if self.__is_cdp_swap_needed():
|
247
|
+
selector = None
|
248
|
+
if "selector" in kwargs:
|
249
|
+
selector = kwargs["selector"]
|
250
|
+
else:
|
251
|
+
selector = args[0]
|
252
|
+
self.driver.cdp.highlight(selector)
|
253
|
+
return
|
241
254
|
if "scroll" in kwargs:
|
242
255
|
kwargs.pop("scroll")
|
243
256
|
w_args = kwargs.copy()
|
@@ -1592,6 +1592,9 @@ class BaseCase(unittest.TestCase):
|
|
1592
1592
|
def click_link_text(self, link_text, timeout=None):
|
1593
1593
|
"""This method clicks link text on a page."""
|
1594
1594
|
self.__check_scope()
|
1595
|
+
if self.__is_cdp_swap_needed():
|
1596
|
+
self.cdp.find_element(link_text).click()
|
1597
|
+
return
|
1595
1598
|
self.__skip_if_esc()
|
1596
1599
|
if not timeout:
|
1597
1600
|
timeout = settings.SMALL_TIMEOUT
|
@@ -2197,6 +2200,9 @@ class BaseCase(unittest.TestCase):
|
|
2197
2200
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
2198
2201
|
timeout = self.__get_new_timeout(timeout)
|
2199
2202
|
selector, by = self.__recalculate_selector(selector, by)
|
2203
|
+
if self.__is_cdp_swap_needed():
|
2204
|
+
self.cdp.click_visible_elements(selector)
|
2205
|
+
return
|
2200
2206
|
self.wait_for_ready_state_complete()
|
2201
2207
|
if self.__needs_minimum_wait():
|
2202
2208
|
time.sleep(0.12)
|
@@ -2637,6 +2643,9 @@ class BaseCase(unittest.TestCase):
|
|
2637
2643
|
original_selector = selector
|
2638
2644
|
original_by = by
|
2639
2645
|
selector, by = self.__recalculate_selector(selector, by)
|
2646
|
+
if self.__is_cdp_swap_needed():
|
2647
|
+
self.cdp.gui_hover_element(selector)
|
2648
|
+
return
|
2640
2649
|
self.wait_for_element_visible(
|
2641
2650
|
original_selector, by=original_by, timeout=timeout
|
2642
2651
|
)
|
@@ -2679,6 +2688,9 @@ class BaseCase(unittest.TestCase):
|
|
2679
2688
|
click_selector, click_by = self.__recalculate_selector(
|
2680
2689
|
click_selector, click_by
|
2681
2690
|
)
|
2691
|
+
if self.__is_cdp_swap_needed():
|
2692
|
+
self.cdp.gui_hover_and_click(hover_selector, click_selector)
|
2693
|
+
return
|
2682
2694
|
dropdown_element = self.wait_for_element_visible(
|
2683
2695
|
original_selector, by=original_by, timeout=timeout
|
2684
2696
|
)
|
@@ -3105,6 +3117,9 @@ class BaseCase(unittest.TestCase):
|
|
3105
3117
|
timeout = settings.SMALL_TIMEOUT
|
3106
3118
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
3107
3119
|
timeout = self.__get_new_timeout(timeout)
|
3120
|
+
if self.__is_cdp_swap_needed():
|
3121
|
+
self.cdp.select_option_by_text(dropdown_selector, option)
|
3122
|
+
return
|
3108
3123
|
self.__select_option(
|
3109
3124
|
dropdown_selector,
|
3110
3125
|
option,
|
@@ -3419,8 +3434,8 @@ class BaseCase(unittest.TestCase):
|
|
3419
3434
|
if self.__is_cdp_swap_needed():
|
3420
3435
|
return self.cdp.get_gui_element_center(selector)
|
3421
3436
|
element_rect = self.get_gui_element_rect(selector, by=by)
|
3422
|
-
x =
|
3423
|
-
y =
|
3437
|
+
x = element_rect["x"] + (element_rect["width"] / 2.0) + 0.5
|
3438
|
+
y = element_rect["y"] + (element_rect["height"] / 2.0) + 0.5
|
3424
3439
|
return (x, y)
|
3425
3440
|
|
3426
3441
|
def get_window_rect(self):
|
@@ -5959,6 +5974,9 @@ class BaseCase(unittest.TestCase):
|
|
5959
5974
|
scroll - the option to scroll to the element first (Default: True)
|
5960
5975
|
timeout - the time to wait for the element to appear """
|
5961
5976
|
self.__check_scope()
|
5977
|
+
if self.__is_cdp_swap_needed():
|
5978
|
+
self.cdp.highlight(selector)
|
5979
|
+
return
|
5962
5980
|
self._check_browser()
|
5963
5981
|
self.__skip_if_esc()
|
5964
5982
|
if isinstance(selector, WebElement):
|
@@ -7676,6 +7694,9 @@ class BaseCase(unittest.TestCase):
|
|
7676
7694
|
but then the title switches over to the actual page title.
|
7677
7695
|
In Recorder Mode, this assertion is skipped because the Recorder
|
7678
7696
|
changes the page title to the selector of the hovered element."""
|
7697
|
+
if self.__is_cdp_swap_needed():
|
7698
|
+
self.cdp.assert_title(title)
|
7699
|
+
return
|
7679
7700
|
self.wait_for_ready_state_complete()
|
7680
7701
|
expected = title.strip()
|
7681
7702
|
actual = self.get_page_title().strip()
|
@@ -8166,7 +8187,7 @@ class BaseCase(unittest.TestCase):
|
|
8166
8187
|
timeout = self.__get_new_timeout(timeout)
|
8167
8188
|
selector, by = self.__recalculate_selector(selector, by, xp_ok=False)
|
8168
8189
|
if self.__is_cdp_swap_needed():
|
8169
|
-
self.cdp.
|
8190
|
+
self.cdp.set_value(selector, text)
|
8170
8191
|
return
|
8171
8192
|
self.wait_for_ready_state_complete()
|
8172
8193
|
self.wait_for_element_present(selector, by=by, timeout=timeout)
|
@@ -8932,6 +8953,9 @@ class BaseCase(unittest.TestCase):
|
|
8932
8953
|
timeout = self.__get_new_timeout(timeout)
|
8933
8954
|
original_selector = selector
|
8934
8955
|
selector, by = self.__recalculate_selector(selector, by)
|
8956
|
+
if self.__is_cdp_swap_needed():
|
8957
|
+
self.cdp.assert_element_absent(selector)
|
8958
|
+
return True
|
8935
8959
|
return page_actions.wait_for_element_absent(
|
8936
8960
|
self.driver,
|
8937
8961
|
selector,
|
@@ -9966,6 +9990,9 @@ class BaseCase(unittest.TestCase):
|
|
9966
9990
|
timeout = settings.SMALL_TIMEOUT
|
9967
9991
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
9968
9992
|
timeout = self.__get_new_timeout(timeout)
|
9993
|
+
if self.__is_cdp_swap_needed():
|
9994
|
+
self.cdp.find_element(link_text)
|
9995
|
+
return
|
9969
9996
|
self.wait_for_link_text_visible(link_text, timeout=timeout)
|
9970
9997
|
if self.demo_mode:
|
9971
9998
|
a_t = "ASSERT LINK TEXT"
|
@@ -10065,6 +10092,9 @@ class BaseCase(unittest.TestCase):
|
|
10065
10092
|
timeout = settings.SMALL_TIMEOUT
|
10066
10093
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
10067
10094
|
timeout = self.__get_new_timeout(timeout)
|
10095
|
+
if self.__is_cdp_swap_needed():
|
10096
|
+
self.cdp.assert_element_absent(selector)
|
10097
|
+
return True
|
10068
10098
|
self.wait_for_element_absent(selector, by=by, timeout=timeout)
|
10069
10099
|
return True
|
10070
10100
|
|
@@ -10083,6 +10113,9 @@ class BaseCase(unittest.TestCase):
|
|
10083
10113
|
timeout = self.__get_new_timeout(timeout)
|
10084
10114
|
original_selector = selector
|
10085
10115
|
selector, by = self.__recalculate_selector(selector, by)
|
10116
|
+
if self.__is_cdp_swap_needed():
|
10117
|
+
self.cdp.assert_element_not_visible(selector)
|
10118
|
+
return True
|
10086
10119
|
return page_actions.wait_for_element_not_visible(
|
10087
10120
|
self.driver,
|
10088
10121
|
selector,
|
@@ -93,9 +93,9 @@ def is_cdp_swap_needed(driver):
|
|
93
93
|
For other webdriver methods, SeleniumBase will reconnect first.
|
94
94
|
"""
|
95
95
|
return (
|
96
|
-
driver
|
97
|
-
|
98
|
-
|
96
|
+
hasattr(driver, "is_cdp_mode_active")
|
97
|
+
and driver.is_cdp_mode_active()
|
98
|
+
and hasattr(driver, "is_connected")
|
99
99
|
and not driver.is_connected()
|
100
100
|
)
|
101
101
|
|
@@ -5,6 +5,7 @@ import logging
|
|
5
5
|
import pathlib
|
6
6
|
import secrets
|
7
7
|
import typing
|
8
|
+
from contextlib import suppress
|
8
9
|
from . import cdp_util as util
|
9
10
|
from ._contradict import ContraDict
|
10
11
|
from .config import PathLike
|
@@ -768,6 +769,11 @@ class Element:
|
|
768
769
|
Gets the text contents of this element and child nodes, concatenated.
|
769
770
|
Note: This includes text in the form of script content, (text nodes).
|
770
771
|
"""
|
772
|
+
with suppress(Exception):
|
773
|
+
if self.node.node_name.lower() in ["input", "textarea"]:
|
774
|
+
input_node = self.node.shadow_roots[0].children[0].children[0]
|
775
|
+
if input_node:
|
776
|
+
return input_node.node_value
|
771
777
|
text_nodes = util.filter_recurse_all(
|
772
778
|
self.node, lambda n: n.node_type == 3
|
773
779
|
)
|
@@ -776,6 +782,11 @@ class Element:
|
|
776
782
|
@property
|
777
783
|
def text_all(self):
|
778
784
|
"""Same as text(). Kept for backwards compatibility."""
|
785
|
+
with suppress(Exception):
|
786
|
+
if self.node.node_name.lower() in ["input", "textarea"]:
|
787
|
+
input_node = self.node.shadow_roots[0].children[0].children[0]
|
788
|
+
if input_node:
|
789
|
+
return input_node.node_value
|
779
790
|
text_nodes = util.filter_recurse_all(
|
780
791
|
self.node, lambda n: n.node_type == 3
|
781
792
|
)
|
@@ -868,7 +879,11 @@ class Element:
|
|
868
879
|
path.write_bytes(data_bytes)
|
869
880
|
return str(path)
|
870
881
|
|
871
|
-
async def flash_async(
|
882
|
+
async def flash_async(
|
883
|
+
self,
|
884
|
+
duration: typing.Union[float, int] = 0.5,
|
885
|
+
color: typing.Optional[str] = "EE4488",
|
886
|
+
):
|
872
887
|
"""
|
873
888
|
Displays for a short time a red dot on the element.
|
874
889
|
(Only if the element itself is visible)
|
@@ -892,11 +907,12 @@ class Element:
|
|
892
907
|
style = (
|
893
908
|
"position:absolute;z-index:99999999;padding:0;margin:0;"
|
894
909
|
"left:{:.1f}px; top: {:.1f}px; opacity:0.7;"
|
895
|
-
"width:8px;height:8px;border-radius:50%;background:#
|
910
|
+
"width:8px;height:8px;border-radius:50%;background:#{};"
|
896
911
|
"animation:show-pointer-ani {:.2f}s ease 1;"
|
897
912
|
).format(
|
898
913
|
pos.center[0] - 4, # -4 to account for drawn circle itself (w,h)
|
899
914
|
pos.center[1] - 4,
|
915
|
+
color,
|
900
916
|
duration,
|
901
917
|
)
|
902
918
|
script = (
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: seleniumbase
|
3
|
-
Version: 4.32.
|
3
|
+
Version: 4.32.10a1
|
4
4
|
Summary: A complete web automation framework for end-to-end testing.
|
5
5
|
Home-page: https://github.com/seleniumbase/SeleniumBase
|
6
6
|
Author: Michael Mintz
|
@@ -67,7 +67,7 @@ Requires-Dist: certifi>=2024.8.30
|
|
67
67
|
Requires-Dist: exceptiongroup>=1.2.2
|
68
68
|
Requires-Dist: filelock>=3.16.1
|
69
69
|
Requires-Dist: fasteners>=0.19
|
70
|
-
Requires-Dist: mycdp>=1.0
|
70
|
+
Requires-Dist: mycdp>=1.1.0
|
71
71
|
Requires-Dist: pynose>=1.5.3
|
72
72
|
Requires-Dist: platformdirs>=4.3.6
|
73
73
|
Requires-Dist: typing-extensions>=4.12.2
|
@@ -117,9 +117,9 @@ Requires-Dist: pyreadline3>=3.5.3; platform_system == "Windows"
|
|
117
117
|
Requires-Dist: setuptools~=70.2; python_version < "3.10"
|
118
118
|
Requires-Dist: urllib3<2,>=1.26.20; python_version < "3.10"
|
119
119
|
Requires-Dist: websockets~=13.1; python_version < "3.9"
|
120
|
-
Requires-Dist: setuptools>=
|
120
|
+
Requires-Dist: setuptools>=75.5.0; python_version >= "3.10"
|
121
121
|
Requires-Dist: urllib3<2.3.0,>=1.26.20; python_version >= "3.10"
|
122
|
-
Requires-Dist: websockets>=14.
|
122
|
+
Requires-Dist: websockets>=14.1; python_version >= "3.9"
|
123
123
|
Provides-Extra: allure
|
124
124
|
Requires-Dist: allure-pytest>=2.13.5; extra == "allure"
|
125
125
|
Requires-Dist: allure-python-commons>=2.13.5; extra == "allure"
|
@@ -3,7 +3,7 @@ sbase/__main__.py,sha256=G0bVB1-DM4PGwQ1KyOupaWCs4ePbChZNNWuX2htim5U,647
|
|
3
3
|
sbase/steps.py,sha256=bKT_u5bJkKzYWEuAXi9NVVRYYxQRCM1_YJUrNFFRVPY,42865
|
4
4
|
seleniumbase/__init__.py,sha256=OtJh8nGKL4xtZpw8KPqmn7Q6R-86t4cWUDyVF5MbMTo,2398
|
5
5
|
seleniumbase/__main__.py,sha256=dn1p6dgCchmcH1zzTzzQvFwwdQQqnTGH6ULV9m4hv24,654
|
6
|
-
seleniumbase/__version__.py,sha256=
|
6
|
+
seleniumbase/__version__.py,sha256=mB07opo9QE8Mwmi2PHdixrHjmflPaAc2Gc-yYAxT6ps,49
|
7
7
|
seleniumbase/behave/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
8
|
seleniumbase/behave/behave_helper.py,sha256=elkl8P9eLulRAioLstE9baYNM9N_PHBmAOcajX-pH_Y,24198
|
9
9
|
seleniumbase/behave/behave_sb.py,sha256=-hza7Nx2U41mSObYiPMi48v3JlPh3sJO3yzP0kqZ1Gk,59174
|
@@ -36,7 +36,7 @@ seleniumbase/console_scripts/sb_print.py,sha256=tNy-bMDgwHJO3bZxMpmo9weSE8uhbH0C
|
|
36
36
|
seleniumbase/console_scripts/sb_recorder.py,sha256=1oAA4wFzVboNhIFDwJLD3jgy9RuoavywKQG7R67bNZE,10908
|
37
37
|
seleniumbase/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
38
38
|
seleniumbase/core/application_manager.py,sha256=e_0sjtI8cjY5BNyZj1QBR0j6_oCScxGmSXYEpcYwuZE,576
|
39
|
-
seleniumbase/core/browser_launcher.py,sha256=
|
39
|
+
seleniumbase/core/browser_launcher.py,sha256=WjW--f7w0hUc8Y86tsUen4s2-bh8aXlhd3ad2G2Ws1Q,219040
|
40
40
|
seleniumbase/core/capabilities_parser.py,sha256=meIS2uHapTCq2ldfNAToC7r0cKmZDRXuYNKExM1GHDY,6038
|
41
41
|
seleniumbase/core/colored_traceback.py,sha256=DrRWfg7XEnKcgY59Xj7Jdk09H-XqHYBSUpB-DiZt6iY,2020
|
42
42
|
seleniumbase/core/create_db_tables.sql,sha256=VWPtrdiW_HQ6yETHjqTu-VIrTwvd8I8o1NfBeaVSHpU,972
|
@@ -50,8 +50,8 @@ seleniumbase/core/proxy_helper.py,sha256=cXhu8ErK9Vjdm82RMaQj7hEq_yUWizSp6LyiD50
|
|
50
50
|
seleniumbase/core/recorder_helper.py,sha256=fNGjbapXmEsht54x1o6Igk198QdnPxDDnjUOzQxNhNQ,25055
|
51
51
|
seleniumbase/core/report_helper.py,sha256=AIl6Qava2yW1uSzbLpJBlPlYDz0KE-rVhogh8hsGWBo,12201
|
52
52
|
seleniumbase/core/s3_manager.py,sha256=bkeI8I4y19ebWuQG1oEZV5qJbotC6eN8vin31OCNWJk,3521
|
53
|
-
seleniumbase/core/sb_cdp.py,sha256=
|
54
|
-
seleniumbase/core/sb_driver.py,sha256
|
53
|
+
seleniumbase/core/sb_cdp.py,sha256=IwK8KeDdO1vCwzqocbok7hWDFY6qOf-aB_tL_WMVMSE,59423
|
54
|
+
seleniumbase/core/sb_driver.py,sha256=Yd9BpjnOUuZqYRGmsERVKc1W-e8qwTt7SAytLatkXPA,12070
|
55
55
|
seleniumbase/core/session_helper.py,sha256=s9zD3PVZEWVzG2h81cCUskbNWLfdjC_LwwQjKptHCak,558
|
56
56
|
seleniumbase/core/settings_parser.py,sha256=KokVXpCiGZhJ-D4Bo-hizPz5r-iefzWoiTANu9zNaq4,7504
|
57
57
|
seleniumbase/core/style_sheet.py,sha256=tPpJ1xl6Kuw425Z-3Y0OgVRLGXk_ciBDREZjXk_NuPE,11395
|
@@ -65,14 +65,14 @@ seleniumbase/extensions/disable_csp.zip,sha256=YMifIIgEBiLrEFrS1sfW4Exh4br1V4oK1
|
|
65
65
|
seleniumbase/extensions/recorder.zip,sha256=OOyzF-Ize2cSRu1CqhzSAq5vusI9hqLLd2OIApUHesI,11918
|
66
66
|
seleniumbase/extensions/sbase_ext.zip,sha256=3s1N8zrVaMz8RQEOIoBzC3KDjtmHwVZRvVsX25Odr_s,8175
|
67
67
|
seleniumbase/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
68
|
-
seleniumbase/fixtures/base_case.py,sha256=
|
68
|
+
seleniumbase/fixtures/base_case.py,sha256=vzgC_qp8nT1-6i7UMLB8KMiqrAyJuvw61oQJDLk0EdU,712816
|
69
69
|
seleniumbase/fixtures/constants.py,sha256=XYYMpB-ZDI756LvfhSK9RxdqQ_qO9fJVXgBqBYlQNkk,13609
|
70
70
|
seleniumbase/fixtures/css_to_xpath.py,sha256=9ouDB1xl4MJ2os6JOgTIAyHKOQfuxtxvXC3O5hSnEKA,1954
|
71
71
|
seleniumbase/fixtures/errors.py,sha256=KyxuEVx_e3MPhVrJfNIa_3ltMpbCFxfy_jxK8RFNTns,555
|
72
72
|
seleniumbase/fixtures/js_utils.py,sha256=5o4CTLcCyd717lJ_atOYcC6kPRiZFx-LJIlixRrP_cE,51061
|
73
73
|
seleniumbase/fixtures/page_actions.py,sha256=fOCb2NB2PpEaE8gpAVu-73VjwLzfwP1R9HsRkix_z6s,66634
|
74
74
|
seleniumbase/fixtures/page_utils.py,sha256=5m7iXpikLs80TJoRO6_gEfXE1AKeQgcH1aFbR8o1C9A,12034
|
75
|
-
seleniumbase/fixtures/shared_utils.py,sha256=
|
75
|
+
seleniumbase/fixtures/shared_utils.py,sha256=MwCrt58YAv_XrfNfYjo_quUTWfYArlnf-aexSZGIyRs,7271
|
76
76
|
seleniumbase/fixtures/unittest_helper.py,sha256=sfZ92rZeBAn_sF_yQ3I6_I7h3lyU5-cV_UMegBNoEm8,1294
|
77
77
|
seleniumbase/fixtures/words.py,sha256=FOA4mAYvl3EPVpBTvgvK6YwCL8BdlRCmed685kEe7Vg,7827
|
78
78
|
seleniumbase/fixtures/xpath_to_css.py,sha256=lML56k656fElXJ4NJF07r35FjctrbgQkXUotNk7A-as,8876
|
@@ -119,7 +119,7 @@ seleniumbase/undetected/cdp_driver/browser.py,sha256=mGmpWuR206yYJoBPTNslru8CbEp
|
|
119
119
|
seleniumbase/undetected/cdp_driver/cdp_util.py,sha256=Erfb62fzpvGr0QIIJOiqvGkyoyBakHOIwgbrQ7dqUgM,16625
|
120
120
|
seleniumbase/undetected/cdp_driver/config.py,sha256=Rjvde7V-XJ0ihZdTmOmHEVWSuDWm3SprQ3njg8SN3Go,12087
|
121
121
|
seleniumbase/undetected/cdp_driver/connection.py,sha256=sOTUGjbUqKA2hPvDcRCdqw1VQjVGJs7mbgVvzS7ldtE,23360
|
122
|
-
seleniumbase/undetected/cdp_driver/element.py,sha256=
|
122
|
+
seleniumbase/undetected/cdp_driver/element.py,sha256=wEHtuF9oiny7cb4QMMjdtD5Yf1z3WOs2_NHEWcscusM,40289
|
123
123
|
seleniumbase/undetected/cdp_driver/tab.py,sha256=wUNF8GHrbhaUqg57A9ZTYHKhNPjZIcOHwrz3pj1SAg0,50526
|
124
124
|
seleniumbase/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
125
125
|
seleniumbase/utilities/selenium_grid/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -135,9 +135,9 @@ seleniumbase/utilities/selenium_grid/start-grid-hub.bat,sha256=Ftq-GrAKRYH2ssDPr
|
|
135
135
|
seleniumbase/utilities/selenium_grid/start-grid-hub.sh,sha256=KADv0RUHONLL2_I443QFK8PryBpDmKn5Gy0s4o0vDSM,106
|
136
136
|
seleniumbase/utilities/selenium_ide/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
137
137
|
seleniumbase/utilities/selenium_ide/convert_ide.py,sha256=pZFnqEJQEKZPyNFjkLD29s2HPQgCrWW9XJWpCPhWOoM,31691
|
138
|
-
seleniumbase-4.32.
|
139
|
-
seleniumbase-4.32.
|
140
|
-
seleniumbase-4.32.
|
141
|
-
seleniumbase-4.32.
|
142
|
-
seleniumbase-4.32.
|
143
|
-
seleniumbase-4.32.
|
138
|
+
seleniumbase-4.32.10a1.dist-info/LICENSE,sha256=odSYtWibXBnQ1gBg6CnDZ82n8kLF_if5-2nbqnEyD8k,1085
|
139
|
+
seleniumbase-4.32.10a1.dist-info/METADATA,sha256=rXnleRderXsIB3mEybQOL3r-Kes-dpZtM9rCeJ_v_A8,86464
|
140
|
+
seleniumbase-4.32.10a1.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
|
141
|
+
seleniumbase-4.32.10a1.dist-info/entry_points.txt,sha256=CNrh2EKNaHYEhO6pP1RJyVLB99LkDDYX7TnUK8xfjqk,623
|
142
|
+
seleniumbase-4.32.10a1.dist-info/top_level.txt,sha256=4N97aBOQ8ETCnDnokBsWb07lJfTaq3C1ZzYRxvLMxqU,19
|
143
|
+
seleniumbase-4.32.10a1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|