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.
Files changed (33) hide show
  1. seleniumbase/__version__.py +1 -1
  2. seleniumbase/behave/behave_sb.py +10 -2
  3. seleniumbase/console_scripts/run.py +6 -2
  4. seleniumbase/console_scripts/sb_commander.py +5 -5
  5. seleniumbase/console_scripts/sb_install.py +235 -6
  6. seleniumbase/console_scripts/sb_mkdir.py +1 -0
  7. seleniumbase/core/browser_launcher.py +358 -105
  8. seleniumbase/core/log_helper.py +33 -12
  9. seleniumbase/core/proxy_helper.py +35 -30
  10. seleniumbase/core/sb_cdp.py +277 -74
  11. seleniumbase/core/settings_parser.py +2 -0
  12. seleniumbase/core/style_sheet.py +10 -0
  13. seleniumbase/fixtures/base_case.py +216 -127
  14. seleniumbase/fixtures/constants.py +3 -0
  15. seleniumbase/fixtures/js_utils.py +2 -0
  16. seleniumbase/fixtures/page_actions.py +7 -2
  17. seleniumbase/fixtures/shared_utils.py +25 -0
  18. seleniumbase/plugins/driver_manager.py +28 -0
  19. seleniumbase/plugins/pytest_plugin.py +110 -0
  20. seleniumbase/plugins/sb_manager.py +41 -0
  21. seleniumbase/plugins/selenium_plugin.py +9 -0
  22. seleniumbase/undetected/cdp_driver/_contradict.py +3 -3
  23. seleniumbase/undetected/cdp_driver/browser.py +8 -6
  24. seleniumbase/undetected/cdp_driver/cdp_util.py +3 -0
  25. seleniumbase/undetected/cdp_driver/config.py +0 -1
  26. seleniumbase/undetected/cdp_driver/element.py +22 -20
  27. seleniumbase/undetected/patcher.py +20 -5
  28. {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/LICENSE +1 -1
  29. {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/METADATA +111 -86
  30. {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/RECORD +33 -33
  31. {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/WHEEL +1 -1
  32. {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/entry_points.txt +0 -0
  33. {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="html", by="css 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="html", by="css 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="html", by="css 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="html", by="css selector", timeout=None):
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="html", by="css selector", timeout=None
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 self.get_attribute(
2497
- selector, "checked", by=by, timeout=timeout, hard_fail=False
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.wait_for_ready_state_complete()
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 "linux" not in sys.platform:
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 "linux" not in sys.platform:
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 "linux" not in sys.platform:
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() and ":contains(" not in selector:
6055
- self.cdp.highlight(selector)
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="html", times=1, by="css 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="html", times=1, by="css 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="html", times=1, by="css 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="html", times=1, by="css 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="html", by="css selector", timeout=None
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="html", by="css selector", timeout=None
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="html", by="css selector", timeout=None
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="html", by="css selector", timeout=None
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="html", by="css selector", timeout=None
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="html", by="css selector", timeout=None
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="html", by="css selector", timeout=None
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="html", by="css selector", timeout=None
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="html", by="css selector", timeout=None
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="html", by="css selector", timeout=None
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="html", by="css selector", timeout=None
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="html", by="css selector", timeout=None
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="html", by="css selector", timeout=None
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="html", by="css selector", timeout=None
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="html", by="css selector", timeout=None
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="html", by="css selector", timeout=None
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="html", by="css selector", timeout=None
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="html", by="css selector", timeout=None, fs=False
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="html", by="css selector", timeout=None, fs=False
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="html",
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="html", by="css selector", timeout=None, fs=False
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="html", by="css selector", timeout=None, fs=False
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="html",
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
- self.switch_to_window(current_window)
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.wait_for_ready_state_complete()
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
- sb_config.headless_active = True
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 "linux" in sys.platform and (not self.headed or self.xvfb):
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
- # Need write permissions
13991
- with suppress(Exception):
13992
- mode = os.stat(constants.PipInstall.FINDLOCK).st_mode
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
- if self.undetectable and not (self.headless or self.headless2):
13997
- import Xlib.display
13998
- try:
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.wait_for_ready_state_complete()
15118
- with suppress(Exception):
15119
- self.driver.delete_all_cookies()
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 hasattr(self, "_xvfb_display") and self._xvfb_display:
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: