seleniumbase 4.33.5__py3-none-any.whl → 4.33.7__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 +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
|