seleniumbase 4.33.4__py3-none-any.whl → 4.34.2__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/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:
|