seleniumbase 4.27.4__py3-none-any.whl → 4.28.0__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/__init__.py +3 -0
- seleniumbase/__version__.py +1 -1
- seleniumbase/behave/behave_sb.py +11 -8
- seleniumbase/core/browser_launcher.py +247 -23
- seleniumbase/core/sb_driver.py +58 -5
- seleniumbase/extensions/recorder.zip +0 -0
- seleniumbase/fixtures/base_case.py +113 -25
- seleniumbase/fixtures/constants.py +6 -0
- seleniumbase/fixtures/page_actions.py +37 -3
- seleniumbase/js_code/active_css_js.py +1 -1
- seleniumbase/js_code/recorder_js.py +1 -1
- seleniumbase/plugins/driver_manager.py +48 -31
- seleniumbase/plugins/pytest_plugin.py +11 -8
- seleniumbase/plugins/sb_manager.py +70 -56
- seleniumbase/plugins/selenium_plugin.py +13 -9
- seleniumbase/undetected/__init__.py +5 -0
- {seleniumbase-4.27.4.dist-info → seleniumbase-4.28.0.dist-info}/METADATA +17 -11
- {seleniumbase-4.27.4.dist-info → seleniumbase-4.28.0.dist-info}/RECORD +22 -22
- {seleniumbase-4.27.4.dist-info → seleniumbase-4.28.0.dist-info}/WHEEL +1 -1
- {seleniumbase-4.27.4.dist-info → seleniumbase-4.28.0.dist-info}/LICENSE +0 -0
- {seleniumbase-4.27.4.dist-info → seleniumbase-4.28.0.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.27.4.dist-info → seleniumbase-4.28.0.dist-info}/top_level.txt +0 -0
seleniumbase/__init__.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import collections
|
2
|
+
import os
|
2
3
|
import pdb
|
3
4
|
try:
|
4
5
|
import pdbp # (Pdb+) --- Python Debugger Plus
|
@@ -34,11 +35,13 @@ if sys.version_info[0] < 3 and "pdbp" in locals():
|
|
34
35
|
pdb.DefaultConfig.truncate_long_lines = False
|
35
36
|
pdb.DefaultConfig.sticky_by_default = True
|
36
37
|
colored_traceback.add_hook()
|
38
|
+
os.environ["SE_AVOID_STATS"] = "true" # Disable Selenium Manager stats
|
37
39
|
if sys.version_info >= (3, 7):
|
38
40
|
webdriver.TouchActions = None # Lifeline for past selenium-wire versions
|
39
41
|
if sys.version_info >= (3, 10):
|
40
42
|
collections.Callable = collections.abc.Callable # Lifeline for nosetests
|
41
43
|
del collections # Undo "import collections" / Simplify "dir(seleniumbase)"
|
44
|
+
del os # Undo "import os" / Simplify "dir(seleniumbase)"
|
42
45
|
del sys # Undo "import sys" / Simplify "dir(seleniumbase)"
|
43
46
|
del webdriver # Undo "import webdriver" / Simplify "dir(seleniumbase)"
|
44
47
|
|
seleniumbase/__version__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
# seleniumbase package
|
2
|
-
__version__ = "4.
|
2
|
+
__version__ = "4.28.0"
|
seleniumbase/behave/behave_sb.py
CHANGED
@@ -862,14 +862,17 @@ def get_configured_sb(context):
|
|
862
862
|
and not sb.headless2
|
863
863
|
and not sb.xvfb
|
864
864
|
):
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
865
|
+
if not sb.undetectable:
|
866
|
+
print(
|
867
|
+
'(Linux uses "-D headless" by default. '
|
868
|
+
'To override, use "-D headed" / "-D gui". '
|
869
|
+
'For Xvfb mode instead, use "-D xvfb". '
|
870
|
+
"Or you can hide this info by using"
|
871
|
+
'"-D headless" / "-D headless2" / "-D uc".)'
|
872
|
+
)
|
873
|
+
sb.headless = True
|
874
|
+
else:
|
875
|
+
sb.xvfb = True
|
873
876
|
# Recorder Mode can still optimize scripts in --headless2 mode.
|
874
877
|
if sb.recorder_mode and sb.headless:
|
875
878
|
sb.headless = False
|
@@ -11,6 +11,7 @@ import urllib3
|
|
11
11
|
import warnings
|
12
12
|
from selenium import webdriver
|
13
13
|
from selenium.common.exceptions import ElementClickInterceptedException
|
14
|
+
from selenium.common.exceptions import InvalidSessionIdException
|
14
15
|
from selenium.webdriver.chrome.service import Service as ChromeService
|
15
16
|
from selenium.webdriver.common.options import ArgOptions
|
16
17
|
from selenium.webdriver.common.service import utils as service_utils
|
@@ -28,6 +29,7 @@ from seleniumbase.core import proxy_helper
|
|
28
29
|
from seleniumbase.core import sb_driver
|
29
30
|
from seleniumbase.fixtures import constants
|
30
31
|
from seleniumbase.fixtures import js_utils
|
32
|
+
from seleniumbase.fixtures import page_actions
|
31
33
|
from seleniumbase.fixtures import shared_utils
|
32
34
|
|
33
35
|
urllib3.disable_warnings()
|
@@ -130,9 +132,13 @@ def extend_driver(driver):
|
|
130
132
|
page.assert_element_not_visible = DM.assert_element_not_visible
|
131
133
|
page.assert_text = DM.assert_text
|
132
134
|
page.assert_exact_text = DM.assert_exact_text
|
135
|
+
page.assert_non_empty_text = DM.assert_non_empty_text
|
136
|
+
page.assert_text_not_visible = DM.assert_text_not_visible
|
133
137
|
page.wait_for_element = DM.wait_for_element
|
134
138
|
page.wait_for_text = DM.wait_for_text
|
135
139
|
page.wait_for_exact_text = DM.wait_for_exact_text
|
140
|
+
page.wait_for_non_empty_text = DM.wait_for_non_empty_text
|
141
|
+
page.wait_for_text_not_visible = DM.wait_for_text_not_visible
|
136
142
|
page.wait_for_and_accept_alert = DM.wait_for_and_accept_alert
|
137
143
|
page.wait_for_and_dismiss_alert = DM.wait_for_and_dismiss_alert
|
138
144
|
page.is_element_present = DM.is_element_present
|
@@ -140,12 +146,20 @@ def extend_driver(driver):
|
|
140
146
|
page.is_text_visible = DM.is_text_visible
|
141
147
|
page.is_exact_text_visible = DM.is_exact_text_visible
|
142
148
|
page.is_attribute_present = DM.is_attribute_present
|
149
|
+
page.is_non_empty_text_visible = DM.is_non_empty_text_visible
|
143
150
|
page.get_text = DM.get_text
|
144
151
|
page.find_element = DM.find_element
|
145
152
|
page.find_elements = DM.find_elements
|
146
153
|
page.locator = DM.locator
|
147
154
|
page.get_page_source = DM.get_page_source
|
148
155
|
page.get_title = DM.get_title
|
156
|
+
page.switch_to_default_window = DM.switch_to_default_window
|
157
|
+
page.switch_to_newest_window = DM.switch_to_newest_window
|
158
|
+
page.open_new_window = DM.open_new_window
|
159
|
+
page.open_new_tab = DM.open_new_tab
|
160
|
+
page.switch_to_window = DM.switch_to_window
|
161
|
+
page.switch_to_tab = DM.switch_to_tab
|
162
|
+
page.switch_to_frame = DM.switch_to_frame
|
149
163
|
driver.page = page
|
150
164
|
js = types.SimpleNamespace()
|
151
165
|
js.js_click = DM.js_click
|
@@ -169,12 +183,16 @@ def extend_driver(driver):
|
|
169
183
|
driver.assert_element_not_visible = DM.assert_element_not_visible
|
170
184
|
driver.assert_text = DM.assert_text
|
171
185
|
driver.assert_exact_text = DM.assert_exact_text
|
186
|
+
driver.assert_non_empty_text = DM.assert_non_empty_text
|
187
|
+
driver.assert_text_not_visible = DM.assert_text_not_visible
|
172
188
|
driver.wait_for_element = DM.wait_for_element
|
173
189
|
driver.wait_for_element_visible = DM.wait_for_element_visible
|
174
190
|
driver.wait_for_element_present = DM.wait_for_element_present
|
175
191
|
driver.wait_for_selector = DM.wait_for_selector
|
176
192
|
driver.wait_for_text = DM.wait_for_text
|
177
193
|
driver.wait_for_exact_text = DM.wait_for_exact_text
|
194
|
+
driver.wait_for_non_empty_text = DM.wait_for_non_empty_text
|
195
|
+
driver.wait_for_text_not_visible = DM.wait_for_text_not_visible
|
178
196
|
driver.wait_for_and_accept_alert = DM.wait_for_and_accept_alert
|
179
197
|
driver.wait_for_and_dismiss_alert = DM.wait_for_and_dismiss_alert
|
180
198
|
driver.is_element_present = DM.is_element_present
|
@@ -182,8 +200,10 @@ def extend_driver(driver):
|
|
182
200
|
driver.is_text_visible = DM.is_text_visible
|
183
201
|
driver.is_exact_text_visible = DM.is_exact_text_visible
|
184
202
|
driver.is_attribute_present = DM.is_attribute_present
|
185
|
-
driver.
|
203
|
+
driver.is_non_empty_text_visible = DM.is_non_empty_text_visible
|
204
|
+
driver.is_online = DM.is_online
|
186
205
|
driver.js_click = DM.js_click
|
206
|
+
driver.get_text = DM.get_text
|
187
207
|
driver.get_active_element_css = DM.get_active_element_css
|
188
208
|
driver.get_locale_code = DM.get_locale_code
|
189
209
|
driver.get_origin = DM.get_origin
|
@@ -195,6 +215,12 @@ def extend_driver(driver):
|
|
195
215
|
driver.get_attribute = DM.get_attribute
|
196
216
|
driver.get_page_source = DM.get_page_source
|
197
217
|
driver.get_title = DM.get_title
|
218
|
+
driver.switch_to_default_window = DM.switch_to_default_window
|
219
|
+
driver.switch_to_newest_window = DM.switch_to_newest_window
|
220
|
+
driver.open_new_window = DM.open_new_window
|
221
|
+
driver.open_new_tab = DM.open_new_tab
|
222
|
+
driver.switch_to_window = DM.switch_to_window
|
223
|
+
driver.switch_to_tab = DM.switch_to_tab
|
198
224
|
driver.switch_to_frame = DM.switch_to_frame
|
199
225
|
if hasattr(driver, "proxy"):
|
200
226
|
driver.set_wire_proxy = DM.set_wire_proxy
|
@@ -409,7 +435,7 @@ def uc_open(driver, url):
|
|
409
435
|
if (url.startswith("http:") or url.startswith("https:")):
|
410
436
|
with driver:
|
411
437
|
script = 'window.location.href = "%s";' % url
|
412
|
-
js_utils.call_me_later(driver, script,
|
438
|
+
js_utils.call_me_later(driver, script, 5)
|
413
439
|
else:
|
414
440
|
driver.default_get(url) # The original one
|
415
441
|
return None
|
@@ -440,22 +466,28 @@ def uc_open_with_reconnect(driver, url, reconnect_time=None):
|
|
440
466
|
url = "https://" + url
|
441
467
|
if (url.startswith("http:") or url.startswith("https:")):
|
442
468
|
script = 'window.open("%s","_blank");' % url
|
443
|
-
|
444
|
-
time.sleep(0.
|
469
|
+
driver.execute_script(script)
|
470
|
+
time.sleep(0.05)
|
445
471
|
driver.close()
|
446
472
|
if reconnect_time == "disconnect":
|
447
473
|
driver.disconnect()
|
448
|
-
time.sleep(0.
|
474
|
+
time.sleep(0.008)
|
449
475
|
else:
|
450
476
|
driver.reconnect(reconnect_time)
|
451
|
-
|
477
|
+
time.sleep(0.004)
|
478
|
+
try:
|
479
|
+
driver.switch_to.window(driver.window_handles[-1])
|
480
|
+
except InvalidSessionIdException:
|
481
|
+
time.sleep(0.05)
|
482
|
+
driver.switch_to.window(driver.window_handles[-1])
|
452
483
|
else:
|
453
484
|
driver.default_get(url) # The original one
|
454
485
|
return None
|
455
486
|
|
456
487
|
|
457
|
-
def uc_open_with_disconnect(driver, url):
|
488
|
+
def uc_open_with_disconnect(driver, url, timeout=None):
|
458
489
|
"""Open a url and disconnect chromedriver.
|
490
|
+
Then waits for the duration of the timeout.
|
459
491
|
Note: You can't perform Selenium actions again
|
460
492
|
until after you've called driver.connect()."""
|
461
493
|
if url.startswith("//"):
|
@@ -464,11 +496,16 @@ def uc_open_with_disconnect(driver, url):
|
|
464
496
|
url = "https://" + url
|
465
497
|
if (url.startswith("http:") or url.startswith("https:")):
|
466
498
|
script = 'window.open("%s","_blank");' % url
|
467
|
-
|
468
|
-
time.sleep(0.
|
499
|
+
driver.execute_script(script)
|
500
|
+
time.sleep(0.05)
|
469
501
|
driver.close()
|
470
502
|
driver.disconnect()
|
471
|
-
|
503
|
+
min_timeout = 0.008
|
504
|
+
if timeout and not str(timeout).replace(".", "", 1).isdigit():
|
505
|
+
timeout = min_timeout
|
506
|
+
if not timeout or timeout < min_timeout:
|
507
|
+
timeout = min_timeout
|
508
|
+
time.sleep(timeout)
|
472
509
|
else:
|
473
510
|
driver.default_get(url) # The original one
|
474
511
|
return None
|
@@ -490,7 +527,7 @@ def uc_click(
|
|
490
527
|
pass
|
491
528
|
element = driver.wait_for_selector(selector, by=by, timeout=timeout)
|
492
529
|
tag_name = element.tag_name
|
493
|
-
if not tag_name == "span": #
|
530
|
+
if not tag_name == "span" and not tag_name == "input": # Must be "visible"
|
494
531
|
element = driver.wait_for_element(selector, by=by, timeout=timeout)
|
495
532
|
try:
|
496
533
|
element.uc_click(
|
@@ -509,7 +546,154 @@ def uc_click(
|
|
509
546
|
driver.reconnect(reconnect_time)
|
510
547
|
|
511
548
|
|
512
|
-
def
|
549
|
+
def verify_pyautogui_has_a_headed_browser():
|
550
|
+
"""PyAutoGUI requires a headed browser so that it can
|
551
|
+
focus on the correct element when performing actions."""
|
552
|
+
if sb_config.headless or sb_config.headless2:
|
553
|
+
raise Exception(
|
554
|
+
"PyAutoGUI can't be used in headless mode!"
|
555
|
+
)
|
556
|
+
|
557
|
+
|
558
|
+
def install_pyautogui_if_missing():
|
559
|
+
verify_pyautogui_has_a_headed_browser()
|
560
|
+
pip_find_lock = fasteners.InterProcessLock(
|
561
|
+
constants.PipInstall.FINDLOCK
|
562
|
+
)
|
563
|
+
with pip_find_lock: # Prevent issues with multiple processes
|
564
|
+
try:
|
565
|
+
import pyautogui
|
566
|
+
try:
|
567
|
+
use_pyautogui_ver = constants.PyAutoGUI.VER
|
568
|
+
if pyautogui.__version__ != use_pyautogui_ver:
|
569
|
+
del pyautogui
|
570
|
+
shared_utils.pip_install(
|
571
|
+
"pyautogui", version=use_pyautogui_ver
|
572
|
+
)
|
573
|
+
import pyautogui
|
574
|
+
except Exception:
|
575
|
+
pass
|
576
|
+
except Exception:
|
577
|
+
print("\nPyAutoGUI required! Installing now...")
|
578
|
+
shared_utils.pip_install(
|
579
|
+
"pyautogui", version=constants.PyAutoGUI.VER
|
580
|
+
)
|
581
|
+
|
582
|
+
|
583
|
+
def get_configured_pyautogui(pyautogui_copy):
|
584
|
+
if (
|
585
|
+
IS_LINUX
|
586
|
+
and hasattr(pyautogui_copy, "_pyautogui_x11")
|
587
|
+
and "DISPLAY" in os.environ.keys()
|
588
|
+
):
|
589
|
+
if (
|
590
|
+
hasattr(sb_config, "_pyautogui_x11_display")
|
591
|
+
and sb_config._pyautogui_x11_display
|
592
|
+
and hasattr(pyautogui_copy._pyautogui_x11, "_display")
|
593
|
+
and (
|
594
|
+
sb_config._pyautogui_x11_display
|
595
|
+
== pyautogui_copy._pyautogui_x11._display
|
596
|
+
)
|
597
|
+
):
|
598
|
+
pass
|
599
|
+
else:
|
600
|
+
import Xlib.display
|
601
|
+
pyautogui_copy._pyautogui_x11._display = (
|
602
|
+
Xlib.display.Display(os.environ['DISPLAY'])
|
603
|
+
)
|
604
|
+
sb_config._pyautogui_x11_display = (
|
605
|
+
pyautogui_copy._pyautogui_x11._display
|
606
|
+
)
|
607
|
+
return pyautogui_copy
|
608
|
+
|
609
|
+
|
610
|
+
def uc_gui_press_key(driver, key):
|
611
|
+
install_pyautogui_if_missing()
|
612
|
+
import pyautogui
|
613
|
+
pyautogui = get_configured_pyautogui(pyautogui)
|
614
|
+
gui_lock = fasteners.InterProcessLock(
|
615
|
+
constants.MultiBrowser.PYAUTOGUILOCK
|
616
|
+
)
|
617
|
+
with gui_lock:
|
618
|
+
pyautogui.press(key)
|
619
|
+
|
620
|
+
|
621
|
+
def uc_gui_press_keys(driver, keys):
|
622
|
+
install_pyautogui_if_missing()
|
623
|
+
import pyautogui
|
624
|
+
pyautogui = get_configured_pyautogui(pyautogui)
|
625
|
+
gui_lock = fasteners.InterProcessLock(
|
626
|
+
constants.MultiBrowser.PYAUTOGUILOCK
|
627
|
+
)
|
628
|
+
with gui_lock:
|
629
|
+
for key in keys:
|
630
|
+
pyautogui.press(key)
|
631
|
+
|
632
|
+
|
633
|
+
def uc_gui_write(driver, text):
|
634
|
+
install_pyautogui_if_missing()
|
635
|
+
import pyautogui
|
636
|
+
pyautogui = get_configured_pyautogui(pyautogui)
|
637
|
+
gui_lock = fasteners.InterProcessLock(
|
638
|
+
constants.MultiBrowser.PYAUTOGUILOCK
|
639
|
+
)
|
640
|
+
with gui_lock:
|
641
|
+
pyautogui.write(text)
|
642
|
+
|
643
|
+
|
644
|
+
def uc_gui_handle_cf(driver, frame="iframe"):
|
645
|
+
source = driver.get_page_source()
|
646
|
+
if (
|
647
|
+
"//challenges.cloudflare.com" not in source
|
648
|
+
and 'aria-label="Cloudflare"' not in source
|
649
|
+
):
|
650
|
+
return
|
651
|
+
install_pyautogui_if_missing()
|
652
|
+
import pyautogui
|
653
|
+
pyautogui = get_configured_pyautogui(pyautogui)
|
654
|
+
gui_lock = fasteners.InterProcessLock(
|
655
|
+
constants.MultiBrowser.PYAUTOGUILOCK
|
656
|
+
)
|
657
|
+
with gui_lock: # Prevent issues with multiple processes
|
658
|
+
needs_switch = False
|
659
|
+
is_in_frame = js_utils.is_in_frame(driver)
|
660
|
+
if is_in_frame and driver.is_element_present("#challenge-stage"):
|
661
|
+
driver.switch_to.parent_frame()
|
662
|
+
needs_switch = True
|
663
|
+
is_in_frame = js_utils.is_in_frame(driver)
|
664
|
+
if not is_in_frame:
|
665
|
+
# Make sure the window is on top
|
666
|
+
page_actions.switch_to_window(
|
667
|
+
driver,
|
668
|
+
driver.current_window_handle,
|
669
|
+
timeout=settings.SMALL_TIMEOUT,
|
670
|
+
)
|
671
|
+
if not is_in_frame or needs_switch:
|
672
|
+
# Currently not in frame (or nested frame outside CF one)
|
673
|
+
try:
|
674
|
+
driver.switch_to_frame(frame)
|
675
|
+
except Exception:
|
676
|
+
if driver.is_element_present("iframe"):
|
677
|
+
driver.switch_to_frame("iframe")
|
678
|
+
else:
|
679
|
+
return
|
680
|
+
try:
|
681
|
+
driver.execute_script('document.querySelector("input").focus()')
|
682
|
+
except Exception:
|
683
|
+
try:
|
684
|
+
driver.switch_to.default_content()
|
685
|
+
except Exception:
|
686
|
+
return
|
687
|
+
driver.disconnect()
|
688
|
+
try:
|
689
|
+
pyautogui.press(" ")
|
690
|
+
except Exception:
|
691
|
+
pass
|
692
|
+
reconnect_time = (float(constants.UC.RECONNECT_TIME) / 2.0) + 0.5
|
693
|
+
driver.reconnect(reconnect_time)
|
694
|
+
|
695
|
+
|
696
|
+
def uc_switch_to_frame(driver, frame="iframe", reconnect_time=None):
|
513
697
|
from selenium.webdriver.remote.webelement import WebElement
|
514
698
|
if isinstance(frame, WebElement):
|
515
699
|
if not reconnect_time:
|
@@ -847,7 +1031,7 @@ def _set_chrome_options(
|
|
847
1031
|
prefs["download.prompt_for_download"] = False
|
848
1032
|
prefs["credentials_enable_service"] = False
|
849
1033
|
prefs["local_discovery.notifications_enabled"] = False
|
850
|
-
prefs["safebrowsing.enabled"] = False
|
1034
|
+
prefs["safebrowsing.enabled"] = False # Prevent PW "data breach" pop-ups
|
851
1035
|
prefs["safebrowsing.disable_download_protection"] = True
|
852
1036
|
prefs["omnibox-max-zero-suggest-matches"] = 0
|
853
1037
|
prefs["omnibox-use-existing-autocomplete-client"] = 0
|
@@ -1145,6 +1329,7 @@ def _set_chrome_options(
|
|
1145
1329
|
chrome_options.add_argument("--auto-open-devtools-for-tabs")
|
1146
1330
|
if user_agent:
|
1147
1331
|
chrome_options.add_argument("--user-agent=%s" % user_agent)
|
1332
|
+
chrome_options.add_argument("--safebrowsing-disable-download-protection")
|
1148
1333
|
chrome_options.add_argument("--disable-browser-side-navigation")
|
1149
1334
|
chrome_options.add_argument("--disable-save-password-bubble")
|
1150
1335
|
chrome_options.add_argument("--disable-single-click-autofill")
|
@@ -1165,6 +1350,14 @@ def _set_chrome_options(
|
|
1165
1350
|
chrome_options.add_argument("--ash-no-nudges")
|
1166
1351
|
chrome_options.add_argument("--no-crash-upload")
|
1167
1352
|
chrome_options.add_argument("--deny-permission-prompts")
|
1353
|
+
chrome_options.add_argument(
|
1354
|
+
'--simulate-outdated-no-au="Tue, 31 Dec 2099 23:59:59 GMT"'
|
1355
|
+
)
|
1356
|
+
chrome_options.add_argument("--disable-ipc-flooding-protection")
|
1357
|
+
chrome_options.add_argument("--disable-password-generation")
|
1358
|
+
chrome_options.add_argument("--disable-domain-reliability")
|
1359
|
+
chrome_options.add_argument("--disable-component-update")
|
1360
|
+
chrome_options.add_argument("--disable-breakpad")
|
1168
1361
|
included_disabled_features = []
|
1169
1362
|
included_disabled_features.append("OptimizationHints")
|
1170
1363
|
included_disabled_features.append("OptimizationHintsFetching")
|
@@ -1175,10 +1368,9 @@ def _set_chrome_options(
|
|
1175
1368
|
included_disabled_features.append("DownloadBubbleV2")
|
1176
1369
|
included_disabled_features.append("InsecureDownloadWarnings")
|
1177
1370
|
included_disabled_features.append("InterestFeedContentSuggestions")
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
included_disabled_features.append("SidePanelPinning")
|
1371
|
+
included_disabled_features.append("PrivacySandboxSettings4")
|
1372
|
+
included_disabled_features.append("SidePanelPinning")
|
1373
|
+
included_disabled_features.append("UserAgentClientHint")
|
1182
1374
|
for item in extra_disabled_features:
|
1183
1375
|
if item not in included_disabled_features:
|
1184
1376
|
included_disabled_features.append(item)
|
@@ -1366,7 +1558,7 @@ def _set_firefox_options(
|
|
1366
1558
|
f_pref_value = False
|
1367
1559
|
elif f_pref_value.isdigit():
|
1368
1560
|
f_pref_value = int(f_pref_value)
|
1369
|
-
elif f_pref_value.
|
1561
|
+
elif f_pref_value.replace(".", "", 1).isdigit():
|
1370
1562
|
f_pref_value = float(f_pref_value)
|
1371
1563
|
else:
|
1372
1564
|
pass # keep as string
|
@@ -2286,11 +2478,13 @@ def get_local_driver(
|
|
2286
2478
|
or "Process unexpectedly closed" in str(e)
|
2287
2479
|
or "Failed to read marionette port" in str(e)
|
2288
2480
|
or "A connection attempt failed" in str(e)
|
2481
|
+
or "Expected browser binary" in str(e)
|
2289
2482
|
or hasattr(e, "msg") and (
|
2290
2483
|
"geckodriver unexpectedly exited" in e.msg
|
2291
2484
|
or "Process unexpectedly closed" in e.msg
|
2292
2485
|
or "Failed to read marionette port" in e.msg
|
2293
2486
|
or "A connection attempt failed" in e.msg
|
2487
|
+
or "Expected browser binary" in e.msg
|
2294
2488
|
)
|
2295
2489
|
):
|
2296
2490
|
time.sleep(0.1)
|
@@ -2326,11 +2520,13 @@ def get_local_driver(
|
|
2326
2520
|
or "Process unexpectedly closed" in str(e)
|
2327
2521
|
or "Failed to read marionette port" in str(e)
|
2328
2522
|
or "A connection attempt failed" in str(e)
|
2523
|
+
or "Expected browser binary" in str(e)
|
2329
2524
|
or hasattr(e, "msg") and (
|
2330
2525
|
"geckodriver unexpectedly exited" in e.msg
|
2331
2526
|
or "Process unexpectedly closed" in e.msg
|
2332
2527
|
or "Failed to read marionette port" in e.msg
|
2333
2528
|
or "A connection attempt failed" in e.msg
|
2529
|
+
or "Expected browser binary" in e.msg
|
2334
2530
|
)
|
2335
2531
|
):
|
2336
2532
|
time.sleep(0.1)
|
@@ -2426,7 +2622,7 @@ def get_local_driver(
|
|
2426
2622
|
"credentials_enable_service": False,
|
2427
2623
|
"local_discovery.notifications_enabled": False,
|
2428
2624
|
"safebrowsing.disable_download_protection": True,
|
2429
|
-
"safebrowsing.enabled": False,
|
2625
|
+
"safebrowsing.enabled": False, # Prevent PW "data breach" pop-ups
|
2430
2626
|
"omnibox-max-zero-suggest-matches": 0,
|
2431
2627
|
"omnibox-use-existing-autocomplete-client": 0,
|
2432
2628
|
"omnibox-trending-zero-prefix-suggestions-on-ntp": 0,
|
@@ -2695,6 +2891,7 @@ def get_local_driver(
|
|
2695
2891
|
edge_options.add_argument(
|
2696
2892
|
"--disable-autofill-keyboard-accessory-view[8]"
|
2697
2893
|
)
|
2894
|
+
edge_options.add_argument("--safebrowsing-disable-download-protection")
|
2698
2895
|
edge_options.add_argument("--disable-browser-side-navigation")
|
2699
2896
|
edge_options.add_argument("--disable-translate")
|
2700
2897
|
if not enable_ws:
|
@@ -2820,6 +3017,14 @@ def get_local_driver(
|
|
2820
3017
|
edge_options.add_argument(chromium_arg_item)
|
2821
3018
|
if disable_features:
|
2822
3019
|
extra_disabled_features.extend(disable_features.split(","))
|
3020
|
+
edge_options.add_argument(
|
3021
|
+
'--simulate-outdated-no-au="Tue, 31 Dec 2099 23:59:59 GMT"'
|
3022
|
+
)
|
3023
|
+
edge_options.add_argument("--disable-ipc-flooding-protection")
|
3024
|
+
edge_options.add_argument("--disable-password-generation")
|
3025
|
+
edge_options.add_argument("--disable-domain-reliability")
|
3026
|
+
edge_options.add_argument("--disable-component-update")
|
3027
|
+
edge_options.add_argument("--disable-breakpad")
|
2823
3028
|
included_disabled_features = []
|
2824
3029
|
included_disabled_features.append("OptimizationHints")
|
2825
3030
|
included_disabled_features.append("OptimizationHintsFetching")
|
@@ -2828,10 +3033,9 @@ def get_local_driver(
|
|
2828
3033
|
included_disabled_features.append("OptimizationGuideModelDownloading")
|
2829
3034
|
included_disabled_features.append("InsecureDownloadWarnings")
|
2830
3035
|
included_disabled_features.append("InterestFeedContentSuggestions")
|
2831
|
-
|
2832
|
-
|
2833
|
-
|
2834
|
-
included_disabled_features.append("SidePanelPinning")
|
3036
|
+
included_disabled_features.append("PrivacySandboxSettings4")
|
3037
|
+
included_disabled_features.append("SidePanelPinning")
|
3038
|
+
included_disabled_features.append("UserAgentClientHint")
|
2835
3039
|
for item in extra_disabled_features:
|
2836
3040
|
if item not in included_disabled_features:
|
2837
3041
|
included_disabled_features.append(item)
|
@@ -3802,6 +4006,26 @@ def get_local_driver(
|
|
3802
4006
|
driver.uc_click = lambda *args, **kwargs: uc_click(
|
3803
4007
|
driver, *args, **kwargs
|
3804
4008
|
)
|
4009
|
+
driver.uc_gui_press_key = (
|
4010
|
+
lambda *args, **kwargs: uc_gui_press_key(
|
4011
|
+
driver, *args, **kwargs
|
4012
|
+
)
|
4013
|
+
)
|
4014
|
+
driver.uc_gui_press_keys = (
|
4015
|
+
lambda *args, **kwargs: uc_gui_press_keys(
|
4016
|
+
driver, *args, **kwargs
|
4017
|
+
)
|
4018
|
+
)
|
4019
|
+
driver.uc_gui_write = (
|
4020
|
+
lambda *args, **kwargs: uc_gui_write(
|
4021
|
+
driver, *args, **kwargs
|
4022
|
+
)
|
4023
|
+
)
|
4024
|
+
driver.uc_gui_handle_cf = (
|
4025
|
+
lambda *args, **kwargs: uc_gui_handle_cf(
|
4026
|
+
driver, *args, **kwargs
|
4027
|
+
)
|
4028
|
+
)
|
3805
4029
|
driver.uc_switch_to_frame = (
|
3806
4030
|
lambda *args, **kwargs: uc_switch_to_frame(
|
3807
4031
|
driver, *args, **kwargs
|
seleniumbase/core/sb_driver.py
CHANGED
@@ -94,6 +94,16 @@ class DriverMethods():
|
|
94
94
|
def assert_exact_text(self, *args, **kwargs):
|
95
95
|
page_actions.assert_exact_text(self.driver, *args, **kwargs)
|
96
96
|
|
97
|
+
def assert_non_empty_text(self, *args, **kwargs):
|
98
|
+
return page_actions.assert_non_empty_text(
|
99
|
+
self.driver, *args, **kwargs
|
100
|
+
)
|
101
|
+
|
102
|
+
def assert_text_not_visible(self, *args, **kwargs):
|
103
|
+
return page_actions.assert_text_not_visible(
|
104
|
+
self.driver, *args, **kwargs
|
105
|
+
)
|
106
|
+
|
97
107
|
def wait_for_element(self, *args, **kwargs):
|
98
108
|
return page_actions.wait_for_element(self.driver, *args, **kwargs)
|
99
109
|
|
@@ -112,6 +122,16 @@ class DriverMethods():
|
|
112
122
|
def wait_for_exact_text(self, *args, **kwargs):
|
113
123
|
return page_actions.wait_for_exact_text(self.driver, *args, **kwargs)
|
114
124
|
|
125
|
+
def wait_for_non_empty_text(self, *args, **kwargs):
|
126
|
+
return page_actions.wait_for_non_empty_text(
|
127
|
+
self.driver, *args, **kwargs
|
128
|
+
)
|
129
|
+
|
130
|
+
def wait_for_text_not_visible(self, *args, **kwargs):
|
131
|
+
return page_actions.wait_for_text_not_visible(
|
132
|
+
self.driver, *args, **kwargs
|
133
|
+
)
|
134
|
+
|
115
135
|
def wait_for_and_accept_alert(self, *args, **kwargs):
|
116
136
|
return page_actions.wait_for_and_accept_alert(
|
117
137
|
self.driver, *args, **kwargs
|
@@ -134,14 +154,22 @@ class DriverMethods():
|
|
134
154
|
def is_exact_text_visible(self, *args, **kwargs):
|
135
155
|
return page_actions.is_exact_text_visible(self.driver, *args, **kwargs)
|
136
156
|
|
137
|
-
def
|
138
|
-
return page_actions.
|
157
|
+
def is_attribute_present(self, *args, **kwargs):
|
158
|
+
return page_actions.has_attribute(self.driver, *args, **kwargs)
|
159
|
+
|
160
|
+
def is_non_empty_text_visible(self, *args, **kwargs):
|
161
|
+
return page_actions.is_non_empty_text_visible(
|
162
|
+
self.driver, *args, **kwargs
|
163
|
+
)
|
164
|
+
|
165
|
+
def is_online(self):
|
166
|
+
return self.driver.execute_script("return navigator.onLine;")
|
139
167
|
|
140
168
|
def js_click(self, *args, **kwargs):
|
141
169
|
return page_actions.js_click(self.driver, *args, **kwargs)
|
142
170
|
|
143
|
-
def
|
144
|
-
return page_actions.
|
171
|
+
def get_text(self, *args, **kwargs):
|
172
|
+
return page_actions.get_text(self.driver, *args, **kwargs)
|
145
173
|
|
146
174
|
def get_active_element_css(self, *args, **kwargs):
|
147
175
|
return js_utils.get_active_element_css(self.driver, *args, **kwargs)
|
@@ -182,7 +210,32 @@ class DriverMethods():
|
|
182
210
|
if self.is_element_visible(selector, by=by):
|
183
211
|
self.highlight(selector, by=by, loops=loops, scroll=scroll)
|
184
212
|
|
185
|
-
def
|
213
|
+
def switch_to_default_window(self):
|
214
|
+
self.driver.switch_to.window(self.driver.window_handles[0])
|
215
|
+
|
216
|
+
def switch_to_newest_window(self):
|
217
|
+
self.driver.switch_to.window(self.driver.window_handles[-1])
|
218
|
+
|
219
|
+
def open_new_window(self, switch_to=True):
|
220
|
+
if switch_to:
|
221
|
+
try:
|
222
|
+
self.driver.switch_to.new_window("tab")
|
223
|
+
except Exception:
|
224
|
+
self.driver.execute_script("window.open('');")
|
225
|
+
self.switch_to_newest_window()
|
226
|
+
else:
|
227
|
+
self.driver.execute_script("window.open('');")
|
228
|
+
|
229
|
+
def open_new_tab(self, switch_to=True):
|
230
|
+
self.open_new_window(switch_to=switch_to)
|
231
|
+
|
232
|
+
def switch_to_window(self, *args, **kwargs):
|
233
|
+
page_actions.switch_to_window(self.driver, *args, **kwargs)
|
234
|
+
|
235
|
+
def switch_to_tab(self, *args, **kwargs):
|
236
|
+
self.switch_to_window(*args, **kwargs)
|
237
|
+
|
238
|
+
def switch_to_frame(self, frame="iframe"):
|
186
239
|
if isinstance(frame, WebElement):
|
187
240
|
self.driver.switch_to.frame(frame)
|
188
241
|
else:
|
Binary file
|