seleniumbase 4.33.5__py3-none-any.whl → 4.33.7__py3-none-any.whl
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.
- seleniumbase/__version__.py +1 -1
- seleniumbase/core/browser_launcher.py +104 -52
- seleniumbase/core/log_helper.py +18 -10
- seleniumbase/core/proxy_helper.py +35 -30
- seleniumbase/core/sb_cdp.py +86 -22
- seleniumbase/core/style_sheet.py +10 -0
- seleniumbase/fixtures/base_case.py +61 -44
- seleniumbase/fixtures/js_utils.py +2 -0
- seleniumbase/fixtures/shared_utils.py +25 -0
- seleniumbase/plugins/pytest_plugin.py +47 -2
- seleniumbase/undetected/cdp_driver/element.py +4 -2
- {seleniumbase-4.33.5.dist-info → seleniumbase-4.33.7.dist-info}/METADATA +2 -2
- {seleniumbase-4.33.5.dist-info → seleniumbase-4.33.7.dist-info}/RECORD +17 -17
- {seleniumbase-4.33.5.dist-info → seleniumbase-4.33.7.dist-info}/LICENSE +0 -0
- {seleniumbase-4.33.5.dist-info → seleniumbase-4.33.7.dist-info}/WHEEL +0 -0
- {seleniumbase-4.33.5.dist-info → seleniumbase-4.33.7.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.33.5.dist-info → seleniumbase-4.33.7.dist-info}/top_level.txt +0 -0
seleniumbase/core/sb_cdp.py
CHANGED
@@ -268,6 +268,7 @@ class CDPMethods():
|
|
268
268
|
if number < 0:
|
269
269
|
number = 0
|
270
270
|
element = elements[number]
|
271
|
+
element.scroll_into_view()
|
271
272
|
element.click()
|
272
273
|
|
273
274
|
def click_nth_visible_element(self, selector, number):
|
@@ -284,6 +285,7 @@ class CDPMethods():
|
|
284
285
|
if number < 0:
|
285
286
|
number = 0
|
286
287
|
element = elements[number]
|
288
|
+
element.scroll_into_view()
|
287
289
|
element.click()
|
288
290
|
|
289
291
|
def click_link(self, link_text):
|
@@ -311,6 +313,13 @@ class CDPMethods():
|
|
311
313
|
return result
|
312
314
|
|
313
315
|
def __flash(self, element, *args, **kwargs):
|
316
|
+
element.scroll_into_view()
|
317
|
+
if len(args) < 3 and "x_offset" not in kwargs:
|
318
|
+
x_offset = self.__get_x_scroll_offset()
|
319
|
+
kwargs["x_offset"] = x_offset
|
320
|
+
if len(args) < 3 and "y_offset" not in kwargs:
|
321
|
+
y_offset = self.__get_y_scroll_offset()
|
322
|
+
kwargs["y_offset"] = y_offset
|
314
323
|
return (
|
315
324
|
self.loop.run_until_complete(
|
316
325
|
element.flash_async(*args, **kwargs)
|
@@ -382,9 +391,9 @@ class CDPMethods():
|
|
382
391
|
)
|
383
392
|
|
384
393
|
def __scroll_into_view(self, element):
|
385
|
-
|
386
|
-
|
387
|
-
|
394
|
+
self.loop.run_until_complete(element.scroll_into_view_async())
|
395
|
+
self.__add_light_pause()
|
396
|
+
return None
|
388
397
|
|
389
398
|
def __select_option(self, element):
|
390
399
|
return (
|
@@ -431,6 +440,18 @@ class CDPMethods():
|
|
431
440
|
self.loop.run_until_complete(element.get_js_attributes_async())
|
432
441
|
)
|
433
442
|
|
443
|
+
def __get_x_scroll_offset(self):
|
444
|
+
x_scroll_offset = self.loop.run_until_complete(
|
445
|
+
self.page.evaluate("window.pageXOffset")
|
446
|
+
)
|
447
|
+
return x_scroll_offset or 0
|
448
|
+
|
449
|
+
def __get_y_scroll_offset(self):
|
450
|
+
y_scroll_offset = self.loop.run_until_complete(
|
451
|
+
self.page.evaluate("window.pageYOffset")
|
452
|
+
)
|
453
|
+
return y_scroll_offset or 0
|
454
|
+
|
434
455
|
def tile_windows(self, windows=None, max_columns=0):
|
435
456
|
"""Tile windows and return the grid of tiled windows."""
|
436
457
|
driver = self.driver
|
@@ -504,7 +525,7 @@ class CDPMethods():
|
|
504
525
|
def click(self, selector, timeout=settings.SMALL_TIMEOUT):
|
505
526
|
self.__slow_mode_pause_if_set()
|
506
527
|
element = self.find_element(selector, timeout=timeout)
|
507
|
-
|
528
|
+
element.scroll_into_view()
|
508
529
|
element.click()
|
509
530
|
self.__slow_mode_pause_if_set()
|
510
531
|
self.loop.run_until_complete(self.page.wait())
|
@@ -518,7 +539,9 @@ class CDPMethods():
|
|
518
539
|
|
519
540
|
def click_if_visible(self, selector):
|
520
541
|
if self.is_element_visible(selector):
|
521
|
-
self.find_element(selector)
|
542
|
+
element = self.find_element(selector)
|
543
|
+
element.scroll_into_view()
|
544
|
+
element.click()
|
522
545
|
self.__slow_mode_pause_if_set()
|
523
546
|
self.loop.run_until_complete(self.page.wait())
|
524
547
|
|
@@ -545,9 +568,10 @@ class CDPMethods():
|
|
545
568
|
except Exception:
|
546
569
|
continue
|
547
570
|
if (width != 0 or height != 0):
|
571
|
+
element.scroll_into_view()
|
548
572
|
element.click()
|
549
573
|
click_count += 1
|
550
|
-
time.sleep(0.
|
574
|
+
time.sleep(0.042)
|
551
575
|
self.__slow_mode_pause_if_set()
|
552
576
|
self.loop.run_until_complete(self.page.wait())
|
553
577
|
except Exception:
|
@@ -557,7 +581,7 @@ class CDPMethods():
|
|
557
581
|
"""(Attempt simulating a mouse click)"""
|
558
582
|
self.__slow_mode_pause_if_set()
|
559
583
|
element = self.find_element(selector, timeout=timeout)
|
560
|
-
|
584
|
+
element.scroll_into_view()
|
561
585
|
element.mouse_click()
|
562
586
|
self.__slow_mode_pause_if_set()
|
563
587
|
self.loop.run_until_complete(self.page.wait())
|
@@ -579,6 +603,7 @@ class CDPMethods():
|
|
579
603
|
|
580
604
|
def select_option_by_text(self, dropdown_selector, option):
|
581
605
|
element = self.find_element(dropdown_selector)
|
606
|
+
element.scroll_into_view()
|
582
607
|
options = element.query_selector_all("option")
|
583
608
|
for found_option in options:
|
584
609
|
if found_option.text.strip() == option.strip():
|
@@ -599,7 +624,10 @@ class CDPMethods():
|
|
599
624
|
"""Paint a quickly-vanishing dot over an element."""
|
600
625
|
selector = self.__convert_to_css_if_xpath(selector)
|
601
626
|
element = self.find_element(selector)
|
602
|
-
element.
|
627
|
+
element.scroll_into_view()
|
628
|
+
x_offset = self.__get_x_scroll_offset()
|
629
|
+
y_offset = self.__get_y_scroll_offset()
|
630
|
+
element.flash(duration, color, x_offset, y_offset)
|
603
631
|
if pause and isinstance(pause, (int, float)):
|
604
632
|
time.sleep(pause)
|
605
633
|
|
@@ -607,17 +635,22 @@ class CDPMethods():
|
|
607
635
|
"""Highlight an element with multi-colors."""
|
608
636
|
selector = self.__convert_to_css_if_xpath(selector)
|
609
637
|
element = self.find_element(selector)
|
610
|
-
element.
|
638
|
+
element.scroll_into_view()
|
639
|
+
x_offset = self.__get_x_scroll_offset()
|
640
|
+
y_offset = self.__get_y_scroll_offset()
|
641
|
+
element.flash(0.46, "44CC88", x_offset, y_offset)
|
611
642
|
time.sleep(0.15)
|
612
|
-
element.flash(0.42, "8844CC")
|
643
|
+
element.flash(0.42, "8844CC", x_offset, y_offset)
|
613
644
|
time.sleep(0.15)
|
614
|
-
element.flash(0.38, "CC8844")
|
645
|
+
element.flash(0.38, "CC8844", x_offset, y_offset)
|
615
646
|
time.sleep(0.15)
|
616
|
-
element.flash(0.30, "44CC88")
|
647
|
+
element.flash(0.30, "44CC88", x_offset, y_offset)
|
617
648
|
time.sleep(0.30)
|
618
649
|
|
619
650
|
def focus(self, selector):
|
620
|
-
self.find_element(selector)
|
651
|
+
element = self.find_element(selector)
|
652
|
+
element.scroll_into_view()
|
653
|
+
element.focus()
|
621
654
|
|
622
655
|
def highlight_overlay(self, selector):
|
623
656
|
self.find_element(selector).highlight_overlay()
|
@@ -646,7 +679,7 @@ class CDPMethods():
|
|
646
679
|
def send_keys(self, selector, text, timeout=settings.SMALL_TIMEOUT):
|
647
680
|
self.__slow_mode_pause_if_set()
|
648
681
|
element = self.select(selector, timeout=timeout)
|
649
|
-
|
682
|
+
element.scroll_into_view()
|
650
683
|
if text.endswith("\n") or text.endswith("\r"):
|
651
684
|
text = text[:-1] + "\r\n"
|
652
685
|
element.send_keys(text)
|
@@ -657,7 +690,7 @@ class CDPMethods():
|
|
657
690
|
"""Similar to send_keys(), but presses keys at human speed."""
|
658
691
|
self.__slow_mode_pause_if_set()
|
659
692
|
element = self.select(selector, timeout=timeout)
|
660
|
-
|
693
|
+
element.scroll_into_view()
|
661
694
|
submit = False
|
662
695
|
if text.endswith("\n") or text.endswith("\r"):
|
663
696
|
submit = True
|
@@ -675,7 +708,7 @@ class CDPMethods():
|
|
675
708
|
"""Similar to send_keys(), but clears the text field first."""
|
676
709
|
self.__slow_mode_pause_if_set()
|
677
710
|
element = self.select(selector, timeout=timeout)
|
678
|
-
|
711
|
+
element.scroll_into_view()
|
679
712
|
with suppress(Exception):
|
680
713
|
element.clear_input()
|
681
714
|
if text.endswith("\n") or text.endswith("\r"):
|
@@ -688,8 +721,8 @@ class CDPMethods():
|
|
688
721
|
"""Similar to send_keys(), but clears the text field first."""
|
689
722
|
self.__slow_mode_pause_if_set()
|
690
723
|
selector = self.__convert_to_css_if_xpath(selector)
|
691
|
-
self.select(selector, timeout=timeout)
|
692
|
-
|
724
|
+
element = self.select(selector, timeout=timeout)
|
725
|
+
element.scroll_into_view()
|
693
726
|
press_enter = False
|
694
727
|
if text.endswith("\n"):
|
695
728
|
text = text[:-1]
|
@@ -1019,6 +1052,10 @@ class CDPMethods():
|
|
1019
1052
|
with suppress(Exception):
|
1020
1053
|
self.loop.run_until_complete(self.page.evaluate(js_code))
|
1021
1054
|
|
1055
|
+
def __make_sure_pyautogui_lock_is_writable(self):
|
1056
|
+
with suppress(Exception):
|
1057
|
+
shared_utils.make_writable(constants.MultiBrowser.PYAUTOGUILOCK)
|
1058
|
+
|
1022
1059
|
def __verify_pyautogui_has_a_headed_browser(self):
|
1023
1060
|
"""PyAutoGUI requires a headed browser so that it can
|
1024
1061
|
focus on the correct element when performing actions."""
|
@@ -1039,6 +1076,8 @@ class CDPMethods():
|
|
1039
1076
|
constants.PipInstall.FINDLOCK
|
1040
1077
|
)
|
1041
1078
|
with pip_find_lock: # Prevent issues with multiple processes
|
1079
|
+
with suppress(Exception):
|
1080
|
+
shared_utils.make_writable(constants.PipInstall.FINDLOCK)
|
1042
1081
|
try:
|
1043
1082
|
import pyautogui
|
1044
1083
|
with suppress(Exception):
|
@@ -1124,6 +1163,7 @@ class CDPMethods():
|
|
1124
1163
|
constants.MultiBrowser.PYAUTOGUILOCK
|
1125
1164
|
)
|
1126
1165
|
with gui_lock:
|
1166
|
+
self.__make_sure_pyautogui_lock_is_writable()
|
1127
1167
|
pyautogui.press(key)
|
1128
1168
|
time.sleep(0.044)
|
1129
1169
|
self.__slow_mode_pause_if_set()
|
@@ -1137,6 +1177,7 @@ class CDPMethods():
|
|
1137
1177
|
constants.MultiBrowser.PYAUTOGUILOCK
|
1138
1178
|
)
|
1139
1179
|
with gui_lock:
|
1180
|
+
self.__make_sure_pyautogui_lock_is_writable()
|
1140
1181
|
for key in keys:
|
1141
1182
|
pyautogui.press(key)
|
1142
1183
|
time.sleep(0.044)
|
@@ -1151,6 +1192,7 @@ class CDPMethods():
|
|
1151
1192
|
constants.MultiBrowser.PYAUTOGUILOCK
|
1152
1193
|
)
|
1153
1194
|
with gui_lock:
|
1195
|
+
self.__make_sure_pyautogui_lock_is_writable()
|
1154
1196
|
pyautogui.write(text)
|
1155
1197
|
self.__slow_mode_pause_if_set()
|
1156
1198
|
self.loop.run_until_complete(self.page.wait())
|
@@ -1171,6 +1213,7 @@ class CDPMethods():
|
|
1171
1213
|
constants.MultiBrowser.PYAUTOGUILOCK
|
1172
1214
|
)
|
1173
1215
|
with gui_lock: # Prevent issues with multiple processes
|
1216
|
+
self.__make_sure_pyautogui_lock_is_writable()
|
1174
1217
|
pyautogui.moveTo(x, y, timeframe, pyautogui.easeOutQuad)
|
1175
1218
|
if timeframe >= 0.25:
|
1176
1219
|
time.sleep(0.056) # Wait if moving at human-speed
|
@@ -1191,6 +1234,7 @@ class CDPMethods():
|
|
1191
1234
|
constants.MultiBrowser.PYAUTOGUILOCK
|
1192
1235
|
)
|
1193
1236
|
with gui_lock: # Prevent issues with multiple processes
|
1237
|
+
self.__make_sure_pyautogui_lock_is_writable()
|
1194
1238
|
self.__install_pyautogui_if_missing()
|
1195
1239
|
import pyautogui
|
1196
1240
|
pyautogui = self.__get_configured_pyautogui(pyautogui)
|
@@ -1408,6 +1452,7 @@ class CDPMethods():
|
|
1408
1452
|
constants.MultiBrowser.PYAUTOGUILOCK
|
1409
1453
|
)
|
1410
1454
|
with gui_lock:
|
1455
|
+
self.__make_sure_pyautogui_lock_is_writable()
|
1411
1456
|
self.bring_active_window_to_front()
|
1412
1457
|
self.gui_hover_element(hover_selector)
|
1413
1458
|
time.sleep(0.15)
|
@@ -1643,17 +1688,24 @@ class CDPMethods():
|
|
1643
1688
|
raise Exception(error % (expected, actual))
|
1644
1689
|
|
1645
1690
|
def assert_text(
|
1646
|
-
self, text, selector="
|
1691
|
+
self, text, selector="body", timeout=settings.SMALL_TIMEOUT
|
1647
1692
|
):
|
1693
|
+
start_ms = time.time() * 1000.0
|
1694
|
+
stop_ms = start_ms + (timeout * 1000.0)
|
1648
1695
|
text = text.strip()
|
1649
1696
|
element = None
|
1650
1697
|
try:
|
1651
1698
|
element = self.find_element(selector, timeout=timeout)
|
1652
1699
|
except Exception:
|
1653
1700
|
raise Exception("Element {%s} not found!" % selector)
|
1654
|
-
for i in range(
|
1701
|
+
for i in range(int(timeout * 10)):
|
1702
|
+
with suppress(Exception):
|
1703
|
+
element = self.find_element(selector, timeout=0.1)
|
1655
1704
|
if text in element.text_all:
|
1656
1705
|
return True
|
1706
|
+
now_ms = time.time() * 1000.0
|
1707
|
+
if now_ms >= stop_ms:
|
1708
|
+
break
|
1657
1709
|
time.sleep(0.1)
|
1658
1710
|
raise Exception(
|
1659
1711
|
"Text {%s} not found in {%s}! Actual text: {%s}"
|
@@ -1661,20 +1713,27 @@ class CDPMethods():
|
|
1661
1713
|
)
|
1662
1714
|
|
1663
1715
|
def assert_exact_text(
|
1664
|
-
self, text, selector="
|
1716
|
+
self, text, selector="body", timeout=settings.SMALL_TIMEOUT
|
1665
1717
|
):
|
1718
|
+
start_ms = time.time() * 1000.0
|
1719
|
+
stop_ms = start_ms + (timeout * 1000.0)
|
1666
1720
|
text = text.strip()
|
1667
1721
|
element = None
|
1668
1722
|
try:
|
1669
1723
|
element = self.select(selector, timeout=timeout)
|
1670
1724
|
except Exception:
|
1671
1725
|
raise Exception("Element {%s} not found!" % selector)
|
1672
|
-
for i in range(
|
1726
|
+
for i in range(int(timeout * 10)):
|
1727
|
+
with suppress(Exception):
|
1728
|
+
element = self.select(selector, timeout=0.1)
|
1673
1729
|
if (
|
1674
1730
|
self.is_element_visible(selector)
|
1675
1731
|
and text.strip() == element.text_all.strip()
|
1676
1732
|
):
|
1677
1733
|
return True
|
1734
|
+
now_ms = time.time() * 1000.0
|
1735
|
+
if now_ms >= stop_ms:
|
1736
|
+
break
|
1678
1737
|
time.sleep(0.1)
|
1679
1738
|
raise Exception(
|
1680
1739
|
"Expected Text {%s}, is not equal to {%s} in {%s}!"
|
@@ -1715,26 +1774,31 @@ class CDPMethods():
|
|
1715
1774
|
with suppress(Exception):
|
1716
1775
|
self.loop.run_until_complete(self.page.evaluate(js_code))
|
1717
1776
|
self.loop.run_until_complete(self.page.wait())
|
1777
|
+
self.__add_light_pause()
|
1718
1778
|
|
1719
1779
|
def scroll_to_top(self):
|
1720
1780
|
js_code = "window.scrollTo(0, 0);"
|
1721
1781
|
with suppress(Exception):
|
1722
1782
|
self.loop.run_until_complete(self.page.evaluate(js_code))
|
1723
1783
|
self.loop.run_until_complete(self.page.wait())
|
1784
|
+
self.__add_light_pause()
|
1724
1785
|
|
1725
1786
|
def scroll_to_bottom(self):
|
1726
1787
|
js_code = "window.scrollTo(0, 10000);"
|
1727
1788
|
with suppress(Exception):
|
1728
1789
|
self.loop.run_until_complete(self.page.evaluate(js_code))
|
1729
1790
|
self.loop.run_until_complete(self.page.wait())
|
1791
|
+
self.__add_light_pause()
|
1730
1792
|
|
1731
1793
|
def scroll_up(self, amount=25):
|
1732
1794
|
self.loop.run_until_complete(self.page.scroll_up(amount))
|
1733
1795
|
self.loop.run_until_complete(self.page.wait())
|
1796
|
+
self.__add_light_pause()
|
1734
1797
|
|
1735
1798
|
def scroll_down(self, amount=25):
|
1736
1799
|
self.loop.run_until_complete(self.page.scroll_down(amount))
|
1737
1800
|
self.loop.run_until_complete(self.page.wait())
|
1801
|
+
self.__add_light_pause()
|
1738
1802
|
|
1739
1803
|
def save_screenshot(self, name, folder=None, selector=None):
|
1740
1804
|
filename = name
|
seleniumbase/core/style_sheet.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import sys
|
2
|
+
import textwrap
|
2
3
|
from seleniumbase.fixtures import constants
|
3
4
|
|
4
5
|
|
@@ -116,6 +117,7 @@ def get_report_style():
|
|
116
117
|
}
|
117
118
|
</style>"""
|
118
119
|
)
|
120
|
+
style = textwrap.dedent(style)
|
119
121
|
Saved.report_style = style
|
120
122
|
return style
|
121
123
|
|
@@ -132,6 +134,7 @@ def get_bt_backdrop_style():
|
|
132
134
|
box-shadow: 0 0 0 88422px rgba(0, 0, 0, 0.42);
|
133
135
|
pointer-events: auto !important;
|
134
136
|
}"""
|
137
|
+
bt_backdrop_style = textwrap.dedent(bt_backdrop_style)
|
135
138
|
Saved.bt_backdrop_style = bt_backdrop_style
|
136
139
|
return bt_backdrop_style
|
137
140
|
|
@@ -150,6 +153,7 @@ def get_dt_backdrop_style():
|
|
150
153
|
button.driver-prev-btn.driver-disabled {
|
151
154
|
visibility: hidden;
|
152
155
|
}"""
|
156
|
+
dt_backdrop_style = textwrap.dedent(dt_backdrop_style)
|
153
157
|
Saved.dt_backdrop_style = dt_backdrop_style
|
154
158
|
return dt_backdrop_style
|
155
159
|
|
@@ -167,6 +171,7 @@ def get_messenger_style():
|
|
167
171
|
box-shadow: 2px 2px 9px 4px rgba(32, 142, 120, 0.28),
|
168
172
|
2px 2px 9px 4px rgba(200, 240, 80, 0.34) !important;
|
169
173
|
}""" % font_family
|
174
|
+
messenger_style = textwrap.dedent(messenger_style)
|
170
175
|
Saved.messenger_style = messenger_style
|
171
176
|
return messenger_style
|
172
177
|
|
@@ -181,6 +186,7 @@ def get_sh_style_test():
|
|
181
186
|
scrollTo: true
|
182
187
|
}
|
183
188
|
});"""
|
189
|
+
sh_style_test = textwrap.dedent(sh_style_test)
|
184
190
|
Saved.sh_style_test = sh_style_test
|
185
191
|
return sh_style_test
|
186
192
|
|
@@ -193,6 +199,7 @@ def get_hops_backdrop_style():
|
|
193
199
|
.hopscotch-bubble-container {
|
194
200
|
font-size: 110%;
|
195
201
|
}"""
|
202
|
+
hops_backdrop_style = textwrap.dedent(hops_backdrop_style)
|
196
203
|
Saved.hops_backdrop_style = hops_backdrop_style
|
197
204
|
return hops_backdrop_style
|
198
205
|
|
@@ -227,6 +234,7 @@ def get_introjs_style():
|
|
227
234
|
box-sizing: content-box;
|
228
235
|
position: absolute;
|
229
236
|
}"""
|
237
|
+
introjs_style = textwrap.dedent(introjs_style)
|
230
238
|
Saved.introjs_style = introjs_style
|
231
239
|
return introjs_style
|
232
240
|
|
@@ -261,6 +269,7 @@ def get_sh_backdrop_style():
|
|
261
269
|
body.shepherd-active {
|
262
270
|
pointer-events: none !important;
|
263
271
|
}"""
|
272
|
+
sh_backdrop_style = textwrap.dedent(sh_backdrop_style)
|
264
273
|
Saved.sh_backdrop_style = sh_backdrop_style
|
265
274
|
return sh_backdrop_style
|
266
275
|
|
@@ -387,5 +396,6 @@ def get_pytest_style():
|
|
387
396
|
.desc.active .sort-icon {
|
388
397
|
border-top: 8px solid #999;
|
389
398
|
}"""
|
399
|
+
pytest_style = textwrap.dedent(pytest_style)
|
390
400
|
Saved.pytest_style = pytest_style
|
391
401
|
return pytest_style
|