seleniumbase 4.34.15__py3-none-any.whl → 4.35.1__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/console_scripts/sb_mkdir.py +3 -0
- seleniumbase/core/browser_launcher.py +27 -1
- seleniumbase/core/sb_cdp.py +203 -79
- seleniumbase/fixtures/base_case.py +25 -11
- seleniumbase/fixtures/js_utils.py +33 -9
- seleniumbase/plugins/base_plugin.py +12 -15
- seleniumbase/plugins/driver_manager.py +2 -2
- seleniumbase/plugins/pytest_plugin.py +3 -0
- seleniumbase/plugins/sb_manager.py +1 -1
- seleniumbase/plugins/selenium_plugin.py +1 -0
- seleniumbase/undetected/cdp_driver/browser.py +2 -0
- seleniumbase/undetected/cdp_driver/cdp_util.py +104 -2
- seleniumbase/undetected/cdp_driver/config.py +10 -0
- {seleniumbase-4.34.15.dist-info → seleniumbase-4.35.1.dist-info}/METADATA +8 -8
- {seleniumbase-4.34.15.dist-info → seleniumbase-4.35.1.dist-info}/RECORD +20 -20
- {seleniumbase-4.34.15.dist-info → seleniumbase-4.35.1.dist-info}/LICENSE +0 -0
- {seleniumbase-4.34.15.dist-info → seleniumbase-4.35.1.dist-info}/WHEEL +0 -0
- {seleniumbase-4.34.15.dist-info → seleniumbase-4.35.1.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.34.15.dist-info → seleniumbase-4.35.1.dist-info}/top_level.txt +0 -0
seleniumbase/__version__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
# seleniumbase package
|
2
|
-
__version__ = "4.
|
2
|
+
__version__ = "4.35.1"
|
@@ -631,10 +631,13 @@ def main():
|
|
631
631
|
data = []
|
632
632
|
data.append("from seleniumbase import BaseCase")
|
633
633
|
data.append("from .google_objects import HomePage, ResultsPage")
|
634
|
+
data.append('BaseCase.main(__name__, __file__, "--uc")')
|
634
635
|
data.append("")
|
635
636
|
data.append("")
|
636
637
|
data.append("class GoogleTests(BaseCase):")
|
637
638
|
data.append(" def test_google_dot_com(self):")
|
639
|
+
data.append(" if not self.undetectable:")
|
640
|
+
data.append(" self.get_new_driver(undetectable=True)")
|
638
641
|
data.append(' self.open("https://google.com/ncr")')
|
639
642
|
data.append(' self.assert_title_contains("Google")')
|
640
643
|
data.append(" self.sleep(0.05)")
|
@@ -718,7 +718,13 @@ def uc_open_with_cdp_mode(driver, url=None):
|
|
718
718
|
cdp.is_selected = CDPM.is_selected
|
719
719
|
cdp.is_element_present = CDPM.is_element_present
|
720
720
|
cdp.is_element_visible = CDPM.is_element_visible
|
721
|
+
cdp.is_text_visible = CDPM.is_text_visible
|
722
|
+
cdp.is_exact_text_visible = CDPM.is_exact_text_visible
|
723
|
+
cdp.wait_for_text = CDPM.wait_for_text
|
724
|
+
cdp.wait_for_text_not_visible = CDPM.wait_for_text_not_visible
|
721
725
|
cdp.wait_for_element_visible = CDPM.wait_for_element_visible
|
726
|
+
cdp.wait_for_element_not_visible = CDPM.wait_for_element_not_visible
|
727
|
+
cdp.wait_for_element_absent = CDPM.wait_for_element_absent
|
722
728
|
cdp.assert_element = CDPM.assert_element
|
723
729
|
cdp.assert_element_visible = CDPM.assert_element_visible
|
724
730
|
cdp.assert_element_present = CDPM.assert_element_present
|
@@ -731,6 +737,7 @@ def uc_open_with_cdp_mode(driver, url=None):
|
|
731
737
|
cdp.assert_url_contains = CDPM.assert_url_contains
|
732
738
|
cdp.assert_text = CDPM.assert_text
|
733
739
|
cdp.assert_exact_text = CDPM.assert_exact_text
|
740
|
+
cdp.assert_text_not_visible = CDPM.assert_text_not_visible
|
734
741
|
cdp.assert_true = CDPM.assert_true
|
735
742
|
cdp.assert_false = CDPM.assert_false
|
736
743
|
cdp.assert_equal = CDPM.assert_equal
|
@@ -1623,9 +1630,19 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
|
|
1623
1630
|
):
|
1624
1631
|
driver.uc_open_with_disconnect(driver.current_url, 3.8)
|
1625
1632
|
with suppress(Exception):
|
1633
|
+
if "--debug" in sys.argv:
|
1634
|
+
if sb_config._saved_cf_tab_count == 1:
|
1635
|
+
print(' <DEBUG> pyautogui.press("\\t")')
|
1636
|
+
else:
|
1637
|
+
print(
|
1638
|
+
' <DEBUG> pyautogui.press("\\t") * %s'
|
1639
|
+
% sb_config._saved_cf_tab_count
|
1640
|
+
)
|
1626
1641
|
for i in range(sb_config._saved_cf_tab_count):
|
1627
1642
|
pyautogui.press("\t")
|
1628
1643
|
time.sleep(0.027)
|
1644
|
+
if "--debug" in sys.argv:
|
1645
|
+
print(' <DEBUG> pyautogui.press(" ")')
|
1629
1646
|
pyautogui.press(" ")
|
1630
1647
|
else:
|
1631
1648
|
driver.disconnect()
|
@@ -2280,6 +2297,7 @@ def _set_chrome_options(
|
|
2280
2297
|
or proxy_string
|
2281
2298
|
):
|
2282
2299
|
chrome_options.add_argument("--ignore-certificate-errors")
|
2300
|
+
chrome_options.add_argument("--ignore-ssl-errors=yes")
|
2283
2301
|
if not enable_ws:
|
2284
2302
|
chrome_options.add_argument("--disable-web-security")
|
2285
2303
|
if (
|
@@ -2304,7 +2322,14 @@ def _set_chrome_options(
|
|
2304
2322
|
and not enable_3d_apis
|
2305
2323
|
):
|
2306
2324
|
chrome_options.add_argument("--disable-gpu")
|
2307
|
-
if
|
2325
|
+
if (
|
2326
|
+
(not IS_LINUX and is_using_uc(undetectable, browser_name))
|
2327
|
+
or (
|
2328
|
+
IS_MAC
|
2329
|
+
and binary_location
|
2330
|
+
and "chrome-headless-shell" in binary_location
|
2331
|
+
)
|
2332
|
+
):
|
2308
2333
|
chrome_options.add_argument("--disable-dev-shm-usage")
|
2309
2334
|
chrome_options.add_argument("--disable-application-cache")
|
2310
2335
|
if IS_LINUX:
|
@@ -4231,6 +4256,7 @@ def get_local_driver(
|
|
4231
4256
|
edge_options.add_argument("--log-level=3")
|
4232
4257
|
edge_options.add_argument("--no-first-run")
|
4233
4258
|
edge_options.add_argument("--ignore-certificate-errors")
|
4259
|
+
edge_options.add_argument("--ignore-ssl-errors=yes")
|
4234
4260
|
if devtools and not headless:
|
4235
4261
|
edge_options.add_argument("--auto-open-devtools-for-tabs")
|
4236
4262
|
edge_options.add_argument("--allow-file-access-from-files")
|
seleniumbase/core/sb_cdp.py
CHANGED
@@ -56,12 +56,16 @@ class CDPMethods():
|
|
56
56
|
element, *args, **kwargs
|
57
57
|
)
|
58
58
|
element.focus = lambda: self.__focus(element)
|
59
|
+
element.gui_click = (
|
60
|
+
lambda *args, **kwargs: self.__gui_click(element, *args, **kwargs)
|
61
|
+
)
|
59
62
|
element.highlight_overlay = lambda: self.__highlight_overlay(element)
|
60
63
|
element.mouse_click = lambda: self.__mouse_click(element)
|
61
64
|
element.mouse_drag = (
|
62
65
|
lambda destination: self.__mouse_drag(element, destination)
|
63
66
|
)
|
64
67
|
element.mouse_move = lambda: self.__mouse_move(element)
|
68
|
+
element.press_keys = lambda text: self.__press_keys(element, text)
|
65
69
|
element.query_selector = (
|
66
70
|
lambda selector: self.__query_selector(element, selector)
|
67
71
|
)
|
@@ -211,7 +215,8 @@ class CDPMethods():
|
|
211
215
|
element = self.__add_sync_methods(element.parent)
|
212
216
|
return self.__add_sync_methods(element)
|
213
217
|
elif (
|
214
|
-
element.parent
|
218
|
+
element.parent
|
219
|
+
and element.parent.parent
|
215
220
|
and tag_name in element.parent.parent.tag_name.lower()
|
216
221
|
and text.strip() in element.parent.parent.text
|
217
222
|
):
|
@@ -272,7 +277,8 @@ class CDPMethods():
|
|
272
277
|
if element not in updated_elements:
|
273
278
|
updated_elements.append(element)
|
274
279
|
elif (
|
275
|
-
element.parent
|
280
|
+
element.parent
|
281
|
+
and element.parent.parent
|
276
282
|
and tag_name in element.parent.parent.tag_name.lower()
|
277
283
|
and text.strip() in element.parent.parent.text
|
278
284
|
):
|
@@ -282,7 +288,7 @@ class CDPMethods():
|
|
282
288
|
return updated_elements
|
283
289
|
|
284
290
|
def select(self, selector, timeout=None):
|
285
|
-
"""Similar to find_element()
|
291
|
+
"""Similar to find_element()."""
|
286
292
|
if not timeout:
|
287
293
|
timeout = settings.SMALL_TIMEOUT
|
288
294
|
self.__add_light_pause()
|
@@ -291,12 +297,25 @@ class CDPMethods():
|
|
291
297
|
tag_name = selector.split(":contains(")[0].split(" ")[-1]
|
292
298
|
text = selector.split(":contains(")[1].split(")")[0][1:-1]
|
293
299
|
with suppress(Exception):
|
300
|
+
new_timeout = timeout
|
301
|
+
if new_timeout < 1:
|
302
|
+
new_timeout = 1
|
294
303
|
self.loop.run_until_complete(
|
295
|
-
self.page.select(tag_name, timeout=
|
304
|
+
self.page.select(tag_name, timeout=new_timeout)
|
296
305
|
)
|
297
|
-
self.loop.run_until_complete(
|
298
|
-
|
299
|
-
|
306
|
+
self.loop.run_until_complete(
|
307
|
+
self.page.find(text, timeout=new_timeout)
|
308
|
+
)
|
309
|
+
elements = self.find_elements_by_text(text, tag_name=tag_name)
|
310
|
+
if not elements:
|
311
|
+
plural = "s"
|
312
|
+
if timeout == 1:
|
313
|
+
plural = ""
|
314
|
+
msg = "\n Element {%s} was not found after %s second%s!"
|
315
|
+
message = msg % (selector, timeout, plural)
|
316
|
+
raise Exception(message)
|
317
|
+
element = self.__add_sync_methods(elements[0])
|
318
|
+
return element
|
300
319
|
failure = False
|
301
320
|
try:
|
302
321
|
element = self.loop.run_until_complete(
|
@@ -307,11 +326,8 @@ class CDPMethods():
|
|
307
326
|
plural = "s"
|
308
327
|
if timeout == 1:
|
309
328
|
plural = ""
|
310
|
-
|
311
|
-
|
312
|
-
timeout,
|
313
|
-
plural,
|
314
|
-
)
|
329
|
+
msg = "\n Element {%s} was not found after %s second%s!"
|
330
|
+
message = msg % (selector, timeout, plural)
|
315
331
|
if failure:
|
316
332
|
raise Exception(message)
|
317
333
|
element = self.__add_sync_methods(element)
|
@@ -423,6 +439,39 @@ class CDPMethods():
|
|
423
439
|
self.loop.run_until_complete(element.focus_async())
|
424
440
|
)
|
425
441
|
|
442
|
+
def __gui_click(self, element, timeframe=None):
|
443
|
+
element.scroll_into_view()
|
444
|
+
self.__add_light_pause()
|
445
|
+
position = element.get_position()
|
446
|
+
x = position.x
|
447
|
+
y = position.y
|
448
|
+
e_width = position.width
|
449
|
+
e_height = position.height
|
450
|
+
# Relative to window
|
451
|
+
element_rect = {"height": e_height, "width": e_width, "x": x, "y": y}
|
452
|
+
window_rect = self.get_window_rect()
|
453
|
+
w_bottom_y = window_rect["y"] + window_rect["height"]
|
454
|
+
viewport_height = window_rect["innerHeight"]
|
455
|
+
x = window_rect["x"] + element_rect["x"]
|
456
|
+
y = w_bottom_y - viewport_height + element_rect["y"]
|
457
|
+
y_scroll_offset = window_rect["pageYOffset"]
|
458
|
+
y = y - y_scroll_offset
|
459
|
+
x = x + window_rect["scrollX"]
|
460
|
+
y = y + window_rect["scrollY"]
|
461
|
+
# Relative to screen
|
462
|
+
element_rect = {"height": e_height, "width": e_width, "x": x, "y": y}
|
463
|
+
e_width = element_rect["width"]
|
464
|
+
e_height = element_rect["height"]
|
465
|
+
e_x = element_rect["x"]
|
466
|
+
e_y = element_rect["y"]
|
467
|
+
x, y = ((e_x + e_width / 2.0) + 0.5), ((e_y + e_height / 2.0) + 0.5)
|
468
|
+
if not timeframe or not isinstance(timeframe, (int, float)):
|
469
|
+
timeframe = 0.25
|
470
|
+
if timeframe > 3:
|
471
|
+
timeframe = 3
|
472
|
+
self.gui_click_x_y(x, y, timeframe=timeframe)
|
473
|
+
return self.loop.run_until_complete(self.page.wait())
|
474
|
+
|
426
475
|
def __highlight_overlay(self, element):
|
427
476
|
return (
|
428
477
|
self.loop.run_until_complete(element.highlight_overlay_async())
|
@@ -445,6 +494,21 @@ class CDPMethods():
|
|
445
494
|
self.loop.run_until_complete(element.mouse_move_async())
|
446
495
|
)
|
447
496
|
|
497
|
+
def __press_keys(self, element, text):
|
498
|
+
element.scroll_into_view()
|
499
|
+
submit = False
|
500
|
+
if text.endswith("\n") or text.endswith("\r"):
|
501
|
+
submit = True
|
502
|
+
text = text[:-1]
|
503
|
+
for key in text:
|
504
|
+
element.send_keys(key)
|
505
|
+
time.sleep(0.044)
|
506
|
+
if submit:
|
507
|
+
element.send_keys("\r\n")
|
508
|
+
time.sleep(0.044)
|
509
|
+
self.__slow_mode_pause_if_set()
|
510
|
+
return self.loop.run_until_complete(self.page.sleep(0.025))
|
511
|
+
|
448
512
|
def __query_selector(self, element, selector):
|
449
513
|
selector = self.__convert_to_css_if_xpath(selector)
|
450
514
|
element2 = self.loop.run_until_complete(
|
@@ -810,7 +874,7 @@ class CDPMethods():
|
|
810
874
|
text = text[:-1] + "\r\n"
|
811
875
|
element.send_keys(text)
|
812
876
|
self.__slow_mode_pause_if_set()
|
813
|
-
self.loop.run_until_complete(self.page.
|
877
|
+
self.loop.run_until_complete(self.page.sleep(0.025))
|
814
878
|
|
815
879
|
def press_keys(self, selector, text, timeout=None):
|
816
880
|
"""Similar to send_keys(), but presses keys at human speed."""
|
@@ -830,7 +894,7 @@ class CDPMethods():
|
|
830
894
|
element.send_keys("\r\n")
|
831
895
|
time.sleep(0.044)
|
832
896
|
self.__slow_mode_pause_if_set()
|
833
|
-
self.loop.run_until_complete(self.page.
|
897
|
+
self.loop.run_until_complete(self.page.sleep(0.025))
|
834
898
|
|
835
899
|
def type(self, selector, text, timeout=None):
|
836
900
|
"""Similar to send_keys(), but clears the text field first."""
|
@@ -845,7 +909,7 @@ class CDPMethods():
|
|
845
909
|
text = text[:-1] + "\r\n"
|
846
910
|
element.send_keys(text)
|
847
911
|
self.__slow_mode_pause_if_set()
|
848
|
-
self.loop.run_until_complete(self.page.
|
912
|
+
self.loop.run_until_complete(self.page.sleep(0.025))
|
849
913
|
|
850
914
|
def set_value(self, selector, text, timeout=None):
|
851
915
|
"""Similar to send_keys(), but clears the text field first."""
|
@@ -883,7 +947,7 @@ class CDPMethods():
|
|
883
947
|
self.__add_light_pause()
|
884
948
|
self.send_keys(selector, "\n")
|
885
949
|
self.__slow_mode_pause_if_set()
|
886
|
-
self.loop.run_until_complete(self.page.
|
950
|
+
self.loop.run_until_complete(self.page.sleep(0.025))
|
887
951
|
|
888
952
|
def evaluate(self, expression):
|
889
953
|
"""Run a JavaScript expression and return the result."""
|
@@ -1323,7 +1387,7 @@ class CDPMethods():
|
|
1323
1387
|
pyautogui.press(key)
|
1324
1388
|
time.sleep(0.044)
|
1325
1389
|
self.__slow_mode_pause_if_set()
|
1326
|
-
self.loop.run_until_complete(self.page.
|
1390
|
+
self.loop.run_until_complete(self.page.sleep(0.025))
|
1327
1391
|
|
1328
1392
|
def gui_press_keys(self, keys):
|
1329
1393
|
self.__install_pyautogui_if_missing()
|
@@ -1338,7 +1402,7 @@ class CDPMethods():
|
|
1338
1402
|
pyautogui.press(key)
|
1339
1403
|
time.sleep(0.044)
|
1340
1404
|
self.__slow_mode_pause_if_set()
|
1341
|
-
self.loop.run_until_complete(self.page.
|
1405
|
+
self.loop.run_until_complete(self.page.sleep(0.025))
|
1342
1406
|
|
1343
1407
|
def gui_write(self, text):
|
1344
1408
|
self.__install_pyautogui_if_missing()
|
@@ -1351,7 +1415,7 @@ class CDPMethods():
|
|
1351
1415
|
self.__make_sure_pyautogui_lock_is_writable()
|
1352
1416
|
pyautogui.write(text)
|
1353
1417
|
self.__slow_mode_pause_if_set()
|
1354
|
-
self.loop.run_until_complete(self.page.
|
1418
|
+
self.loop.run_until_complete(self.page.sleep(0.025))
|
1355
1419
|
|
1356
1420
|
def __gui_click_x_y(self, x, y, timeframe=0.25, uc_lock=False):
|
1357
1421
|
self.__install_pyautogui_if_missing()
|
@@ -1681,59 +1745,93 @@ class CDPMethods():
|
|
1681
1745
|
return True
|
1682
1746
|
return False
|
1683
1747
|
|
1684
|
-
def
|
1685
|
-
|
1686
|
-
|
1748
|
+
def is_text_visible(self, text, selector="body"):
|
1749
|
+
selector = self.__convert_to_css_if_xpath(selector)
|
1750
|
+
text = text.strip()
|
1751
|
+
element = None
|
1687
1752
|
try:
|
1688
|
-
self.
|
1753
|
+
element = self.find_element(selector, timeout=0.1)
|
1689
1754
|
except Exception:
|
1690
|
-
|
1691
|
-
|
1692
|
-
if
|
1693
|
-
return
|
1694
|
-
|
1695
|
-
raise Exception("Element {%s} was not visible!" % selector)
|
1755
|
+
return False
|
1756
|
+
with suppress(Exception):
|
1757
|
+
if text in element.text_all:
|
1758
|
+
return True
|
1759
|
+
return False
|
1696
1760
|
|
1697
|
-
def
|
1698
|
-
|
1761
|
+
def is_exact_text_visible(self, text, selector="body"):
|
1762
|
+
selector = self.__convert_to_css_if_xpath(selector)
|
1763
|
+
text = text.strip()
|
1764
|
+
element = None
|
1765
|
+
try:
|
1766
|
+
element = self.find_element(selector, timeout=0.1)
|
1767
|
+
except Exception:
|
1768
|
+
return False
|
1769
|
+
with suppress(Exception):
|
1770
|
+
if text == element.text_all.strip():
|
1771
|
+
return True
|
1772
|
+
return False
|
1773
|
+
|
1774
|
+
def wait_for_text(self, text, selector="body", timeout=None):
|
1699
1775
|
if not timeout:
|
1700
1776
|
timeout = settings.SMALL_TIMEOUT
|
1777
|
+
start_ms = time.time() * 1000.0
|
1778
|
+
stop_ms = start_ms + (timeout * 1000.0)
|
1779
|
+
text = text.strip()
|
1780
|
+
element = None
|
1701
1781
|
try:
|
1702
|
-
self.
|
1782
|
+
element = self.find_element(selector, timeout=timeout)
|
1703
1783
|
except Exception:
|
1704
|
-
raise Exception("Element {%s}
|
1705
|
-
for i in range(
|
1706
|
-
|
1784
|
+
raise Exception("Element {%s} not found!" % selector)
|
1785
|
+
for i in range(int(timeout * 10)):
|
1786
|
+
with suppress(Exception):
|
1787
|
+
element = self.find_element(selector, timeout=0.1)
|
1788
|
+
if text in element.text_all:
|
1707
1789
|
return True
|
1790
|
+
now_ms = time.time() * 1000.0
|
1791
|
+
if now_ms >= stop_ms:
|
1792
|
+
break
|
1708
1793
|
time.sleep(0.1)
|
1709
|
-
raise Exception(
|
1794
|
+
raise Exception(
|
1795
|
+
"Text {%s} not found in {%s}! Actual text: {%s}"
|
1796
|
+
% (text, selector, element.text_all)
|
1797
|
+
)
|
1710
1798
|
|
1711
|
-
def
|
1712
|
-
"""Same as assert_element()"""
|
1799
|
+
def wait_for_text_not_visible(self, text, selector="body", timeout=None):
|
1713
1800
|
if not timeout:
|
1714
1801
|
timeout = settings.SMALL_TIMEOUT
|
1715
|
-
|
1716
|
-
|
1717
|
-
|
1718
|
-
|
1719
|
-
|
1720
|
-
if self.is_element_visible(selector):
|
1802
|
+
text = text.strip()
|
1803
|
+
start_ms = time.time() * 1000.0
|
1804
|
+
stop_ms = start_ms + (timeout * 1000.0)
|
1805
|
+
for i in range(int(timeout * 10)):
|
1806
|
+
if not self.is_text_visible(text, selector):
|
1721
1807
|
return True
|
1808
|
+
now_ms = time.time() * 1000.0
|
1809
|
+
if now_ms >= stop_ms:
|
1810
|
+
break
|
1722
1811
|
time.sleep(0.1)
|
1723
|
-
|
1812
|
+
plural = "s"
|
1813
|
+
if timeout == 1:
|
1814
|
+
plural = ""
|
1815
|
+
raise Exception(
|
1816
|
+
"Text {%s} in {%s} was still visible after %s second%s!"
|
1817
|
+
% (text, selector, timeout, plural)
|
1818
|
+
)
|
1724
1819
|
|
1725
|
-
def
|
1726
|
-
"""Assert element is present in the DOM. (Visibility NOT required)"""
|
1820
|
+
def wait_for_element_visible(self, selector, timeout=None):
|
1727
1821
|
if not timeout:
|
1728
1822
|
timeout = settings.SMALL_TIMEOUT
|
1729
1823
|
try:
|
1730
1824
|
self.select(selector, timeout=timeout)
|
1731
1825
|
except Exception:
|
1732
1826
|
raise Exception("Element {%s} was not found!" % selector)
|
1733
|
-
|
1827
|
+
for i in range(30):
|
1828
|
+
if self.is_element_visible(selector):
|
1829
|
+
return self.select(selector)
|
1830
|
+
time.sleep(0.1)
|
1831
|
+
raise Exception("Element {%s} was not visible!" % selector)
|
1734
1832
|
|
1735
|
-
def
|
1736
|
-
"""
|
1833
|
+
def wait_for_element_not_visible(self, selector, timeout=None):
|
1834
|
+
"""Wait for element to not be visible on page. (May still be in DOM)"""
|
1737
1835
|
if not timeout:
|
1738
1836
|
timeout = settings.SMALL_TIMEOUT
|
1739
1837
|
start_ms = time.time() * 1000.0
|
@@ -1741,6 +1839,8 @@ class CDPMethods():
|
|
1741
1839
|
for i in range(int(timeout * 10)):
|
1742
1840
|
if not self.is_element_present(selector):
|
1743
1841
|
return True
|
1842
|
+
elif not self.is_element_visible(selector):
|
1843
|
+
return True
|
1744
1844
|
now_ms = time.time() * 1000.0
|
1745
1845
|
if now_ms >= stop_ms:
|
1746
1846
|
break
|
@@ -1749,12 +1849,12 @@ class CDPMethods():
|
|
1749
1849
|
if timeout == 1:
|
1750
1850
|
plural = ""
|
1751
1851
|
raise Exception(
|
1752
|
-
"Element {%s} was still
|
1852
|
+
"Element {%s} was still visible after %s second%s!"
|
1753
1853
|
% (selector, timeout, plural)
|
1754
1854
|
)
|
1755
1855
|
|
1756
|
-
def
|
1757
|
-
"""
|
1856
|
+
def wait_for_element_absent(self, selector, timeout=None):
|
1857
|
+
"""Wait for element to not be present in the DOM."""
|
1758
1858
|
if not timeout:
|
1759
1859
|
timeout = settings.SMALL_TIMEOUT
|
1760
1860
|
start_ms = time.time() * 1000.0
|
@@ -1762,8 +1862,6 @@ class CDPMethods():
|
|
1762
1862
|
for i in range(int(timeout * 10)):
|
1763
1863
|
if not self.is_element_present(selector):
|
1764
1864
|
return True
|
1765
|
-
elif not self.is_element_visible(selector):
|
1766
|
-
return True
|
1767
1865
|
now_ms = time.time() * 1000.0
|
1768
1866
|
if now_ms >= stop_ms:
|
1769
1867
|
break
|
@@ -1772,10 +1870,49 @@ class CDPMethods():
|
|
1772
1870
|
if timeout == 1:
|
1773
1871
|
plural = ""
|
1774
1872
|
raise Exception(
|
1775
|
-
"Element {%s} was still
|
1873
|
+
"Element {%s} was still present after %s second%s!"
|
1776
1874
|
% (selector, timeout, plural)
|
1777
1875
|
)
|
1778
1876
|
|
1877
|
+
def assert_element(self, selector, timeout=None):
|
1878
|
+
"""Same as assert_element_visible()"""
|
1879
|
+
self.assert_element_visible(selector, timeout=timeout)
|
1880
|
+
return True
|
1881
|
+
|
1882
|
+
def assert_element_visible(self, selector, timeout=None):
|
1883
|
+
"""Same as assert_element()"""
|
1884
|
+
if not timeout:
|
1885
|
+
timeout = settings.SMALL_TIMEOUT
|
1886
|
+
try:
|
1887
|
+
self.select(selector, timeout=timeout)
|
1888
|
+
except Exception:
|
1889
|
+
raise Exception("Element {%s} was not found!" % selector)
|
1890
|
+
for i in range(30):
|
1891
|
+
if self.is_element_visible(selector):
|
1892
|
+
return True
|
1893
|
+
time.sleep(0.1)
|
1894
|
+
raise Exception("Element {%s} was not visible!" % selector)
|
1895
|
+
|
1896
|
+
def assert_element_present(self, selector, timeout=None):
|
1897
|
+
"""Assert element is present in the DOM. (Visibility NOT required)"""
|
1898
|
+
if not timeout:
|
1899
|
+
timeout = settings.SMALL_TIMEOUT
|
1900
|
+
try:
|
1901
|
+
self.select(selector, timeout=timeout)
|
1902
|
+
except Exception:
|
1903
|
+
raise Exception("Element {%s} was not found!" % selector)
|
1904
|
+
return True
|
1905
|
+
|
1906
|
+
def assert_element_absent(self, selector, timeout=None):
|
1907
|
+
"""Assert element is not present in the DOM."""
|
1908
|
+
self.wait_for_element_absent(selector, timeout=timeout)
|
1909
|
+
return True
|
1910
|
+
|
1911
|
+
def assert_element_not_visible(self, selector, timeout=None):
|
1912
|
+
"""Assert element is not visible on page. (May still be in DOM)"""
|
1913
|
+
self.wait_for_element_not_visible(selector, timeout=timeout)
|
1914
|
+
return True
|
1915
|
+
|
1779
1916
|
def assert_element_attribute(self, selector, attribute, value=None):
|
1780
1917
|
attributes = self.get_element_attributes(selector)
|
1781
1918
|
if attribute not in attributes:
|
@@ -1852,29 +1989,9 @@ class CDPMethods():
|
|
1852
1989
|
raise Exception(error % (expected, actual))
|
1853
1990
|
|
1854
1991
|
def assert_text(self, text, selector="body", timeout=None):
|
1855
|
-
|
1856
|
-
|
1857
|
-
|
1858
|
-
stop_ms = start_ms + (timeout * 1000.0)
|
1859
|
-
text = text.strip()
|
1860
|
-
element = None
|
1861
|
-
try:
|
1862
|
-
element = self.find_element(selector, timeout=timeout)
|
1863
|
-
except Exception:
|
1864
|
-
raise Exception("Element {%s} not found!" % selector)
|
1865
|
-
for i in range(int(timeout * 10)):
|
1866
|
-
with suppress(Exception):
|
1867
|
-
element = self.find_element(selector, timeout=0.1)
|
1868
|
-
if text in element.text_all:
|
1869
|
-
return True
|
1870
|
-
now_ms = time.time() * 1000.0
|
1871
|
-
if now_ms >= stop_ms:
|
1872
|
-
break
|
1873
|
-
time.sleep(0.1)
|
1874
|
-
raise Exception(
|
1875
|
-
"Text {%s} not found in {%s}! Actual text: {%s}"
|
1876
|
-
% (text, selector, element.text_all)
|
1877
|
-
)
|
1992
|
+
"""Same as wait_for_text()"""
|
1993
|
+
self.wait_for_text(text, selector=selector, timeout=timeout)
|
1994
|
+
return True
|
1878
1995
|
|
1879
1996
|
def assert_exact_text(self, text, selector="body", timeout=None):
|
1880
1997
|
if not timeout:
|
@@ -1904,6 +2021,13 @@ class CDPMethods():
|
|
1904
2021
|
% (text, element.text_all, selector)
|
1905
2022
|
)
|
1906
2023
|
|
2024
|
+
def assert_text_not_visible(self, text, selector="body", timeout=None):
|
2025
|
+
"""Raises an exception if the text is still visible after timeout."""
|
2026
|
+
self.wait_for_text_not_visible(
|
2027
|
+
text, selector=selector, timeout=timeout
|
2028
|
+
)
|
2029
|
+
return True
|
2030
|
+
|
1907
2031
|
def assert_true(self, expression):
|
1908
2032
|
if not expression:
|
1909
2033
|
raise AssertionError("%s is not true" % expression)
|
@@ -1454,6 +1454,8 @@ class BaseCase(unittest.TestCase):
|
|
1454
1454
|
|
1455
1455
|
def is_text_visible(self, text, selector="body", by="css selector"):
|
1456
1456
|
"""Returns whether the text substring is visible in the element."""
|
1457
|
+
if self.__is_cdp_swap_needed():
|
1458
|
+
return self.cdp.is_text_visible(text, selector)
|
1457
1459
|
self.wait_for_ready_state_complete()
|
1458
1460
|
time.sleep(0.01)
|
1459
1461
|
selector, by = self.__recalculate_selector(selector, by)
|
@@ -1464,6 +1466,8 @@ class BaseCase(unittest.TestCase):
|
|
1464
1466
|
def is_exact_text_visible(self, text, selector="body", by="css selector"):
|
1465
1467
|
"""Returns whether the text is exactly equal to the element text.
|
1466
1468
|
(Leading and trailing whitespace is ignored in the verification.)"""
|
1469
|
+
if self.__is_cdp_swap_needed():
|
1470
|
+
return self.cdp.is_exact_text_visible(text, selector)
|
1467
1471
|
self.wait_for_ready_state_complete()
|
1468
1472
|
time.sleep(0.01)
|
1469
1473
|
selector, by = self.__recalculate_selector(selector, by)
|
@@ -9120,7 +9124,7 @@ class BaseCase(unittest.TestCase):
|
|
9120
9124
|
original_selector = selector
|
9121
9125
|
selector, by = self.__recalculate_selector(selector, by)
|
9122
9126
|
if self.__is_cdp_swap_needed():
|
9123
|
-
self.cdp.
|
9127
|
+
self.cdp.wait_for_element_absent(selector, timeout=timeout)
|
9124
9128
|
return True
|
9125
9129
|
return page_actions.wait_for_element_absent(
|
9126
9130
|
self.driver,
|
@@ -9281,7 +9285,8 @@ class BaseCase(unittest.TestCase):
|
|
9281
9285
|
"bottom_left", "bottom_center", "bottom_right"]
|
9282
9286
|
max_messages: The limit of concurrent messages to display."""
|
9283
9287
|
self.__check_scope()
|
9284
|
-
self.
|
9288
|
+
if not self.__is_cdp_swap_needed():
|
9289
|
+
self._check_browser()
|
9285
9290
|
if not theme:
|
9286
9291
|
theme = "default" # "flat"
|
9287
9292
|
if not location:
|
@@ -9308,7 +9313,8 @@ class BaseCase(unittest.TestCase):
|
|
9308
9313
|
You can also post messages by using =>
|
9309
9314
|
self.execute_script('Messenger().post("My Message")') """
|
9310
9315
|
self.__check_scope()
|
9311
|
-
self.
|
9316
|
+
if not self.__is_cdp_swap_needed():
|
9317
|
+
self._check_browser()
|
9312
9318
|
if style not in ["info", "success", "error"]:
|
9313
9319
|
style = "info"
|
9314
9320
|
if not duration:
|
@@ -9579,7 +9585,7 @@ class BaseCase(unittest.TestCase):
|
|
9579
9585
|
self.assert_elements_present(selector, by=by, timeout=timeout)
|
9580
9586
|
return True
|
9581
9587
|
if self.__is_cdp_swap_needed():
|
9582
|
-
self.cdp.assert_element_present(selector)
|
9588
|
+
self.cdp.assert_element_present(selector, timeout=timeout)
|
9583
9589
|
return True
|
9584
9590
|
if self.__is_shadow_selector(selector):
|
9585
9591
|
self.__assert_shadow_element_present(selector)
|
@@ -9656,7 +9662,7 @@ class BaseCase(unittest.TestCase):
|
|
9656
9662
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
9657
9663
|
timeout = self.__get_new_timeout(timeout)
|
9658
9664
|
if self.__is_cdp_swap_needed():
|
9659
|
-
self.cdp.assert_element(selector)
|
9665
|
+
self.cdp.assert_element(selector, timeout=timeout)
|
9660
9666
|
return True
|
9661
9667
|
if isinstance(selector, list):
|
9662
9668
|
self.assert_elements(selector, by=by, timeout=timeout)
|
@@ -9949,7 +9955,7 @@ class BaseCase(unittest.TestCase):
|
|
9949
9955
|
messenger_post, selector, by
|
9950
9956
|
)
|
9951
9957
|
elif self.__is_cdp_swap_needed():
|
9952
|
-
self.cdp.assert_text(text, selector)
|
9958
|
+
self.cdp.assert_text(text, selector, timeout=timeout)
|
9953
9959
|
return True
|
9954
9960
|
elif not self.is_connected():
|
9955
9961
|
self.connect()
|
@@ -9999,7 +10005,7 @@ class BaseCase(unittest.TestCase):
|
|
9999
10005
|
original_selector = selector
|
10000
10006
|
selector, by = self.__recalculate_selector(selector, by)
|
10001
10007
|
if self.__is_cdp_swap_needed():
|
10002
|
-
self.cdp.assert_exact_text(text, selector)
|
10008
|
+
self.cdp.assert_exact_text(text, selector, timeout=timeout)
|
10003
10009
|
return True
|
10004
10010
|
if self.__is_shadow_selector(selector):
|
10005
10011
|
self.__assert_exact_shadow_text_visible(text, selector, timeout)
|
@@ -10239,6 +10245,9 @@ class BaseCase(unittest.TestCase):
|
|
10239
10245
|
timeout = self.__get_new_timeout(timeout)
|
10240
10246
|
original_selector = selector
|
10241
10247
|
selector, by = self.__recalculate_selector(selector, by)
|
10248
|
+
if self.__is_cdp_swap_needed():
|
10249
|
+
self.cdp.wait_for_element_absent(selector, timeout=timeout)
|
10250
|
+
return True
|
10242
10251
|
return page_actions.wait_for_element_absent(
|
10243
10252
|
self.driver,
|
10244
10253
|
selector,
|
@@ -10261,7 +10270,7 @@ class BaseCase(unittest.TestCase):
|
|
10261
10270
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
10262
10271
|
timeout = self.__get_new_timeout(timeout)
|
10263
10272
|
if self.__is_cdp_swap_needed():
|
10264
|
-
self.cdp.assert_element_absent(selector)
|
10273
|
+
self.cdp.assert_element_absent(selector, timeout=timeout)
|
10265
10274
|
return True
|
10266
10275
|
self.wait_for_element_absent(selector, by=by, timeout=timeout)
|
10267
10276
|
return True
|
@@ -10282,7 +10291,7 @@ class BaseCase(unittest.TestCase):
|
|
10282
10291
|
original_selector = selector
|
10283
10292
|
selector, by = self.__recalculate_selector(selector, by)
|
10284
10293
|
if self.__is_cdp_swap_needed():
|
10285
|
-
self.cdp.
|
10294
|
+
self.cdp.wait_for_element_not_visible(selector, timeout=timeout)
|
10286
10295
|
return True
|
10287
10296
|
return page_actions.wait_for_element_not_visible(
|
10288
10297
|
self.driver,
|
@@ -10304,7 +10313,7 @@ class BaseCase(unittest.TestCase):
|
|
10304
10313
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
10305
10314
|
timeout = self.__get_new_timeout(timeout)
|
10306
10315
|
if self.__is_cdp_swap_needed():
|
10307
|
-
self.cdp.assert_element_not_visible(selector)
|
10316
|
+
self.cdp.assert_element_not_visible(selector, timeout=timeout)
|
10308
10317
|
return True
|
10309
10318
|
self.wait_for_element_not_visible(selector, by=by, timeout=timeout)
|
10310
10319
|
if self.recorder_mode and self.__current_url_is_recordable():
|
@@ -10326,6 +10335,10 @@ class BaseCase(unittest.TestCase):
|
|
10326
10335
|
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
10327
10336
|
timeout = self.__get_new_timeout(timeout)
|
10328
10337
|
selector, by = self.__recalculate_selector(selector, by)
|
10338
|
+
if self.__is_cdp_swap_needed():
|
10339
|
+
return self.cdp.wait_for_text(
|
10340
|
+
text, selector=selector, timeout=timeout
|
10341
|
+
)
|
10329
10342
|
return page_actions.wait_for_text_not_visible(
|
10330
10343
|
self.driver, text, selector, by, timeout
|
10331
10344
|
)
|
@@ -13909,7 +13922,8 @@ class BaseCase(unittest.TestCase):
|
|
13909
13922
|
js_utils.highlight_element_with_js(self.driver, element, loops, o_bs)
|
13910
13923
|
|
13911
13924
|
def __highlight_with_jquery(self, selector, loops, o_bs):
|
13912
|
-
self.
|
13925
|
+
if not self.__is_cdp_swap_needed():
|
13926
|
+
self.wait_for_ready_state_complete()
|
13913
13927
|
js_utils.highlight_with_jquery(self.driver, selector, loops, o_bs)
|
13914
13928
|
|
13915
13929
|
def __highlight_with_js_2(self, message, selector, o_bs):
|
@@ -585,52 +585,60 @@ def highlight_with_jquery(driver, selector, loops=4, o_bs=""):
|
|
585
585
|
'0px 0px 6px 6px rgba(128, 128, 128, 0.5)');"""
|
586
586
|
% selector
|
587
587
|
)
|
588
|
-
|
588
|
+
with suppress(Exception):
|
589
|
+
safe_execute_script(driver, script)
|
589
590
|
for n in range(loops):
|
590
591
|
script = (
|
591
592
|
"""jQuery('%s').css('box-shadow',
|
592
593
|
'0px 0px 6px 6px rgba(255, 0, 0, 1)');"""
|
593
594
|
% selector
|
594
595
|
)
|
595
|
-
|
596
|
+
with suppress(Exception):
|
597
|
+
execute_script(driver, script)
|
596
598
|
time.sleep(0.0181)
|
597
599
|
script = (
|
598
600
|
"""jQuery('%s').css('box-shadow',
|
599
601
|
'0px 0px 6px 6px rgba(128, 0, 128, 1)');"""
|
600
602
|
% selector
|
601
603
|
)
|
602
|
-
|
604
|
+
with suppress(Exception):
|
605
|
+
execute_script(driver, script)
|
603
606
|
time.sleep(0.0181)
|
604
607
|
script = (
|
605
608
|
"""jQuery('%s').css('box-shadow',
|
606
609
|
'0px 0px 6px 6px rgba(0, 0, 255, 1)');"""
|
607
610
|
% selector
|
608
611
|
)
|
609
|
-
|
612
|
+
with suppress(Exception):
|
613
|
+
execute_script(driver, script)
|
610
614
|
time.sleep(0.0181)
|
611
615
|
script = (
|
612
616
|
"""jQuery('%s').css('box-shadow',
|
613
617
|
'0px 0px 6px 6px rgba(0, 255, 0, 1)');"""
|
614
618
|
% selector
|
615
619
|
)
|
616
|
-
|
620
|
+
with suppress(Exception):
|
621
|
+
execute_script(driver, script)
|
617
622
|
time.sleep(0.0181)
|
618
623
|
script = (
|
619
624
|
"""jQuery('%s').css('box-shadow',
|
620
625
|
'0px 0px 6px 6px rgba(128, 128, 0, 1)');"""
|
621
626
|
% selector
|
622
627
|
)
|
623
|
-
|
628
|
+
with suppress(Exception):
|
629
|
+
execute_script(driver, script)
|
624
630
|
time.sleep(0.0181)
|
625
631
|
script = (
|
626
632
|
"""jQuery('%s').css('box-shadow',
|
627
633
|
'0px 0px 6px 6px rgba(128, 0, 128, 1)');"""
|
628
634
|
% selector
|
629
635
|
)
|
630
|
-
|
636
|
+
with suppress(Exception):
|
637
|
+
execute_script(driver, script)
|
631
638
|
time.sleep(0.0181)
|
632
639
|
script = """jQuery('%s').css('box-shadow', '%s');""" % (selector, o_bs)
|
633
|
-
|
640
|
+
with suppress(Exception):
|
641
|
+
execute_script(driver, script)
|
634
642
|
|
635
643
|
|
636
644
|
def add_css_link(driver, css_link):
|
@@ -924,13 +932,26 @@ def post_message(driver, message, msg_dur=None, style="info"):
|
|
924
932
|
"""hideAfter: %s, hideOnNavigate: true});"""
|
925
933
|
% (message, style, msg_dur)
|
926
934
|
)
|
935
|
+
retry = False
|
927
936
|
try:
|
928
937
|
execute_script(driver, messenger_script)
|
938
|
+
except TypeError as e:
|
939
|
+
if (
|
940
|
+
shared_utils.is_cdp_swap_needed(driver)
|
941
|
+
and "cannot unpack non-iterable" in str(e)
|
942
|
+
):
|
943
|
+
pass
|
944
|
+
else:
|
945
|
+
retry = True
|
929
946
|
except Exception:
|
947
|
+
retry = True
|
948
|
+
if retry:
|
930
949
|
activate_messenger(driver)
|
931
950
|
set_messenger_theme(driver)
|
932
951
|
try:
|
933
952
|
execute_script(driver, messenger_script)
|
953
|
+
except TypeError:
|
954
|
+
pass
|
934
955
|
except Exception:
|
935
956
|
time.sleep(0.17)
|
936
957
|
activate_messenger(driver)
|
@@ -1273,7 +1294,10 @@ def slow_scroll_to_element(driver, element, *args, **kwargs):
|
|
1273
1294
|
scroll_position = execute_script(driver, "return window.scrollY;")
|
1274
1295
|
element_location_y = None
|
1275
1296
|
try:
|
1276
|
-
|
1297
|
+
if shared_utils.is_cdp_swap_needed(driver):
|
1298
|
+
element.get_position().y
|
1299
|
+
else:
|
1300
|
+
element_location_y = element.location["y"]
|
1277
1301
|
except Exception:
|
1278
1302
|
element.location_once_scrolled_into_view
|
1279
1303
|
return
|
@@ -208,7 +208,6 @@ class Base(Plugin):
|
|
208
208
|
self.duration = float(0)
|
209
209
|
self.page_results_list = []
|
210
210
|
self.test_count = 0
|
211
|
-
self.import_error = False
|
212
211
|
log_path = constants.Logs.LATEST + "/"
|
213
212
|
archive_logs = options.archive_logs
|
214
213
|
log_helper.log_folder_setup(log_path, archive_logs)
|
@@ -238,6 +237,7 @@ class Base(Plugin):
|
|
238
237
|
)
|
239
238
|
else:
|
240
239
|
variables = {}
|
240
|
+
test.test.test_id = test.id()
|
241
241
|
test.test.is_nosetest = True
|
242
242
|
test.test.environment = self.options.environment
|
243
243
|
test.test.env = self.options.environment # Add a shortened version
|
@@ -263,17 +263,16 @@ class Base(Plugin):
|
|
263
263
|
)
|
264
264
|
log_helper.clear_empty_logs()
|
265
265
|
if self.report_on:
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
)
|
266
|
+
report_helper.add_bad_page_log_file(self.page_results_list)
|
267
|
+
report_log_path = report_helper.archive_new_report_logs()
|
268
|
+
report_helper.build_report(
|
269
|
+
report_log_path,
|
270
|
+
self.page_results_list,
|
271
|
+
self.successes,
|
272
|
+
self.failures,
|
273
|
+
self.options.browser,
|
274
|
+
self.show_report,
|
275
|
+
)
|
277
276
|
|
278
277
|
def addSuccess(self, test, capt):
|
279
278
|
if self.report_on:
|
@@ -293,9 +292,6 @@ class Base(Plugin):
|
|
293
292
|
"%.2fs" % (float(time.time()) - float(self.start_time))
|
294
293
|
)
|
295
294
|
if test.id() == "nose.failure.Failure.runTest":
|
296
|
-
print(">>> ERROR: Could not locate tests to run!")
|
297
|
-
print(">>> The Test Report WILL NOT be generated!")
|
298
|
-
self.import_error = True
|
299
295
|
return
|
300
296
|
self.failures.append(test.id())
|
301
297
|
self.page_results_list.append(
|
@@ -314,6 +310,7 @@ class Base(Plugin):
|
|
314
310
|
test._log_fail_data()
|
315
311
|
sb_config._excinfo_tb = err
|
316
312
|
log_path = None
|
313
|
+
source = None
|
317
314
|
if hasattr(sb_config, "_test_logpath"):
|
318
315
|
log_path = sb_config._test_logpath
|
319
316
|
if hasattr(sb_config, "_last_page_source"):
|
@@ -10,7 +10,7 @@ Example -->
|
|
10
10
|
```python
|
11
11
|
from seleniumbase import DriverContext
|
12
12
|
|
13
|
-
with DriverContext() as driver:
|
13
|
+
with DriverContext(uc=True) as driver:
|
14
14
|
driver.get("https://google.com/ncr")
|
15
15
|
```
|
16
16
|
|
@@ -30,7 +30,7 @@ Example -->
|
|
30
30
|
```python
|
31
31
|
from seleniumbase import Driver
|
32
32
|
|
33
|
-
driver = Driver()
|
33
|
+
driver = Driver(uc=True)
|
34
34
|
driver.get("https://google.com/ncr")
|
35
35
|
```
|
36
36
|
|
@@ -2496,6 +2496,9 @@ def pytest_unconfigure(config):
|
|
2496
2496
|
"""This runs after all tests have completed with pytest."""
|
2497
2497
|
if "--co" in sys_argv or "--collect-only" in sys_argv:
|
2498
2498
|
return
|
2499
|
+
reporter = config.pluginmanager.get_plugin("terminalreporter")
|
2500
|
+
if not hasattr(reporter, "_sessionstarttime"):
|
2501
|
+
return
|
2499
2502
|
if hasattr(sb_config, "_multithreaded") and sb_config._multithreaded:
|
2500
2503
|
import fasteners
|
2501
2504
|
|
@@ -10,7 +10,7 @@ Example -->
|
|
10
10
|
```python
|
11
11
|
from seleniumbase import SB
|
12
12
|
|
13
|
-
with SB() as sb: # Many args! Eg. SB(browser="edge")
|
13
|
+
with SB(uc=True) as sb: # Many args! Eg. SB(browser="edge")
|
14
14
|
sb.open("https://google.com/ncr")
|
15
15
|
sb.type('[name="q"]', "SeleniumBase on GitHub\n")
|
16
16
|
sb.click('a[href*="github.com/seleniumbase"]')
|
@@ -1309,6 +1309,7 @@ class SeleniumBrowser(Plugin):
|
|
1309
1309
|
test.test.dashboard = False
|
1310
1310
|
test.test._multithreaded = False
|
1311
1311
|
test.test._reuse_session = False
|
1312
|
+
sb_config.recorder_mode = test.test.recorder_mode
|
1312
1313
|
sb_config.no_screenshot = test.test.no_screenshot_after_test
|
1313
1314
|
if test.test.servername != "localhost":
|
1314
1315
|
# Using Selenium Grid
|
@@ -265,6 +265,8 @@ class Browser:
|
|
265
265
|
:param new_window: Open new window
|
266
266
|
:return: Page
|
267
267
|
"""
|
268
|
+
if url and ":" not in url:
|
269
|
+
url = "https://" + url
|
268
270
|
if new_tab or new_window:
|
269
271
|
# Create new target using the browser session.
|
270
272
|
target_id = await self.connection.send(
|
@@ -4,6 +4,7 @@ import asyncio
|
|
4
4
|
import fasteners
|
5
5
|
import logging
|
6
6
|
import os
|
7
|
+
import sys
|
7
8
|
import time
|
8
9
|
import types
|
9
10
|
import typing
|
@@ -11,6 +12,7 @@ from contextlib import suppress
|
|
11
12
|
from seleniumbase import config as sb_config
|
12
13
|
from seleniumbase.config import settings
|
13
14
|
from seleniumbase.core import detect_b_ver
|
15
|
+
from seleniumbase.core import proxy_helper
|
14
16
|
from seleniumbase.fixtures import constants
|
15
17
|
from seleniumbase.fixtures import shared_utils
|
16
18
|
from typing import Optional, List, Union, Callable
|
@@ -23,6 +25,7 @@ import mycdp as cdp
|
|
23
25
|
|
24
26
|
logger = logging.getLogger(__name__)
|
25
27
|
IS_LINUX = shared_utils.is_linux()
|
28
|
+
PROXY_DIR_LOCK = proxy_helper.PROXY_DIR_LOCK
|
26
29
|
T = typing.TypeVar("T")
|
27
30
|
|
28
31
|
|
@@ -139,6 +142,85 @@ def __activate_virtual_display_as_needed(
|
|
139
142
|
__activate_standard_virtual_display()
|
140
143
|
|
141
144
|
|
145
|
+
def __set_proxy_filenames():
|
146
|
+
DOWNLOADS_DIR = constants.Files.DOWNLOADS_FOLDER
|
147
|
+
for num in range(1000):
|
148
|
+
PROXY_DIR_PATH = os.path.join(DOWNLOADS_DIR, "proxy_ext_dir_%s" % num)
|
149
|
+
if os.path.exists(PROXY_DIR_PATH):
|
150
|
+
continue
|
151
|
+
proxy_helper.PROXY_DIR_PATH = PROXY_DIR_PATH
|
152
|
+
return
|
153
|
+
# Exceeded upper bound. Use Defaults:
|
154
|
+
PROXY_DIR_PATH = os.path.join(DOWNLOADS_DIR, "proxy_ext_dir")
|
155
|
+
proxy_helper.PROXY_DIR_PATH = PROXY_DIR_PATH
|
156
|
+
|
157
|
+
|
158
|
+
def __add_chrome_ext_dir(extension_dir, dir_path):
|
159
|
+
# Add dir_path to the existing extension_dir
|
160
|
+
option_exists = False
|
161
|
+
if extension_dir:
|
162
|
+
option_exists = True
|
163
|
+
extension_dir = "%s,%s" % (
|
164
|
+
extension_dir, os.path.realpath(dir_path)
|
165
|
+
)
|
166
|
+
if not option_exists:
|
167
|
+
extension_dir = os.path.realpath(dir_path)
|
168
|
+
return extension_dir
|
169
|
+
|
170
|
+
|
171
|
+
def __add_chrome_proxy_extension(
|
172
|
+
extension_dir,
|
173
|
+
proxy_string,
|
174
|
+
proxy_user,
|
175
|
+
proxy_pass,
|
176
|
+
proxy_bypass_list=None,
|
177
|
+
multi_proxy=False,
|
178
|
+
):
|
179
|
+
"""Implementation of https://stackoverflow.com/a/35293284/7058266
|
180
|
+
for https://stackoverflow.com/q/12848327/7058266
|
181
|
+
(Run Selenium on a proxy server that requires authentication.)"""
|
182
|
+
args = " ".join(sys.argv)
|
183
|
+
bypass_list = proxy_bypass_list
|
184
|
+
if (
|
185
|
+
not ("-n" in sys.argv or " -n=" in args or args == "-c")
|
186
|
+
and not multi_proxy
|
187
|
+
):
|
188
|
+
# Single-threaded
|
189
|
+
proxy_dir_lock = fasteners.InterProcessLock(PROXY_DIR_LOCK)
|
190
|
+
with proxy_dir_lock:
|
191
|
+
proxy_helper.create_proxy_ext(
|
192
|
+
proxy_string,
|
193
|
+
proxy_user,
|
194
|
+
proxy_pass,
|
195
|
+
bypass_list,
|
196
|
+
zip_it=False,
|
197
|
+
)
|
198
|
+
proxy_dir_path = proxy_helper.PROXY_DIR_PATH
|
199
|
+
extension_dir = __add_chrome_ext_dir(
|
200
|
+
extension_dir, proxy_dir_path
|
201
|
+
)
|
202
|
+
else:
|
203
|
+
# Multi-threaded
|
204
|
+
proxy_dir_lock = fasteners.InterProcessLock(PROXY_DIR_LOCK)
|
205
|
+
with proxy_dir_lock:
|
206
|
+
with suppress(Exception):
|
207
|
+
shared_utils.make_writable(PROXY_DIR_LOCK)
|
208
|
+
if multi_proxy:
|
209
|
+
__set_proxy_filenames()
|
210
|
+
if not os.path.exists(proxy_helper.PROXY_DIR_PATH):
|
211
|
+
proxy_helper.create_proxy_ext(
|
212
|
+
proxy_string,
|
213
|
+
proxy_user,
|
214
|
+
proxy_pass,
|
215
|
+
bypass_list,
|
216
|
+
zip_it=False,
|
217
|
+
)
|
218
|
+
extension_dir = __add_chrome_ext_dir(
|
219
|
+
extension_dir, proxy_helper.PROXY_DIR_PATH
|
220
|
+
)
|
221
|
+
return extension_dir
|
222
|
+
|
223
|
+
|
142
224
|
async def start(
|
143
225
|
config: Optional[Config] = None,
|
144
226
|
*,
|
@@ -156,6 +238,8 @@ async def start(
|
|
156
238
|
xvfb: Optional[int] = None, # Use a special virtual display on Linux
|
157
239
|
headed: Optional[bool] = None, # Override default Xvfb mode on Linux
|
158
240
|
expert: Optional[bool] = None, # Open up closed Shadow-root elements
|
241
|
+
proxy: Optional[str] = None, # "host:port" or "user:pass@host:port"
|
242
|
+
extension_dir: Optional[str] = None, # Chrome extension directory
|
159
243
|
**kwargs: Optional[dict],
|
160
244
|
) -> Browser:
|
161
245
|
"""
|
@@ -200,6 +284,18 @@ async def start(
|
|
200
284
|
if IS_LINUX and not headless and not headed and not xvfb:
|
201
285
|
xvfb = True # The default setting on Linux
|
202
286
|
__activate_virtual_display_as_needed(headless, headed, xvfb, xvfb_metrics)
|
287
|
+
if proxy and "@" in str(proxy):
|
288
|
+
user_with_pass = proxy.split("@")[0]
|
289
|
+
if ":" in user_with_pass:
|
290
|
+
proxy_user = user_with_pass.split(":")[0]
|
291
|
+
proxy_pass = user_with_pass.split(":")[1]
|
292
|
+
proxy_string = proxy.split("@")[1]
|
293
|
+
extension_dir = __add_chrome_proxy_extension(
|
294
|
+
extension_dir,
|
295
|
+
proxy_string,
|
296
|
+
proxy_user,
|
297
|
+
proxy_pass,
|
298
|
+
)
|
203
299
|
if not config:
|
204
300
|
config = Config(
|
205
301
|
user_data_dir,
|
@@ -213,13 +309,19 @@ async def start(
|
|
213
309
|
host=host,
|
214
310
|
port=port,
|
215
311
|
expert=expert,
|
312
|
+
proxy=proxy,
|
313
|
+
extension_dir=extension_dir,
|
216
314
|
**kwargs,
|
217
315
|
)
|
316
|
+
driver = None
|
218
317
|
try:
|
219
|
-
|
318
|
+
driver = await Browser.create(config)
|
220
319
|
except Exception:
|
221
320
|
time.sleep(0.15)
|
222
|
-
|
321
|
+
driver = await Browser.create(config)
|
322
|
+
if proxy and "@" in str(proxy):
|
323
|
+
time.sleep(0.11)
|
324
|
+
return driver
|
223
325
|
|
224
326
|
|
225
327
|
async def start_async(*args, **kwargs) -> Browser:
|
@@ -40,6 +40,8 @@ class Config:
|
|
40
40
|
host: str = AUTO,
|
41
41
|
port: int = AUTO,
|
42
42
|
expert: bool = AUTO,
|
43
|
+
proxy: Optional[str] = None,
|
44
|
+
extension_dir: Optional[str] = None,
|
43
45
|
**kwargs: dict,
|
44
46
|
):
|
45
47
|
"""
|
@@ -91,6 +93,8 @@ class Config:
|
|
91
93
|
self.host = host
|
92
94
|
self.port = port
|
93
95
|
self.expert = expert
|
96
|
+
self.proxy = proxy
|
97
|
+
self.extension_dir = extension_dir
|
94
98
|
self._extensions = []
|
95
99
|
# When using posix-ish operating system and running as root,
|
96
100
|
# you must use no_sandbox=True
|
@@ -195,6 +199,12 @@ class Config:
|
|
195
199
|
"--disable-web-security",
|
196
200
|
"--disable-site-isolation-trials",
|
197
201
|
]
|
202
|
+
if self.proxy:
|
203
|
+
args.append("--proxy-server=%s" % self.proxy.split("@")[-1])
|
204
|
+
args.append("--ignore-certificate-errors")
|
205
|
+
args.append("--ignore-ssl-errors=yes")
|
206
|
+
if self.extension_dir:
|
207
|
+
args.append("--load-extension=%s" % self.extension_dir)
|
198
208
|
if self._browser_args:
|
199
209
|
args.extend([arg for arg in self._browser_args if arg not in args])
|
200
210
|
if self.headless:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: seleniumbase
|
3
|
-
Version: 4.
|
3
|
+
Version: 4.35.1
|
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
|
@@ -68,12 +68,12 @@ Requires-Dist: attrs>=25.1.0
|
|
68
68
|
Requires-Dist: certifi>=2025.1.31
|
69
69
|
Requires-Dist: exceptiongroup>=1.2.2
|
70
70
|
Requires-Dist: websockets~=13.1; python_version < "3.9"
|
71
|
-
Requires-Dist: websockets>=
|
71
|
+
Requires-Dist: websockets>=15.0; python_version >= "3.9"
|
72
72
|
Requires-Dist: filelock~=3.16.1; python_version < "3.9"
|
73
73
|
Requires-Dist: filelock>=3.17.0; python_version >= "3.9"
|
74
74
|
Requires-Dist: fasteners>=0.19
|
75
75
|
Requires-Dist: mycdp>=1.1.0
|
76
|
-
Requires-Dist: pynose>=1.5.
|
76
|
+
Requires-Dist: pynose>=1.5.4
|
77
77
|
Requires-Dist: platformdirs>=4.3.6
|
78
78
|
Requires-Dist: typing-extensions>=4.12.2
|
79
79
|
Requires-Dist: sbvirtualdisplay>=1.4.0
|
@@ -99,12 +99,12 @@ Requires-Dist: sniffio==1.3.1
|
|
99
99
|
Requires-Dist: h11==0.14.0
|
100
100
|
Requires-Dist: outcome==1.3.0.post0
|
101
101
|
Requires-Dist: trio==0.27.0; python_version < "3.9"
|
102
|
-
Requires-Dist: trio==0.
|
103
|
-
Requires-Dist: trio-websocket==0.
|
102
|
+
Requires-Dist: trio==0.29.0; python_version >= "3.9"
|
103
|
+
Requires-Dist: trio-websocket==0.12.1
|
104
104
|
Requires-Dist: wsproto==1.2.0
|
105
105
|
Requires-Dist: websocket-client==1.8.0
|
106
106
|
Requires-Dist: selenium==4.27.1; python_version < "3.9"
|
107
|
-
Requires-Dist: selenium==4.
|
107
|
+
Requires-Dist: selenium==4.29.0; python_version >= "3.9"
|
108
108
|
Requires-Dist: cssselect==1.2.0
|
109
109
|
Requires-Dist: sortedcontainers==2.4.0
|
110
110
|
Requires-Dist: execnet==2.1.1
|
@@ -137,7 +137,7 @@ Requires-Dist: pytest-cov>=5.0.0; python_version < "3.9" and extra == "coverage"
|
|
137
137
|
Requires-Dist: pytest-cov>=6.0.0; python_version >= "3.9" and extra == "coverage"
|
138
138
|
Provides-Extra: flake8
|
139
139
|
Requires-Dist: flake8==5.0.4; python_version < "3.9" and extra == "flake8"
|
140
|
-
Requires-Dist: flake8==7.1.
|
140
|
+
Requires-Dist: flake8==7.1.2; python_version >= "3.9" and extra == "flake8"
|
141
141
|
Requires-Dist: mccabe==0.7.0; extra == "flake8"
|
142
142
|
Requires-Dist: pyflakes==2.5.0; python_version < "3.9" and extra == "flake8"
|
143
143
|
Requires-Dist: pyflakes==3.2.0; python_version >= "3.9" and extra == "flake8"
|
@@ -265,7 +265,7 @@ Dynamic: summary
|
|
265
265
|
```python
|
266
266
|
from seleniumbase import SB
|
267
267
|
|
268
|
-
with SB(test=True) as sb:
|
268
|
+
with SB(test=True, uc=True) as sb:
|
269
269
|
sb.open("https://google.com/ncr")
|
270
270
|
sb.type('[title="Search"]', "SeleniumBase GitHub page\n")
|
271
271
|
sb.click('[href*="github.com/seleniumbase/"]')
|
@@ -3,7 +3,7 @@ sbase/__main__.py,sha256=G0bVB1-DM4PGwQ1KyOupaWCs4ePbChZNNWuX2htim5U,647
|
|
3
3
|
sbase/steps.py,sha256=_WvAjydKqZfTdnZW9LPKkRty-g-lfdUPmLqnZj6ulcs,43013
|
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=Db8lU-34AfPk_0zWgBNe5iBhYA1JOuCwJ1W2-rdR45g,46
|
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=qQF85LoohJBfrPK5ZcPi50v-pWtOrC9qcN1B3Ki_3tY,59401
|
@@ -27,7 +27,7 @@ seleniumbase/console_scripts/sb_caseplans.py,sha256=qlmvjQ49bOBE1Q29fVmabimkVibC
|
|
27
27
|
seleniumbase/console_scripts/sb_commander.py,sha256=exQGKzqRAoGqRmQtDmlmoHnSG9eSy9eh8HVy-tXw6s4,13343
|
28
28
|
seleniumbase/console_scripts/sb_install.py,sha256=RdByOmTQebibRFk5ym-FtFr0Gf91_ZfOsBB2MN5izUc,55524
|
29
29
|
seleniumbase/console_scripts/sb_mkchart.py,sha256=ep9g-9CSIwaOJKVxhB3xjRQpfsuApyN8-Dr129cNXwQ,10941
|
30
|
-
seleniumbase/console_scripts/sb_mkdir.py,sha256=
|
30
|
+
seleniumbase/console_scripts/sb_mkdir.py,sha256=iFN6ZMOgmH_GAvEuvzYltWuYiS3PRFQcL5fJIj1yX_Y,30897
|
31
31
|
seleniumbase/console_scripts/sb_mkfile.py,sha256=OWYd4yFccmjrd-gNn1t1una-HDRU2_N2-r4Tg3nHsj0,17744
|
32
32
|
seleniumbase/console_scripts/sb_mkpres.py,sha256=EWFRVacjYTX49y-fEiYTZacM9_01IxuuaO4nMjHrIGo,11015
|
33
33
|
seleniumbase/console_scripts/sb_mkrec.py,sha256=PrizjTmyrROYPO0yDm-zQS3QSfsZNeAmcJKKUvfgLhc,11966
|
@@ -36,7 +36,7 @@ seleniumbase/console_scripts/sb_print.py,sha256=tNy-bMDgwHJO3bZxMpmo9weSE8uhbH0C
|
|
36
36
|
seleniumbase/console_scripts/sb_recorder.py,sha256=fnHb5-kh11Hit-E9Ha-e4QXzqLcZvtij6mb5qNd4B1Q,11032
|
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=jUDL2RlOXnSDUwhQuZekgGisY11hhmMU-ftFVyM-afs,236519
|
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,7 +50,7 @@ seleniumbase/core/proxy_helper.py,sha256=4VkpMwavz0fx8wcOqJ_jyBT0HIXwcxmAcpd1gjJ
|
|
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=
|
53
|
+
seleniumbase/core/sb_cdp.py,sha256=rfMcBNGY90qfusHyTJzexWk6wHv9GTH9klQspgxENHE,81554
|
54
54
|
seleniumbase/core/sb_driver.py,sha256=yvTDRblBzG6bDX7XcLiAA6QcBelSJj_HHL_04lcfeeE,13760
|
55
55
|
seleniumbase/core/session_helper.py,sha256=s9zD3PVZEWVzG2h81cCUskbNWLfdjC_LwwQjKptHCak,558
|
56
56
|
seleniumbase/core/settings_parser.py,sha256=gqVohHVlE_5L5Cqe2L24uYrRzvoK-saX8E_Df7_-_3I,7609
|
@@ -65,11 +65,11 @@ seleniumbase/extensions/disable_csp.zip,sha256=5RvomXnm2PdivUVcxTV6jfvD8WhTEsQYH
|
|
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=ncejN3q7m6_GHQTASuy4LHkeeCn829RRZN4lRB0-MkA,722341
|
69
69
|
seleniumbase/fixtures/constants.py,sha256=WMrItuNyKq3XVJ64NluLIRc4gJCxDw8K8qXED0b9S2w,13752
|
70
70
|
seleniumbase/fixtures/css_to_xpath.py,sha256=9ouDB1xl4MJ2os6JOgTIAyHKOQfuxtxvXC3O5hSnEKA,1954
|
71
71
|
seleniumbase/fixtures/errors.py,sha256=KyxuEVx_e3MPhVrJfNIa_3ltMpbCFxfy_jxK8RFNTns,555
|
72
|
-
seleniumbase/fixtures/js_utils.py,sha256=
|
72
|
+
seleniumbase/fixtures/js_utils.py,sha256=Ykt019DFP8S27o8Kai_ihT01qQWo3RqHUeljqOEUdFU,52247
|
73
73
|
seleniumbase/fixtures/page_actions.py,sha256=LPcFSkUvBkxLrOt4laQHHN-NLmqInT41E2vlPiOlLFY,66753
|
74
74
|
seleniumbase/fixtures/page_utils.py,sha256=H1iV8f9vDyEy87DBntyiBXC_tg8HskcebUOAJVn0hxE,12160
|
75
75
|
seleniumbase/fixtures/shared_utils.py,sha256=G6CsE-Adt-GfuZF-71jXWKSIQW7YZPx8FIM24pVd_yI,8368
|
@@ -83,16 +83,16 @@ seleniumbase/js_code/recorder_js.py,sha256=ApFNh6DImuPGmaydvq8OOzGixc0t-xdYSCzfQ
|
|
83
83
|
seleniumbase/masterqa/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
84
84
|
seleniumbase/masterqa/master_qa.py,sha256=jLWmAx32Rnu1IhmvrRt8BbsUIcDW5xYj2ouVozny-Y4,19258
|
85
85
|
seleniumbase/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
86
|
-
seleniumbase/plugins/base_plugin.py,sha256=
|
86
|
+
seleniumbase/plugins/base_plugin.py,sha256=ItLgtaZmu_363iycy8BNX0Do5LyIWGiTMLW6krXM-WQ,14748
|
87
87
|
seleniumbase/plugins/basic_test_info.py,sha256=8ov6n417gPbqqvrlT4zrch7l2XcRt-GF2ny6rR9AMWk,2108
|
88
88
|
seleniumbase/plugins/db_reporting_plugin.py,sha256=En09qUCoojrk9-vbcnsoHdSELoGmag2GDIyu3jTiJas,7331
|
89
|
-
seleniumbase/plugins/driver_manager.py,sha256=
|
89
|
+
seleniumbase/plugins/driver_manager.py,sha256=UqWDnhOFB7GNftaSAqWFsR76vOyeaqMc0JqQKiAw3lU,35877
|
90
90
|
seleniumbase/plugins/page_source.py,sha256=loTnXxOj4kxEukuTZEiGyvKBhY3KDVDMnNlHHheTBDE,1889
|
91
|
-
seleniumbase/plugins/pytest_plugin.py,sha256=
|
91
|
+
seleniumbase/plugins/pytest_plugin.py,sha256=952AIyaH-PdmNksoeXjzhXxoc8Z53yV-WPjlrHhp2OM,108382
|
92
92
|
seleniumbase/plugins/s3_logging_plugin.py,sha256=WDfertQgGOW_SRJpFMaekYD6vBVW9VO62POtXXy2HCM,2319
|
93
|
-
seleniumbase/plugins/sb_manager.py,sha256=
|
93
|
+
seleniumbase/plugins/sb_manager.py,sha256=9hWfSA2DGclgQ2QMJISR8k_rF53NCMGcQbr-K5eh5Dg,56249
|
94
94
|
seleniumbase/plugins/screen_shots.py,sha256=1hrXw-hzuZ1BR6Yh7AyWX2ABnvnP73-RCbwdz958gj4,1127
|
95
|
-
seleniumbase/plugins/selenium_plugin.py,sha256=
|
95
|
+
seleniumbase/plugins/selenium_plugin.py,sha256=y0eNco8T4KgGLProLPHPLw479QH5lRms4wqwOnTgkSc,60081
|
96
96
|
seleniumbase/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
97
97
|
seleniumbase/translate/__init__.py,sha256=N2i5XntTwJZmwr9-qvdX5gC6Rdm5-ClIbnQ8yyPn4Oo,459
|
98
98
|
seleniumbase/translate/chinese.py,sha256=0QhK2eadtsdN4KCvwki1J7jBCe8I4xxWbKzteJKJozY,24698
|
@@ -115,9 +115,9 @@ seleniumbase/undetected/reactor.py,sha256=NropaXcO54pzmDq6quR27qPJxab6636H7LRAaq
|
|
115
115
|
seleniumbase/undetected/webelement.py,sha256=OOpUYbEiOG52KsYYyuDW9tYLdA2SMnukvwQHUdPVn9E,1389
|
116
116
|
seleniumbase/undetected/cdp_driver/__init__.py,sha256=c0TjMwPfVFyoqYOJ7PQ-Jln_L_dpN3ebHyaD-juQoM0,64
|
117
117
|
seleniumbase/undetected/cdp_driver/_contradict.py,sha256=lP4b0h5quAy573ETn_TBbYV889cL1AuPLVInpJ0ZkiU,3183
|
118
|
-
seleniumbase/undetected/cdp_driver/browser.py,sha256=
|
119
|
-
seleniumbase/undetected/cdp_driver/cdp_util.py,sha256=
|
120
|
-
seleniumbase/undetected/cdp_driver/config.py,sha256=
|
118
|
+
seleniumbase/undetected/cdp_driver/browser.py,sha256=ruPunmJKwE67Veh1MjSkZAF5W38FMwc32lHgy1YULho,30261
|
119
|
+
seleniumbase/undetected/cdp_driver/cdp_util.py,sha256=zlYc_oTqtCSjV_T7lzPbFyJlj_78NHMxKkrpleXcfpQ,21374
|
120
|
+
seleniumbase/undetected/cdp_driver/config.py,sha256=t8KV1Vqa5SQRBq3-gjkHHmj9h85AplAM01asO3AWufs,12507
|
121
121
|
seleniumbase/undetected/cdp_driver/connection.py,sha256=sOTUGjbUqKA2hPvDcRCdqw1VQjVGJs7mbgVvzS7ldtE,23360
|
122
122
|
seleniumbase/undetected/cdp_driver/element.py,sha256=FIC6v7OmumLCT-_vIc3H4oju_oBbaLpWJUJIKm2c_q4,40467
|
123
123
|
seleniumbase/undetected/cdp_driver/tab.py,sha256=rcASsWY_mC7L0wXpFSWM5mtojzA47qG9BWEMXe7ZGF8,50906
|
@@ -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.
|
139
|
-
seleniumbase-4.
|
140
|
-
seleniumbase-4.
|
141
|
-
seleniumbase-4.
|
142
|
-
seleniumbase-4.
|
143
|
-
seleniumbase-4.
|
138
|
+
seleniumbase-4.35.1.dist-info/LICENSE,sha256=BRblZsX7HyPUjQmYTiyWr_e9tzWvmR3R4SFclM2R3W0,1085
|
139
|
+
seleniumbase-4.35.1.dist-info/METADATA,sha256=-RJH6DIDAyALXSl9bXjwxbJQQhMoqi0BBjtb_vTVmCI,86530
|
140
|
+
seleniumbase-4.35.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
141
|
+
seleniumbase-4.35.1.dist-info/entry_points.txt,sha256=CNrh2EKNaHYEhO6pP1RJyVLB99LkDDYX7TnUK8xfjqk,623
|
142
|
+
seleniumbase-4.35.1.dist-info/top_level.txt,sha256=4N97aBOQ8ETCnDnokBsWb07lJfTaq3C1ZzYRxvLMxqU,19
|
143
|
+
seleniumbase-4.35.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|