seleniumbase 4.33.4__py3-none-any.whl → 4.34.2__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/behave/behave_sb.py +10 -2
- seleniumbase/console_scripts/run.py +6 -2
- seleniumbase/console_scripts/sb_commander.py +5 -5
- seleniumbase/console_scripts/sb_install.py +235 -6
- seleniumbase/console_scripts/sb_mkdir.py +1 -0
- seleniumbase/core/browser_launcher.py +358 -105
- seleniumbase/core/log_helper.py +33 -12
- seleniumbase/core/proxy_helper.py +35 -30
- seleniumbase/core/sb_cdp.py +277 -74
- seleniumbase/core/settings_parser.py +2 -0
- seleniumbase/core/style_sheet.py +10 -0
- seleniumbase/fixtures/base_case.py +216 -127
- seleniumbase/fixtures/constants.py +3 -0
- seleniumbase/fixtures/js_utils.py +2 -0
- seleniumbase/fixtures/page_actions.py +7 -2
- seleniumbase/fixtures/shared_utils.py +25 -0
- seleniumbase/plugins/driver_manager.py +28 -0
- seleniumbase/plugins/pytest_plugin.py +110 -0
- seleniumbase/plugins/sb_manager.py +41 -0
- seleniumbase/plugins/selenium_plugin.py +9 -0
- seleniumbase/undetected/cdp_driver/_contradict.py +3 -3
- seleniumbase/undetected/cdp_driver/browser.py +8 -6
- seleniumbase/undetected/cdp_driver/cdp_util.py +3 -0
- seleniumbase/undetected/cdp_driver/config.py +0 -1
- seleniumbase/undetected/cdp_driver/element.py +22 -20
- seleniumbase/undetected/patcher.py +20 -5
- {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/LICENSE +1 -1
- {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/METADATA +111 -86
- {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/RECORD +33 -33
- {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/WHEEL +1 -1
- {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/top_level.txt +0 -0
@@ -95,6 +95,7 @@ logging.getLogger("requests").setLevel(logging.ERROR)
|
|
95
95
|
logging.getLogger("urllib3").setLevel(logging.ERROR)
|
96
96
|
urllib3.disable_warnings()
|
97
97
|
LOGGER.setLevel(logging.WARNING)
|
98
|
+
is_linux = shared_utils.is_linux()
|
98
99
|
is_windows = shared_utils.is_windows()
|
99
100
|
python3_11_or_newer = False
|
100
101
|
if sys.version_info >= (3, 11):
|
@@ -1451,7 +1452,7 @@ class BaseCase(unittest.TestCase):
|
|
1451
1452
|
return self.__is_shadow_element_enabled(selector)
|
1452
1453
|
return page_actions.is_element_enabled(self.driver, selector, by)
|
1453
1454
|
|
1454
|
-
def is_text_visible(self, text, selector="
|
1455
|
+
def is_text_visible(self, text, selector="body", by="css selector"):
|
1455
1456
|
"""Returns whether the text substring is visible in the element."""
|
1456
1457
|
self.wait_for_ready_state_complete()
|
1457
1458
|
time.sleep(0.01)
|
@@ -1460,7 +1461,7 @@ class BaseCase(unittest.TestCase):
|
|
1460
1461
|
return self.__is_shadow_text_visible(text, selector)
|
1461
1462
|
return page_actions.is_text_visible(self.driver, text, selector, by)
|
1462
1463
|
|
1463
|
-
def is_exact_text_visible(self, text, selector="
|
1464
|
+
def is_exact_text_visible(self, text, selector="body", by="css selector"):
|
1464
1465
|
"""Returns whether the text is exactly equal to the element text.
|
1465
1466
|
(Leading and trailing whitespace is ignored in the verification.)"""
|
1466
1467
|
self.wait_for_ready_state_complete()
|
@@ -1472,7 +1473,7 @@ class BaseCase(unittest.TestCase):
|
|
1472
1473
|
self.driver, text, selector, by
|
1473
1474
|
)
|
1474
1475
|
|
1475
|
-
def is_non_empty_text_visible(self, selector="
|
1476
|
+
def is_non_empty_text_visible(self, selector="body", by="css selector"):
|
1476
1477
|
"""Returns whether the element has any non-empty text visible.
|
1477
1478
|
Whitespace-only text is considered empty text."""
|
1478
1479
|
self.wait_for_ready_state_complete()
|
@@ -1842,7 +1843,7 @@ class BaseCase(unittest.TestCase):
|
|
1842
1843
|
elif self.slow_mode:
|
1843
1844
|
self.__slow_mode_pause_if_active()
|
1844
1845
|
|
1845
|
-
def get_text(self, selector="
|
1846
|
+
def get_text(self, selector="body", by="css selector", timeout=None):
|
1846
1847
|
self.__check_scope()
|
1847
1848
|
if not timeout:
|
1848
1849
|
timeout = settings.LARGE_TIMEOUT
|
@@ -1901,7 +1902,7 @@ class BaseCase(unittest.TestCase):
|
|
1901
1902
|
timeout = self.__get_new_timeout(timeout)
|
1902
1903
|
selector, by = self.__recalculate_selector(selector, by)
|
1903
1904
|
if self.__is_cdp_swap_needed():
|
1904
|
-
return self.cdp.get_element_attribute(selector)
|
1905
|
+
return self.cdp.get_element_attribute(selector, attribute)
|
1905
1906
|
self.wait_for_ready_state_complete()
|
1906
1907
|
time.sleep(0.01)
|
1907
1908
|
if self.__is_shadow_selector(selector):
|
@@ -2105,7 +2106,7 @@ class BaseCase(unittest.TestCase):
|
|
2105
2106
|
return property_value
|
2106
2107
|
|
2107
2108
|
def get_text_content(
|
2108
|
-
self, selector="
|
2109
|
+
self, selector="body", by="css selector", timeout=None
|
2109
2110
|
):
|
2110
2111
|
"""Returns the text that appears in the HTML for an element.
|
2111
2112
|
This is different from "self.get_text(selector, by="css selector")"
|
@@ -2493,8 +2494,10 @@ class BaseCase(unittest.TestCase):
|
|
2493
2494
|
kind = self.get_attribute(selector, "type", by=by, timeout=timeout)
|
2494
2495
|
if kind != "checkbox" and kind != "radio":
|
2495
2496
|
raise Exception("Expecting a checkbox or a radio button element!")
|
2496
|
-
return
|
2497
|
-
|
2497
|
+
return bool(
|
2498
|
+
self.get_attribute(
|
2499
|
+
selector, "checked", by=by, timeout=timeout, hard_fail=False
|
2500
|
+
)
|
2498
2501
|
)
|
2499
2502
|
|
2500
2503
|
def is_selected(self, selector, by="css selector", timeout=None):
|
@@ -3416,6 +3419,14 @@ class BaseCase(unittest.TestCase):
|
|
3416
3419
|
self.activate_jquery()
|
3417
3420
|
return self.driver.execute_script(script, *args, **kwargs)
|
3418
3421
|
|
3422
|
+
def get_element_at_x_y(self, x, y):
|
3423
|
+
"""Return element at current window's x,y coordinates."""
|
3424
|
+
self.__check_scope()
|
3425
|
+
self._check_browser()
|
3426
|
+
return self.execute_script(
|
3427
|
+
"return document.elementFromPoint(%s, %s);" % (x, y)
|
3428
|
+
)
|
3429
|
+
|
3419
3430
|
def get_gui_element_rect(self, selector, by="css selector"):
|
3420
3431
|
"""Very similar to element.rect, but the x, y coordinates are
|
3421
3432
|
relative to the entire screen, rather than the browser window.
|
@@ -4484,7 +4495,8 @@ class BaseCase(unittest.TestCase):
|
|
4484
4495
|
@Params
|
4485
4496
|
name - The file name to save the current page's HTML to.
|
4486
4497
|
folder - The folder to save the file to. (Default = current folder)"""
|
4487
|
-
self.
|
4498
|
+
if not self.__is_cdp_swap_needed():
|
4499
|
+
self.wait_for_ready_state_complete()
|
4488
4500
|
return page_actions.save_page_source(self.driver, name, folder)
|
4489
4501
|
|
4490
4502
|
def save_cookies(self, name="cookies.txt"):
|
@@ -4542,6 +4554,9 @@ class BaseCase(unittest.TestCase):
|
|
4542
4554
|
def delete_all_cookies(self):
|
4543
4555
|
"""Deletes all cookies in the web browser.
|
4544
4556
|
Does NOT delete the saved cookies file."""
|
4557
|
+
if self.__is_cdp_swap_needed():
|
4558
|
+
self.cdp.clear_cookies()
|
4559
|
+
return
|
4545
4560
|
self.wait_for_ready_state_complete()
|
4546
4561
|
self.driver.delete_all_cookies()
|
4547
4562
|
if self.recorder_mode:
|
@@ -4553,7 +4568,6 @@ class BaseCase(unittest.TestCase):
|
|
4553
4568
|
def delete_saved_cookies(self, name="cookies.txt"):
|
4554
4569
|
"""Deletes the cookies file from the "saved_cookies" folder.
|
4555
4570
|
Does NOT delete the cookies from the web browser."""
|
4556
|
-
self.wait_for_ready_state_complete()
|
4557
4571
|
if name.endswith("/"):
|
4558
4572
|
raise Exception("Invalid filename for Cookies!")
|
4559
4573
|
if "/" in name:
|
@@ -4592,14 +4606,20 @@ class BaseCase(unittest.TestCase):
|
|
4592
4606
|
return json.loads(json_cookies)
|
4593
4607
|
|
4594
4608
|
def get_cookie(self, name):
|
4609
|
+
self.__check_scope()
|
4610
|
+
self._check_browser()
|
4595
4611
|
return self.driver.get_cookie(name)
|
4596
4612
|
|
4597
4613
|
def get_cookies(self):
|
4614
|
+
self.__check_scope()
|
4615
|
+
self._check_browser()
|
4598
4616
|
return self.driver.get_cookies()
|
4599
4617
|
|
4600
4618
|
def get_cookie_string(self):
|
4619
|
+
self.__check_scope()
|
4601
4620
|
if self.__is_cdp_swap_needed():
|
4602
4621
|
return self.cdp.get_cookie_string()
|
4622
|
+
self._check_browser()
|
4603
4623
|
return self.execute_script("return document.cookie;")
|
4604
4624
|
|
4605
4625
|
def add_cookie(self, cookie_dict, expiry=False):
|
@@ -4614,6 +4634,8 @@ class BaseCase(unittest.TestCase):
|
|
4614
4634
|
If expiry > 0: Set "expiry" to expiry minutes in the future.
|
4615
4635
|
If expiry == True: Set "expiry" to 24 hours in the future.
|
4616
4636
|
"""
|
4637
|
+
self.__check_scope()
|
4638
|
+
self._check_browser()
|
4617
4639
|
cookie = cookie_dict
|
4618
4640
|
if "domain" in cookie:
|
4619
4641
|
origin = self.get_origin()
|
@@ -4638,6 +4660,8 @@ class BaseCase(unittest.TestCase):
|
|
4638
4660
|
If expiry > 0: Set "expiry" to expiry minutes in the future.
|
4639
4661
|
If expiry == True: Set "expiry" to 24 hours in the future.
|
4640
4662
|
"""
|
4663
|
+
self.__check_scope()
|
4664
|
+
self._check_browser()
|
4641
4665
|
origin = self.get_origin()
|
4642
4666
|
trim_origin = origin.split("://")[-1]
|
4643
4667
|
for cookie in cookies:
|
@@ -4807,7 +4831,7 @@ class BaseCase(unittest.TestCase):
|
|
4807
4831
|
from seleniumbase.js_code.recorder_js import recorder_js
|
4808
4832
|
|
4809
4833
|
if not self.is_chromium():
|
4810
|
-
if
|
4834
|
+
if not is_linux:
|
4811
4835
|
c1 = colorama.Fore.BLUE + colorama.Back.LIGHTCYAN_EX
|
4812
4836
|
c2 = colorama.Fore.BLUE + colorama.Back.LIGHTGREEN_EX
|
4813
4837
|
cr = colorama.Style.RESET_ALL
|
@@ -5637,7 +5661,7 @@ class BaseCase(unittest.TestCase):
|
|
5637
5661
|
c1 = ""
|
5638
5662
|
c2 = ""
|
5639
5663
|
cr = ""
|
5640
|
-
if
|
5664
|
+
if not is_linux:
|
5641
5665
|
c1 = colorama.Fore.RED + colorama.Back.LIGHTYELLOW_EX
|
5642
5666
|
c2 = colorama.Fore.LIGHTRED_EX + colorama.Back.LIGHTYELLOW_EX
|
5643
5667
|
cr = colorama.Style.RESET_ALL
|
@@ -5739,7 +5763,7 @@ class BaseCase(unittest.TestCase):
|
|
5739
5763
|
c1 = ""
|
5740
5764
|
c2 = ""
|
5741
5765
|
cr = ""
|
5742
|
-
if
|
5766
|
+
if not is_linux:
|
5743
5767
|
c1 = colorama.Fore.RED + colorama.Back.LIGHTYELLOW_EX
|
5744
5768
|
c2 = colorama.Fore.LIGHTRED_EX + colorama.Back.LIGHTYELLOW_EX
|
5745
5769
|
cr = colorama.Style.RESET_ALL
|
@@ -6051,10 +6075,8 @@ class BaseCase(unittest.TestCase):
|
|
6051
6075
|
scroll - the option to scroll to the element first (Default: True)
|
6052
6076
|
timeout - the time to wait for the element to appear """
|
6053
6077
|
self.__check_scope()
|
6054
|
-
if self.__is_cdp_swap_needed()
|
6055
|
-
self.
|
6056
|
-
return
|
6057
|
-
self._check_browser()
|
6078
|
+
if not self.__is_cdp_swap_needed():
|
6079
|
+
self._check_browser()
|
6058
6080
|
self.__skip_if_esc()
|
6059
6081
|
if isinstance(selector, WebElement):
|
6060
6082
|
self.__highlight_element(selector, loops=loops, scroll=scroll)
|
@@ -6093,7 +6115,7 @@ class BaseCase(unittest.TestCase):
|
|
6093
6115
|
if limit > 0 and count >= limit:
|
6094
6116
|
break
|
6095
6117
|
|
6096
|
-
def press_up_arrow(self, selector="
|
6118
|
+
def press_up_arrow(self, selector="body", times=1, by="css selector"):
|
6097
6119
|
"""Simulates pressing the UP Arrow on the keyboard.
|
6098
6120
|
By default, "html" will be used as the CSS Selector target.
|
6099
6121
|
You can specify how many times in-a-row the action happens."""
|
@@ -6115,7 +6137,7 @@ class BaseCase(unittest.TestCase):
|
|
6115
6137
|
if self.slow_mode:
|
6116
6138
|
time.sleep(0.1)
|
6117
6139
|
|
6118
|
-
def press_down_arrow(self, selector="
|
6140
|
+
def press_down_arrow(self, selector="body", times=1, by="css selector"):
|
6119
6141
|
"""Simulates pressing the DOWN Arrow on the keyboard.
|
6120
6142
|
By default, "html" will be used as the CSS Selector target.
|
6121
6143
|
You can specify how many times in-a-row the action happens."""
|
@@ -6137,7 +6159,7 @@ class BaseCase(unittest.TestCase):
|
|
6137
6159
|
if self.slow_mode:
|
6138
6160
|
time.sleep(0.1)
|
6139
6161
|
|
6140
|
-
def press_left_arrow(self, selector="
|
6162
|
+
def press_left_arrow(self, selector="body", times=1, by="css selector"):
|
6141
6163
|
"""Simulates pressing the LEFT Arrow on the keyboard.
|
6142
6164
|
By default, "html" will be used as the CSS Selector target.
|
6143
6165
|
You can specify how many times in-a-row the action happens."""
|
@@ -6159,7 +6181,7 @@ class BaseCase(unittest.TestCase):
|
|
6159
6181
|
if self.slow_mode:
|
6160
6182
|
time.sleep(0.1)
|
6161
6183
|
|
6162
|
-
def press_right_arrow(self, selector="
|
6184
|
+
def press_right_arrow(self, selector="body", times=1, by="css selector"):
|
6163
6185
|
"""Simulates pressing the RIGHT Arrow on the keyboard.
|
6164
6186
|
By default, "html" will be used as the CSS Selector target.
|
6165
6187
|
You can specify how many times in-a-row the action happens."""
|
@@ -7042,6 +7064,8 @@ class BaseCase(unittest.TestCase):
|
|
7042
7064
|
constants.PipInstall.FINDLOCK
|
7043
7065
|
)
|
7044
7066
|
with pip_find_lock:
|
7067
|
+
with suppress(Exception):
|
7068
|
+
shared_utils.make_writable(constants.PipInstall.FINDLOCK)
|
7045
7069
|
if sys.version_info < (3, 9):
|
7046
7070
|
# Fix bug in newer cryptography for Python 3.7 and 3.8:
|
7047
7071
|
# "pyo3_runtime.PanicException: Python API call failed"
|
@@ -7292,6 +7316,8 @@ class BaseCase(unittest.TestCase):
|
|
7292
7316
|
constants.PipInstall.FINDLOCK
|
7293
7317
|
)
|
7294
7318
|
with pip_find_lock:
|
7319
|
+
with suppress(Exception):
|
7320
|
+
shared_utils.make_writable(constants.PipInstall.FINDLOCK)
|
7295
7321
|
try:
|
7296
7322
|
from PIL import Image, ImageDraw
|
7297
7323
|
except Exception:
|
@@ -7337,6 +7363,10 @@ class BaseCase(unittest.TestCase):
|
|
7337
7363
|
constants.MultiBrowser.DOWNLOAD_FILE_LOCK
|
7338
7364
|
)
|
7339
7365
|
with download_file_lock:
|
7366
|
+
with suppress(Exception):
|
7367
|
+
shared_utils.make_writable(
|
7368
|
+
constants.MultiBrowser.DOWNLOAD_FILE_LOCK
|
7369
|
+
)
|
7340
7370
|
if not destination_folder:
|
7341
7371
|
destination_folder = constants.Files.DOWNLOADS_FOLDER
|
7342
7372
|
if not os.path.exists(destination_folder):
|
@@ -7357,6 +7387,10 @@ class BaseCase(unittest.TestCase):
|
|
7357
7387
|
constants.MultiBrowser.DOWNLOAD_FILE_LOCK
|
7358
7388
|
)
|
7359
7389
|
with download_file_lock:
|
7390
|
+
with suppress(Exception):
|
7391
|
+
shared_utils.make_writable(
|
7392
|
+
constants.MultiBrowser.DOWNLOAD_FILE_LOCK
|
7393
|
+
)
|
7360
7394
|
if not destination_folder:
|
7361
7395
|
destination_folder = constants.Files.DOWNLOADS_FOLDER
|
7362
7396
|
if not os.path.exists(destination_folder):
|
@@ -7462,6 +7496,8 @@ class BaseCase(unittest.TestCase):
|
|
7462
7496
|
constants.MultiBrowser.FILE_IO_LOCK
|
7463
7497
|
)
|
7464
7498
|
with file_io_lock:
|
7499
|
+
with suppress(Exception):
|
7500
|
+
shared_utils.make_writable(constants.MultiBrowser.FILE_IO_LOCK)
|
7465
7501
|
with open(fpath, "r") as f:
|
7466
7502
|
data = f.read().strip()
|
7467
7503
|
return data
|
@@ -9716,7 +9752,7 @@ class BaseCase(unittest.TestCase):
|
|
9716
9752
|
############
|
9717
9753
|
|
9718
9754
|
def wait_for_text_visible(
|
9719
|
-
self, text, selector="
|
9755
|
+
self, text, selector="body", by="css selector", timeout=None
|
9720
9756
|
):
|
9721
9757
|
self.__check_scope()
|
9722
9758
|
if not timeout:
|
@@ -9734,7 +9770,7 @@ class BaseCase(unittest.TestCase):
|
|
9734
9770
|
)
|
9735
9771
|
|
9736
9772
|
def wait_for_exact_text_visible(
|
9737
|
-
self, text, selector="
|
9773
|
+
self, text, selector="body", by="css selector", timeout=None
|
9738
9774
|
):
|
9739
9775
|
self.__check_scope()
|
9740
9776
|
if not timeout:
|
@@ -9751,7 +9787,7 @@ class BaseCase(unittest.TestCase):
|
|
9751
9787
|
)
|
9752
9788
|
|
9753
9789
|
def wait_for_non_empty_text_visible(
|
9754
|
-
self, selector="
|
9790
|
+
self, selector="body", by="css selector", timeout=None
|
9755
9791
|
):
|
9756
9792
|
"""Searches for any text in the element of the given selector.
|
9757
9793
|
Returns the element if it has visible text within the timeout.
|
@@ -9772,7 +9808,7 @@ class BaseCase(unittest.TestCase):
|
|
9772
9808
|
)
|
9773
9809
|
|
9774
9810
|
def wait_for_text(
|
9775
|
-
self, text, selector="
|
9811
|
+
self, text, selector="body", by="css selector", timeout=None
|
9776
9812
|
):
|
9777
9813
|
"""The shorter version of wait_for_text_visible()"""
|
9778
9814
|
self.__check_scope()
|
@@ -9785,7 +9821,7 @@ class BaseCase(unittest.TestCase):
|
|
9785
9821
|
)
|
9786
9822
|
|
9787
9823
|
def wait_for_exact_text(
|
9788
|
-
self, text, selector="
|
9824
|
+
self, text, selector="body", by="css selector", timeout=None
|
9789
9825
|
):
|
9790
9826
|
"""The shorter version of wait_for_exact_text_visible()"""
|
9791
9827
|
self.__check_scope()
|
@@ -9798,7 +9834,7 @@ class BaseCase(unittest.TestCase):
|
|
9798
9834
|
)
|
9799
9835
|
|
9800
9836
|
def wait_for_non_empty_text(
|
9801
|
-
self, selector="
|
9837
|
+
self, selector="body", by="css selector", timeout=None
|
9802
9838
|
):
|
9803
9839
|
"""The shorter version of wait_for_non_empty_text_visible()"""
|
9804
9840
|
self.__check_scope()
|
@@ -9811,7 +9847,7 @@ class BaseCase(unittest.TestCase):
|
|
9811
9847
|
)
|
9812
9848
|
|
9813
9849
|
def find_text(
|
9814
|
-
self, text, selector="
|
9850
|
+
self, text, selector="body", by="css selector", timeout=None
|
9815
9851
|
):
|
9816
9852
|
"""Same as wait_for_text_visible() - returns the element"""
|
9817
9853
|
self.__check_scope()
|
@@ -9824,7 +9860,7 @@ class BaseCase(unittest.TestCase):
|
|
9824
9860
|
)
|
9825
9861
|
|
9826
9862
|
def find_exact_text(
|
9827
|
-
self, text, selector="
|
9863
|
+
self, text, selector="body", by="css selector", timeout=None
|
9828
9864
|
):
|
9829
9865
|
"""Same as wait_for_exact_text_visible() - returns the element"""
|
9830
9866
|
self.__check_scope()
|
@@ -9837,7 +9873,7 @@ class BaseCase(unittest.TestCase):
|
|
9837
9873
|
)
|
9838
9874
|
|
9839
9875
|
def find_non_empty_text(
|
9840
|
-
self, selector="
|
9876
|
+
self, selector="body", by="css selector", timeout=None
|
9841
9877
|
):
|
9842
9878
|
"""Same as wait_for_non_empty_text_visible() - returns the element"""
|
9843
9879
|
self.__check_scope()
|
@@ -9850,7 +9886,7 @@ class BaseCase(unittest.TestCase):
|
|
9850
9886
|
)
|
9851
9887
|
|
9852
9888
|
def assert_text_visible(
|
9853
|
-
self, text, selector="
|
9889
|
+
self, text, selector="body", by="css selector", timeout=None
|
9854
9890
|
):
|
9855
9891
|
"""Same as assert_text()"""
|
9856
9892
|
self.__check_scope()
|
@@ -9861,7 +9897,7 @@ class BaseCase(unittest.TestCase):
|
|
9861
9897
|
return self.assert_text(text, selector, by=by, timeout=timeout)
|
9862
9898
|
|
9863
9899
|
def assert_text(
|
9864
|
-
self, text, selector="
|
9900
|
+
self, text, selector="body", by="css selector", timeout=None
|
9865
9901
|
):
|
9866
9902
|
"""Similar to wait_for_text_visible()
|
9867
9903
|
Raises an exception if the element or the text is not found.
|
@@ -9931,7 +9967,7 @@ class BaseCase(unittest.TestCase):
|
|
9931
9967
|
return True
|
9932
9968
|
|
9933
9969
|
def assert_exact_text(
|
9934
|
-
self, text, selector="
|
9970
|
+
self, text, selector="body", by="css selector", timeout=None
|
9935
9971
|
):
|
9936
9972
|
"""Similar to assert_text(), but the text must be exact,
|
9937
9973
|
rather than exist as a subset of the full text.
|
@@ -9978,7 +10014,7 @@ class BaseCase(unittest.TestCase):
|
|
9978
10014
|
return True
|
9979
10015
|
|
9980
10016
|
def assert_non_empty_text(
|
9981
|
-
self, selector="
|
10017
|
+
self, selector="body", by="css selector", timeout=None
|
9982
10018
|
):
|
9983
10019
|
"""Assert that the element has any non-empty text visible.
|
9984
10020
|
Raises an exception if the element has no text within the timeout.
|
@@ -10265,7 +10301,7 @@ class BaseCase(unittest.TestCase):
|
|
10265
10301
|
############
|
10266
10302
|
|
10267
10303
|
def wait_for_text_not_visible(
|
10268
|
-
self, text, selector="
|
10304
|
+
self, text, selector="body", by="css selector", timeout=None
|
10269
10305
|
):
|
10270
10306
|
self.__check_scope()
|
10271
10307
|
if not timeout:
|
@@ -10278,7 +10314,7 @@ class BaseCase(unittest.TestCase):
|
|
10278
10314
|
)
|
10279
10315
|
|
10280
10316
|
def wait_for_exact_text_not_visible(
|
10281
|
-
self, text, selector="
|
10317
|
+
self, text, selector="body", by="css selector", timeout=None
|
10282
10318
|
):
|
10283
10319
|
self.__check_scope()
|
10284
10320
|
if not timeout:
|
@@ -10291,7 +10327,7 @@ class BaseCase(unittest.TestCase):
|
|
10291
10327
|
)
|
10292
10328
|
|
10293
10329
|
def assert_text_not_visible(
|
10294
|
-
self, text, selector="
|
10330
|
+
self, text, selector="body", by="css selector", timeout=None
|
10295
10331
|
):
|
10296
10332
|
"""Similar to wait_for_text_not_visible()
|
10297
10333
|
Raises an exception if the text is still visible after timeout.
|
@@ -10312,7 +10348,7 @@ class BaseCase(unittest.TestCase):
|
|
10312
10348
|
return True
|
10313
10349
|
|
10314
10350
|
def assert_exact_text_not_visible(
|
10315
|
-
self, text, selector="
|
10351
|
+
self, text, selector="body", by="css selector", timeout=None
|
10316
10352
|
):
|
10317
10353
|
"""Similar to wait_for_exact_text_not_visible()
|
10318
10354
|
Raises an exception if the exact text is still visible after timeout.
|
@@ -11069,7 +11105,7 @@ class BaseCase(unittest.TestCase):
|
|
11069
11105
|
return False
|
11070
11106
|
|
11071
11107
|
def deferred_assert_text(
|
11072
|
-
self, text, selector="
|
11108
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
11073
11109
|
):
|
11074
11110
|
"""A non-terminating assertion for text from an element on a page.
|
11075
11111
|
Failures will be saved until the process_deferred_asserts()
|
@@ -11105,7 +11141,7 @@ class BaseCase(unittest.TestCase):
|
|
11105
11141
|
return False
|
11106
11142
|
|
11107
11143
|
def deferred_assert_exact_text(
|
11108
|
-
self, text, selector="
|
11144
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
11109
11145
|
):
|
11110
11146
|
"""A non-terminating assertion for exact text from an element.
|
11111
11147
|
Failures will be saved until the process_deferred_asserts()
|
@@ -11144,7 +11180,7 @@ class BaseCase(unittest.TestCase):
|
|
11144
11180
|
|
11145
11181
|
def deferred_assert_non_empty_text(
|
11146
11182
|
self,
|
11147
|
-
selector="
|
11183
|
+
selector="body",
|
11148
11184
|
by="css selector",
|
11149
11185
|
timeout=None,
|
11150
11186
|
fs=False,
|
@@ -11264,7 +11300,7 @@ class BaseCase(unittest.TestCase):
|
|
11264
11300
|
)
|
11265
11301
|
|
11266
11302
|
def delayed_assert_text(
|
11267
|
-
self, text, selector="
|
11303
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
11268
11304
|
):
|
11269
11305
|
"""Same as self.deferred_assert_text()"""
|
11270
11306
|
return self.deferred_assert_text(
|
@@ -11272,7 +11308,7 @@ class BaseCase(unittest.TestCase):
|
|
11272
11308
|
)
|
11273
11309
|
|
11274
11310
|
def delayed_assert_exact_text(
|
11275
|
-
self, text, selector="
|
11311
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
11276
11312
|
):
|
11277
11313
|
"""Same as self.deferred_assert_exact_text()"""
|
11278
11314
|
return self.deferred_assert_exact_text(
|
@@ -11281,7 +11317,7 @@ class BaseCase(unittest.TestCase):
|
|
11281
11317
|
|
11282
11318
|
def delayed_assert_non_empty_text(
|
11283
11319
|
self,
|
11284
|
-
selector="
|
11320
|
+
selector="body",
|
11285
11321
|
by="css selector",
|
11286
11322
|
timeout=None,
|
11287
11323
|
fs=False,
|
@@ -13762,7 +13798,8 @@ class BaseCase(unittest.TestCase):
|
|
13762
13798
|
if self.get_current_url() == "about:blank":
|
13763
13799
|
self.switch_to_window(current_window)
|
13764
13800
|
except Exception:
|
13765
|
-
|
13801
|
+
with suppress(Exception):
|
13802
|
+
self.switch_to_window(current_window)
|
13766
13803
|
|
13767
13804
|
def __needs_minimum_wait(self):
|
13768
13805
|
if (
|
@@ -13846,7 +13883,8 @@ class BaseCase(unittest.TestCase):
|
|
13846
13883
|
js_utils.scroll_to_element(self.driver, element)
|
13847
13884
|
|
13848
13885
|
def __highlight_with_js(self, selector, loops, o_bs):
|
13849
|
-
self.
|
13886
|
+
if not self.__is_cdp_swap_needed():
|
13887
|
+
self.wait_for_ready_state_complete()
|
13850
13888
|
js_utils.highlight_with_js(self.driver, selector, loops, o_bs)
|
13851
13889
|
|
13852
13890
|
def __highlight_element_with_js(self, element, loops, o_bs):
|
@@ -13970,16 +14008,95 @@ class BaseCase(unittest.TestCase):
|
|
13970
14008
|
visible=0, size=(width, height)
|
13971
14009
|
)
|
13972
14010
|
self._xvfb_display.start()
|
13973
|
-
sb_config._virtual_display = self._xvfb_display
|
13974
14011
|
self.headless_active = True
|
13975
|
-
|
14012
|
+
if not self.undetectable:
|
14013
|
+
sb_config._virtual_display = self._xvfb_display
|
14014
|
+
sb_config.headless_active = True
|
14015
|
+
if self._reuse_session and hasattr(sb_config, "_vd_list"):
|
14016
|
+
if isinstance(sb_config._vd_list, list):
|
14017
|
+
sb_config._vd_list.append(self._xvfb_display)
|
14018
|
+
|
14019
|
+
def __activate_virtual_display(self):
|
14020
|
+
if self.undetectable and not (self.headless or self.headless2):
|
14021
|
+
from sbvirtualdisplay import Display
|
14022
|
+
import Xlib.display
|
14023
|
+
try:
|
14024
|
+
if not self._xvfb_width:
|
14025
|
+
self._xvfb_width = 1366
|
14026
|
+
if not self._xvfb_height:
|
14027
|
+
self._xvfb_height = 768
|
14028
|
+
self._xvfb_display = Display(
|
14029
|
+
visible=True,
|
14030
|
+
size=(self._xvfb_width, self._xvfb_height),
|
14031
|
+
backend="xvfb",
|
14032
|
+
use_xauth=True,
|
14033
|
+
)
|
14034
|
+
self._xvfb_display.start()
|
14035
|
+
if "DISPLAY" not in os.environ.keys():
|
14036
|
+
print(
|
14037
|
+
"\nX11 display failed! Will use regular xvfb!"
|
14038
|
+
)
|
14039
|
+
self.__activate_standard_virtual_display()
|
14040
|
+
else:
|
14041
|
+
self.headless_active = True
|
14042
|
+
if self._reuse_session and hasattr(sb_config, "_vd_list"):
|
14043
|
+
if isinstance(sb_config._vd_list, list):
|
14044
|
+
sb_config._vd_list.append(self._xvfb_display)
|
14045
|
+
except Exception as e:
|
14046
|
+
if hasattr(e, "msg"):
|
14047
|
+
print("\n" + str(e.msg))
|
14048
|
+
else:
|
14049
|
+
print(e)
|
14050
|
+
print("\nX11 display failed! Will use regular xvfb!")
|
14051
|
+
self.__activate_standard_virtual_display()
|
14052
|
+
return
|
14053
|
+
pyautogui_is_installed = False
|
14054
|
+
try:
|
14055
|
+
import pyautogui
|
14056
|
+
with suppress(Exception):
|
14057
|
+
use_pyautogui_ver = constants.PyAutoGUI.VER
|
14058
|
+
if pyautogui.__version__ != use_pyautogui_ver:
|
14059
|
+
del pyautogui # To get newer ver
|
14060
|
+
shared_utils.pip_install(
|
14061
|
+
"pyautogui", version=use_pyautogui_ver
|
14062
|
+
)
|
14063
|
+
import pyautogui
|
14064
|
+
pyautogui_is_installed = True
|
14065
|
+
except Exception:
|
14066
|
+
message = (
|
14067
|
+
"PyAutoGUI is required for UC Mode on Linux! "
|
14068
|
+
"Installing now..."
|
14069
|
+
)
|
14070
|
+
print("\n" + message)
|
14071
|
+
shared_utils.pip_install(
|
14072
|
+
"pyautogui", version=constants.PyAutoGUI.VER
|
14073
|
+
)
|
14074
|
+
import pyautogui
|
14075
|
+
pyautogui_is_installed = True
|
14076
|
+
if (
|
14077
|
+
pyautogui_is_installed
|
14078
|
+
and hasattr(pyautogui, "_pyautogui_x11")
|
14079
|
+
):
|
14080
|
+
try:
|
14081
|
+
pyautogui._pyautogui_x11._display = (
|
14082
|
+
Xlib.display.Display(os.environ['DISPLAY'])
|
14083
|
+
)
|
14084
|
+
sb_config._pyautogui_x11_display = (
|
14085
|
+
pyautogui._pyautogui_x11._display
|
14086
|
+
)
|
14087
|
+
except Exception as e:
|
14088
|
+
if hasattr(e, "msg"):
|
14089
|
+
print("\n" + str(e.msg))
|
14090
|
+
else:
|
14091
|
+
print(e)
|
14092
|
+
else:
|
14093
|
+
self.__activate_standard_virtual_display()
|
13976
14094
|
|
13977
14095
|
def __activate_virtual_display_as_needed(self):
|
13978
14096
|
"""This is only needed on Linux.
|
13979
14097
|
The "--xvfb" arg is still useful, as it prevents headless mode,
|
13980
14098
|
which is the default mode on Linux unless using another arg."""
|
13981
|
-
if
|
13982
|
-
from sbvirtualdisplay import Display
|
14099
|
+
if is_linux and (not self.headed or self.xvfb):
|
13983
14100
|
pip_find_lock = fasteners.InterProcessLock(
|
13984
14101
|
constants.PipInstall.FINDLOCK
|
13985
14102
|
)
|
@@ -13987,80 +14104,13 @@ class BaseCase(unittest.TestCase):
|
|
13987
14104
|
with pip_find_lock:
|
13988
14105
|
pass
|
13989
14106
|
except Exception:
|
13990
|
-
#
|
13991
|
-
|
13992
|
-
|
13993
|
-
mode |= (mode & 0o444) >> 1 # copy R bits to W
|
13994
|
-
os.chmod(constants.PipInstall.FINDLOCK, mode)
|
14107
|
+
# Since missing permissions, skip the locks
|
14108
|
+
self.__activate_virtual_display()
|
14109
|
+
return
|
13995
14110
|
with pip_find_lock: # Prevent issues with multiple processes
|
13996
|
-
|
13997
|
-
|
13998
|
-
|
13999
|
-
if not self._xvfb_width:
|
14000
|
-
self._xvfb_width = 1366
|
14001
|
-
if not self._xvfb_height:
|
14002
|
-
self._xvfb_height = 768
|
14003
|
-
self._xvfb_display = Display(
|
14004
|
-
visible=True,
|
14005
|
-
size=(self._xvfb_width, self._xvfb_height),
|
14006
|
-
backend="xvfb",
|
14007
|
-
use_xauth=True,
|
14008
|
-
)
|
14009
|
-
self._xvfb_display.start()
|
14010
|
-
if "DISPLAY" not in os.environ.keys():
|
14011
|
-
print(
|
14012
|
-
"\nX11 display failed! Will use regular xvfb!"
|
14013
|
-
)
|
14014
|
-
self.__activate_standard_virtual_display()
|
14015
|
-
except Exception as e:
|
14016
|
-
if hasattr(e, "msg"):
|
14017
|
-
print("\n" + str(e.msg))
|
14018
|
-
else:
|
14019
|
-
print(e)
|
14020
|
-
print("\nX11 display failed! Will use regular xvfb!")
|
14021
|
-
self.__activate_standard_virtual_display()
|
14022
|
-
return
|
14023
|
-
pyautogui_is_installed = False
|
14024
|
-
try:
|
14025
|
-
import pyautogui
|
14026
|
-
with suppress(Exception):
|
14027
|
-
use_pyautogui_ver = constants.PyAutoGUI.VER
|
14028
|
-
if pyautogui.__version__ != use_pyautogui_ver:
|
14029
|
-
del pyautogui # To get newer ver
|
14030
|
-
shared_utils.pip_install(
|
14031
|
-
"pyautogui", version=use_pyautogui_ver
|
14032
|
-
)
|
14033
|
-
import pyautogui
|
14034
|
-
pyautogui_is_installed = True
|
14035
|
-
except Exception:
|
14036
|
-
message = (
|
14037
|
-
"PyAutoGUI is required for UC Mode on Linux! "
|
14038
|
-
"Installing now..."
|
14039
|
-
)
|
14040
|
-
print("\n" + message)
|
14041
|
-
shared_utils.pip_install(
|
14042
|
-
"pyautogui", version=constants.PyAutoGUI.VER
|
14043
|
-
)
|
14044
|
-
import pyautogui
|
14045
|
-
pyautogui_is_installed = True
|
14046
|
-
if (
|
14047
|
-
pyautogui_is_installed
|
14048
|
-
and hasattr(pyautogui, "_pyautogui_x11")
|
14049
|
-
):
|
14050
|
-
try:
|
14051
|
-
pyautogui._pyautogui_x11._display = (
|
14052
|
-
Xlib.display.Display(os.environ['DISPLAY'])
|
14053
|
-
)
|
14054
|
-
sb_config._pyautogui_x11_display = (
|
14055
|
-
pyautogui._pyautogui_x11._display
|
14056
|
-
)
|
14057
|
-
except Exception as e:
|
14058
|
-
if hasattr(e, "msg"):
|
14059
|
-
print("\n" + str(e.msg))
|
14060
|
-
else:
|
14061
|
-
print(e)
|
14062
|
-
else:
|
14063
|
-
self.__activate_standard_virtual_display()
|
14111
|
+
with suppress(Exception):
|
14112
|
+
shared_utils.make_writable(constants.PipInstall.FINDLOCK)
|
14113
|
+
self.__activate_virtual_display()
|
14064
14114
|
|
14065
14115
|
def __ad_block_as_needed(self):
|
14066
14116
|
"""This is an internal method for handling ad-blocking.
|
@@ -15081,6 +15131,10 @@ class BaseCase(unittest.TestCase):
|
|
15081
15131
|
if self.dashboard:
|
15082
15132
|
if self._multithreaded:
|
15083
15133
|
with self.dash_lock:
|
15134
|
+
with suppress(Exception):
|
15135
|
+
shared_utils.make_writable(
|
15136
|
+
constants.Dashboard.LOCKFILE
|
15137
|
+
)
|
15084
15138
|
if not self._dash_initialized:
|
15085
15139
|
sb_config._dashboard_initialized = True
|
15086
15140
|
self._dash_initialized = True
|
@@ -15114,9 +15168,12 @@ class BaseCase(unittest.TestCase):
|
|
15114
15168
|
self.driver.close()
|
15115
15169
|
self.switch_to_window(0)
|
15116
15170
|
if self._crumbs:
|
15117
|
-
self.
|
15118
|
-
|
15119
|
-
|
15171
|
+
if self.binary_location == "chs":
|
15172
|
+
self.delete_session_storage()
|
15173
|
+
else:
|
15174
|
+
self.wait_for_ready_state_complete()
|
15175
|
+
with suppress(Exception):
|
15176
|
+
self.driver.delete_all_cookies()
|
15120
15177
|
if self._reuse_session and sb_config.shared_driver and has_url:
|
15121
15178
|
good_start_page = False
|
15122
15179
|
if self.recorder_ext:
|
@@ -15640,6 +15697,8 @@ class BaseCase(unittest.TestCase):
|
|
15640
15697
|
constants.Dashboard.LOCKFILE
|
15641
15698
|
)
|
15642
15699
|
with self.dash_lock:
|
15700
|
+
with suppress(Exception):
|
15701
|
+
shared_utils.make_writable(constants.Dashboard.LOCKFILE)
|
15643
15702
|
self.__process_dashboard(has_exception, init)
|
15644
15703
|
else:
|
15645
15704
|
self.__process_dashboard(has_exception, init)
|
@@ -16409,6 +16468,10 @@ class BaseCase(unittest.TestCase):
|
|
16409
16468
|
if self.dashboard:
|
16410
16469
|
if self._multithreaded:
|
16411
16470
|
with self.dash_lock:
|
16471
|
+
with suppress(Exception):
|
16472
|
+
shared_utils.make_writable(
|
16473
|
+
constants.Dashboard.LOCKFILE
|
16474
|
+
)
|
16412
16475
|
self.__process_dashboard(has_exception)
|
16413
16476
|
else:
|
16414
16477
|
self.__process_dashboard(has_exception)
|
@@ -16553,7 +16616,12 @@ class BaseCase(unittest.TestCase):
|
|
16553
16616
|
# (Pynose / Behave / Pure Python) Close all open browser windows
|
16554
16617
|
self.__quit_all_drivers()
|
16555
16618
|
# Resume tearDown() for all test runners, (Pytest / Pynose / Behave)
|
16556
|
-
if
|
16619
|
+
if (
|
16620
|
+
hasattr(self, "_xvfb_display")
|
16621
|
+
and self._xvfb_display
|
16622
|
+
and not self._reuse_session
|
16623
|
+
):
|
16624
|
+
# Stop the Xvfb virtual display launched from BaseCase
|
16557
16625
|
try:
|
16558
16626
|
if hasattr(self._xvfb_display, "stop"):
|
16559
16627
|
self._xvfb_display.stop()
|
@@ -16563,6 +16631,27 @@ class BaseCase(unittest.TestCase):
|
|
16563
16631
|
pass
|
16564
16632
|
except Exception:
|
16565
16633
|
pass
|
16634
|
+
if (
|
16635
|
+
hasattr(sb_config, "_virtual_display")
|
16636
|
+
and sb_config._virtual_display
|
16637
|
+
and hasattr(sb_config._virtual_display, "stop")
|
16638
|
+
and (
|
16639
|
+
not hasattr(sb_config, "reuse_session")
|
16640
|
+
or (
|
16641
|
+
hasattr(sb_config, "reuse_session")
|
16642
|
+
and not sb_config.reuse_session
|
16643
|
+
)
|
16644
|
+
)
|
16645
|
+
):
|
16646
|
+
# CDP Mode may launch a 2nd Xvfb virtual display
|
16647
|
+
try:
|
16648
|
+
sb_config._virtual_display.stop()
|
16649
|
+
sb_config._virtual_display = None
|
16650
|
+
sb_config.headless_active = False
|
16651
|
+
except AttributeError:
|
16652
|
+
pass
|
16653
|
+
except Exception:
|
16654
|
+
pass
|
16566
16655
|
if self.__visual_baseline_copies:
|
16567
16656
|
sb_config._visual_baseline_copies = True
|
16568
16657
|
if has_exception:
|