seleniumbase 4.24.10__py3-none-any.whl → 4.33.15__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. sbase/__init__.py +1 -0
  2. sbase/steps.py +7 -0
  3. seleniumbase/__init__.py +16 -7
  4. seleniumbase/__version__.py +1 -1
  5. seleniumbase/behave/behave_sb.py +97 -32
  6. seleniumbase/common/decorators.py +16 -7
  7. seleniumbase/config/proxy_list.py +3 -3
  8. seleniumbase/config/settings.py +4 -0
  9. seleniumbase/console_scripts/logo_helper.py +47 -8
  10. seleniumbase/console_scripts/run.py +345 -335
  11. seleniumbase/console_scripts/sb_behave_gui.py +5 -12
  12. seleniumbase/console_scripts/sb_caseplans.py +6 -13
  13. seleniumbase/console_scripts/sb_commander.py +5 -12
  14. seleniumbase/console_scripts/sb_install.py +62 -54
  15. seleniumbase/console_scripts/sb_mkchart.py +13 -20
  16. seleniumbase/console_scripts/sb_mkdir.py +11 -17
  17. seleniumbase/console_scripts/sb_mkfile.py +69 -43
  18. seleniumbase/console_scripts/sb_mkpres.py +13 -20
  19. seleniumbase/console_scripts/sb_mkrec.py +88 -21
  20. seleniumbase/console_scripts/sb_objectify.py +30 -30
  21. seleniumbase/console_scripts/sb_print.py +5 -12
  22. seleniumbase/console_scripts/sb_recorder.py +16 -11
  23. seleniumbase/core/browser_launcher.py +1658 -221
  24. seleniumbase/core/detect_b_ver.py +7 -8
  25. seleniumbase/core/log_helper.py +42 -27
  26. seleniumbase/core/mysql.py +1 -4
  27. seleniumbase/core/proxy_helper.py +35 -30
  28. seleniumbase/core/recorder_helper.py +24 -5
  29. seleniumbase/core/sb_cdp.py +1951 -0
  30. seleniumbase/core/sb_driver.py +162 -8
  31. seleniumbase/core/settings_parser.py +6 -0
  32. seleniumbase/core/style_sheet.py +10 -0
  33. seleniumbase/extensions/recorder.zip +0 -0
  34. seleniumbase/fixtures/base_case.py +1234 -632
  35. seleniumbase/fixtures/constants.py +10 -1
  36. seleniumbase/fixtures/js_utils.py +171 -144
  37. seleniumbase/fixtures/page_actions.py +177 -13
  38. seleniumbase/fixtures/page_utils.py +25 -53
  39. seleniumbase/fixtures/shared_utils.py +97 -11
  40. seleniumbase/js_code/active_css_js.py +1 -1
  41. seleniumbase/js_code/recorder_js.py +1 -1
  42. seleniumbase/plugins/base_plugin.py +2 -3
  43. seleniumbase/plugins/driver_manager.py +340 -65
  44. seleniumbase/plugins/pytest_plugin.py +276 -47
  45. seleniumbase/plugins/sb_manager.py +412 -99
  46. seleniumbase/plugins/selenium_plugin.py +122 -17
  47. seleniumbase/translate/translator.py +0 -7
  48. seleniumbase/undetected/__init__.py +59 -52
  49. seleniumbase/undetected/cdp.py +0 -1
  50. seleniumbase/undetected/cdp_driver/__init__.py +1 -0
  51. seleniumbase/undetected/cdp_driver/_contradict.py +110 -0
  52. seleniumbase/undetected/cdp_driver/browser.py +829 -0
  53. seleniumbase/undetected/cdp_driver/cdp_util.py +458 -0
  54. seleniumbase/undetected/cdp_driver/config.py +334 -0
  55. seleniumbase/undetected/cdp_driver/connection.py +639 -0
  56. seleniumbase/undetected/cdp_driver/element.py +1168 -0
  57. seleniumbase/undetected/cdp_driver/tab.py +1323 -0
  58. seleniumbase/undetected/dprocess.py +4 -7
  59. seleniumbase/undetected/options.py +6 -8
  60. seleniumbase/undetected/patcher.py +11 -13
  61. seleniumbase/undetected/reactor.py +0 -1
  62. seleniumbase/undetected/webelement.py +16 -3
  63. {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/LICENSE +1 -1
  64. {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/METADATA +299 -252
  65. {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/RECORD +68 -70
  66. {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/WHEEL +1 -1
  67. sbase/ReadMe.txt +0 -2
  68. seleniumbase/ReadMe.md +0 -25
  69. seleniumbase/common/ReadMe.md +0 -71
  70. seleniumbase/console_scripts/ReadMe.md +0 -731
  71. seleniumbase/drivers/ReadMe.md +0 -27
  72. seleniumbase/extensions/ReadMe.md +0 -12
  73. seleniumbase/masterqa/ReadMe.md +0 -61
  74. seleniumbase/resources/ReadMe.md +0 -31
  75. seleniumbase/resources/favicon.ico +0 -0
  76. seleniumbase/utilities/selenium_grid/ReadMe.md +0 -84
  77. seleniumbase/utilities/selenium_ide/ReadMe.md +0 -111
  78. {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/entry_points.txt +0 -0
  79. {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/top_level.txt +0 -0
@@ -33,6 +33,7 @@ Page elements are given enough time to load before WebDriver acts on them.
33
33
  Code becomes greatly simplified and easier to maintain."""
34
34
 
35
35
  import codecs
36
+ import colorama
36
37
  import fasteners
37
38
  import json
38
39
  import logging
@@ -45,7 +46,7 @@ import textwrap
45
46
  import time
46
47
  import unittest
47
48
  import urllib3
48
- from contextlib import contextmanager
49
+ from contextlib import contextmanager, suppress
49
50
  from selenium.common.exceptions import (
50
51
  ElementClickInterceptedException as ECI_Exception,
51
52
  ElementNotInteractableException as ENI_Exception,
@@ -57,9 +58,11 @@ from selenium.common.exceptions import (
57
58
  TimeoutException,
58
59
  WebDriverException,
59
60
  )
61
+ from selenium.webdriver.common.action_chains import ActionChains
60
62
  from selenium.webdriver.common.by import By
61
63
  from selenium.webdriver.common.keys import Keys
62
64
  from selenium.webdriver.remote.remote_connection import LOGGER
65
+ from selenium.webdriver.remote.webelement import WebElement
63
66
  from seleniumbase import config as sb_config
64
67
  from seleniumbase.__version__ import __version__
65
68
  from seleniumbase.common import decorators
@@ -72,9 +75,11 @@ from seleniumbase.common.exceptions import (
72
75
  VisualException,
73
76
  )
74
77
  from seleniumbase.config import settings
78
+ from seleniumbase.core import browser_launcher
75
79
  from seleniumbase.core import download_helper
76
80
  from seleniumbase.core import log_helper
77
81
  from seleniumbase.core import session_helper
82
+ from seleniumbase.core import visual_helper
78
83
  from seleniumbase.fixtures import constants
79
84
  from seleniumbase.fixtures import css_to_xpath
80
85
  from seleniumbase.fixtures import js_utils
@@ -113,6 +118,7 @@ class BaseCase(unittest.TestCase):
113
118
  ]
114
119
  self.version_tuple = tuple(self.version_list)
115
120
  self.version_info = self.version_tuple
121
+ self.time = time.time
116
122
  self.__page_sources = []
117
123
  self.__extra_actions = []
118
124
  self.__js_start_time = 0
@@ -178,6 +184,8 @@ class BaseCase(unittest.TestCase):
178
184
  self._chart_series_count = {}
179
185
  self._tour_steps = {}
180
186
  self._xvfb_display = None
187
+ self._xvfb_width = None
188
+ self._xvfb_height = None
181
189
 
182
190
  @classmethod
183
191
  def main(self, name, file, *args):
@@ -215,14 +223,15 @@ class BaseCase(unittest.TestCase):
215
223
  def open(self, url):
216
224
  """Navigates the current browser window to the specified page."""
217
225
  self.__check_scope()
226
+ if self.__is_cdp_swap_needed():
227
+ self.cdp.open(url)
228
+ return
218
229
  self._check_browser()
219
230
  if self.__needs_minimum_wait():
220
231
  time.sleep(0.04)
221
232
  pre_action_url = None
222
- try:
233
+ with suppress(Exception):
223
234
  pre_action_url = self.driver.current_url
224
- except Exception:
225
- pass
226
235
  url = str(url).strip() # Remove leading and trailing whitespace
227
236
  if not self.__looks_like_a_page_url(url):
228
237
  # url should start with one of the following:
@@ -350,18 +359,12 @@ class BaseCase(unittest.TestCase):
350
359
  if self.undetectable:
351
360
  self.__uc_frame_layer = 0
352
361
  if self.demo_mode:
353
- if (
354
- self.driver.current_url.startswith("http")
355
- or self.driver.current_url.startswith("file")
356
- or self.driver.current_url.startswith("data")
357
- ):
362
+ if self.driver.current_url.startswith(("http", "file", "data")):
358
363
  if not js_utils.is_jquery_activated(self.driver):
359
- try:
364
+ with suppress(Exception):
360
365
  js_utils.add_js_link(
361
366
  self.driver, constants.JQuery.MIN_JS
362
367
  )
363
- except Exception:
364
- pass
365
368
  self.__demo_mode_pause_if_active()
366
369
 
367
370
  def get(self, url):
@@ -380,6 +383,7 @@ class BaseCase(unittest.TestCase):
380
383
  self, selector, by="css selector", timeout=None, delay=0, scroll=True
381
384
  ):
382
385
  self.__check_scope()
386
+ self.__skip_if_esc()
383
387
  if not timeout:
384
388
  timeout = settings.SMALL_TIMEOUT
385
389
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
@@ -387,6 +391,9 @@ class BaseCase(unittest.TestCase):
387
391
  original_selector = selector
388
392
  original_by = by
389
393
  selector, by = self.__recalculate_selector(selector, by)
394
+ if self.__is_cdp_swap_needed():
395
+ self.cdp.click(selector, timeout=timeout)
396
+ return
390
397
  if delay and (type(delay) in [int, float]) and delay > 0:
391
398
  time.sleep(delay)
392
399
  if page_utils.is_link_text_selector(selector) or by == By.LINK_TEXT:
@@ -418,10 +425,8 @@ class BaseCase(unittest.TestCase):
418
425
  if scroll and not self.demo_mode and not self.slow_mode:
419
426
  self.__scroll_to_element(element, selector, by)
420
427
  pre_action_url = None
421
- try:
428
+ with suppress(Exception):
422
429
  pre_action_url = self.driver.current_url
423
- except Exception:
424
- pass
425
430
  pre_window_count = len(self.driver.window_handles)
426
431
  try:
427
432
  if (
@@ -435,7 +440,7 @@ class BaseCase(unittest.TestCase):
435
440
  href = None
436
441
  new_tab = False
437
442
  onclick = None
438
- try:
443
+ with suppress(Exception):
439
444
  if self.headless and element.tag_name.lower() == "a":
440
445
  # Handle a special case of opening a new tab (headless)
441
446
  href = element.get_attribute("href").strip()
@@ -445,20 +450,14 @@ class BaseCase(unittest.TestCase):
445
450
  new_tab = True
446
451
  if new_tab and self.__looks_like_a_page_url(href):
447
452
  if onclick:
448
- try:
453
+ with suppress(Exception):
449
454
  self.execute_script(onclick)
450
- except Exception:
451
- pass
452
455
  current_window = self.driver.current_window_handle
453
456
  self.open_new_window()
454
- try:
457
+ with suppress(Exception):
455
458
  self.open(href)
456
- except Exception:
457
- pass
458
459
  self.switch_to_window(current_window)
459
460
  return
460
- except Exception:
461
- pass
462
461
  # Normal click
463
462
  self.__element_click(element)
464
463
  except Stale_Exception:
@@ -471,10 +470,8 @@ class BaseCase(unittest.TestCase):
471
470
  timeout=timeout,
472
471
  original_selector=original_selector,
473
472
  )
474
- try:
473
+ with suppress(Exception):
475
474
  self.__scroll_to_element(element, selector, by)
476
- except Exception:
477
- pass
478
475
  if self.browser == "safari" and by == By.LINK_TEXT:
479
476
  self.__jquery_click(selector, by=by)
480
477
  elif self.browser == "safari":
@@ -482,7 +479,7 @@ class BaseCase(unittest.TestCase):
482
479
  else:
483
480
  self.__element_click(element)
484
481
  except ENI_Exception as e:
485
- try:
482
+ with suppress(Exception):
486
483
  if (
487
484
  "element has zero size" in e.msg
488
485
  and element.tag_name.lower() == "a"
@@ -494,8 +491,6 @@ class BaseCase(unittest.TestCase):
494
491
  if self.__needs_minimum_wait():
495
492
  time.sleep(0.04)
496
493
  return
497
- except Exception:
498
- pass
499
494
  self.wait_for_ready_state_complete()
500
495
  time.sleep(0.1)
501
496
  element = page_actions.wait_for_element_visible(
@@ -508,12 +503,10 @@ class BaseCase(unittest.TestCase):
508
503
  if not page_actions.is_element_clickable(
509
504
  self.driver, selector, by
510
505
  ):
511
- try:
506
+ with suppress(Exception):
512
507
  self.wait_for_element_clickable(
513
508
  selector, by, timeout=1.8
514
509
  )
515
- except Exception:
516
- pass # Find out which element would get the click instead
517
510
  element = page_actions.wait_for_element_visible(
518
511
  self.driver,
519
512
  selector,
@@ -524,7 +517,7 @@ class BaseCase(unittest.TestCase):
524
517
  href = None
525
518
  new_tab = False
526
519
  onclick = None
527
- try:
520
+ with suppress(Exception):
528
521
  if element.tag_name.lower() == "a":
529
522
  # Handle a special case of opening a new tab (non-headless)
530
523
  href = element.get_attribute("href").strip()
@@ -534,20 +527,14 @@ class BaseCase(unittest.TestCase):
534
527
  new_tab = True
535
528
  if new_tab and self.__looks_like_a_page_url(href):
536
529
  if onclick:
537
- try:
530
+ with suppress(Exception):
538
531
  self.execute_script(onclick)
539
- except Exception:
540
- pass
541
532
  current_window = self.driver.current_window_handle
542
533
  self.open_new_window()
543
- try:
534
+ with suppress(Exception):
544
535
  self.open(href)
545
- except Exception:
546
- pass
547
536
  self.switch_to_window(current_window)
548
537
  return
549
- except Exception:
550
- pass
551
538
  if scroll and not self.demo_mode and not self.slow_mode:
552
539
  self.__scroll_to_element(element, selector, by)
553
540
  if self.browser == "firefox" or self.browser == "safari":
@@ -629,10 +616,8 @@ class BaseCase(unittest.TestCase):
629
616
  self.switch_to_window(-1)
630
617
  if settings.WAIT_FOR_RSC_ON_CLICKS:
631
618
  if not self.undetectable:
632
- try:
619
+ with suppress(Exception):
633
620
  self.wait_for_ready_state_complete()
634
- except Exception:
635
- pass
636
621
  if self.__needs_minimum_wait() or self.browser == "safari":
637
622
  time.sleep(0.05)
638
623
  else:
@@ -640,10 +625,8 @@ class BaseCase(unittest.TestCase):
640
625
  else:
641
626
  if not self.undetectable:
642
627
  # A smaller subset of self.wait_for_ready_state_complete()
643
- try:
628
+ with suppress(Exception):
644
629
  self.wait_for_angularjs(timeout=settings.MINI_TIMEOUT)
645
- except Exception:
646
- pass
647
630
  if self.__needs_minimum_wait() or self.browser == "safari":
648
631
  time.sleep(0.045)
649
632
  try:
@@ -653,10 +636,8 @@ class BaseCase(unittest.TestCase):
653
636
  if self.__needs_minimum_wait():
654
637
  time.sleep(0.075)
655
638
  except Exception:
656
- try:
639
+ with suppress(Exception):
657
640
  self.wait_for_ready_state_complete()
658
- except Exception:
659
- pass
660
641
  if self.__needs_minimum_wait():
661
642
  time.sleep(0.05)
662
643
  else:
@@ -670,6 +651,7 @@ class BaseCase(unittest.TestCase):
670
651
  self.__demo_mode_pause_if_active(tiny=True)
671
652
  elif self.slow_mode:
672
653
  self.__slow_mode_pause_if_active()
654
+ self.__set_esc_skip()
673
655
 
674
656
  def slow_click(self, selector, by="css selector", timeout=None):
675
657
  """Similar to click(), but pauses for a brief moment before clicking.
@@ -693,8 +675,6 @@ class BaseCase(unittest.TestCase):
693
675
  self.click(selector, by=by, timeout=timeout, delay=0.25)
694
676
 
695
677
  def double_click(self, selector, by="css selector", timeout=None):
696
- from selenium.webdriver.common.action_chains import ActionChains
697
-
698
678
  self.__check_scope()
699
679
  if not timeout:
700
680
  timeout = settings.SMALL_TIMEOUT
@@ -725,10 +705,8 @@ class BaseCase(unittest.TestCase):
725
705
  original_selector=original_selector,
726
706
  )
727
707
  pre_action_url = None
728
- try:
708
+ with suppress(Exception):
729
709
  pre_action_url = self.driver.current_url
730
- except Exception:
731
- pass
732
710
  try:
733
711
  if self.browser == "safari":
734
712
  # Jump to the "except" block where the other script should work
@@ -778,8 +756,6 @@ class BaseCase(unittest.TestCase):
778
756
 
779
757
  def context_click(self, selector, by="css selector", timeout=None):
780
758
  """(A context click is a right-click that opens a context menu.)"""
781
- from selenium.webdriver.common.action_chains import ActionChains
782
-
783
759
  self.__check_scope()
784
760
  if not timeout:
785
761
  timeout = settings.SMALL_TIMEOUT
@@ -810,10 +786,8 @@ class BaseCase(unittest.TestCase):
810
786
  original_selector=original_selector,
811
787
  )
812
788
  pre_action_url = None
813
- try:
789
+ with suppress(Exception):
814
790
  pre_action_url = self.driver.current_url
815
- except Exception:
816
- pass
817
791
  try:
818
792
  if self.browser == "safari":
819
793
  # Jump to the "except" block where the other script should work
@@ -910,6 +884,9 @@ class BaseCase(unittest.TestCase):
910
884
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
911
885
  timeout = self.__get_new_timeout(timeout)
912
886
  selector, by = self.__recalculate_selector(selector, by)
887
+ if self.__is_cdp_swap_needed():
888
+ self.cdp.type(selector, text, timeout=timeout)
889
+ return
913
890
  if self.__is_shadow_selector(selector):
914
891
  self.__shadow_type(selector, text, timeout)
915
892
  return
@@ -931,19 +908,15 @@ class BaseCase(unittest.TestCase):
931
908
  element = self.wait_for_element_clickable(
932
909
  selector, by=by, timeout=timeout
933
910
  )
934
- try:
911
+ with suppress(Exception):
935
912
  element.clear()
936
- except Exception:
937
- pass # Clearing the text field first might not be necessary
938
913
  except Exception:
939
914
  pass # Clearing the text field first might not be necessary
940
915
  self.__demo_mode_pause_if_active(tiny=True)
941
916
  pre_action_url = None
942
917
  if self.demo_mode:
943
- try:
918
+ with suppress(Exception):
944
919
  pre_action_url = self.driver.current_url
945
- except Exception:
946
- pass
947
920
  text = self.__get_type_checked_text(text)
948
921
  try:
949
922
  if not text.endswith("\n"):
@@ -1027,6 +1000,9 @@ class BaseCase(unittest.TestCase):
1027
1000
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
1028
1001
  timeout = self.__get_new_timeout(timeout)
1029
1002
  selector, by = self.__recalculate_selector(selector, by)
1003
+ if self.__is_cdp_swap_needed():
1004
+ self.cdp.send_keys(selector, text)
1005
+ return
1030
1006
  if self.__is_shadow_selector(selector):
1031
1007
  self.__shadow_type(selector, text, timeout, clear_first=False)
1032
1008
  return
@@ -1053,10 +1029,8 @@ class BaseCase(unittest.TestCase):
1053
1029
  self.__scroll_to_element(element, selector, by)
1054
1030
  pre_action_url = None
1055
1031
  if self.demo_mode:
1056
- try:
1032
+ with suppress(Exception):
1057
1033
  pre_action_url = self.driver.current_url
1058
- except Exception:
1059
- pass
1060
1034
  text = self.__get_type_checked_text(text)
1061
1035
  try:
1062
1036
  if not text.endswith("\n"):
@@ -1137,6 +1111,9 @@ class BaseCase(unittest.TestCase):
1137
1111
 
1138
1112
  def press_keys(self, selector, text, by="css selector", timeout=None):
1139
1113
  """Use send_keys() to press one key at a time."""
1114
+ if self.__is_cdp_swap_needed():
1115
+ self.cdp.press_keys(selector, text, timeout=timeout)
1116
+ return
1140
1117
  self.wait_for_ready_state_complete()
1141
1118
  element = self.wait_for_element_present(
1142
1119
  selector, by=by, timeout=timeout
@@ -1229,11 +1206,9 @@ class BaseCase(unittest.TestCase):
1229
1206
  selector, by=by, timeout=timeout
1230
1207
  )
1231
1208
  element.clear()
1232
- try:
1209
+ with suppress(Exception):
1233
1210
  backspaces = Keys.BACK_SPACE * 42 # Autofill Defense
1234
1211
  element.send_keys(backspaces)
1235
- except Exception:
1236
- pass
1237
1212
  except Exception:
1238
1213
  element.clear()
1239
1214
 
@@ -1247,9 +1222,20 @@ class BaseCase(unittest.TestCase):
1247
1222
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
1248
1223
  timeout = self.__get_new_timeout(timeout)
1249
1224
  selector, by = self.__recalculate_selector(selector, by)
1250
- element = self.wait_for_element_visible(
1225
+ if self.__is_cdp_swap_needed():
1226
+ self.cdp.focus(selector)
1227
+ return
1228
+ element = self.wait_for_element_present(
1251
1229
  selector, by=by, timeout=timeout
1252
1230
  )
1231
+ if not element.is_displayed():
1232
+ css_selector = self.convert_to_css_selector(selector, by=by)
1233
+ css_selector = re.escape(css_selector) # Add "\\" to special chars
1234
+ css_selector = self.__escape_quotes_if_needed(css_selector)
1235
+ script = """document.querySelector('%s').focus();""" % css_selector
1236
+ self.execute_script(script)
1237
+ self.__demo_mode_pause_if_active()
1238
+ return
1253
1239
  self.scroll_to(selector, by=by, timeout=timeout)
1254
1240
  try:
1255
1241
  element.send_keys(Keys.NULL)
@@ -1269,6 +1255,9 @@ class BaseCase(unittest.TestCase):
1269
1255
  def refresh_page(self):
1270
1256
  self.__check_scope()
1271
1257
  self.__last_page_load_url = None
1258
+ if self.__is_cdp_swap_needed():
1259
+ self.cdp.reload()
1260
+ return
1272
1261
  js_utils.clear_out_console_logs(self.driver)
1273
1262
  self.driver.refresh()
1274
1263
  self.wait_for_ready_state_complete()
@@ -1279,7 +1268,11 @@ class BaseCase(unittest.TestCase):
1279
1268
 
1280
1269
  def get_current_url(self):
1281
1270
  self.__check_scope()
1282
- current_url = self.driver.current_url
1271
+ current_url = None
1272
+ if self.__is_cdp_swap_needed():
1273
+ current_url = self.cdp.get_current_url()
1274
+ else:
1275
+ current_url = self.driver.current_url
1283
1276
  if "%" in current_url:
1284
1277
  try:
1285
1278
  from urllib.parse import unquote
@@ -1294,15 +1287,22 @@ class BaseCase(unittest.TestCase):
1294
1287
  return self.execute_script("return window.location.origin;")
1295
1288
 
1296
1289
  def get_page_source(self):
1290
+ if self.__is_cdp_swap_needed():
1291
+ return self.cdp.get_page_source()
1297
1292
  self.wait_for_ready_state_complete()
1298
1293
  if self.__needs_minimum_wait:
1299
- time.sleep(0.02)
1294
+ time.sleep(0.025)
1300
1295
  return self.driver.page_source
1301
1296
 
1302
1297
  def get_page_title(self):
1298
+ if self.__is_cdp_swap_needed():
1299
+ return self.cdp.get_title()
1303
1300
  self.wait_for_ready_state_complete()
1304
- self.wait_for_element_present("title", timeout=settings.SMALL_TIMEOUT)
1305
- time.sleep(0.03)
1301
+ with suppress(Exception):
1302
+ self.wait_for_element_present(
1303
+ "title", by="css selector", timeout=settings.MINI_TIMEOUT
1304
+ )
1305
+ time.sleep(0.025)
1306
1306
  return self.driver.title
1307
1307
 
1308
1308
  def get_title(self):
@@ -1310,31 +1310,32 @@ class BaseCase(unittest.TestCase):
1310
1310
  return self.get_page_title()
1311
1311
 
1312
1312
  def get_user_agent(self):
1313
- user_agent = self.execute_script("return navigator.userAgent;")
1314
- return user_agent
1313
+ if self.__is_cdp_swap_needed():
1314
+ return self.cdp.get_user_agent()
1315
+ return self.execute_script("return navigator.userAgent;")
1315
1316
 
1316
1317
  def get_locale_code(self):
1317
- locale_code = self.execute_script(
1318
+ if self.__is_cdp_swap_needed():
1319
+ return self.cdp.get_locale_code()
1320
+ return self.execute_script(
1318
1321
  "return navigator.language || navigator.languages[0];"
1319
1322
  )
1320
- return locale_code
1321
1323
 
1322
1324
  def go_back(self):
1323
1325
  self.__check_scope()
1326
+ if self.__is_cdp_swap_needed():
1327
+ self.cdp.go_back()
1328
+ return
1324
1329
  if hasattr(self, "recorder_mode") and self.recorder_mode:
1325
1330
  self.save_recorded_actions()
1326
1331
  pre_action_url = None
1327
- try:
1332
+ with suppress(Exception):
1328
1333
  pre_action_url = self.driver.current_url
1329
- except Exception:
1330
- pass
1331
1334
  self.__last_page_load_url = None
1332
1335
  self.driver.back()
1333
- try:
1336
+ with suppress(Exception):
1334
1337
  if pre_action_url == self.driver.current_url:
1335
1338
  self.driver.back() # Again because the page was redirected
1336
- except Exception:
1337
- pass
1338
1339
  if self.recorder_mode:
1339
1340
  time_stamp = self.execute_script("return Date.now();")
1340
1341
  origin = self.get_origin()
@@ -1350,6 +1351,9 @@ class BaseCase(unittest.TestCase):
1350
1351
 
1351
1352
  def go_forward(self):
1352
1353
  self.__check_scope()
1354
+ if self.__is_cdp_swap_needed():
1355
+ self.cdp.go_forward()
1356
+ return
1353
1357
  if hasattr(self, "recorder_mode") and self.recorder_mode:
1354
1358
  self.save_recorded_actions()
1355
1359
  self.__last_page_load_url = None
@@ -1403,7 +1407,7 @@ class BaseCase(unittest.TestCase):
1403
1407
  to convert the open() action into open_if_not_url() so that the
1404
1408
  same page isn't opened again if the user is already on the page."""
1405
1409
  self.__check_scope()
1406
- current_url = self.driver.current_url
1410
+ current_url = self.get_current_url()
1407
1411
  if current_url != url:
1408
1412
  if (
1409
1413
  "?q=" not in current_url
@@ -1414,6 +1418,9 @@ class BaseCase(unittest.TestCase):
1414
1418
  self.open(url)
1415
1419
 
1416
1420
  def is_element_present(self, selector, by="css selector"):
1421
+ """Returns whether the element exists in the HTML."""
1422
+ if self.__is_cdp_swap_needed():
1423
+ return self.cdp.is_element_present(selector)
1417
1424
  self.wait_for_ready_state_complete()
1418
1425
  selector, by = self.__recalculate_selector(selector, by)
1419
1426
  if self.__is_shadow_selector(selector):
@@ -1421,6 +1428,9 @@ class BaseCase(unittest.TestCase):
1421
1428
  return page_actions.is_element_present(self.driver, selector, by)
1422
1429
 
1423
1430
  def is_element_visible(self, selector, by="css selector"):
1431
+ """Returns whether the element is visible on the page."""
1432
+ if self.__is_cdp_swap_needed():
1433
+ return self.cdp.is_element_visible(selector)
1424
1434
  self.wait_for_ready_state_complete()
1425
1435
  selector, by = self.__recalculate_selector(selector, by)
1426
1436
  if self.__is_shadow_selector(selector):
@@ -1441,7 +1451,8 @@ class BaseCase(unittest.TestCase):
1441
1451
  return self.__is_shadow_element_enabled(selector)
1442
1452
  return page_actions.is_element_enabled(self.driver, selector, by)
1443
1453
 
1444
- def is_text_visible(self, text, selector="html", by="css selector"):
1454
+ def is_text_visible(self, text, selector="body", by="css selector"):
1455
+ """Returns whether the text substring is visible in the element."""
1445
1456
  self.wait_for_ready_state_complete()
1446
1457
  time.sleep(0.01)
1447
1458
  selector, by = self.__recalculate_selector(selector, by)
@@ -1449,7 +1460,9 @@ class BaseCase(unittest.TestCase):
1449
1460
  return self.__is_shadow_text_visible(text, selector)
1450
1461
  return page_actions.is_text_visible(self.driver, text, selector, by)
1451
1462
 
1452
- def is_exact_text_visible(self, text, selector="html", by="css selector"):
1463
+ def is_exact_text_visible(self, text, selector="body", by="css selector"):
1464
+ """Returns whether the text is exactly equal to the element text.
1465
+ (Leading and trailing whitespace is ignored in the verification.)"""
1453
1466
  self.wait_for_ready_state_complete()
1454
1467
  time.sleep(0.01)
1455
1468
  selector, by = self.__recalculate_selector(selector, by)
@@ -1459,7 +1472,7 @@ class BaseCase(unittest.TestCase):
1459
1472
  self.driver, text, selector, by
1460
1473
  )
1461
1474
 
1462
- def is_non_empty_text_visible(self, selector="html", by="css selector"):
1475
+ def is_non_empty_text_visible(self, selector="body", by="css selector"):
1463
1476
  """Returns whether the element has any non-empty text visible.
1464
1477
  Whitespace-only text is considered empty text."""
1465
1478
  self.wait_for_ready_state_complete()
@@ -1488,6 +1501,7 @@ class BaseCase(unittest.TestCase):
1488
1501
  )
1489
1502
 
1490
1503
  def is_link_text_visible(self, link_text):
1504
+ """Returns whether there's an exact match for the link text."""
1491
1505
  self.wait_for_ready_state_complete()
1492
1506
  time.sleep(0.01)
1493
1507
  return page_actions.is_element_visible(
@@ -1495,6 +1509,7 @@ class BaseCase(unittest.TestCase):
1495
1509
  )
1496
1510
 
1497
1511
  def is_partial_link_text_visible(self, partial_link_text):
1512
+ """Returns whether there's a substring match for the link text."""
1498
1513
  self.wait_for_ready_state_complete()
1499
1514
  time.sleep(0.01)
1500
1515
  return page_actions.is_element_visible(
@@ -1587,11 +1602,18 @@ class BaseCase(unittest.TestCase):
1587
1602
  def click_link_text(self, link_text, timeout=None):
1588
1603
  """This method clicks link text on a page."""
1589
1604
  self.__check_scope()
1605
+ if self.__is_cdp_swap_needed():
1606
+ self.cdp.find_element(link_text, timeout=timeout).click()
1607
+ return
1608
+ self.__skip_if_esc()
1590
1609
  if not timeout:
1591
1610
  timeout = settings.SMALL_TIMEOUT
1592
1611
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
1593
1612
  timeout = self.__get_new_timeout(timeout)
1594
1613
  link_text = self.__get_type_checked_text(link_text)
1614
+ if self.__is_cdp_swap_needed():
1615
+ self.cdp.click_link(link_text)
1616
+ return
1595
1617
  if self.browser == "safari":
1596
1618
  if self.demo_mode:
1597
1619
  self.wait_for_link_text_present(link_text, timeout=timeout)
@@ -1622,10 +1644,8 @@ class BaseCase(unittest.TestCase):
1622
1644
  if self.__needs_minimum_wait():
1623
1645
  time.sleep(0.04)
1624
1646
  pre_action_url = None
1625
- try:
1647
+ with suppress(Exception):
1626
1648
  pre_action_url = self.driver.current_url
1627
- except Exception:
1628
- pass
1629
1649
  pre_window_count = len(self.driver.window_handles)
1630
1650
  try:
1631
1651
  element = self.wait_for_link_text_visible(link_text, timeout=0.2)
@@ -1696,10 +1716,8 @@ class BaseCase(unittest.TestCase):
1696
1716
  # switch to the last one if it exists.
1697
1717
  self.switch_to_window(-1)
1698
1718
  if settings.WAIT_FOR_RSC_ON_PAGE_LOADS:
1699
- try:
1719
+ with suppress(Exception):
1700
1720
  self.wait_for_ready_state_complete()
1701
- except Exception:
1702
- pass
1703
1721
  if self.demo_mode:
1704
1722
  if self.driver.current_url != pre_action_url:
1705
1723
  if not js_utils.is_jquery_activated(self.driver):
@@ -1720,15 +1738,16 @@ class BaseCase(unittest.TestCase):
1720
1738
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
1721
1739
  timeout = self.__get_new_timeout(timeout)
1722
1740
  partial_link_text = self.__get_type_checked_text(partial_link_text)
1741
+ if self.__is_cdp_swap_needed():
1742
+ self.cdp.find_element(partial_link_text, timeout=timeout).click()
1743
+ return
1723
1744
  if not self.is_partial_link_text_present(partial_link_text):
1724
1745
  self.wait_for_partial_link_text_present(
1725
1746
  partial_link_text, timeout=timeout
1726
1747
  )
1727
1748
  pre_action_url = None
1728
- try:
1749
+ with suppress(Exception):
1729
1750
  pre_action_url = self.driver.current_url
1730
- except Exception:
1731
- pass
1732
1751
  pre_window_count = len(self.driver.window_handles)
1733
1752
  try:
1734
1753
  element = self.wait_for_partial_link_text(
@@ -1811,10 +1830,8 @@ class BaseCase(unittest.TestCase):
1811
1830
  # switch to the last one if it exists.
1812
1831
  self.switch_to_window(-1)
1813
1832
  if settings.WAIT_FOR_RSC_ON_PAGE_LOADS:
1814
- try:
1833
+ with suppress(Exception):
1815
1834
  self.wait_for_ready_state_complete()
1816
- except Exception:
1817
- pass
1818
1835
  if self.demo_mode:
1819
1836
  if self.driver.current_url != pre_action_url:
1820
1837
  if not js_utils.is_jquery_activated(self.driver):
@@ -1825,13 +1842,15 @@ class BaseCase(unittest.TestCase):
1825
1842
  elif self.slow_mode:
1826
1843
  self.__slow_mode_pause_if_active()
1827
1844
 
1828
- def get_text(self, selector, by="css selector", timeout=None):
1845
+ def get_text(self, selector="body", by="css selector", timeout=None):
1829
1846
  self.__check_scope()
1830
1847
  if not timeout:
1831
1848
  timeout = settings.LARGE_TIMEOUT
1832
1849
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
1833
1850
  timeout = self.__get_new_timeout(timeout)
1834
1851
  selector, by = self.__recalculate_selector(selector, by)
1852
+ if self.__is_cdp_swap_needed():
1853
+ return self.cdp.get_text(selector)
1835
1854
  if self.__is_shadow_selector(selector):
1836
1855
  return self.__get_shadow_text(selector, timeout)
1837
1856
  self.wait_for_ready_state_complete()
@@ -1881,6 +1900,8 @@ class BaseCase(unittest.TestCase):
1881
1900
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
1882
1901
  timeout = self.__get_new_timeout(timeout)
1883
1902
  selector, by = self.__recalculate_selector(selector, by)
1903
+ if self.__is_cdp_swap_needed():
1904
+ return self.cdp.get_element_attribute(selector, attribute)
1884
1905
  self.wait_for_ready_state_complete()
1885
1906
  time.sleep(0.01)
1886
1907
  if self.__is_shadow_selector(selector):
@@ -1930,10 +1951,8 @@ class BaseCase(unittest.TestCase):
1930
1951
  original_attribute = attribute
1931
1952
  original_value = value
1932
1953
  if scroll and self.is_element_visible(selector, by=by):
1933
- try:
1954
+ with suppress(Exception):
1934
1955
  self.scroll_to(selector, by=by, timeout=timeout)
1935
- except Exception:
1936
- pass
1937
1956
  attribute = re.escape(attribute)
1938
1957
  attribute = self.__escape_quotes_if_needed(attribute)
1939
1958
  value = re.escape(value)
@@ -1961,6 +1980,9 @@ class BaseCase(unittest.TestCase):
1961
1980
  self.set_attributes("a", "href", "https://google.com")"""
1962
1981
  self.__check_scope()
1963
1982
  selector, by = self.__recalculate_selector(selector, by)
1983
+ if self.__is_cdp_swap_needed():
1984
+ self.cdp.set_attributes(selector, attribute, value)
1985
+ return
1964
1986
  original_attribute = attribute
1965
1987
  original_value = value
1966
1988
  attribute = re.escape(attribute)
@@ -1978,10 +2000,8 @@ class BaseCase(unittest.TestCase):
1978
2000
  attribute,
1979
2001
  value,
1980
2002
  )
1981
- try:
2003
+ with suppress(Exception):
1982
2004
  self.execute_script(script)
1983
- except Exception:
1984
- pass
1985
2005
  if self.recorder_mode and self.__current_url_is_recordable():
1986
2006
  if self.get_session_storage_item("pause_recorder") == "no":
1987
2007
  time_stamp = self.execute_script("return Date.now();")
@@ -2010,10 +2030,8 @@ class BaseCase(unittest.TestCase):
2010
2030
  timeout = self.__get_new_timeout(timeout)
2011
2031
  selector, by = self.__recalculate_selector(selector, by)
2012
2032
  if self.is_element_visible(selector, by=by):
2013
- try:
2033
+ with suppress(Exception):
2014
2034
  self.scroll_to(selector, by=by, timeout=timeout)
2015
- except Exception:
2016
- pass
2017
2035
  attribute = re.escape(attribute)
2018
2036
  attribute = self.__escape_quotes_if_needed(attribute)
2019
2037
  css_selector = self.convert_to_css_selector(selector, by=by)
@@ -2042,10 +2060,16 @@ class BaseCase(unittest.TestCase):
2042
2060
  css_selector,
2043
2061
  attribute,
2044
2062
  )
2045
- try:
2063
+ with suppress(Exception):
2046
2064
  self.execute_script(script)
2047
- except Exception:
2048
- pass
2065
+
2066
+ def internalize_links(self):
2067
+ """All `target="_blank"` links become `target="_self"`.
2068
+ This prevents those links from opening in a new tab."""
2069
+ if self.__is_cdp_swap_needed():
2070
+ self.cdp.internalize_links()
2071
+ return
2072
+ self.set_attributes('[target="_blank"]', "target", "_self")
2049
2073
 
2050
2074
  def get_property(
2051
2075
  self, selector, property, by="css selector", timeout=None
@@ -2080,7 +2104,9 @@ class BaseCase(unittest.TestCase):
2080
2104
  return ""
2081
2105
  return property_value
2082
2106
 
2083
- def get_text_content(self, selector, by="css selector", timeout=None):
2107
+ def get_text_content(
2108
+ self, selector="body", by="css selector", timeout=None
2109
+ ):
2084
2110
  """Returns the text that appears in the HTML for an element.
2085
2111
  This is different from "self.get_text(selector, by="css selector")"
2086
2112
  because that only returns the visible text on a page for an element,
@@ -2148,6 +2174,11 @@ class BaseCase(unittest.TestCase):
2148
2174
  Elements could be either hidden or visible on the page.
2149
2175
  If "limit" is set and > 0, will only return that many elements."""
2150
2176
  selector, by = self.__recalculate_selector(selector, by)
2177
+ if self.__is_cdp_swap_needed():
2178
+ elements = self.cdp.select_all(selector)
2179
+ if limit and limit > 0 and len(elements) > limit:
2180
+ elements = elements[:limit]
2181
+ return elements
2151
2182
  self.wait_for_ready_state_complete()
2152
2183
  time.sleep(0.05)
2153
2184
  elements = self.driver.find_elements(by=by, value=selector)
@@ -2159,12 +2190,16 @@ class BaseCase(unittest.TestCase):
2159
2190
  """Returns a list of matching WebElements that are visible.
2160
2191
  If "limit" is set and > 0, will only return that many elements."""
2161
2192
  selector, by = self.__recalculate_selector(selector, by)
2193
+ if self.__is_cdp_swap_needed():
2194
+ elements = self.cdp.find_visible_elements(selector)
2195
+ if limit and limit > 0 and len(elements) > limit:
2196
+ elements = elements[:limit]
2197
+ return elements
2162
2198
  self.wait_for_ready_state_complete()
2163
2199
  time.sleep(0.05)
2164
- v_elems = page_actions.find_visible_elements(
2200
+ return page_actions.find_visible_elements(
2165
2201
  self.driver, selector, by, limit
2166
2202
  )
2167
- return v_elems
2168
2203
 
2169
2204
  def click_visible_elements(
2170
2205
  self, selector, by="css selector", limit=0, timeout=None
@@ -2182,6 +2217,9 @@ class BaseCase(unittest.TestCase):
2182
2217
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
2183
2218
  timeout = self.__get_new_timeout(timeout)
2184
2219
  selector, by = self.__recalculate_selector(selector, by)
2220
+ if self.__is_cdp_swap_needed():
2221
+ self.cdp.click_visible_elements(selector, limit)
2222
+ return
2185
2223
  self.wait_for_ready_state_complete()
2186
2224
  if self.__needs_minimum_wait():
2187
2225
  time.sleep(0.12)
@@ -2190,20 +2228,16 @@ class BaseCase(unittest.TestCase):
2190
2228
  element = self.wait_for_element_present(
2191
2229
  selector, by=by, timeout=timeout
2192
2230
  )
2193
- try:
2231
+ with suppress(Exception):
2194
2232
  # If the first element isn't visible, wait a little.
2195
2233
  if not element.is_displayed():
2196
2234
  time.sleep(0.16)
2197
2235
  if self.undetectable:
2198
2236
  time.sleep(0.06)
2199
- except Exception:
2200
- pass
2201
2237
  elements = self.find_elements(selector, by=by)
2202
2238
  pre_action_url = None
2203
- try:
2239
+ with suppress(Exception):
2204
2240
  pre_action_url = self.driver.current_url
2205
- except Exception:
2206
- pass
2207
2241
  pre_window_count = len(self.driver.window_handles)
2208
2242
  click_count = 0
2209
2243
  for element in elements:
@@ -2266,13 +2300,16 @@ class BaseCase(unittest.TestCase):
2266
2300
  ):
2267
2301
  """Finds all matching page elements and clicks the nth visible one.
2268
2302
  Example: self.click_nth_visible_element('[type="checkbox"]', 5)
2269
- (Clicks the 5th visible checkbox on the page.)"""
2303
+ (Clicks the 5th visible checkbox on the page.)"""
2270
2304
  self.__check_scope()
2271
2305
  if not timeout:
2272
2306
  timeout = settings.SMALL_TIMEOUT
2273
2307
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
2274
2308
  timeout = self.__get_new_timeout(timeout)
2275
2309
  selector, by = self.__recalculate_selector(selector, by)
2310
+ if self.__is_cdp_swap_needed():
2311
+ self.cdp.click_nth_visible_element(selector, number)
2312
+ return
2276
2313
  self.wait_for_ready_state_complete()
2277
2314
  self.wait_for_element_present(selector, by=by, timeout=timeout)
2278
2315
  elements = self.find_visible_elements(selector, by=by)
@@ -2286,10 +2323,8 @@ class BaseCase(unittest.TestCase):
2286
2323
  number = 0
2287
2324
  element = elements[number]
2288
2325
  pre_action_url = None
2289
- try:
2326
+ with suppress(Exception):
2290
2327
  pre_action_url = self.driver.current_url
2291
- except Exception:
2292
- pass
2293
2328
  pre_window_count = len(self.driver.window_handles)
2294
2329
  try:
2295
2330
  self.__scroll_to_element(element)
@@ -2328,26 +2363,28 @@ class BaseCase(unittest.TestCase):
2328
2363
  Use click_visible_elements() to click all matching elements.
2329
2364
  If a "timeout" is provided, waits that long for the element
2330
2365
  to appear before giving up and returning without a click()."""
2366
+ if self.__is_cdp_swap_needed():
2367
+ self.cdp.click_if_visible(selector)
2368
+ return
2331
2369
  self.wait_for_ready_state_complete()
2332
2370
  if self.is_element_visible(selector, by=by):
2333
2371
  self.click(selector, by=by)
2334
2372
  elif timeout > 0:
2335
- try:
2373
+ with suppress(Exception):
2336
2374
  self.wait_for_element_visible(
2337
2375
  selector, by=by, timeout=timeout
2338
2376
  )
2339
- except Exception:
2340
- pass
2341
2377
  if self.is_element_visible(selector, by=by):
2342
2378
  self.click(selector, by=by)
2343
2379
 
2344
2380
  def click_active_element(self):
2381
+ if self.__is_cdp_swap_needed():
2382
+ self.cdp.click_active_element()
2383
+ return
2345
2384
  self.wait_for_ready_state_complete()
2346
2385
  pre_action_url = None
2347
- try:
2386
+ with suppress(Exception):
2348
2387
  pre_action_url = self.driver.current_url
2349
- except Exception:
2350
- pass
2351
2388
  pre_window_count = len(self.driver.window_handles)
2352
2389
  if self.recorder_mode:
2353
2390
  selector = js_utils.get_active_element_css(self.driver)
@@ -2451,16 +2488,14 @@ class BaseCase(unittest.TestCase):
2451
2488
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
2452
2489
  timeout = self.__get_new_timeout(timeout)
2453
2490
  selector, by = self.__recalculate_selector(selector, by)
2491
+ if self.__is_cdp_swap_needed():
2492
+ return self.cdp.is_checked(selector)
2454
2493
  kind = self.get_attribute(selector, "type", by=by, timeout=timeout)
2455
2494
  if kind != "checkbox" and kind != "radio":
2456
2495
  raise Exception("Expecting a checkbox or a radio button element!")
2457
- is_checked = self.get_attribute(
2496
+ return self.get_attribute(
2458
2497
  selector, "checked", by=by, timeout=timeout, hard_fail=False
2459
2498
  )
2460
- if is_checked:
2461
- return True
2462
- else: # (NoneType)
2463
- return False
2464
2499
 
2465
2500
  def is_selected(self, selector, by="css selector", timeout=None):
2466
2501
  """Same as is_checked()"""
@@ -2470,6 +2505,9 @@ class BaseCase(unittest.TestCase):
2470
2505
  """If a checkbox or radio button is not checked, will check it."""
2471
2506
  self.__check_scope()
2472
2507
  selector, by = self.__recalculate_selector(selector, by)
2508
+ if self.__is_cdp_swap_needed():
2509
+ self.cdp.check_if_unchecked(selector)
2510
+ return
2473
2511
  if not self.is_checked(selector, by=by):
2474
2512
  if self.is_element_visible(selector, by=by):
2475
2513
  self.click(selector, by=by)
@@ -2480,12 +2518,10 @@ class BaseCase(unittest.TestCase):
2480
2518
  )
2481
2519
  # Handle switches that sit on checkboxes with zero opacity:
2482
2520
  # Change the opacity a bit to allow the click to succeed.
2483
- try:
2521
+ with suppress(Exception):
2484
2522
  self.execute_script(
2485
2523
  'arguments[0].style.opacity="0.001";', element
2486
2524
  )
2487
- except Exception:
2488
- pass
2489
2525
  if self.is_element_visible(selector, by=by):
2490
2526
  self.click(selector, by=by)
2491
2527
  else:
@@ -2493,14 +2529,12 @@ class BaseCase(unittest.TestCase):
2493
2529
  self.__dont_record_js_click = True
2494
2530
  self.js_click(selector, by="css selector")
2495
2531
  self.__dont_record_js_click = False
2496
- try:
2532
+ with suppress(Exception):
2497
2533
  self.execute_script(
2498
2534
  'arguments[0].style.opacity="arguments[1]";',
2499
2535
  element,
2500
2536
  opacity,
2501
2537
  )
2502
- except Exception:
2503
- pass
2504
2538
 
2505
2539
  def select_if_unselected(self, selector, by="css selector"):
2506
2540
  """Same as check_if_unchecked()"""
@@ -2510,6 +2544,9 @@ class BaseCase(unittest.TestCase):
2510
2544
  """If a checkbox is checked, will uncheck it."""
2511
2545
  self.__check_scope()
2512
2546
  selector, by = self.__recalculate_selector(selector, by)
2547
+ if self.__is_cdp_swap_needed():
2548
+ self.cdp.uncheck_if_checked(selector)
2549
+ return
2513
2550
  if self.is_checked(selector, by=by):
2514
2551
  if self.is_element_visible(selector, by=by):
2515
2552
  self.click(selector, by=by)
@@ -2520,12 +2557,10 @@ class BaseCase(unittest.TestCase):
2520
2557
  )
2521
2558
  # Handle switches that sit on checkboxes with zero opacity:
2522
2559
  # Change the opacity a bit to allow the click to succeed.
2523
- try:
2560
+ with suppress(Exception):
2524
2561
  self.execute_script(
2525
2562
  'arguments[0].style.opacity="0.001";', element
2526
2563
  )
2527
- except Exception:
2528
- pass
2529
2564
  if self.is_element_visible(selector, by=by):
2530
2565
  self.click(selector, by=by)
2531
2566
  else:
@@ -2533,14 +2568,12 @@ class BaseCase(unittest.TestCase):
2533
2568
  self.__dont_record_js_click = True
2534
2569
  self.js_click(selector, by="css selector")
2535
2570
  self.__dont_record_js_click = False
2536
- try:
2571
+ with suppress(Exception):
2537
2572
  self.execute_script(
2538
2573
  'arguments[0].style.opacity="arguments[1]";',
2539
2574
  element,
2540
2575
  opacity,
2541
2576
  )
2542
- except Exception:
2543
- pass
2544
2577
 
2545
2578
  def unselect_if_selected(self, selector, by="css selector"):
2546
2579
  """Same as uncheck_if_checked()"""
@@ -2599,14 +2632,12 @@ class BaseCase(unittest.TestCase):
2599
2632
  iframe_identifier = '[class="%s"]' % iframe_class
2600
2633
  else:
2601
2634
  continue
2602
- try:
2635
+ with suppress(Exception):
2603
2636
  self.switch_to_frame(iframe_identifier, timeout=1)
2604
2637
  if self.__needs_minimum_wait():
2605
2638
  time.sleep(0.02)
2606
2639
  if self.is_element_present(selector, by=by):
2607
2640
  return iframe_identifier
2608
- except Exception:
2609
- pass
2610
2641
  self.switch_to_default_content()
2611
2642
  if self.__needs_minimum_wait():
2612
2643
  time.sleep(0.02)
@@ -2632,6 +2663,9 @@ class BaseCase(unittest.TestCase):
2632
2663
  original_selector = selector
2633
2664
  original_by = by
2634
2665
  selector, by = self.__recalculate_selector(selector, by)
2666
+ if self.__is_cdp_swap_needed():
2667
+ self.cdp.gui_hover_element(selector)
2668
+ return
2635
2669
  self.wait_for_element_visible(
2636
2670
  original_selector, by=original_by, timeout=timeout
2637
2671
  )
@@ -2674,16 +2708,17 @@ class BaseCase(unittest.TestCase):
2674
2708
  click_selector, click_by = self.__recalculate_selector(
2675
2709
  click_selector, click_by
2676
2710
  )
2711
+ if self.__is_cdp_swap_needed():
2712
+ self.cdp.gui_hover_and_click(hover_selector, click_selector)
2713
+ return
2677
2714
  dropdown_element = self.wait_for_element_visible(
2678
2715
  original_selector, by=original_by, timeout=timeout
2679
2716
  )
2680
2717
  self.__demo_mode_highlight_if_active(original_selector, original_by)
2681
2718
  self.scroll_to(hover_selector, by=hover_by)
2682
2719
  pre_action_url = None
2683
- try:
2720
+ with suppress(Exception):
2684
2721
  pre_action_url = self.driver.current_url
2685
- except Exception:
2686
- pass
2687
2722
  pre_window_count = len(self.driver.window_handles)
2688
2723
  if self.recorder_mode and self.__current_url_is_recordable():
2689
2724
  if self.get_session_storage_item("pause_recorder") == "no":
@@ -2747,10 +2782,8 @@ class BaseCase(unittest.TestCase):
2747
2782
  self.__switch_to_newest_window_if_not_blank()
2748
2783
  elif self.browser == "safari":
2749
2784
  # Release the hover by hovering elsewhere
2750
- try:
2785
+ with suppress(Exception):
2751
2786
  page_actions.hover_on_element(self.driver, "body")
2752
- except Exception:
2753
- pass
2754
2787
  if self.demo_mode:
2755
2788
  if self.driver.current_url != pre_action_url:
2756
2789
  if not js_utils.is_jquery_activated(self.driver):
@@ -2810,10 +2843,8 @@ class BaseCase(unittest.TestCase):
2810
2843
  self.__demo_mode_highlight_if_active(original_selector, original_by)
2811
2844
  self.scroll_to(hover_selector, by=hover_by)
2812
2845
  pre_action_url = None
2813
- try:
2846
+ with suppress(Exception):
2814
2847
  pre_action_url = self.driver.current_url
2815
- except Exception:
2816
- pass
2817
2848
  pre_window_count = len(self.driver.window_handles)
2818
2849
  outdated_driver = False
2819
2850
  element = None
@@ -2874,7 +2905,7 @@ class BaseCase(unittest.TestCase):
2874
2905
  timeout=None,
2875
2906
  jquery=False,
2876
2907
  ):
2877
- """Drag and drop an element from one selector to another."""
2908
+ """Drag-and-drop an element from one selector to another."""
2878
2909
  self.__check_scope()
2879
2910
  if not timeout:
2880
2911
  timeout = settings.SMALL_TIMEOUT
@@ -2886,6 +2917,9 @@ class BaseCase(unittest.TestCase):
2886
2917
  drop_selector, drop_by = self.__recalculate_selector(
2887
2918
  drop_selector, drop_by
2888
2919
  )
2920
+ if self.__is_cdp_swap_needed():
2921
+ self.cdp.gui_drag_and_drop(drag_selector, drop_selector)
2922
+ return
2889
2923
  drag_element = self.wait_for_element_clickable(
2890
2924
  drag_selector, by=drag_by, timeout=timeout
2891
2925
  )
@@ -2921,7 +2955,7 @@ class BaseCase(unittest.TestCase):
2921
2955
  def drag_and_drop_with_offset(
2922
2956
  self, selector, x, y, by="css selector", timeout=None
2923
2957
  ):
2924
- """Drag and drop an element to an {X,Y}-offset location."""
2958
+ """Drag-and-drop an element to an {X,Y}-offset location."""
2925
2959
  self.__check_scope()
2926
2960
  if not timeout:
2927
2961
  timeout = settings.SMALL_TIMEOUT
@@ -3001,10 +3035,8 @@ class BaseCase(unittest.TestCase):
3001
3035
  dropdown_selector, dropdown_by
3002
3036
  )
3003
3037
  pre_action_url = None
3004
- try:
3038
+ with suppress(Exception):
3005
3039
  pre_action_url = self.driver.current_url
3006
- except Exception:
3007
- pass
3008
3040
  pre_window_count = len(self.driver.window_handles)
3009
3041
  try:
3010
3042
  if option_by == "index":
@@ -3108,6 +3140,9 @@ class BaseCase(unittest.TestCase):
3108
3140
  timeout = settings.SMALL_TIMEOUT
3109
3141
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
3110
3142
  timeout = self.__get_new_timeout(timeout)
3143
+ if self.__is_cdp_swap_needed():
3144
+ self.cdp.select_option_by_text(dropdown_selector, option)
3145
+ return
3111
3146
  self.__select_option(
3112
3147
  dropdown_selector,
3113
3148
  option,
@@ -3279,10 +3314,8 @@ class BaseCase(unittest.TestCase):
3279
3314
  self.open("data:text/html,<head></head><body><div></div></body>")
3280
3315
  inner_head = """document.getElementsByTagName("head")[0].innerHTML"""
3281
3316
  inner_body = """document.getElementsByTagName("body")[0].innerHTML"""
3282
- try:
3317
+ with suppress(Exception):
3283
3318
  self.wait_for_element_present("body", timeout=1)
3284
- except Exception:
3285
- pass
3286
3319
  if not found_body:
3287
3320
  self.execute_script('''%s = \"%s\"''' % (inner_body, html_string))
3288
3321
  elif found_body and not found_head:
@@ -3356,6 +3389,8 @@ class BaseCase(unittest.TestCase):
3356
3389
 
3357
3390
  def execute_script(self, script, *args, **kwargs):
3358
3391
  self.__check_scope()
3392
+ if self.__is_cdp_swap_needed():
3393
+ return self.cdp.evaluate(script)
3359
3394
  self._check_browser()
3360
3395
  return self.driver.execute_script(script, *args, **kwargs)
3361
3396
 
@@ -3381,25 +3416,142 @@ class BaseCase(unittest.TestCase):
3381
3416
  self.activate_jquery()
3382
3417
  return self.driver.execute_script(script, *args, **kwargs)
3383
3418
 
3419
+ def get_element_at_x_y(self, x, y):
3420
+ """Return element at current window's x,y coordinates."""
3421
+ self.__check_scope()
3422
+ self._check_browser()
3423
+ return self.execute_script(
3424
+ "return document.elementFromPoint(%s, %s);" % (x, y)
3425
+ )
3426
+
3427
+ def get_gui_element_rect(self, selector, by="css selector"):
3428
+ """Very similar to element.rect, but the x, y coordinates are
3429
+ relative to the entire screen, rather than the browser window.
3430
+ This is specifically for PyAutoGUI actions on the full screen.
3431
+ (Note: There may be complications if iframes are involved.)"""
3432
+ if self.__is_cdp_swap_needed():
3433
+ return self.cdp.get_gui_element_rect(selector)
3434
+ element = self.wait_for_element_present(selector, by=by, timeout=1)
3435
+ element_rect = element.rect
3436
+ e_width = element_rect["width"]
3437
+ e_height = element_rect["height"]
3438
+ i_x = 0
3439
+ i_y = 0
3440
+ iframe_switch = False
3441
+ if self.__is_in_frame():
3442
+ self.switch_to_parent_frame()
3443
+ if self.__is_in_frame():
3444
+ raise Exception("Nested iframes breaks get_gui_element_rect!")
3445
+ iframe_switch = True
3446
+ iframe = self.wait_for_element_present("iframe", timeout=1)
3447
+ i_x = iframe.rect["x"]
3448
+ i_y = iframe.rect["y"]
3449
+ window_rect = self.get_window_rect()
3450
+ w_bottom_y = window_rect["y"] + window_rect["height"]
3451
+ viewport_height = self.execute_script("return window.innerHeight;")
3452
+ x = math.ceil(window_rect["x"] + i_x + element_rect["x"])
3453
+ y = math.ceil(w_bottom_y - viewport_height + i_y + element_rect["y"])
3454
+ y_scroll_offset = self.execute_script("return window.pageYOffset;")
3455
+ y = int(y - y_scroll_offset)
3456
+ if iframe_switch:
3457
+ self.switch_to_frame()
3458
+ if not self.is_element_present(selector, by=by):
3459
+ self.switch_to_parent_frame()
3460
+ return ({"height": e_height, "width": e_width, "x": x, "y": y})
3461
+
3462
+ def get_gui_element_center(self, selector, by="css selector"):
3463
+ """Returns the x, y coordinates of the element's center based
3464
+ on the entire GUI / screen, rather than on the browser window.
3465
+ This is specifically for PyAutoGUI actions on the full screen.
3466
+ (Note: There may be complications if iframes are involved.)"""
3467
+ if self.__is_cdp_swap_needed():
3468
+ return self.cdp.get_gui_element_center(selector)
3469
+ element_rect = self.get_gui_element_rect(selector, by=by)
3470
+ x = element_rect["x"] + (element_rect["width"] / 2.0) + 0.5
3471
+ y = element_rect["y"] + (element_rect["height"] / 2.0) + 0.5
3472
+ return (x, y)
3473
+
3474
+ def get_screen_rect(self):
3475
+ self.__check_scope()
3476
+ if self.__is_cdp_swap_needed():
3477
+ return self.cdp.get_screen_rect()
3478
+ self._check_browser()
3479
+ return self.driver.get_screen_rect()
3480
+
3481
+ def get_window_rect(self):
3482
+ self.__check_scope()
3483
+ if self.__is_cdp_swap_needed():
3484
+ return self.cdp.get_window_rect()
3485
+ self._check_browser()
3486
+ return self.driver.get_window_rect()
3487
+
3488
+ def get_window_size(self):
3489
+ self.__check_scope()
3490
+ if self.__is_cdp_swap_needed():
3491
+ return self.cdp.get_window_size()
3492
+ self._check_browser()
3493
+ return self.driver.get_window_size()
3494
+
3495
+ def get_window_position(self):
3496
+ self.__check_scope()
3497
+ if self.__is_cdp_swap_needed():
3498
+ return self.cdp.get_window_position()
3499
+ self._check_browser()
3500
+ return self.driver.get_window_position()
3501
+
3384
3502
  def set_window_rect(self, x, y, width, height):
3385
3503
  self.__check_scope()
3504
+ if self.__is_cdp_swap_needed():
3505
+ self.cdp.set_window_rect(x, y, width, height)
3506
+ return
3386
3507
  self._check_browser()
3387
3508
  self.driver.set_window_rect(x, y, width, height)
3388
- self.__demo_mode_pause_if_active()
3509
+ self.__demo_mode_pause_if_active(tiny=True)
3389
3510
 
3390
3511
  def set_window_size(self, width, height):
3391
3512
  self.__check_scope()
3392
3513
  self._check_browser()
3393
3514
  self.driver.set_window_size(width, height)
3394
- self.__demo_mode_pause_if_active()
3515
+ self.__demo_mode_pause_if_active(tiny=True)
3516
+
3517
+ def set_window_position(self, x, y):
3518
+ self.__check_scope()
3519
+ self._check_browser()
3520
+ self.driver.set_window_position(x, y)
3521
+ self.__demo_mode_pause_if_active(tiny=True)
3395
3522
 
3396
3523
  def maximize_window(self):
3397
3524
  self.__check_scope()
3525
+ if self.__is_cdp_swap_needed():
3526
+ self.cdp.maximize()
3527
+ return
3398
3528
  self._check_browser()
3399
3529
  self.driver.maximize_window()
3400
- self.__demo_mode_pause_if_active()
3530
+ self.__demo_mode_pause_if_active(tiny=True)
3531
+
3532
+ def minimize_window(self):
3533
+ self.__check_scope()
3534
+ if self.__is_cdp_swap_needed():
3535
+ self.cdp.minimize()
3536
+ return
3537
+ self._check_browser()
3538
+ self.driver.minimize_window()
3539
+ self.__demo_mode_pause_if_active(tiny=True)
3540
+
3541
+ def reset_window_size(self):
3542
+ self.__check_scope()
3543
+ if self.__is_cdp_swap_needed():
3544
+ self.cdp.reset_window_size()
3545
+ return
3546
+ self._check_browser()
3547
+ x = settings.WINDOW_START_X
3548
+ y = settings.WINDOW_START_Y
3549
+ width = settings.CHROME_START_WIDTH
3550
+ height = settings.CHROME_START_HEIGHT
3551
+ self.set_window_rect(x, y, width, height)
3552
+ self.__demo_mode_pause_if_active(tiny=True)
3401
3553
 
3402
- def switch_to_frame(self, frame, timeout=None):
3554
+ def switch_to_frame(self, frame="iframe", timeout=None):
3403
3555
  """Wait for an iframe to appear, and switch to it. This should be
3404
3556
  usable as a drop-in replacement for driver.switch_to.frame().
3405
3557
  The iframe identifier can be a selector, an index, an id, a name,
@@ -3726,7 +3878,11 @@ class BaseCase(unittest.TestCase):
3726
3878
  """Opens a new browser tab/window and switches to it by default."""
3727
3879
  self.wait_for_ready_state_complete()
3728
3880
  if switch_to:
3729
- self.driver.switch_to.new_window("tab")
3881
+ try:
3882
+ self.driver.switch_to.new_window("tab")
3883
+ except Exception:
3884
+ self.driver.execute_script("window.open('');")
3885
+ self.switch_to_newest_window()
3730
3886
  else:
3731
3887
  self.driver.execute_script("window.open('');")
3732
3888
  time.sleep(0.01)
@@ -3767,6 +3923,7 @@ class BaseCase(unittest.TestCase):
3767
3923
  cap_file=None,
3768
3924
  cap_string=None,
3769
3925
  recorder_ext=None,
3926
+ disable_cookies=None,
3770
3927
  disable_js=None,
3771
3928
  disable_csp=None,
3772
3929
  enable_ws=None,
@@ -3778,6 +3935,7 @@ class BaseCase(unittest.TestCase):
3778
3935
  log_cdp_events=None,
3779
3936
  no_sandbox=None,
3780
3937
  disable_gpu=None,
3938
+ headless1=None,
3781
3939
  headless2=None,
3782
3940
  incognito=None,
3783
3941
  guest_mode=None,
@@ -3826,6 +3984,7 @@ class BaseCase(unittest.TestCase):
3826
3984
  cap_file - the file containing desired capabilities for the browser
3827
3985
  cap_string - the string with desired capabilities for the browser
3828
3986
  recorder_ext - the option to enable the SBase Recorder extension
3987
+ disable_cookies - the option to disable Cookies (May break things!)
3829
3988
  disable_js - the option to disable JavaScript (May break websites!)
3830
3989
  disable_csp - an option to disable Chrome's Content Security Policy
3831
3990
  enable_ws - the option to enable the Web Security feature (Chrome)
@@ -3837,6 +3996,7 @@ class BaseCase(unittest.TestCase):
3837
3996
  log_cdp_events - capture {"performance": "ALL", "browser": "ALL"})
3838
3997
  no_sandbox - the option to enable the "No-Sandbox" feature (Chrome)
3839
3998
  disable_gpu - the option to enable Chrome's "Disable GPU" feature
3999
+ headless1 - the option to use the older headless mode (Chromium)
3840
4000
  headless2 - the option to use the newer headless mode (Chromium)
3841
4001
  incognito - the option to enable Chrome's Incognito mode (Chrome)
3842
4002
  guest_mode - the option to enable Chrome's Guest mode (Chrome)
@@ -3923,6 +4083,8 @@ class BaseCase(unittest.TestCase):
3923
4083
  user_agent = self.user_agent
3924
4084
  if recorder_ext is None:
3925
4085
  recorder_ext = self.recorder_ext
4086
+ if disable_cookies is None:
4087
+ disable_cookies = self.disable_cookies
3926
4088
  if disable_js is None:
3927
4089
  disable_js = self.disable_js
3928
4090
  if disable_csp is None:
@@ -3945,6 +4107,8 @@ class BaseCase(unittest.TestCase):
3945
4107
  no_sandbox = self.no_sandbox
3946
4108
  if disable_gpu is None:
3947
4109
  disable_gpu = self.disable_gpu
4110
+ if headless1 is None:
4111
+ headless1 = self.headless1
3948
4112
  if headless2 is None:
3949
4113
  headless2 = self.headless2
3950
4114
  if incognito is None:
@@ -4016,8 +4180,6 @@ class BaseCase(unittest.TestCase):
4016
4180
  "Valid options = {%s}" % (browser, valid_browsers)
4017
4181
  )
4018
4182
  # Launch a web browser
4019
- from seleniumbase.core import browser_launcher
4020
-
4021
4183
  new_driver = browser_launcher.get_driver(
4022
4184
  browser_name=browser_name,
4023
4185
  headless=headless,
@@ -4034,6 +4196,7 @@ class BaseCase(unittest.TestCase):
4034
4196
  cap_file=cap_file,
4035
4197
  cap_string=cap_string,
4036
4198
  recorder_ext=recorder_ext,
4199
+ disable_cookies=disable_cookies,
4037
4200
  disable_js=disable_js,
4038
4201
  disable_csp=disable_csp,
4039
4202
  enable_ws=enable_ws,
@@ -4045,6 +4208,7 @@ class BaseCase(unittest.TestCase):
4045
4208
  log_cdp_events=log_cdp_events,
4046
4209
  no_sandbox=no_sandbox,
4047
4210
  disable_gpu=disable_gpu,
4211
+ headless1=headless1,
4048
4212
  headless2=headless2,
4049
4213
  incognito=incognito,
4050
4214
  guest_mode=guest_mode,
@@ -4113,7 +4277,8 @@ class BaseCase(unittest.TestCase):
4113
4277
  self.driver.maximize_window()
4114
4278
  self.wait_for_ready_state_complete()
4115
4279
  else:
4116
- self.driver.set_window_size(width, height)
4280
+ with suppress(Exception):
4281
+ self.driver.set_window_size(width, height)
4117
4282
  except Exception:
4118
4283
  pass # Keep existing browser resolution
4119
4284
  elif self.browser == "safari":
@@ -4124,10 +4289,8 @@ class BaseCase(unittest.TestCase):
4124
4289
  except Exception:
4125
4290
  pass # Keep existing browser resolution
4126
4291
  else:
4127
- try:
4128
- self.driver.set_window_rect(10, 20, width, height)
4129
- except Exception:
4130
- pass
4292
+ with suppress(Exception):
4293
+ self.driver.set_window_rect(10, 46, width, height)
4131
4294
  if self.start_page and len(self.start_page) >= 4:
4132
4295
  if page_utils.is_valid_url(self.start_page):
4133
4296
  self.open(self.start_page)
@@ -4137,6 +4300,51 @@ class BaseCase(unittest.TestCase):
4137
4300
  self.__dont_record_open = True
4138
4301
  self.open(new_start_page)
4139
4302
  self.__dont_record_open = False
4303
+ if undetectable:
4304
+ if hasattr(new_driver, "cdp"):
4305
+ self.cdp = new_driver.cdp
4306
+ if hasattr(new_driver, "uc_open"):
4307
+ self.uc_open = new_driver.uc_open
4308
+ if hasattr(new_driver, "uc_open_with_tab"):
4309
+ self.uc_open_with_tab = new_driver.uc_open_with_tab
4310
+ if hasattr(new_driver, "uc_open_with_reconnect"):
4311
+ self.uc_open_with_reconnect = new_driver.uc_open_with_reconnect
4312
+ if hasattr(new_driver, "uc_open_with_cdp_mode"):
4313
+ self.uc_open_with_cdp_mode = new_driver.uc_open_with_cdp_mode
4314
+ if hasattr(new_driver, "uc_open_with_disconnect"):
4315
+ self.uc_open_with_disconnect = (
4316
+ new_driver.uc_open_with_disconnect
4317
+ )
4318
+ if hasattr(new_driver, "reconnect"):
4319
+ self.reconnect = new_driver.reconnect
4320
+ if hasattr(new_driver, "disconnect"):
4321
+ self.disconnect = new_driver.disconnect
4322
+ if hasattr(new_driver, "connect"):
4323
+ self.connect = new_driver.connect
4324
+ if hasattr(new_driver, "uc_click"):
4325
+ self.uc_click = new_driver.uc_click
4326
+ if hasattr(new_driver, "uc_gui_press_key"):
4327
+ self.uc_gui_press_key = new_driver.uc_gui_press_key
4328
+ if hasattr(new_driver, "uc_gui_press_keys"):
4329
+ self.uc_gui_press_keys = new_driver.uc_gui_press_keys
4330
+ if hasattr(new_driver, "uc_gui_write"):
4331
+ self.uc_gui_write = new_driver.uc_gui_write
4332
+ if hasattr(new_driver, "uc_gui_click_x_y"):
4333
+ self.uc_gui_click_x_y = new_driver.uc_gui_click_x_y
4334
+ if hasattr(new_driver, "uc_gui_click_captcha"):
4335
+ self.uc_gui_click_captcha = new_driver.uc_gui_click_captcha
4336
+ if hasattr(new_driver, "uc_gui_click_cf"):
4337
+ self.uc_gui_click_cf = new_driver.uc_gui_click_cf
4338
+ if hasattr(new_driver, "uc_gui_click_rc"):
4339
+ self.uc_gui_click_rc = new_driver.uc_gui_click_rc
4340
+ if hasattr(new_driver, "uc_gui_handle_captcha"):
4341
+ self.uc_gui_handle_captcha = new_driver.uc_gui_handle_captcha
4342
+ if hasattr(new_driver, "uc_gui_handle_cf"):
4343
+ self.uc_gui_handle_cf = new_driver.uc_gui_handle_cf
4344
+ if hasattr(new_driver, "uc_gui_handle_rc"):
4345
+ self.uc_gui_handle_rc = new_driver.uc_gui_handle_rc
4346
+ if hasattr(new_driver, "uc_switch_to_frame"):
4347
+ self.uc_switch_to_frame = new_driver.uc_switch_to_frame
4140
4348
  return new_driver
4141
4349
 
4142
4350
  def switch_to_driver(self, driver):
@@ -4166,6 +4374,9 @@ class BaseCase(unittest.TestCase):
4166
4374
  If a provided selector is not found, then takes a full-page screenshot.
4167
4375
  If the folder provided doesn't exist, it will get created.
4168
4376
  The screenshot will be in PNG format: (*.png)"""
4377
+ if self.__is_cdp_swap_needed():
4378
+ self.cdp.save_screenshot(name, folder=folder, selector=selector)
4379
+ return
4169
4380
  self.wait_for_ready_state_complete()
4170
4381
  if selector and by:
4171
4382
  selector, by = self.__recalculate_selector(selector, by)
@@ -4281,7 +4492,8 @@ class BaseCase(unittest.TestCase):
4281
4492
  @Params
4282
4493
  name - The file name to save the current page's HTML to.
4283
4494
  folder - The folder to save the file to. (Default = current folder)"""
4284
- self.wait_for_ready_state_complete()
4495
+ if not self.__is_cdp_swap_needed():
4496
+ self.wait_for_ready_state_complete()
4285
4497
  return page_actions.save_page_source(self.driver, name, folder)
4286
4498
 
4287
4499
  def save_cookies(self, name="cookies.txt"):
@@ -4309,35 +4521,39 @@ class BaseCase(unittest.TestCase):
4309
4521
  cookies_file.writelines(json_cookies)
4310
4522
  cookies_file.close()
4311
4523
 
4312
- def load_cookies(self, name="cookies.txt"):
4313
- """Loads the page cookies from the "saved_cookies" folder."""
4524
+ def load_cookies(self, name="cookies.txt", expiry=False):
4525
+ """
4526
+ Loads the page cookies from the "saved_cookies" folder.
4527
+ Usage for setting expiry:
4528
+ If expiry == 0 or False: Delete "expiry".
4529
+ If expiry == -1 (or < 0): Do not modify "expiry".
4530
+ If expiry > 0: Set "expiry" to expiry minutes in the future.
4531
+ If expiry == True: Set "expiry" to 24 hours in the future.
4532
+ """
4533
+ cookies = self.get_saved_cookies(name)
4314
4534
  self.wait_for_ready_state_complete()
4315
- if name.endswith("/"):
4316
- raise Exception("Invalid filename for Cookies!")
4317
- if "/" in name:
4318
- name = name.split("/")[-1]
4319
- if "\\" in name:
4320
- name = name.split("\\")[-1]
4321
- if len(name) < 1:
4322
- raise Exception("Filename for Cookies is too short!")
4323
- if not name.endswith(".txt"):
4324
- name = name + ".txt"
4325
- folder = constants.SavedCookies.STORAGE_FOLDER
4326
- abs_path = os.path.abspath(".")
4327
- file_path = os.path.join(abs_path, folder)
4328
- cookies_file_path = os.path.join(file_path, name)
4329
- json_cookies = None
4330
- with open(cookies_file_path, "r") as f:
4331
- json_cookies = f.read().strip()
4332
- cookies = json.loads(json_cookies)
4535
+ origin = self.get_origin()
4536
+ trim_origin = origin.split("://")[-1]
4333
4537
  for cookie in cookies:
4334
- if "expiry" in cookie:
4538
+ if "domain" in cookie:
4539
+ if cookie["domain"] not in origin:
4540
+ cookie["domain"] = trim_origin
4541
+ if "expiry" in cookie and (not expiry or expiry == 0):
4335
4542
  del cookie["expiry"]
4543
+ elif isinstance(expiry, (int, float)) and expiry < 0:
4544
+ pass
4545
+ elif isinstance(expiry, (int, float)) and expiry > 0:
4546
+ cookie["expiry"] = int(time.time()) + int(expiry * 60.0)
4547
+ elif expiry:
4548
+ cookie["expiry"] = int(time.time()) + 86400
4336
4549
  self.driver.add_cookie(cookie)
4337
4550
 
4338
4551
  def delete_all_cookies(self):
4339
4552
  """Deletes all cookies in the web browser.
4340
4553
  Does NOT delete the saved cookies file."""
4554
+ if self.__is_cdp_swap_needed():
4555
+ self.cdp.clear_cookies()
4556
+ return
4341
4557
  self.wait_for_ready_state_complete()
4342
4558
  self.driver.delete_all_cookies()
4343
4559
  if self.recorder_mode:
@@ -4349,7 +4565,6 @@ class BaseCase(unittest.TestCase):
4349
4565
  def delete_saved_cookies(self, name="cookies.txt"):
4350
4566
  """Deletes the cookies file from the "saved_cookies" folder.
4351
4567
  Does NOT delete the cookies from the web browser."""
4352
- self.wait_for_ready_state_complete()
4353
4568
  if name.endswith("/"):
4354
4569
  raise Exception("Invalid filename for Cookies!")
4355
4570
  if "/" in name:
@@ -4366,11 +4581,129 @@ class BaseCase(unittest.TestCase):
4366
4581
  if cookies_file_path.endswith(".txt"):
4367
4582
  os.remove(cookies_file_path)
4368
4583
 
4584
+ def get_saved_cookies(self, name="cookies.txt"):
4585
+ """Gets the page cookies from the "saved_cookies" folder."""
4586
+ if name.endswith("/"):
4587
+ raise Exception("Invalid filename for Cookies!")
4588
+ if "/" in name:
4589
+ name = name.split("/")[-1]
4590
+ if "\\" in name:
4591
+ name = name.split("\\")[-1]
4592
+ if len(name) < 1:
4593
+ raise Exception("Filename for Cookies is too short!")
4594
+ if not name.endswith(".txt"):
4595
+ name = name + ".txt"
4596
+ folder = constants.SavedCookies.STORAGE_FOLDER
4597
+ abs_path = os.path.abspath(".")
4598
+ file_path = os.path.join(abs_path, folder)
4599
+ cookies_file_path = os.path.join(file_path, name)
4600
+ json_cookies = None
4601
+ with open(cookies_file_path, "r") as f:
4602
+ json_cookies = f.read().strip()
4603
+ return json.loads(json_cookies)
4604
+
4605
+ def get_cookie(self, name):
4606
+ self.__check_scope()
4607
+ self._check_browser()
4608
+ return self.driver.get_cookie(name)
4609
+
4610
+ def get_cookies(self):
4611
+ self.__check_scope()
4612
+ self._check_browser()
4613
+ return self.driver.get_cookies()
4614
+
4615
+ def get_cookie_string(self):
4616
+ self.__check_scope()
4617
+ if self.__is_cdp_swap_needed():
4618
+ return self.cdp.get_cookie_string()
4619
+ self._check_browser()
4620
+ return self.execute_script("return document.cookie;")
4621
+
4622
+ def add_cookie(self, cookie_dict, expiry=False):
4623
+ """Usage examples:
4624
+ self.add_cookie({'name': 'foo', 'value': 'bar'})
4625
+ self.add_cookie({'name': 'foo', 'value': 'bar', 'path': '/'})
4626
+ self.add_cookie({'name': 'foo', 'value': 'bar', 'secure': True})
4627
+ self.add_cookie({'name': 'foo', 'value': 'bar', 'sameSite': 'Strict'})
4628
+ Usage for setting expiry:
4629
+ If expiry == 0 or False: Delete "expiry".
4630
+ If expiry == -1 (or < 0): Do not modify "expiry".
4631
+ If expiry > 0: Set "expiry" to expiry minutes in the future.
4632
+ If expiry == True: Set "expiry" to 24 hours in the future.
4633
+ """
4634
+ self.__check_scope()
4635
+ self._check_browser()
4636
+ cookie = cookie_dict
4637
+ if "domain" in cookie:
4638
+ origin = self.get_origin()
4639
+ trim_origin = origin.split("://")[-1]
4640
+ if cookie["domain"] not in origin:
4641
+ cookie["domain"] = trim_origin
4642
+ if "expiry" in cookie and (not expiry or expiry == 0):
4643
+ del cookie["expiry"]
4644
+ elif isinstance(expiry, (int, float)) and expiry < 0:
4645
+ pass
4646
+ elif isinstance(expiry, (int, float)) and expiry > 0:
4647
+ cookie["expiry"] = int(time.time()) + int(expiry * 60.0)
4648
+ elif expiry:
4649
+ cookie["expiry"] = int(time.time()) + 86400
4650
+ self.driver.add_cookie(cookie_dict)
4651
+
4652
+ def add_cookies(self, cookies, expiry=False):
4653
+ """
4654
+ Usage for setting expiry:
4655
+ If expiry == 0 or False: Delete "expiry".
4656
+ If expiry == -1 (or < 0): Do not modify "expiry".
4657
+ If expiry > 0: Set "expiry" to expiry minutes in the future.
4658
+ If expiry == True: Set "expiry" to 24 hours in the future.
4659
+ """
4660
+ self.__check_scope()
4661
+ self._check_browser()
4662
+ origin = self.get_origin()
4663
+ trim_origin = origin.split("://")[-1]
4664
+ for cookie in cookies:
4665
+ if "domain" in cookie:
4666
+ if cookie["domain"] not in origin:
4667
+ cookie["domain"] = trim_origin
4668
+ if "expiry" in cookie and (not expiry or expiry == 0):
4669
+ del cookie["expiry"]
4670
+ elif isinstance(expiry, (int, float)) and expiry < 0:
4671
+ pass
4672
+ elif isinstance(expiry, (int, float)) and expiry > 0:
4673
+ cookie["expiry"] = int(time.time()) + int(expiry * 60.0)
4674
+ elif expiry:
4675
+ cookie["expiry"] = int(time.time()) + 86400
4676
+ self.driver.add_cookie(cookie)
4677
+
4678
+ def __set_esc_skip(self):
4679
+ if hasattr(self, "esc_end") and self.esc_end:
4680
+ script = (
4681
+ """document.onkeydown = function(evt) {
4682
+ evt = evt || window.event;
4683
+ var isEscape = false;
4684
+ if ("key" in evt) {
4685
+ isEscape = (evt.key === "Escape" || evt.key === "Esc");
4686
+ } else {
4687
+ isEscape = (evt.keyCode === 27);
4688
+ }
4689
+ if (isEscape) {
4690
+ document.sb_esc_end = 'yes';
4691
+ }
4692
+ };"""
4693
+ )
4694
+ self.execute_script(script)
4695
+
4696
+ def __skip_if_esc(self):
4697
+ if hasattr(self, "esc_end") and self.esc_end:
4698
+ if self.execute_script("return document.sb_esc_end;") == "yes":
4699
+ self.skip()
4700
+
4369
4701
  def wait_for_ready_state_complete(self, timeout=None):
4370
4702
  """Waits for the "readyState" of the page to be "complete".
4371
4703
  Returns True when the method completes."""
4372
4704
  self.__check_scope()
4373
4705
  self._check_browser()
4706
+ self.__skip_if_esc()
4374
4707
  if not timeout:
4375
4708
  timeout = settings.EXTREME_TIMEOUT
4376
4709
  if self.timeout_multiplier and timeout == settings.EXTREME_TIMEOUT:
@@ -4389,6 +4722,7 @@ class BaseCase(unittest.TestCase):
4389
4722
  time.sleep(0.01)
4390
4723
  if self.undetectable:
4391
4724
  time.sleep(0.035)
4725
+ self.__set_esc_skip()
4392
4726
  return True
4393
4727
 
4394
4728
  def wait_for_angularjs(self, timeout=None, **kwargs):
@@ -4476,24 +4810,35 @@ class BaseCase(unittest.TestCase):
4476
4810
  script = """document.designMode = 'on';"""
4477
4811
  self.execute_script(script)
4478
4812
 
4479
- def deactivate_design_mode(self):
4813
+ def deactivate_design_mode(self, url=None):
4480
4814
  # Deactivate Chrome's Design Mode.
4481
4815
  self.wait_for_ready_state_complete()
4482
4816
  script = """document.designMode = 'off';"""
4483
4817
  self.execute_script(script)
4484
4818
 
4819
+ def activate_cdp_mode(self, url=None):
4820
+ if hasattr(self.driver, "_is_using_uc") and self.driver._is_using_uc:
4821
+ self.driver.uc_open_with_cdp_mode(url)
4822
+ else:
4823
+ self.get_new_driver(undetectable=True)
4824
+ self.driver.uc_open_with_cdp_mode(url)
4825
+ self.cdp = self.driver.cdp
4826
+
4485
4827
  def activate_recorder(self):
4486
4828
  from seleniumbase.js_code.recorder_js import recorder_js
4487
4829
 
4488
4830
  if not self.is_chromium():
4831
+ if "linux" not in sys.platform:
4832
+ c1 = colorama.Fore.BLUE + colorama.Back.LIGHTCYAN_EX
4833
+ c2 = colorama.Fore.BLUE + colorama.Back.LIGHTGREEN_EX
4834
+ cr = colorama.Style.RESET_ALL
4835
+ sc = c1 + "Selenium" + c2 + "Base" + cr
4489
4836
  raise Exception(
4490
- "The Recorder is only for Chromium browsers: (Chrome or Edge)"
4837
+ "The %s Recorder is for Chromium only!\n"
4838
+ " (Supported browsers: Chrome and Edge)" % sc
4491
4839
  )
4492
4840
  url = self.driver.current_url
4493
- if (
4494
- url.startswith("data:") or url.startswith("about:")
4495
- or url.startswith("chrome:") or url.startswith("edge:")
4496
- ):
4841
+ if url.startswith(("data:", "about:", "chrome:", "edge:")):
4497
4842
  message = (
4498
4843
  "The URL in Recorder-Mode cannot start with: "
4499
4844
  '"data:", "about:", "chrome:", or "edge:"!'
@@ -4502,7 +4847,7 @@ class BaseCase(unittest.TestCase):
4502
4847
  return
4503
4848
  if self.recorder_ext:
4504
4849
  return # The Recorder extension is already active
4505
- try:
4850
+ with suppress(Exception):
4506
4851
  recorder_on = self.get_session_storage_item("recorder_activated")
4507
4852
  if not recorder_on == "yes":
4508
4853
  self.execute_script(recorder_js)
@@ -4511,8 +4856,6 @@ class BaseCase(unittest.TestCase):
4511
4856
  print("\n" + message)
4512
4857
  p_msg = "Recorder Mode ACTIVE.<br>[ESC]: Pause. [~`]: Resume."
4513
4858
  self.post_message(p_msg, pause=False, style="error")
4514
- except Exception:
4515
- pass
4516
4859
 
4517
4860
  def __current_url_is_recordable(self):
4518
4861
  url = self.get_current_url()
@@ -4552,10 +4895,7 @@ class BaseCase(unittest.TestCase):
4552
4895
 
4553
4896
  def __get_recorded_actions_on_active_tab(self):
4554
4897
  url = self.driver.current_url
4555
- if (
4556
- url.startswith("data:") or url.startswith("about:")
4557
- or url.startswith("chrome:") or url.startswith("edge:")
4558
- ):
4898
+ if url.startswith(("data:", "about:", "chrome:", "edge:")):
4559
4899
  return []
4560
4900
  self.__origins_to_save.append(self.get_origin())
4561
4901
  actions = self.get_session_storage_item("recorded_actions")
@@ -4566,9 +4906,9 @@ class BaseCase(unittest.TestCase):
4566
4906
  return []
4567
4907
 
4568
4908
  def __process_recorded_actions(self):
4909
+ """Generates code after the SeleniumBase Recorder runs."""
4569
4910
  if self.driver is None:
4570
4911
  return
4571
- import colorama
4572
4912
  from seleniumbase.core import recorder_helper
4573
4913
 
4574
4914
  raw_actions = [] # All raw actions from sessionStorage
@@ -4770,10 +5110,7 @@ class BaseCase(unittest.TestCase):
4770
5110
  or srt_actions[n - 1][0] == "jq_cl"
4771
5111
  or srt_actions[n - 1][0] == "jq_ca"
4772
5112
  ):
4773
- if (
4774
- srt_actions[n - 1][1].startswith("input")
4775
- or srt_actions[n - 1][1].startswith("button")
4776
- ):
5113
+ if srt_actions[n - 1][1].startswith(("input", "button")):
4777
5114
  srt_actions[n][0] = "f_url"
4778
5115
  elif srt_actions[n - 1][0] == "input":
4779
5116
  if srt_actions[n - 1][2].endswith("\n"):
@@ -5121,7 +5458,6 @@ class BaseCase(unittest.TestCase):
5121
5458
  and (filename == "base_case.py" or methodname == "runTest")
5122
5459
  ):
5123
5460
  import traceback
5124
-
5125
5461
  stack_base = traceback.format_stack()[0].split(os.sep)[-1]
5126
5462
  test_base = stack_base.split(", in ")[0]
5127
5463
  if hasattr(self, "cm_filename") and self.cm_filename:
@@ -5169,7 +5505,10 @@ class BaseCase(unittest.TestCase):
5169
5505
  new_file = True
5170
5506
  sb_config._recorded_actions[filename] = []
5171
5507
  data.append("from seleniumbase import BaseCase")
5172
- data.append("BaseCase.main(__name__, __file__)")
5508
+ if "--uc" in sys.argv:
5509
+ data.append('BaseCase.main(__name__, __file__, "--uc")')
5510
+ else:
5511
+ data.append("BaseCase.main(__name__, __file__)")
5173
5512
  data.append("")
5174
5513
  data.append("")
5175
5514
  data.append("class %s(BaseCase):" % classname)
@@ -5179,7 +5518,13 @@ class BaseCase(unittest.TestCase):
5179
5518
  data.append("class %s(BaseCase):" % classname)
5180
5519
  data.append(" def %s(self):" % methodname)
5181
5520
  if len(sb_actions) > 0:
5521
+ if "--uc" in sys.argv:
5522
+ data.append(" self.activate_cdp_mode()")
5182
5523
  for action in sb_actions:
5524
+ if "--uc" in sys.argv:
5525
+ action = action.replace(
5526
+ "self.type(", "self.press_keys("
5527
+ )
5183
5528
  data.append(" " + action)
5184
5529
  else:
5185
5530
  data.append(" pass")
@@ -5191,11 +5536,9 @@ class BaseCase(unittest.TestCase):
5191
5536
  if recordings_folder.endswith("/"):
5192
5537
  recordings_folder = recordings_folder[:-1]
5193
5538
  if not os.path.exists(recordings_folder):
5194
- try:
5539
+ with suppress(Exception):
5195
5540
  os.makedirs(recordings_folder)
5196
5541
  sys.stdout.write("\nCreated recordings%s" % os.sep)
5197
- except Exception:
5198
- pass
5199
5542
 
5200
5543
  data = []
5201
5544
  data.append("")
@@ -5296,12 +5639,10 @@ class BaseCase(unittest.TestCase):
5296
5639
  if not new_file:
5297
5640
  rec_message = ">>> RECORDING ADDED to: "
5298
5641
  star_len = len(rec_message) + len(file_path)
5299
- try:
5642
+ with suppress(Exception):
5300
5643
  terminal_size = os.get_terminal_size().columns
5301
5644
  if terminal_size > 30 and star_len > terminal_size:
5302
5645
  star_len = terminal_size
5303
- except Exception:
5304
- pass
5305
5646
  spc = "\n\n"
5306
5647
  if hasattr(self, "rec_print") and self.rec_print:
5307
5648
  spc = ""
@@ -5361,6 +5702,9 @@ class BaseCase(unittest.TestCase):
5361
5702
  data.append(" Scenario: %s" % scenario_test)
5362
5703
  if len(behave_actions) > 0:
5363
5704
  count = 0
5705
+ if "--uc" in sys.argv:
5706
+ data.append(" Given Activate CDP Mode")
5707
+ count += 1
5364
5708
  for action in behave_actions:
5365
5709
  if count == 0:
5366
5710
  data.append(" Given " + action)
@@ -5374,22 +5718,16 @@ class BaseCase(unittest.TestCase):
5374
5718
  if recordings_folder.endswith("/"):
5375
5719
  recordings_folder = recordings_folder[:-1]
5376
5720
  if not os.path.exists(recordings_folder):
5377
- try:
5721
+ with suppress(Exception):
5378
5722
  os.makedirs(recordings_folder)
5379
- except Exception:
5380
- pass
5381
5723
  features_folder = os.path.join(recordings_folder, "features")
5382
5724
  if not os.path.exists(features_folder):
5383
- try:
5725
+ with suppress(Exception):
5384
5726
  os.makedirs(features_folder)
5385
- except Exception:
5386
- pass
5387
5727
  steps_folder = os.path.join(features_folder, "steps")
5388
5728
  if not os.path.exists(steps_folder):
5389
- try:
5729
+ with suppress(Exception):
5390
5730
  os.makedirs(steps_folder)
5391
- except Exception:
5392
- pass
5393
5731
 
5394
5732
  file_name = filename.split(".")[0]
5395
5733
  if hasattr(self, "is_behave") and self.is_behave:
@@ -5404,12 +5742,10 @@ class BaseCase(unittest.TestCase):
5404
5742
  if not new_file:
5405
5743
  rec_message = ">>> RECORDING ADDED to: "
5406
5744
  star_len = len(rec_message) + len(file_path)
5407
- try:
5745
+ with suppress(Exception):
5408
5746
  terminal_size = os.get_terminal_size().columns
5409
5747
  if terminal_size > 30 and star_len > terminal_size:
5410
5748
  star_len = terminal_size
5411
- except Exception:
5412
- pass
5413
5749
  spc = "\n"
5414
5750
  if hasattr(self, "rec_print") and self.rec_print:
5415
5751
  spc = ""
@@ -5515,16 +5851,17 @@ class BaseCase(unittest.TestCase):
5515
5851
  print("Created recordings/features/steps/imported.py")
5516
5852
 
5517
5853
  def bring_active_window_to_front(self):
5518
- """Brings the active browser window to the front.
5519
- This is useful when multiple drivers are being used."""
5854
+ """Brings the active browser window to the front (on top).
5855
+ Useful when multiple drivers are being used at the same time."""
5520
5856
  self.__check_scope()
5521
- try:
5857
+ if self.__is_cdp_swap_needed():
5858
+ self.cdp.bring_active_window_to_front()
5859
+ return
5860
+ with suppress(Exception):
5522
5861
  if not self.__is_in_frame():
5523
5862
  # Only bring the window to the front if not in a frame
5524
5863
  # because the driver resets itself to default content.
5525
5864
  self.switch_to_window(self.driver.current_window_handle)
5526
- except Exception:
5527
- pass
5528
5865
 
5529
5866
  def bring_to_front(self, selector, by="css selector"):
5530
5867
  """Updates the Z-index of a page element to bring it into view.
@@ -5554,7 +5891,7 @@ class BaseCase(unittest.TestCase):
5554
5891
  def highlight_click(
5555
5892
  self, selector, by="css selector", loops=3, scroll=True, timeout=None,
5556
5893
  ):
5557
- """Highlights the element and then clicks it."""
5894
+ """Highlights the element, and then clicks it."""
5558
5895
  self.__check_scope()
5559
5896
  if not timeout:
5560
5897
  timeout = settings.SMALL_TIMEOUT
@@ -5608,11 +5945,43 @@ class BaseCase(unittest.TestCase):
5608
5945
  if self.is_element_visible(selector, by=by):
5609
5946
  self.__highlight(selector, by=by, loops=loops, scroll=scroll)
5610
5947
 
5948
+ def __highlight_element(self, element, loops=None, scroll=True):
5949
+ self.__check_scope()
5950
+ if not loops:
5951
+ loops = settings.HIGHLIGHTS
5952
+ if scroll and self.browser != "safari":
5953
+ with suppress(Exception):
5954
+ self.__slow_scroll_to_element(element)
5955
+ if self.highlights:
5956
+ loops = self.highlights
5957
+ if self.browser == "ie":
5958
+ loops = 1 # Override previous setting because IE is slow
5959
+ loops = int(loops)
5960
+ if self.headless or self.headless2 or self.xvfb:
5961
+ # Headless modes have less need for highlighting elements.
5962
+ # However, highlight() may be used as a sleep alternative.
5963
+ loops = int(math.ceil(loops * 0.5))
5964
+ o_bs = "" # original_box_shadow
5965
+ try:
5966
+ style = element.get_attribute("style")
5967
+ except Exception:
5968
+ self.wait_for_ready_state_complete()
5969
+ time.sleep(0.12)
5970
+ style = element.get_attribute("style")
5971
+ if style:
5972
+ if "box-shadow: " in style:
5973
+ box_start = style.find("box-shadow: ")
5974
+ box_end = style.find(";", box_start) + 1
5975
+ original_box_shadow = style[box_start:box_end]
5976
+ o_bs = original_box_shadow
5977
+ self.__highlight_element_with_js(element, loops, o_bs)
5978
+ time.sleep(0.065)
5979
+
5611
5980
  def __highlight(
5612
5981
  self, selector, by="css selector", loops=None, scroll=True
5613
5982
  ):
5614
5983
  """This method uses fancy JavaScript to highlight an element.
5615
- (Commonly used during Demo Mode automatically)"""
5984
+ (Automatically using in S_e_l_e_n_i_u_m_B_a_s_e Demo Mode)"""
5616
5985
  self.__check_scope()
5617
5986
  selector, by = self.__recalculate_selector(selector, by, xp_ok=False)
5618
5987
  element = self.wait_for_element_visible(
@@ -5696,13 +6065,19 @@ class BaseCase(unittest.TestCase):
5696
6065
  ):
5697
6066
  """This method uses fancy JavaScript to highlight an element.
5698
6067
  @Params
5699
- selector - the selector of the element to find
6068
+ selector - the selector of the element to find (Accepts WebElement)
5700
6069
  by - the type of selector to search by (Default: CSS)
5701
6070
  loops - # of times to repeat the highlight animation
5702
6071
  (Default: 4. Each loop lasts for about 0.2s)
5703
6072
  scroll - the option to scroll to the element first (Default: True)
5704
6073
  timeout - the time to wait for the element to appear """
5705
6074
  self.__check_scope()
6075
+ if not self.__is_cdp_swap_needed():
6076
+ self._check_browser()
6077
+ self.__skip_if_esc()
6078
+ if isinstance(selector, WebElement):
6079
+ self.__highlight_element(selector, loops=loops, scroll=scroll)
6080
+ return
5706
6081
  if not timeout:
5707
6082
  timeout = settings.SMALL_TIMEOUT
5708
6083
  self.wait_for_element_visible(selector, by=by, timeout=timeout)
@@ -5714,7 +6089,30 @@ class BaseCase(unittest.TestCase):
5714
6089
  action = ["hi_li", selector, origin, time_stamp]
5715
6090
  self.__extra_actions.append(action)
5716
6091
 
5717
- def press_up_arrow(self, selector="html", times=1, by="css selector"):
6092
+ def highlight_elements(
6093
+ self,
6094
+ selector,
6095
+ by="css selector",
6096
+ loops=None,
6097
+ scroll=True,
6098
+ limit=0,
6099
+ ):
6100
+ if not limit:
6101
+ limit = 0 # 0 means no limit
6102
+ limit = int(limit)
6103
+ count = 0
6104
+ elements = self.find_elements(selector, by=by)
6105
+ for element in elements:
6106
+ with suppress(Exception):
6107
+ if element.is_displayed():
6108
+ self.__highlight_element(
6109
+ element, loops=loops, scroll=scroll
6110
+ )
6111
+ count += 1
6112
+ if limit > 0 and count >= limit:
6113
+ break
6114
+
6115
+ def press_up_arrow(self, selector="body", times=1, by="css selector"):
5718
6116
  """Simulates pressing the UP Arrow on the keyboard.
5719
6117
  By default, "html" will be used as the CSS Selector target.
5720
6118
  You can specify how many times in-a-row the action happens."""
@@ -5736,7 +6134,7 @@ class BaseCase(unittest.TestCase):
5736
6134
  if self.slow_mode:
5737
6135
  time.sleep(0.1)
5738
6136
 
5739
- def press_down_arrow(self, selector="html", times=1, by="css selector"):
6137
+ def press_down_arrow(self, selector="body", times=1, by="css selector"):
5740
6138
  """Simulates pressing the DOWN Arrow on the keyboard.
5741
6139
  By default, "html" will be used as the CSS Selector target.
5742
6140
  You can specify how many times in-a-row the action happens."""
@@ -5758,7 +6156,7 @@ class BaseCase(unittest.TestCase):
5758
6156
  if self.slow_mode:
5759
6157
  time.sleep(0.1)
5760
6158
 
5761
- def press_left_arrow(self, selector="html", times=1, by="css selector"):
6159
+ def press_left_arrow(self, selector="body", times=1, by="css selector"):
5762
6160
  """Simulates pressing the LEFT Arrow on the keyboard.
5763
6161
  By default, "html" will be used as the CSS Selector target.
5764
6162
  You can specify how many times in-a-row the action happens."""
@@ -5780,7 +6178,7 @@ class BaseCase(unittest.TestCase):
5780
6178
  if self.slow_mode:
5781
6179
  time.sleep(0.1)
5782
6180
 
5783
- def press_right_arrow(self, selector="html", times=1, by="css selector"):
6181
+ def press_right_arrow(self, selector="body", times=1, by="css selector"):
5784
6182
  """Simulates pressing the RIGHT Arrow on the keyboard.
5785
6183
  By default, "html" will be used as the CSS Selector target.
5786
6184
  You can specify how many times in-a-row the action happens."""
@@ -5809,6 +6207,9 @@ class BaseCase(unittest.TestCase):
5809
6207
  timeout = settings.SMALL_TIMEOUT
5810
6208
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
5811
6209
  timeout = self.__get_new_timeout(timeout)
6210
+ if self.__is_cdp_swap_needed():
6211
+ self.cdp.scroll_into_view(selector)
6212
+ return
5812
6213
  if self.demo_mode or self.slow_mode:
5813
6214
  self.slow_scroll_to(selector, by=by, timeout=timeout)
5814
6215
  return
@@ -5839,6 +6240,9 @@ class BaseCase(unittest.TestCase):
5839
6240
  original_selector = selector
5840
6241
  original_by = by
5841
6242
  selector, by = self.__recalculate_selector(selector, by)
6243
+ if self.__is_cdp_swap_needed() and ":contains(" not in selector:
6244
+ self.cdp.scroll_into_view(selector)
6245
+ return
5842
6246
  element = self.wait_for_element_visible(
5843
6247
  original_selector, by=original_by, timeout=timeout
5844
6248
  )
@@ -5876,30 +6280,45 @@ class BaseCase(unittest.TestCase):
5876
6280
  timeout = settings.SMALL_TIMEOUT
5877
6281
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
5878
6282
  timeout = self.__get_new_timeout(timeout)
6283
+ if self.__is_cdp_swap_needed():
6284
+ self.cdp.scroll_into_view(selector)
6285
+ return
5879
6286
  element = self.wait_for_element_visible(selector, by, timeout=timeout)
5880
6287
  self.execute_script("arguments[0].scrollIntoView();", element)
5881
6288
 
5882
6289
  def scroll_to_top(self):
5883
6290
  """Scroll to the top of the page."""
5884
6291
  self.__check_scope()
6292
+ if self.__is_cdp_swap_needed():
6293
+ self.cdp.scroll_to_top()
6294
+ return
5885
6295
  scroll_script = "window.scrollTo(0, 0);"
5886
- try:
6296
+ with suppress(Exception):
5887
6297
  self.execute_script(scroll_script)
5888
6298
  time.sleep(0.012)
5889
- return True
5890
- except Exception:
5891
- return False
5892
6299
 
5893
6300
  def scroll_to_bottom(self):
5894
6301
  """Scroll to the bottom of the page."""
5895
6302
  self.__check_scope()
6303
+ if self.__is_cdp_swap_needed():
6304
+ self.cdp.scroll_to_bottom()
6305
+ return
5896
6306
  scroll_script = "window.scrollTo(0, 10000);"
5897
- try:
6307
+ with suppress(Exception):
6308
+ self.execute_script(scroll_script)
6309
+ time.sleep(0.012)
6310
+
6311
+ def scroll_to_y(self, y):
6312
+ """Scroll to y position on the page."""
6313
+ self.__check_scope()
6314
+ y = int(y)
6315
+ if self.__is_cdp_swap_needed():
6316
+ self.cdp.scroll_to_y(y)
6317
+ return
6318
+ scroll_script = "window.scrollTo(0, %s);" % y
6319
+ with suppress(Exception):
5898
6320
  self.execute_script(scroll_script)
5899
6321
  time.sleep(0.012)
5900
- return True
5901
- except Exception:
5902
- return False
5903
6322
 
5904
6323
  def click_xpath(self, xpath):
5905
6324
  """Technically, self.click() automatically detects xpath selectors,
@@ -5918,6 +6337,9 @@ class BaseCase(unittest.TestCase):
5918
6337
  Can be used to click hidden / invisible elements.
5919
6338
  If "all_matches" is False, only the first match is clicked.
5920
6339
  If "scroll" is False, won't scroll unless running in Demo Mode."""
6340
+ if self.__is_cdp_swap_needed():
6341
+ self.cdp.click(selector, timeout=timeout)
6342
+ return
5921
6343
  self.wait_for_ready_state_complete()
5922
6344
  if not timeout or timeout is True:
5923
6345
  timeout = settings.SMALL_TIMEOUT
@@ -5957,10 +6379,8 @@ class BaseCase(unittest.TestCase):
5957
6379
  time_stamp = 0
5958
6380
  action = ["", "", "", time_stamp]
5959
6381
  pre_action_url = None
5960
- try:
6382
+ with suppress(Exception):
5961
6383
  pre_action_url = self.driver.current_url
5962
- except Exception:
5963
- pass
5964
6384
  pre_window_count = len(self.driver.window_handles)
5965
6385
  if self.recorder_mode and not self.__dont_record_js_click:
5966
6386
  time_stamp = self.execute_script("return Date.now();")
@@ -6062,10 +6482,8 @@ class BaseCase(unittest.TestCase):
6062
6482
  # If a click closes the active window,
6063
6483
  # switch to the last one if it exists.
6064
6484
  self.switch_to_window(-1)
6065
- try:
6485
+ with suppress(Exception):
6066
6486
  self.wait_for_ready_state_complete()
6067
- except Exception:
6068
- pass
6069
6487
  self.__demo_mode_pause_if_active()
6070
6488
 
6071
6489
  def js_click_if_present(self, selector, by="css selector", timeout=0):
@@ -6077,10 +6495,8 @@ class BaseCase(unittest.TestCase):
6077
6495
  if self.is_element_present(selector, by=by):
6078
6496
  self.js_click(selector, by=by)
6079
6497
  elif timeout > 0:
6080
- try:
6498
+ with suppress(Exception):
6081
6499
  self.wait_for_element_present(selector, by=by, timeout=timeout)
6082
- except Exception:
6083
- pass
6084
6500
  if self.is_element_present(selector, by=by):
6085
6501
  self.js_click(selector, by=by)
6086
6502
 
@@ -6093,10 +6509,8 @@ class BaseCase(unittest.TestCase):
6093
6509
  if self.is_element_visible(selector, by=by):
6094
6510
  self.js_click(selector, by=by)
6095
6511
  elif timeout > 0:
6096
- try:
6512
+ with suppress(Exception):
6097
6513
  self.wait_for_element_visible(selector, by=by, timeout=timeout)
6098
- except Exception:
6099
- pass
6100
6514
  if self.is_element_visible(selector, by=by):
6101
6515
  self.js_click(selector, by=by)
6102
6516
 
@@ -6189,13 +6603,11 @@ class BaseCase(unittest.TestCase):
6189
6603
  """Hide the first element on the page that matches the selector."""
6190
6604
  self.__check_scope()
6191
6605
  element = None
6192
- try:
6606
+ with suppress(Exception):
6193
6607
  self.wait_for_element_visible("body", timeout=1.5)
6194
6608
  element = self.wait_for_element_present(
6195
6609
  selector, by=by, timeout=0.5
6196
6610
  )
6197
- except Exception:
6198
- pass
6199
6611
  selector, by = self.__recalculate_selector(selector, by)
6200
6612
  css_selector = self.convert_to_css_selector(selector, by=by)
6201
6613
  if ":contains(" in css_selector and element:
@@ -6221,10 +6633,8 @@ class BaseCase(unittest.TestCase):
6221
6633
  def hide_elements(self, selector, by="css selector"):
6222
6634
  """Hide all elements on the page that match the selector."""
6223
6635
  self.__check_scope()
6224
- try:
6636
+ with suppress(Exception):
6225
6637
  self.wait_for_element_visible("body", timeout=1.5)
6226
- except Exception:
6227
- pass
6228
6638
  selector, by = self.__recalculate_selector(selector, by)
6229
6639
  css_selector = self.convert_to_css_selector(selector, by=by)
6230
6640
  if ":contains(" in css_selector:
@@ -6247,11 +6657,9 @@ class BaseCase(unittest.TestCase):
6247
6657
  """Show the first element on the page that matches the selector."""
6248
6658
  self.__check_scope()
6249
6659
  element = None
6250
- try:
6660
+ with suppress(Exception):
6251
6661
  self.wait_for_element_visible("body", timeout=1.5)
6252
6662
  element = self.wait_for_element_present(selector, by=by, timeout=1)
6253
- except Exception:
6254
- pass
6255
6663
  selector, by = self.__recalculate_selector(selector, by)
6256
6664
  css_selector = self.convert_to_css_selector(selector, by=by)
6257
6665
  if ":contains(" in css_selector and element:
@@ -6277,10 +6685,8 @@ class BaseCase(unittest.TestCase):
6277
6685
  def show_elements(self, selector, by="css selector"):
6278
6686
  """Show all elements on the page that match the selector."""
6279
6687
  self.__check_scope()
6280
- try:
6688
+ with suppress(Exception):
6281
6689
  self.wait_for_element_visible("body", timeout=1.5)
6282
- except Exception:
6283
- pass
6284
6690
  selector, by = self.__recalculate_selector(selector, by)
6285
6691
  css_selector = self.convert_to_css_selector(selector, by=by)
6286
6692
  if ":contains(" in css_selector:
@@ -6302,14 +6708,15 @@ class BaseCase(unittest.TestCase):
6302
6708
  def remove_element(self, selector, by="css selector"):
6303
6709
  """Remove the first element on the page that matches the selector."""
6304
6710
  self.__check_scope()
6711
+ if self.__is_cdp_swap_needed():
6712
+ self.cdp.remove_element(selector)
6713
+ return
6305
6714
  element = None
6306
- try:
6715
+ with suppress(Exception):
6307
6716
  self.wait_for_element_visible("body", timeout=1.5)
6308
6717
  element = self.wait_for_element_present(
6309
6718
  selector, by=by, timeout=0.5
6310
6719
  )
6311
- except Exception:
6312
- pass
6313
6720
  selector, by = self.__recalculate_selector(selector, by)
6314
6721
  css_selector = self.convert_to_css_selector(selector, by=by)
6315
6722
  if ":contains(" in css_selector and element:
@@ -6335,10 +6742,11 @@ class BaseCase(unittest.TestCase):
6335
6742
  def remove_elements(self, selector, by="css selector"):
6336
6743
  """Remove all elements on the page that match the selector."""
6337
6744
  self.__check_scope()
6338
- try:
6745
+ if self.__is_cdp_swap_needed():
6746
+ self.cdp.remove_elements(selector)
6747
+ return
6748
+ with suppress(Exception):
6339
6749
  self.wait_for_element_visible("body", timeout=1.5)
6340
- except Exception:
6341
- pass
6342
6750
  selector, by = self.__recalculate_selector(selector, by)
6343
6751
  css_selector = self.convert_to_css_selector(selector, by=by)
6344
6752
  if ":contains(" in css_selector:
@@ -6403,10 +6811,8 @@ class BaseCase(unittest.TestCase):
6403
6811
  $elements[index].setAttribute('class', new_class);}"""
6404
6812
  % css_selector
6405
6813
  )
6406
- try:
6814
+ with suppress(Exception):
6407
6815
  self.execute_script(script)
6408
- except Exception:
6409
- pass
6410
6816
  if self.recorder_mode and self.__current_url_is_recordable():
6411
6817
  if self.get_session_storage_item("pause_recorder") == "no":
6412
6818
  time_stamp = self.execute_script("return Date.now();")
@@ -6424,10 +6830,8 @@ class BaseCase(unittest.TestCase):
6424
6830
  self.is_chromium()
6425
6831
  and self.driver.current_url.startswith("http")
6426
6832
  ):
6427
- try:
6833
+ with suppress(Exception):
6428
6834
  self.driver.execute_script("window.onbeforeunload=null;")
6429
- except Exception:
6430
- pass
6431
6835
 
6432
6836
  def get_domain_url(self, url):
6433
6837
  self.__check_scope()
@@ -6443,15 +6847,12 @@ class BaseCase(unittest.TestCase):
6443
6847
  from bs4 import BeautifulSoup
6444
6848
 
6445
6849
  if not source:
6446
- try:
6850
+ with suppress(Exception):
6447
6851
  self.wait_for_element_visible(
6448
6852
  "body", timeout=settings.MINI_TIMEOUT
6449
6853
  )
6450
- except Exception:
6451
- pass
6452
6854
  source = self.get_page_source()
6453
- soup = BeautifulSoup(source, "html.parser")
6454
- return soup
6855
+ return BeautifulSoup(source, "html.parser")
6455
6856
 
6456
6857
  def get_unique_links(self):
6457
6858
  """Get all unique links in the html of the page source.
@@ -6462,19 +6863,16 @@ class BaseCase(unittest.TestCase):
6462
6863
  time.sleep(0.08)
6463
6864
  if self.undetectable:
6464
6865
  time.sleep(0.02)
6465
- try:
6866
+ with suppress(Exception):
6466
6867
  self.wait_for_element_present("body", timeout=1.5)
6467
6868
  self.wait_for_element_visible("body", timeout=1.5)
6468
- except Exception:
6469
- pass
6470
6869
  if self.__needs_minimum_wait():
6471
6870
  time.sleep(0.25)
6472
6871
  if self.undetectable:
6473
6872
  time.sleep(0.123)
6474
6873
  soup = self.get_beautiful_soup(self.get_page_source())
6475
6874
  page_url = self.get_current_url()
6476
- links = page_utils._get_unique_links(page_url, soup)
6477
- return links
6875
+ return page_utils._get_unique_links(page_url, soup)
6478
6876
 
6479
6877
  def get_link_status_code(
6480
6878
  self,
@@ -6493,13 +6891,12 @@ class BaseCase(unittest.TestCase):
6493
6891
  timeout = self.__requests_timeout
6494
6892
  if timeout < 1:
6495
6893
  timeout = 1
6496
- status_code = page_utils._get_link_status_code(
6894
+ return page_utils._get_link_status_code(
6497
6895
  link,
6498
6896
  allow_redirects=allow_redirects,
6499
6897
  timeout=timeout,
6500
6898
  verify=verify,
6501
6899
  )
6502
- return status_code
6503
6900
 
6504
6901
  def assert_link_status_code_is_not_404(self, link):
6505
6902
  status_code = str(self.get_link_status_code(link))
@@ -6530,6 +6927,7 @@ class BaseCase(unittest.TestCase):
6530
6927
  for link in all_links:
6531
6928
  if (
6532
6929
  "data:" not in link
6930
+ and "tel:" not in link
6533
6931
  and "mailto:" not in link
6534
6932
  and "javascript:" not in link
6535
6933
  and "://fonts.gstatic.com" not in link
@@ -6663,18 +7061,19 @@ class BaseCase(unittest.TestCase):
6663
7061
  constants.PipInstall.FINDLOCK
6664
7062
  )
6665
7063
  with pip_find_lock:
6666
- if (
6667
- sys.version_info >= (3, 7)
6668
- and sys.version_info < (3, 9)
6669
- ):
7064
+ with suppress(Exception):
7065
+ shared_utils.make_writable(constants.PipInstall.FINDLOCK)
7066
+ if sys.version_info < (3, 9):
6670
7067
  # Fix bug in newer cryptography for Python 3.7 and 3.8:
6671
7068
  # "pyo3_runtime.PanicException: Python API call failed"
6672
7069
  try:
6673
7070
  import cryptography
6674
7071
  if cryptography.__version__ != "39.0.2":
7072
+ del cryptography # To get newer ver
6675
7073
  shared_utils.pip_install(
6676
7074
  "cryptography", version="39.0.2"
6677
7075
  )
7076
+ import cryptography
6678
7077
  except Exception:
6679
7078
  shared_utils.pip_install(
6680
7079
  "cryptography", version="39.0.2"
@@ -6682,12 +7081,7 @@ class BaseCase(unittest.TestCase):
6682
7081
  try:
6683
7082
  from pdfminer.high_level import extract_text
6684
7083
  except Exception:
6685
- if not sys.version_info >= (3, 8):
6686
- shared_utils.pip_install(
6687
- "pdfminer.six", version="20221105"
6688
- )
6689
- else:
6690
- shared_utils.pip_install("pdfminer.six")
7084
+ shared_utils.pip_install("pdfminer.six")
6691
7085
  from pdfminer.high_level import extract_text
6692
7086
  if not password:
6693
7087
  password = ""
@@ -6735,8 +7129,7 @@ class BaseCase(unittest.TestCase):
6735
7129
  pdf_text = self.__fix_unicode_conversion(pdf_text)
6736
7130
  if wrap:
6737
7131
  pdf_text = pdf_text.replace(" \n", " ")
6738
- pdf_text = pdf_text.strip() # Remove leading and trailing whitespace
6739
- return pdf_text
7132
+ return pdf_text.strip()
6740
7133
 
6741
7134
  def assert_pdf_text(
6742
7135
  self,
@@ -6808,10 +7201,8 @@ class BaseCase(unittest.TestCase):
6808
7201
  if len(folder) < 1:
6809
7202
  raise Exception("Minimum folder name length = 1.")
6810
7203
  if not os.path.exists(folder):
6811
- try:
7204
+ with suppress(Exception):
6812
7205
  os.makedirs(folder)
6813
- except Exception:
6814
- pass
6815
7206
 
6816
7207
  def choose_file(
6817
7208
  self, selector, file_path, by="css selector", timeout=None
@@ -6851,10 +7242,8 @@ class BaseCase(unittest.TestCase):
6851
7242
  self.__scroll_to_element(element, selector, by)
6852
7243
  pre_action_url = None
6853
7244
  if self.demo_mode:
6854
- try:
7245
+ with suppress(Exception):
6855
7246
  pre_action_url = self.driver.current_url
6856
- except Exception:
6857
- pass
6858
7247
  if self.recorder_mode and self.__current_url_is_recordable():
6859
7248
  if self.get_session_storage_item("pause_recorder") == "no":
6860
7249
  time_stamp = self.execute_script("return Date.now();")
@@ -6924,6 +7313,8 @@ class BaseCase(unittest.TestCase):
6924
7313
  constants.PipInstall.FINDLOCK
6925
7314
  )
6926
7315
  with pip_find_lock:
7316
+ with suppress(Exception):
7317
+ shared_utils.make_writable(constants.PipInstall.FINDLOCK)
6927
7318
  try:
6928
7319
  from PIL import Image, ImageDraw
6929
7320
  except Exception:
@@ -6969,6 +7360,10 @@ class BaseCase(unittest.TestCase):
6969
7360
  constants.MultiBrowser.DOWNLOAD_FILE_LOCK
6970
7361
  )
6971
7362
  with download_file_lock:
7363
+ with suppress(Exception):
7364
+ shared_utils.make_writable(
7365
+ constants.MultiBrowser.DOWNLOAD_FILE_LOCK
7366
+ )
6972
7367
  if not destination_folder:
6973
7368
  destination_folder = constants.Files.DOWNLOADS_FOLDER
6974
7369
  if not os.path.exists(destination_folder):
@@ -6989,6 +7384,10 @@ class BaseCase(unittest.TestCase):
6989
7384
  constants.MultiBrowser.DOWNLOAD_FILE_LOCK
6990
7385
  )
6991
7386
  with download_file_lock:
7387
+ with suppress(Exception):
7388
+ shared_utils.make_writable(
7389
+ constants.MultiBrowser.DOWNLOAD_FILE_LOCK
7390
+ )
6992
7391
  if not destination_folder:
6993
7392
  destination_folder = constants.Files.DOWNLOADS_FOLDER
6994
7393
  if not os.path.exists(destination_folder):
@@ -7094,6 +7493,8 @@ class BaseCase(unittest.TestCase):
7094
7493
  constants.MultiBrowser.FILE_IO_LOCK
7095
7494
  )
7096
7495
  with file_io_lock:
7496
+ with suppress(Exception):
7497
+ shared_utils.make_writable(constants.MultiBrowser.FILE_IO_LOCK)
7097
7498
  with open(fpath, "r") as f:
7098
7499
  data = f.read().strip()
7099
7500
  return data
@@ -7142,10 +7543,8 @@ class BaseCase(unittest.TestCase):
7142
7543
  Those paths are usually the same. (browser-dependent)."""
7143
7544
  if self.is_downloaded_file_present(file, browser=browser):
7144
7545
  file_path = self.get_path_of_downloaded_file(file, browser=browser)
7145
- try:
7546
+ with suppress(Exception):
7146
7547
  os.remove(file_path)
7147
- except Exception:
7148
- pass
7149
7548
 
7150
7549
  def delete_downloaded_file(self, file, browser=False):
7151
7550
  """Same as self.delete_downloaded_file_if_present()
@@ -7162,10 +7561,8 @@ class BaseCase(unittest.TestCase):
7162
7561
  Those paths are usually the same. (browser-dependent)."""
7163
7562
  if self.is_downloaded_file_present(file, browser=browser):
7164
7563
  file_path = self.get_path_of_downloaded_file(file, browser=browser)
7165
- try:
7564
+ with suppress(Exception):
7166
7565
  os.remove(file_path)
7167
- except Exception:
7168
- pass
7169
7566
 
7170
7567
  def assert_downloaded_file(self, file, timeout=None, browser=False):
7171
7568
  """Asserts that the file exists in SeleniumBase's [Downloads Folder].
@@ -7222,13 +7619,11 @@ class BaseCase(unittest.TestCase):
7222
7619
  self.__extra_actions.append(action)
7223
7620
  if self.demo_mode:
7224
7621
  messenger_post = "<b>ASSERT DOWNLOADED FILE</b>: [%s]" % file
7225
- try:
7622
+ with suppress(Exception):
7226
7623
  js_utils.activate_jquery(self.driver)
7227
7624
  js_utils.post_messenger_success_message(
7228
7625
  self.driver, messenger_post, self.message_duration
7229
7626
  )
7230
- except Exception:
7231
- pass
7232
7627
 
7233
7628
  def assert_downloaded_file_regex(self, regex, timeout=None, browser=False):
7234
7629
  """Assert the filename regex exists in SeleniumBase's Downloads Folder.
@@ -7277,13 +7672,11 @@ class BaseCase(unittest.TestCase):
7277
7672
  messenger_post = (
7278
7673
  "<b>ASSERT DOWNLOADED FILE REGEX</b>: [%s]" % regex
7279
7674
  )
7280
- try:
7675
+ with suppress(Exception):
7281
7676
  js_utils.activate_jquery(self.driver)
7282
7677
  js_utils.post_messenger_success_message(
7283
7678
  self.driver, messenger_post, self.message_duration
7284
7679
  )
7285
- except Exception:
7286
- pass
7287
7680
 
7288
7681
  def assert_data_in_downloaded_file(
7289
7682
  self, data, file, timeout=None, browser=False
@@ -7302,37 +7695,37 @@ class BaseCase(unittest.TestCase):
7302
7695
 
7303
7696
  def assert_true(self, expr, msg=None):
7304
7697
  """Asserts that the expression is True.
7305
- Will raise an exception if the statement if False."""
7698
+ Raises an exception if the statement if False."""
7306
7699
  self.assertTrue(expr, msg=msg)
7307
7700
 
7308
7701
  def assert_false(self, expr, msg=None):
7309
7702
  """Asserts that the expression is False.
7310
- Will raise an exception if the statement if True."""
7703
+ Raises an exception if the statement if True."""
7311
7704
  self.assertFalse(expr, msg=msg)
7312
7705
 
7313
7706
  def assert_equal(self, first, second, msg=None):
7314
7707
  """Asserts that the two values are equal.
7315
- Will raise an exception if the values are not equal."""
7708
+ Raises an exception if the values are not equal."""
7316
7709
  self.assertEqual(first, second, msg=msg)
7317
7710
 
7318
7711
  def assert_not_equal(self, first, second, msg=None):
7319
7712
  """Asserts that the two values are not equal.
7320
- Will raise an exception if the values are equal."""
7713
+ Raises an exception if the values are equal."""
7321
7714
  self.assertNotEqual(first, second, msg=msg)
7322
7715
 
7323
7716
  def assert_in(self, first, second, msg=None):
7324
7717
  """Asserts that the first string is in the second string.
7325
- Will raise an exception if the first string is not in the second."""
7718
+ Raises an exception if the first string is not in the second."""
7326
7719
  self.assertIn(first, second, msg=msg)
7327
7720
 
7328
7721
  def assert_not_in(self, first, second, msg=None):
7329
7722
  """Asserts that the first string is not in the second string.
7330
- Will raise an exception if the first string is in the second string."""
7723
+ Raises an exception if the first string is in the second string."""
7331
7724
  self.assertNotIn(first, second, msg=msg)
7332
7725
 
7333
7726
  def assert_raises(self, *args, **kwargs):
7334
7727
  """Asserts that the following block of code raises an exception.
7335
- Will raise an exception if the block of code has no exception.
7728
+ Raises an exception if the block of code has no exception.
7336
7729
  Usage Example =>
7337
7730
  # Verify that the expected exception is raised.
7338
7731
  with self.assert_raises(Exception):
@@ -7352,7 +7745,10 @@ class BaseCase(unittest.TestCase):
7352
7745
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
7353
7746
  timeout = self.__get_new_timeout(timeout)
7354
7747
  selector, by = self.__recalculate_selector(selector, by)
7355
- if self.__is_shadow_selector(selector):
7748
+ if self.__is_cdp_swap_needed():
7749
+ self.cdp.assert_element_attribute(selector, attribute, value)
7750
+ return
7751
+ elif self.__is_shadow_selector(selector):
7356
7752
  return self.__wait_for_shadow_attribute_present(
7357
7753
  selector, attribute, value=value, timeout=timeout
7358
7754
  )
@@ -7377,6 +7773,9 @@ class BaseCase(unittest.TestCase):
7377
7773
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
7378
7774
  timeout = self.__get_new_timeout(timeout)
7379
7775
  selector, by = self.__recalculate_selector(selector, by)
7776
+ if self.__is_cdp_swap_needed():
7777
+ self.cdp.assert_element_attribute(selector, attribute, value)
7778
+ return
7380
7779
  self.wait_for_attribute(
7381
7780
  selector, attribute, value=value, by=by, timeout=timeout
7382
7781
  )
@@ -7426,6 +7825,9 @@ class BaseCase(unittest.TestCase):
7426
7825
  but then the title switches over to the actual page title.
7427
7826
  In Recorder Mode, this assertion is skipped because the Recorder
7428
7827
  changes the page title to the selector of the hovered element."""
7828
+ if self.__is_cdp_swap_needed():
7829
+ self.cdp.assert_title(title)
7830
+ return
7429
7831
  self.wait_for_ready_state_complete()
7430
7832
  expected = title.strip()
7431
7833
  actual = self.get_page_title().strip()
@@ -7472,6 +7874,9 @@ class BaseCase(unittest.TestCase):
7472
7874
  but then the title switches over to the actual page title.
7473
7875
  In Recorder Mode, this assertion is skipped because the Recorder
7474
7876
  changes the page title to the selector of the hovered element."""
7877
+ if self.__is_cdp_swap_needed():
7878
+ self.cdp.assert_title_contains(substring)
7879
+ return
7475
7880
  self.wait_for_ready_state_complete()
7476
7881
  expected = substring.strip()
7477
7882
  actual = self.get_page_title().strip()
@@ -7515,6 +7920,9 @@ class BaseCase(unittest.TestCase):
7515
7920
 
7516
7921
  def assert_url(self, url):
7517
7922
  """Asserts that the web page URL matches the expected URL."""
7923
+ if self.__is_cdp_swap_needed():
7924
+ self.cdp.assert_url(url)
7925
+ return
7518
7926
  self.wait_for_ready_state_complete()
7519
7927
  expected = url.strip()
7520
7928
  actual = self.get_current_url().strip()
@@ -7550,6 +7958,9 @@ class BaseCase(unittest.TestCase):
7550
7958
 
7551
7959
  def assert_url_contains(self, substring):
7552
7960
  """Asserts that the URL substring appears in the full URL."""
7961
+ if self.__is_cdp_swap_needed():
7962
+ self.cdp.assert_url_contains(substring)
7963
+ return
7553
7964
  self.wait_for_ready_state_complete()
7554
7965
  expected = substring.strip()
7555
7966
  actual = self.get_current_url().strip()
@@ -7739,14 +8150,33 @@ class BaseCase(unittest.TestCase):
7739
8150
  """Return True if the url is a valid url."""
7740
8151
  return page_utils.is_valid_url(url)
7741
8152
 
8153
+ def is_alert_present(self):
8154
+ try:
8155
+ self.driver.switch_to.alert
8156
+ return True
8157
+ except Exception:
8158
+ return False
8159
+
7742
8160
  def is_online(self):
7743
8161
  """Return True if connected to the Internet."""
7744
- online = self.execute_script("return navigator.onLine;")
7745
- return online
8162
+ if self.__is_cdp_swap_needed():
8163
+ return self.cdp.evaluate("navigator.onLine;")
8164
+ return self.execute_script("return navigator.onLine;")
8165
+
8166
+ def is_connected(self):
8167
+ """
8168
+ Return True if WebDriver is connected to the browser.
8169
+ Note that the stealthy CDP-Driver isn't a WebDriver.
8170
+ In CDP Mode, the CDP-Driver controls the web browser.
8171
+ The CDP-Driver can be connected while WebDriver isn't.
8172
+ """
8173
+ return self.driver.is_connected()
7746
8174
 
7747
8175
  def is_chromium(self):
7748
8176
  """Return True if the browser is Chrome or Edge."""
7749
8177
  self.__check_scope()
8178
+ if self.__is_cdp_swap_needed():
8179
+ return True
7750
8180
  chromium = False
7751
8181
  if (
7752
8182
  "chrome" in self.driver.capabilities
@@ -7859,6 +8289,10 @@ class BaseCase(unittest.TestCase):
7859
8289
  self.__check_scope()
7860
8290
  if not timeout:
7861
8291
  timeout = settings.SMALL_TIMEOUT
8292
+ if self.__is_cdp_swap_needed():
8293
+ mfa_code = self.get_mfa_code(totp_key)
8294
+ self.cdp.type(selector, mfa_code + "\n", timeout=timeout)
8295
+ return
7862
8296
  self.wait_for_element_visible(selector, by=by, timeout=timeout)
7863
8297
  if self.recorder_mode and self.__current_url_is_recordable():
7864
8298
  if self.get_session_storage_item("pause_recorder") == "no":
@@ -7884,27 +8318,7 @@ class BaseCase(unittest.TestCase):
7884
8318
  jQuery commands require a CSS_SELECTOR for finding elements.
7885
8319
  This method should only be used for jQuery/JavaScript actions.
7886
8320
  Pure JavaScript doesn't support using a:contains("LINK_TEXT")."""
7887
- if by == By.CSS_SELECTOR:
7888
- return selector
7889
- elif by == By.ID:
7890
- return "#%s" % selector
7891
- elif by == By.CLASS_NAME:
7892
- return ".%s" % selector
7893
- elif by == By.NAME:
7894
- return '[name="%s"]' % selector
7895
- elif by == By.TAG_NAME:
7896
- return selector
7897
- elif by == By.XPATH:
7898
- return self.convert_xpath_to_css(selector)
7899
- elif by == By.LINK_TEXT:
7900
- return 'a:contains("%s")' % selector
7901
- elif by == By.PARTIAL_LINK_TEXT:
7902
- return 'a:contains("%s")' % selector
7903
- else:
7904
- raise Exception(
7905
- "Exception: Could not convert {%s}(by=%s) to CSS_SELECTOR!"
7906
- % (selector, by)
7907
- )
8321
+ return js_utils.convert_to_css_selector(selector, by)
7908
8322
 
7909
8323
  def set_value(
7910
8324
  self, selector, text, by="css selector", timeout=None, scroll=True
@@ -7916,6 +8330,9 @@ class BaseCase(unittest.TestCase):
7916
8330
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
7917
8331
  timeout = self.__get_new_timeout(timeout)
7918
8332
  selector, by = self.__recalculate_selector(selector, by, xp_ok=False)
8333
+ if self.__is_cdp_swap_needed():
8334
+ self.cdp.set_value(selector, text)
8335
+ return
7919
8336
  self.wait_for_ready_state_complete()
7920
8337
  self.wait_for_element_present(selector, by=by, timeout=timeout)
7921
8338
  original_selector = selector
@@ -7973,17 +8390,15 @@ class BaseCase(unittest.TestCase):
7973
8390
  else:
7974
8391
  if the_type == "range" and ":contains\\(" not in css_selector:
7975
8392
  # Some input sliders need a mouse event to trigger listeners.
7976
- try:
8393
+ with suppress(Exception):
7977
8394
  mouse_move_script = (
7978
8395
  """m_elm = document.querySelector('%s');"""
7979
8396
  """m_evt = new Event('mousemove');"""
7980
8397
  """m_elm.dispatchEvent(m_evt);""" % css_selector
7981
8398
  )
7982
8399
  self.execute_script(mouse_move_script)
7983
- except Exception:
7984
- pass
7985
8400
  elif the_type == "range" and ":contains\\(" in css_selector:
7986
- try:
8401
+ with suppress(Exception):
7987
8402
  element = self.wait_for_element_present(
7988
8403
  original_selector, by=by, timeout=1
7989
8404
  )
@@ -7993,8 +8408,6 @@ class BaseCase(unittest.TestCase):
7993
8408
  """m_elm.dispatchEvent(m_evt);"""
7994
8409
  )
7995
8410
  self.execute_script(mouse_move_script, element)
7996
- except Exception:
7997
- pass
7998
8411
  self.__demo_mode_pause_if_active()
7999
8412
  if not self.demo_mode and not self.slow_mode:
8000
8413
  if self.__needs_minimum_wait():
@@ -8014,13 +8427,11 @@ class BaseCase(unittest.TestCase):
8014
8427
  text = self.__get_type_checked_text(text)
8015
8428
  self.set_value(selector, text, by=by, timeout=timeout)
8016
8429
  if not text.endswith("\n"):
8017
- try:
8430
+ with suppress(Exception):
8018
8431
  element = page_actions.wait_for_element_present(
8019
8432
  self.driver, selector, by, timeout=0.2
8020
8433
  )
8021
8434
  element.send_keys(" " + Keys.BACK_SPACE)
8022
- except Exception:
8023
- pass
8024
8435
 
8025
8436
  def js_type(self, selector, text, by="css selector", timeout=None):
8026
8437
  """Same as self.js_update_text()
@@ -8140,13 +8551,11 @@ class BaseCase(unittest.TestCase):
8140
8551
  )
8141
8552
  element.send_keys(Keys.RETURN)
8142
8553
  else:
8143
- try:
8554
+ with suppress(Exception):
8144
8555
  element = self.wait_for_element_present(
8145
8556
  original_selector, by=original_by, timeout=0.2
8146
8557
  )
8147
8558
  element.send_keys(" " + Keys.BACK_SPACE)
8148
- except Exception:
8149
- pass
8150
8559
  self.__demo_mode_pause_if_active()
8151
8560
 
8152
8561
  def jquery_type(self, selector, text, by="css selector", timeout=None):
@@ -8323,10 +8732,8 @@ class BaseCase(unittest.TestCase):
8323
8732
  def get_recorded_console_logs(self):
8324
8733
  """Get console logs recorded after "start_recording_console_logs()"."""
8325
8734
  logs = []
8326
- try:
8735
+ with suppress(Exception):
8327
8736
  logs = self.execute_script("return console.logs;")
8328
- except Exception:
8329
- pass
8330
8737
  return logs
8331
8738
 
8332
8739
  ############
@@ -8634,12 +9041,15 @@ class BaseCase(unittest.TestCase):
8634
9041
  ):
8635
9042
  """Same as self.wait_for_element()"""
8636
9043
  self.__check_scope()
9044
+ self.__skip_if_esc()
8637
9045
  if not timeout:
8638
9046
  timeout = settings.LARGE_TIMEOUT
8639
9047
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
8640
9048
  timeout = self.__get_new_timeout(timeout)
8641
9049
  original_selector = selector
8642
9050
  selector, by = self.__recalculate_selector(selector, by)
9051
+ if self.__is_cdp_swap_needed():
9052
+ return self.cdp.select(selector, timeout=timeout)
8643
9053
  if self.__is_shadow_selector(selector):
8644
9054
  return self.__get_shadow_element(selector, timeout)
8645
9055
  return page_actions.wait_for_element_visible(
@@ -8661,7 +9071,9 @@ class BaseCase(unittest.TestCase):
8661
9071
  timeout = self.__get_new_timeout(timeout)
8662
9072
  original_selector = selector
8663
9073
  selector, by = self.__recalculate_selector(selector, by)
8664
- if self.__is_shadow_selector(selector):
9074
+ if self.__is_cdp_swap_needed():
9075
+ return self.cdp.select(selector, timeout=timeout)
9076
+ elif self.__is_shadow_selector(selector):
8665
9077
  # If a shadow selector, use visible instead of clickable
8666
9078
  return self.__wait_for_shadow_element_visible(selector, timeout)
8667
9079
  return page_actions.wait_for_element_clickable(
@@ -8687,6 +9099,9 @@ class BaseCase(unittest.TestCase):
8687
9099
  timeout = self.__get_new_timeout(timeout)
8688
9100
  original_selector = selector
8689
9101
  selector, by = self.__recalculate_selector(selector, by)
9102
+ if self.__is_cdp_swap_needed():
9103
+ self.cdp.assert_element_absent(selector)
9104
+ return True
8690
9105
  return page_actions.wait_for_element_absent(
8691
9106
  self.driver,
8692
9107
  selector,
@@ -8695,6 +9110,9 @@ class BaseCase(unittest.TestCase):
8695
9110
  original_selector=original_selector,
8696
9111
  )
8697
9112
 
9113
+ def select_all(self, selector, by="css selector", limit=0):
9114
+ return self.find_elements(selector, by=by, limit=limit)
9115
+
8698
9116
  def assert_link(self, link_text, timeout=None):
8699
9117
  """Same as self.assert_link_text()"""
8700
9118
  self.__check_scope()
@@ -8708,7 +9126,7 @@ class BaseCase(unittest.TestCase):
8708
9126
  self, selector, by="css selector", timeout=None
8709
9127
  ):
8710
9128
  """Same as self.assert_element_absent()
8711
- Will raise an exception if the element stays present.
9129
+ Raises an exception if the element stays present.
8712
9130
  A hidden element counts as a present element, which fails this assert.
8713
9131
  If you want to assert that elements are hidden instead of nonexistent,
8714
9132
  use assert_element_not_visible() instead.
@@ -8746,6 +9164,14 @@ class BaseCase(unittest.TestCase):
8746
9164
  """Same as self.delete_all_cookies()"""
8747
9165
  self.delete_all_cookies()
8748
9166
 
9167
+ def delete_local_storage(self):
9168
+ """Same as self.clear_local_storage()"""
9169
+ self.clear_local_storage()
9170
+
9171
+ def delete_session_storage(self):
9172
+ """Same as clear_session_storage()"""
9173
+ self.clear_session_storage()
9174
+
8749
9175
  def assert_no_broken_links(self, multithreaded=True):
8750
9176
  """Same as self.assert_no_404_errors()"""
8751
9177
  self.assert_no_404_errors(multithreaded=multithreaded)
@@ -8761,11 +9187,10 @@ class BaseCase(unittest.TestCase):
8761
9187
  def _check_browser(self):
8762
9188
  """This method raises an exception if the active window is closed.
8763
9189
  (This provides a much cleaner exception message in this situation.)"""
9190
+ page_actions._reconnect_if_disconnected(self.driver)
8764
9191
  active_window = None
8765
- try:
9192
+ with suppress(Exception):
8766
9193
  active_window = self.driver.current_window_handle # Fails if None
8767
- except Exception:
8768
- pass
8769
9194
  if not active_window:
8770
9195
  raise NoSuchWindowException("Active window was already closed!")
8771
9196
 
@@ -8779,10 +9204,8 @@ class BaseCase(unittest.TestCase):
8779
9204
  """
8780
9205
  if hasattr(sb_config, "_multithreaded") and sb_config._multithreaded:
8781
9206
  if not isinstance(msg, str):
8782
- try:
9207
+ with suppress(Exception):
8783
9208
  msg = str(msg)
8784
- except Exception:
8785
- pass
8786
9209
  sys.stderr.write(msg + "\n")
8787
9210
  else:
8788
9211
  print(msg)
@@ -9049,7 +9472,9 @@ class BaseCase(unittest.TestCase):
9049
9472
  timeout = self.__get_new_timeout(timeout)
9050
9473
  original_selector = selector
9051
9474
  selector, by = self.__recalculate_selector(selector, by)
9052
- if self.__is_shadow_selector(selector):
9475
+ if self.__is_cdp_swap_needed():
9476
+ return self.cdp.select(selector, timeout=timeout)
9477
+ elif self.__is_shadow_selector(selector):
9053
9478
  return self.__wait_for_shadow_element_present(selector, timeout)
9054
9479
  return page_actions.wait_for_element_present(
9055
9480
  self.driver,
@@ -9069,6 +9494,8 @@ class BaseCase(unittest.TestCase):
9069
9494
  timeout = self.__get_new_timeout(timeout)
9070
9495
  original_selector = selector
9071
9496
  selector, by = self.__recalculate_selector(selector, by)
9497
+ if self.__is_cdp_swap_needed():
9498
+ return self.cdp.select(selector, timeout=timeout)
9072
9499
  if self.recorder_mode and self.__current_url_is_recordable():
9073
9500
  if self.get_session_storage_item("pause_recorder") == "no":
9074
9501
  if by == By.XPATH:
@@ -9110,6 +9537,8 @@ class BaseCase(unittest.TestCase):
9110
9537
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
9111
9538
  timeout = self.__get_new_timeout(timeout)
9112
9539
  css_selector = self.convert_to_css_selector(selector, by=by)
9540
+ if self.__is_cdp_swap_needed():
9541
+ return self.cdp.select(css_selector, timeout=timeout)
9113
9542
  return js_utils.wait_for_css_query_selector(
9114
9543
  self.driver, css_selector, timeout
9115
9544
  )
@@ -9129,6 +9558,9 @@ class BaseCase(unittest.TestCase):
9129
9558
  if isinstance(selector, list):
9130
9559
  self.assert_elements_present(selector, by=by, timeout=timeout)
9131
9560
  return True
9561
+ if self.__is_cdp_swap_needed():
9562
+ self.cdp.assert_element_present(selector)
9563
+ return True
9132
9564
  if self.__is_shadow_selector(selector):
9133
9565
  self.__assert_shadow_element_present(selector)
9134
9566
  return True
@@ -9196,13 +9628,16 @@ class BaseCase(unittest.TestCase):
9196
9628
 
9197
9629
  def assert_element(self, selector, by="css selector", timeout=None):
9198
9630
  """Similar to wait_for_element_visible(), but returns nothing.
9199
- As above, will raise an exception if nothing can be found.
9631
+ As above, raises an exception if nothing can be found.
9200
9632
  Returns True if successful. Default timeout = SMALL_TIMEOUT."""
9201
9633
  self.__check_scope()
9202
9634
  if not timeout:
9203
9635
  timeout = settings.SMALL_TIMEOUT
9204
9636
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
9205
9637
  timeout = self.__get_new_timeout(timeout)
9638
+ if self.__is_cdp_swap_needed():
9639
+ self.cdp.assert_element(selector)
9640
+ return True
9206
9641
  if isinstance(selector, list):
9207
9642
  self.assert_elements(selector, by=by, timeout=timeout)
9208
9643
  return True
@@ -9236,7 +9671,7 @@ class BaseCase(unittest.TestCase):
9236
9671
  self, selector, by="css selector", timeout=None
9237
9672
  ):
9238
9673
  """Same as self.assert_element()
9239
- As above, will raise an exception if nothing can be found."""
9674
+ As above, raises an exception if nothing can be found."""
9240
9675
  self.__check_scope()
9241
9676
  if not timeout:
9242
9677
  timeout = settings.SMALL_TIMEOUT
@@ -9314,7 +9749,7 @@ class BaseCase(unittest.TestCase):
9314
9749
  ############
9315
9750
 
9316
9751
  def wait_for_text_visible(
9317
- self, text, selector="html", by="css selector", timeout=None
9752
+ self, text, selector="body", by="css selector", timeout=None
9318
9753
  ):
9319
9754
  self.__check_scope()
9320
9755
  if not timeout:
@@ -9323,14 +9758,16 @@ class BaseCase(unittest.TestCase):
9323
9758
  timeout = self.__get_new_timeout(timeout)
9324
9759
  text = self.__get_type_checked_text(text)
9325
9760
  selector, by = self.__recalculate_selector(selector, by)
9326
- if self.__is_shadow_selector(selector):
9761
+ if self.__is_cdp_swap_needed():
9762
+ return self.cdp.find_element(selector, timeout=timeout)
9763
+ elif self.__is_shadow_selector(selector):
9327
9764
  return self.__wait_for_shadow_text_visible(text, selector, timeout)
9328
9765
  return page_actions.wait_for_text_visible(
9329
9766
  self.driver, text, selector, by, timeout
9330
9767
  )
9331
9768
 
9332
9769
  def wait_for_exact_text_visible(
9333
- self, text, selector="html", by="css selector", timeout=None
9770
+ self, text, selector="body", by="css selector", timeout=None
9334
9771
  ):
9335
9772
  self.__check_scope()
9336
9773
  if not timeout:
@@ -9347,7 +9784,7 @@ class BaseCase(unittest.TestCase):
9347
9784
  )
9348
9785
 
9349
9786
  def wait_for_non_empty_text_visible(
9350
- self, selector="html", by="css selector", timeout=None
9787
+ self, selector="body", by="css selector", timeout=None
9351
9788
  ):
9352
9789
  """Searches for any text in the element of the given selector.
9353
9790
  Returns the element if it has visible text within the timeout.
@@ -9368,7 +9805,7 @@ class BaseCase(unittest.TestCase):
9368
9805
  )
9369
9806
 
9370
9807
  def wait_for_text(
9371
- self, text, selector="html", by="css selector", timeout=None
9808
+ self, text, selector="body", by="css selector", timeout=None
9372
9809
  ):
9373
9810
  """The shorter version of wait_for_text_visible()"""
9374
9811
  self.__check_scope()
@@ -9381,7 +9818,7 @@ class BaseCase(unittest.TestCase):
9381
9818
  )
9382
9819
 
9383
9820
  def wait_for_exact_text(
9384
- self, text, selector="html", by="css selector", timeout=None
9821
+ self, text, selector="body", by="css selector", timeout=None
9385
9822
  ):
9386
9823
  """The shorter version of wait_for_exact_text_visible()"""
9387
9824
  self.__check_scope()
@@ -9394,7 +9831,7 @@ class BaseCase(unittest.TestCase):
9394
9831
  )
9395
9832
 
9396
9833
  def wait_for_non_empty_text(
9397
- self, selector="html", by="css selector", timeout=None
9834
+ self, selector="body", by="css selector", timeout=None
9398
9835
  ):
9399
9836
  """The shorter version of wait_for_non_empty_text_visible()"""
9400
9837
  self.__check_scope()
@@ -9407,7 +9844,7 @@ class BaseCase(unittest.TestCase):
9407
9844
  )
9408
9845
 
9409
9846
  def find_text(
9410
- self, text, selector="html", by="css selector", timeout=None
9847
+ self, text, selector="body", by="css selector", timeout=None
9411
9848
  ):
9412
9849
  """Same as wait_for_text_visible() - returns the element"""
9413
9850
  self.__check_scope()
@@ -9420,7 +9857,7 @@ class BaseCase(unittest.TestCase):
9420
9857
  )
9421
9858
 
9422
9859
  def find_exact_text(
9423
- self, text, selector="html", by="css selector", timeout=None
9860
+ self, text, selector="body", by="css selector", timeout=None
9424
9861
  ):
9425
9862
  """Same as wait_for_exact_text_visible() - returns the element"""
9426
9863
  self.__check_scope()
@@ -9433,7 +9870,7 @@ class BaseCase(unittest.TestCase):
9433
9870
  )
9434
9871
 
9435
9872
  def find_non_empty_text(
9436
- self, selector="html", by="css selector", timeout=None
9873
+ self, selector="body", by="css selector", timeout=None
9437
9874
  ):
9438
9875
  """Same as wait_for_non_empty_text_visible() - returns the element"""
9439
9876
  self.__check_scope()
@@ -9446,7 +9883,7 @@ class BaseCase(unittest.TestCase):
9446
9883
  )
9447
9884
 
9448
9885
  def assert_text_visible(
9449
- self, text, selector="html", by="css selector", timeout=None
9886
+ self, text, selector="body", by="css selector", timeout=None
9450
9887
  ):
9451
9888
  """Same as assert_text()"""
9452
9889
  self.__check_scope()
@@ -9457,11 +9894,12 @@ class BaseCase(unittest.TestCase):
9457
9894
  return self.assert_text(text, selector, by=by, timeout=timeout)
9458
9895
 
9459
9896
  def assert_text(
9460
- self, text, selector="html", by="css selector", timeout=None
9897
+ self, text, selector="body", by="css selector", timeout=None
9461
9898
  ):
9462
9899
  """Similar to wait_for_text_visible()
9463
9900
  Raises an exception if the element or the text is not found.
9464
9901
  The text only needs to be a subset within the complete text.
9902
+ The text can be a string or a list/tuple of text substrings.
9465
9903
  Returns True if successful. Default timeout = SMALL_TIMEOUT."""
9466
9904
  self.__check_scope()
9467
9905
  if not timeout:
@@ -9470,26 +9908,50 @@ class BaseCase(unittest.TestCase):
9470
9908
  timeout = self.__get_new_timeout(timeout)
9471
9909
  original_selector = selector
9472
9910
  selector, by = self.__recalculate_selector(selector, by)
9473
- if self.__is_shadow_selector(selector):
9911
+ if isinstance(text, (list, tuple)):
9912
+ text_list = text
9913
+ for _text in text_list:
9914
+ self.wait_for_text_visible(
9915
+ _text, selector, by=by, timeout=timeout
9916
+ )
9917
+ if self.demo_mode:
9918
+ a_t = "ASSERT TEXT"
9919
+ i_n = "in"
9920
+ if self._language != "English":
9921
+ from seleniumbase.fixtures.words import SD
9922
+
9923
+ a_t = SD.translate_assert_text(self._language)
9924
+ i_n = SD.translate_in(self._language)
9925
+ messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
9926
+ a_t, _text, i_n, by.upper(), selector
9927
+ )
9928
+ self.__highlight_with_assert_success(
9929
+ messenger_post, selector, by
9930
+ )
9931
+ elif self.__is_cdp_swap_needed():
9932
+ self.cdp.assert_text(text, selector)
9933
+ return True
9934
+ elif not self.is_connected():
9935
+ self.connect()
9936
+ elif self.__is_shadow_selector(selector):
9474
9937
  self.__assert_shadow_text_visible(text, selector, timeout)
9475
9938
  return True
9476
- self.wait_for_text_visible(text, selector, by=by, timeout=timeout)
9477
- if self.demo_mode:
9478
- a_t = "ASSERT TEXT"
9479
- i_n = "in"
9480
- if self._language != "English":
9481
- from seleniumbase.fixtures.words import SD
9939
+ else:
9940
+ self.wait_for_text_visible(text, selector, by=by, timeout=timeout)
9941
+ if self.demo_mode:
9942
+ a_t = "ASSERT TEXT"
9943
+ i_n = "in"
9944
+ if self._language != "English":
9945
+ from seleniumbase.fixtures.words import SD
9482
9946
 
9483
- a_t = SD.translate_assert_text(self._language)
9484
- i_n = SD.translate_in(self._language)
9485
- messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
9486
- a_t,
9487
- text,
9488
- i_n,
9489
- by.upper(),
9490
- selector,
9491
- )
9492
- self.__highlight_with_assert_success(messenger_post, selector, by)
9947
+ a_t = SD.translate_assert_text(self._language)
9948
+ i_n = SD.translate_in(self._language)
9949
+ messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
9950
+ a_t, text, i_n, by.upper(), selector
9951
+ )
9952
+ self.__highlight_with_assert_success(
9953
+ messenger_post, selector, by
9954
+ )
9493
9955
  if self.recorder_mode and self.__current_url_is_recordable():
9494
9956
  if self.get_session_storage_item("pause_recorder") == "no":
9495
9957
  if by == By.XPATH:
@@ -9502,7 +9964,7 @@ class BaseCase(unittest.TestCase):
9502
9964
  return True
9503
9965
 
9504
9966
  def assert_exact_text(
9505
- self, text, selector="html", by="css selector", timeout=None
9967
+ self, text, selector="body", by="css selector", timeout=None
9506
9968
  ):
9507
9969
  """Similar to assert_text(), but the text must be exact,
9508
9970
  rather than exist as a subset of the full text.
@@ -9516,6 +9978,9 @@ class BaseCase(unittest.TestCase):
9516
9978
  timeout = self.__get_new_timeout(timeout)
9517
9979
  original_selector = selector
9518
9980
  selector, by = self.__recalculate_selector(selector, by)
9981
+ if self.__is_cdp_swap_needed():
9982
+ self.cdp.assert_exact_text(text, selector)
9983
+ return True
9519
9984
  if self.__is_shadow_selector(selector):
9520
9985
  self.__assert_exact_shadow_text_visible(text, selector, timeout)
9521
9986
  return True
@@ -9531,11 +9996,7 @@ class BaseCase(unittest.TestCase):
9531
9996
  a_t = SD.translate_assert_exact_text(self._language)
9532
9997
  i_n = SD.translate_in(self._language)
9533
9998
  messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
9534
- a_t,
9535
- text,
9536
- i_n,
9537
- by.upper(),
9538
- selector,
9999
+ a_t, text, i_n, by.upper(), selector
9539
10000
  )
9540
10001
  self.__highlight_with_assert_success(messenger_post, selector, by)
9541
10002
  if self.recorder_mode and self.__current_url_is_recordable():
@@ -9550,7 +10011,7 @@ class BaseCase(unittest.TestCase):
9550
10011
  return True
9551
10012
 
9552
10013
  def assert_non_empty_text(
9553
- self, selector="html", by="css selector", timeout=None
10014
+ self, selector="body", by="css selector", timeout=None
9554
10015
  ):
9555
10016
  """Assert that the element has any non-empty text visible.
9556
10017
  Raises an exception if the element has no text within the timeout.
@@ -9575,10 +10036,7 @@ class BaseCase(unittest.TestCase):
9575
10036
  a_t = SD.translate_assert_non_empty_text(self._language)
9576
10037
  i_n = SD.translate_in(self._language)
9577
10038
  messenger_post = "<b>%s</b> %s %s: %s" % (
9578
- a_t,
9579
- i_n,
9580
- by.upper(),
9581
- selector,
10039
+ a_t, i_n, by.upper(), selector
9582
10040
  )
9583
10041
  self.__highlight_with_assert_success(messenger_post, selector, by)
9584
10042
  if self.recorder_mode and self.__current_url_is_recordable():
@@ -9673,13 +10131,16 @@ class BaseCase(unittest.TestCase):
9673
10131
 
9674
10132
  def assert_link_text(self, link_text, timeout=None):
9675
10133
  """Similar to wait_for_link_text_visible(), but returns nothing.
9676
- As above, will raise an exception if nothing can be found.
10134
+ As above, raises an exception if nothing can be found.
9677
10135
  Returns True if successful. Default timeout = SMALL_TIMEOUT."""
9678
10136
  self.__check_scope()
9679
10137
  if not timeout:
9680
10138
  timeout = settings.SMALL_TIMEOUT
9681
10139
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
9682
10140
  timeout = self.__get_new_timeout(timeout)
10141
+ if self.__is_cdp_swap_needed():
10142
+ self.cdp.find_element(link_text, timeout=timeout)
10143
+ return
9683
10144
  self.wait_for_link_text_visible(link_text, timeout=timeout)
9684
10145
  if self.demo_mode:
9685
10146
  a_t = "ASSERT LINK TEXT"
@@ -9722,7 +10183,7 @@ class BaseCase(unittest.TestCase):
9722
10183
 
9723
10184
  def assert_partial_link_text(self, partial_link_text, timeout=None):
9724
10185
  """Similar to wait_for_partial_link_text(), but returns nothing.
9725
- As above, will raise an exception if nothing can be found.
10186
+ As above, raises an exception if nothing can be found.
9726
10187
  Returns True if successful. Default timeout = SMALL_TIMEOUT."""
9727
10188
  self.__check_scope()
9728
10189
  if not timeout:
@@ -9768,7 +10229,7 @@ class BaseCase(unittest.TestCase):
9768
10229
 
9769
10230
  def assert_element_absent(self, selector, by="css selector", timeout=None):
9770
10231
  """Similar to wait_for_element_absent()
9771
- As above, will raise an exception if the element stays present.
10232
+ As above, raises an exception if the element stays present.
9772
10233
  A hidden element counts as a present element, which fails this assert.
9773
10234
  If you want to assert that elements are hidden instead of nonexistent,
9774
10235
  use assert_element_not_visible() instead.
@@ -9779,6 +10240,9 @@ class BaseCase(unittest.TestCase):
9779
10240
  timeout = settings.SMALL_TIMEOUT
9780
10241
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
9781
10242
  timeout = self.__get_new_timeout(timeout)
10243
+ if self.__is_cdp_swap_needed():
10244
+ self.cdp.assert_element_absent(selector)
10245
+ return True
9782
10246
  self.wait_for_element_absent(selector, by=by, timeout=timeout)
9783
10247
  return True
9784
10248
 
@@ -9797,6 +10261,9 @@ class BaseCase(unittest.TestCase):
9797
10261
  timeout = self.__get_new_timeout(timeout)
9798
10262
  original_selector = selector
9799
10263
  selector, by = self.__recalculate_selector(selector, by)
10264
+ if self.__is_cdp_swap_needed():
10265
+ self.cdp.assert_element_not_visible(selector)
10266
+ return True
9800
10267
  return page_actions.wait_for_element_not_visible(
9801
10268
  self.driver,
9802
10269
  selector,
@@ -9809,13 +10276,16 @@ class BaseCase(unittest.TestCase):
9809
10276
  self, selector, by="css selector", timeout=None
9810
10277
  ):
9811
10278
  """Similar to wait_for_element_not_visible()
9812
- As above, will raise an exception if the element stays visible.
10279
+ As above, raises an exception if the element stays visible.
9813
10280
  Returns True if successful. Default timeout = SMALL_TIMEOUT."""
9814
10281
  self.__check_scope()
9815
10282
  if not timeout:
9816
10283
  timeout = settings.SMALL_TIMEOUT
9817
10284
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
9818
10285
  timeout = self.__get_new_timeout(timeout)
10286
+ if self.__is_cdp_swap_needed():
10287
+ self.cdp.assert_element_not_visible(selector)
10288
+ return True
9819
10289
  self.wait_for_element_not_visible(selector, by=by, timeout=timeout)
9820
10290
  if self.recorder_mode and self.__current_url_is_recordable():
9821
10291
  if self.get_session_storage_item("pause_recorder") == "no":
@@ -9828,7 +10298,7 @@ class BaseCase(unittest.TestCase):
9828
10298
  ############
9829
10299
 
9830
10300
  def wait_for_text_not_visible(
9831
- self, text, selector="html", by="css selector", timeout=None
10301
+ self, text, selector="body", by="css selector", timeout=None
9832
10302
  ):
9833
10303
  self.__check_scope()
9834
10304
  if not timeout:
@@ -9841,7 +10311,7 @@ class BaseCase(unittest.TestCase):
9841
10311
  )
9842
10312
 
9843
10313
  def wait_for_exact_text_not_visible(
9844
- self, text, selector="html", by="css selector", timeout=None
10314
+ self, text, selector="body", by="css selector", timeout=None
9845
10315
  ):
9846
10316
  self.__check_scope()
9847
10317
  if not timeout:
@@ -9854,7 +10324,7 @@ class BaseCase(unittest.TestCase):
9854
10324
  )
9855
10325
 
9856
10326
  def assert_text_not_visible(
9857
- self, text, selector="html", by="css selector", timeout=None
10327
+ self, text, selector="body", by="css selector", timeout=None
9858
10328
  ):
9859
10329
  """Similar to wait_for_text_not_visible()
9860
10330
  Raises an exception if the text is still visible after timeout.
@@ -9875,7 +10345,7 @@ class BaseCase(unittest.TestCase):
9875
10345
  return True
9876
10346
 
9877
10347
  def assert_exact_text_not_visible(
9878
- self, text, selector="html", by="css selector", timeout=None
10348
+ self, text, selector="body", by="css selector", timeout=None
9879
10349
  ):
9880
10350
  """Similar to wait_for_exact_text_not_visible()
9881
10351
  Raises an exception if the exact text is still visible after timeout.
@@ -10125,7 +10595,7 @@ class BaseCase(unittest.TestCase):
10125
10595
  countdown_on = True
10126
10596
  countdown = 3
10127
10597
  minified_exception += line + "\n"
10128
- elif line.startswith("+") or line.startswith("-"):
10598
+ elif line.startswith(("+", "-")):
10129
10599
  minified_exception += line + "\n"
10130
10600
  elif line.startswith("?"):
10131
10601
  minified_exception += line + "\n"
@@ -10174,8 +10644,6 @@ class BaseCase(unittest.TestCase):
10174
10644
  shutil.copy(latest_png_path, latest_copy_path)
10175
10645
  if len(self.__visual_baseline_copies) != 1:
10176
10646
  return # Skip the rest when deferred visual asserts are used
10177
- from seleniumbase.core import visual_helper
10178
-
10179
10647
  the_html = visual_helper.get_sbs_html()
10180
10648
  file_path = os.path.join(test_logpath, constants.SideBySide.HTML_FILE)
10181
10649
  out_file = codecs.open(file_path, "w+", encoding="utf-8")
@@ -10262,12 +10730,10 @@ class BaseCase(unittest.TestCase):
10262
10730
  self.check_window(name="github_page", level=2)
10263
10731
  self.check_window(name="wikipedia_page", level=3) """
10264
10732
  self.wait_for_ready_state_complete()
10265
- try:
10733
+ with suppress(Exception):
10266
10734
  self.wait_for_element_visible(
10267
10735
  "body", timeout=settings.MINI_TIMEOUT
10268
10736
  )
10269
- except Exception:
10270
- pass
10271
10737
  if self.__needs_minimum_wait():
10272
10738
  time.sleep(0.08)
10273
10739
  if level == "0":
@@ -10293,7 +10759,6 @@ class BaseCase(unittest.TestCase):
10293
10759
  if not name or len(name) < 1:
10294
10760
  name = "default"
10295
10761
  name = str(name)
10296
- from seleniumbase.core import visual_helper
10297
10762
 
10298
10763
  visual_helper.visual_baseline_folder_setup()
10299
10764
  baseline_dir = constants.VisualBaseline.STORAGE_FOLDER
@@ -10510,6 +10975,12 @@ class BaseCase(unittest.TestCase):
10510
10975
 
10511
10976
  ############
10512
10977
 
10978
+ def __is_cdp_swap_needed(self):
10979
+ """If the driver is disconnected, use a CDP method when available."""
10980
+ return shared_utils.is_cdp_swap_needed(self.driver)
10981
+
10982
+ ############
10983
+
10513
10984
  def __check_scope(self):
10514
10985
  if hasattr(self, "browser"): # self.browser stores the type of browser
10515
10986
  return # All good: setUp() already initialized variables in "self"
@@ -10576,14 +11047,12 @@ class BaseCase(unittest.TestCase):
10576
11047
  if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
10577
11048
  timeout = self.__get_new_timeout(timeout)
10578
11049
  self.__deferred_assert_count += 1
10579
- try:
11050
+ with suppress(Exception):
10580
11051
  url = self.get_current_url()
10581
11052
  if url == self.__last_url_of_deferred_assert:
10582
11053
  timeout = 0.6 # Was already on page (full wait not needed)
10583
11054
  else:
10584
11055
  self.__last_url_of_deferred_assert = url
10585
- except Exception:
10586
- pass
10587
11056
  if self.recorder_mode and self.__current_url_is_recordable():
10588
11057
  if self.get_session_storage_item("pause_recorder") == "no":
10589
11058
  time_stamp = self.execute_script("return Date.now();")
@@ -10613,14 +11082,12 @@ class BaseCase(unittest.TestCase):
10613
11082
  if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
10614
11083
  timeout = self.__get_new_timeout(timeout)
10615
11084
  self.__deferred_assert_count += 1
10616
- try:
11085
+ with suppress(Exception):
10617
11086
  url = self.get_current_url()
10618
11087
  if url == self.__last_url_of_deferred_assert:
10619
11088
  timeout = 0.6 # Was already on page (full wait not needed)
10620
11089
  else:
10621
11090
  self.__last_url_of_deferred_assert = url
10622
- except Exception:
10623
- pass
10624
11091
  if self.recorder_mode and self.__current_url_is_recordable():
10625
11092
  if self.get_session_storage_item("pause_recorder") == "no":
10626
11093
  time_stamp = self.execute_script("return Date.now();")
@@ -10635,7 +11102,7 @@ class BaseCase(unittest.TestCase):
10635
11102
  return False
10636
11103
 
10637
11104
  def deferred_assert_text(
10638
- self, text, selector="html", by="css selector", timeout=None, fs=False
11105
+ self, text, selector="body", by="css selector", timeout=None, fs=False
10639
11106
  ):
10640
11107
  """A non-terminating assertion for text from an element on a page.
10641
11108
  Failures will be saved until the process_deferred_asserts()
@@ -10650,14 +11117,12 @@ class BaseCase(unittest.TestCase):
10650
11117
  if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
10651
11118
  timeout = self.__get_new_timeout(timeout)
10652
11119
  self.__deferred_assert_count += 1
10653
- try:
11120
+ with suppress(Exception):
10654
11121
  url = self.get_current_url()
10655
11122
  if url == self.__last_url_of_deferred_assert:
10656
11123
  timeout = 0.6 # Was already on page (full wait not needed)
10657
11124
  else:
10658
11125
  self.__last_url_of_deferred_assert = url
10659
- except Exception:
10660
- pass
10661
11126
  if self.recorder_mode and self.__current_url_is_recordable():
10662
11127
  if self.get_session_storage_item("pause_recorder") == "no":
10663
11128
  time_stamp = self.execute_script("return Date.now();")
@@ -10673,7 +11138,7 @@ class BaseCase(unittest.TestCase):
10673
11138
  return False
10674
11139
 
10675
11140
  def deferred_assert_exact_text(
10676
- self, text, selector="html", by="css selector", timeout=None, fs=False
11141
+ self, text, selector="body", by="css selector", timeout=None, fs=False
10677
11142
  ):
10678
11143
  """A non-terminating assertion for exact text from an element.
10679
11144
  Failures will be saved until the process_deferred_asserts()
@@ -10688,14 +11153,12 @@ class BaseCase(unittest.TestCase):
10688
11153
  if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
10689
11154
  timeout = self.__get_new_timeout(timeout)
10690
11155
  self.__deferred_assert_count += 1
10691
- try:
11156
+ with suppress(Exception):
10692
11157
  url = self.get_current_url()
10693
11158
  if url == self.__last_url_of_deferred_assert:
10694
11159
  timeout = 0.6 # Was already on page (full wait not needed)
10695
11160
  else:
10696
11161
  self.__last_url_of_deferred_assert = url
10697
- except Exception:
10698
- pass
10699
11162
  if self.recorder_mode and self.__current_url_is_recordable():
10700
11163
  if self.get_session_storage_item("pause_recorder") == "no":
10701
11164
  time_stamp = self.execute_script("return Date.now();")
@@ -10714,7 +11177,7 @@ class BaseCase(unittest.TestCase):
10714
11177
 
10715
11178
  def deferred_assert_non_empty_text(
10716
11179
  self,
10717
- selector="html",
11180
+ selector="body",
10718
11181
  by="css selector",
10719
11182
  timeout=None,
10720
11183
  fs=False,
@@ -10732,14 +11195,12 @@ class BaseCase(unittest.TestCase):
10732
11195
  if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
10733
11196
  timeout = self.__get_new_timeout(timeout)
10734
11197
  self.__deferred_assert_count += 1
10735
- try:
11198
+ with suppress(Exception):
10736
11199
  url = self.get_current_url()
10737
11200
  if url == self.__last_url_of_deferred_assert:
10738
11201
  timeout = 0.6 # Was already on page (full wait not needed)
10739
11202
  else:
10740
11203
  self.__last_url_of_deferred_assert = url
10741
- except Exception:
10742
- pass
10743
11204
  if self.recorder_mode and self.__current_url_is_recordable():
10744
11205
  if self.get_session_storage_item("pause_recorder") == "no":
10745
11206
  time_stamp = self.execute_script("return Date.now();")
@@ -10836,7 +11297,7 @@ class BaseCase(unittest.TestCase):
10836
11297
  )
10837
11298
 
10838
11299
  def delayed_assert_text(
10839
- self, text, selector="html", by="css selector", timeout=None, fs=False
11300
+ self, text, selector="body", by="css selector", timeout=None, fs=False
10840
11301
  ):
10841
11302
  """Same as self.deferred_assert_text()"""
10842
11303
  return self.deferred_assert_text(
@@ -10844,7 +11305,7 @@ class BaseCase(unittest.TestCase):
10844
11305
  )
10845
11306
 
10846
11307
  def delayed_assert_exact_text(
10847
- self, text, selector="html", by="css selector", timeout=None, fs=False
11308
+ self, text, selector="body", by="css selector", timeout=None, fs=False
10848
11309
  ):
10849
11310
  """Same as self.deferred_assert_exact_text()"""
10850
11311
  return self.deferred_assert_exact_text(
@@ -10853,7 +11314,7 @@ class BaseCase(unittest.TestCase):
10853
11314
 
10854
11315
  def delayed_assert_non_empty_text(
10855
11316
  self,
10856
- selector="html",
11317
+ selector="body",
10857
11318
  by="css selector",
10858
11319
  timeout=None,
10859
11320
  fs=False,
@@ -11175,10 +11636,8 @@ class BaseCase(unittest.TestCase):
11175
11636
  if saved_presentations_folder.endswith("/"):
11176
11637
  saved_presentations_folder = saved_presentations_folder[:-1]
11177
11638
  if not os.path.exists(saved_presentations_folder):
11178
- try:
11639
+ with suppress(Exception):
11179
11640
  os.makedirs(saved_presentations_folder)
11180
- except Exception:
11181
- pass
11182
11641
  file_path = os.path.join(saved_presentations_folder, filename)
11183
11642
  out_file = codecs.open(file_path, "w+", encoding="utf-8")
11184
11643
  out_file.writelines(the_html)
@@ -11232,7 +11691,7 @@ class BaseCase(unittest.TestCase):
11232
11691
  self._presentation_slides[name].pop()
11233
11692
  self.open_html_file(file_path)
11234
11693
  presentation_folder = constants.Presentations.SAVED_FOLDER
11235
- try:
11694
+ with suppress(Exception):
11236
11695
  while (
11237
11696
  len(self.driver.window_handles) > 0
11238
11697
  and presentation_folder in self.get_current_url()
@@ -11243,8 +11702,6 @@ class BaseCase(unittest.TestCase):
11243
11702
  ):
11244
11703
  break
11245
11704
  time.sleep(0.05)
11246
- except Exception:
11247
- pass
11248
11705
 
11249
11706
  ############
11250
11707
 
@@ -11874,10 +12331,8 @@ class BaseCase(unittest.TestCase):
11874
12331
  if saved_charts_folder.endswith("/"):
11875
12332
  saved_charts_folder = saved_charts_folder[:-1]
11876
12333
  if not os.path.exists(saved_charts_folder):
11877
- try:
12334
+ with suppress(Exception):
11878
12335
  os.makedirs(saved_charts_folder)
11879
- except Exception:
11880
- pass
11881
12336
  file_path = os.path.join(saved_charts_folder, filename)
11882
12337
  out_file = codecs.open(file_path, "w+", encoding="utf-8")
11883
12338
  out_file.writelines(the_html)
@@ -11917,17 +12372,15 @@ class BaseCase(unittest.TestCase):
11917
12372
  self.open_html_file(file_path)
11918
12373
  chart_folder = constants.Charts.SAVED_FOLDER
11919
12374
  if interval == 0:
11920
- try:
12375
+ with suppress(Exception):
11921
12376
  print("\n*** Close the browser window to continue ***")
11922
12377
  # Will also continue if manually navigating to a new page
11923
12378
  while len(self.driver.window_handles) > 0 and (
11924
12379
  chart_folder in self.get_current_url()
11925
12380
  ):
11926
12381
  time.sleep(0.05)
11927
- except Exception:
11928
- pass
11929
12382
  else:
11930
- try:
12383
+ with suppress(Exception):
11931
12384
  start_ms = time.time() * 1000.0
11932
12385
  stop_ms = start_ms + (interval * 1000.0)
11933
12386
  for x in range(int(interval * 10)):
@@ -11939,8 +12392,6 @@ class BaseCase(unittest.TestCase):
11939
12392
  if chart_folder not in self.get_current_url():
11940
12393
  break
11941
12394
  time.sleep(0.1)
11942
- except Exception:
11943
- pass
11944
12395
 
11945
12396
  def extract_chart(self, chart_name=None):
11946
12397
  """Extracts the HTML from a SeleniumBase-generated chart.
@@ -12752,10 +13203,8 @@ class BaseCase(unittest.TestCase):
12752
13203
  )
12753
13204
  time.sleep(0.02)
12754
13205
  jf = "document.querySelector('.jconfirm-box').focus();"
12755
- try:
13206
+ with suppress(Exception):
12756
13207
  self.execute_script(jf)
12757
- except Exception:
12758
- pass
12759
13208
  waiting_for_response = True
12760
13209
  while waiting_for_response:
12761
13210
  time.sleep(0.05)
@@ -12827,10 +13276,8 @@ class BaseCase(unittest.TestCase):
12827
13276
  )
12828
13277
  time.sleep(0.02)
12829
13278
  jf = "document.querySelector('.jconfirm-box input.jqc_input').focus();"
12830
- try:
13279
+ with suppress(Exception):
12831
13280
  self.execute_script(jf)
12832
- except Exception:
12833
- pass
12834
13281
  waiting_for_response = True
12835
13282
  while waiting_for_response:
12836
13283
  time.sleep(0.05)
@@ -12891,10 +13338,8 @@ class BaseCase(unittest.TestCase):
12891
13338
  )
12892
13339
  time.sleep(0.02)
12893
13340
  jf = "document.querySelector('.jconfirm-box input.jqc_input').focus();"
12894
- try:
13341
+ with suppress(Exception):
12895
13342
  self.execute_script(jf)
12896
- except Exception:
12897
- pass
12898
13343
  waiting_for_response = True
12899
13344
  while waiting_for_response:
12900
13345
  time.sleep(0.05)
@@ -12969,12 +13414,10 @@ class BaseCase(unittest.TestCase):
12969
13414
  if not page_actions.is_element_clickable(
12970
13415
  self.driver, selector, by
12971
13416
  ):
12972
- try:
13417
+ with suppress(Exception):
12973
13418
  self.wait_for_element_clickable(
12974
13419
  selector, by, timeout=1.8
12975
13420
  )
12976
- except Exception:
12977
- pass
12978
13421
  # If the regular mouse-simulated click fails, do a basic JS click
12979
13422
  script = (
12980
13423
  """document.querySelector('%s').click();"""
@@ -13050,8 +13493,6 @@ class BaseCase(unittest.TestCase):
13050
13493
  timeout=None,
13051
13494
  center=None,
13052
13495
  ):
13053
- from selenium.webdriver.common.action_chains import ActionChains
13054
-
13055
13496
  self.wait_for_ready_state_complete()
13056
13497
  if self.__needs_minimum_wait():
13057
13498
  time.sleep(0.14)
@@ -13210,8 +13651,7 @@ class BaseCase(unittest.TestCase):
13210
13651
 
13211
13652
  def __get_major_browser_version(self):
13212
13653
  version = self.driver.__dict__["caps"]["browserVersion"]
13213
- major_browser_version = version.split(".")[0]
13214
- return major_browser_version
13654
+ return version.split(".")[0]
13215
13655
 
13216
13656
  def __get_href_from_link_text(self, link_text, hard_fail=True):
13217
13657
  href = self.get_link_attribute(link_text, "href", hard_fail)
@@ -13249,7 +13689,7 @@ class BaseCase(unittest.TestCase):
13249
13689
  for dropdown in matching_dropdowns:
13250
13690
  # The same class names might be used for multiple dropdowns
13251
13691
  if dropdown.is_displayed():
13252
- try:
13692
+ with suppress(Exception):
13253
13693
  try:
13254
13694
  page_actions.hover_element(
13255
13695
  self.driver,
@@ -13270,9 +13710,6 @@ class BaseCase(unittest.TestCase):
13270
13710
  timeout=0.12,
13271
13711
  )
13272
13712
  return True
13273
- except Exception:
13274
- pass
13275
-
13276
13713
  return False
13277
13714
 
13278
13715
  def __get_href_from_partial_link_text(self, link_text, hard_fail=True):
@@ -13313,7 +13750,7 @@ class BaseCase(unittest.TestCase):
13313
13750
  for dropdown in matching_dropdowns:
13314
13751
  # The same class names might be used for multiple dropdowns
13315
13752
  if dropdown.is_displayed():
13316
- try:
13753
+ with suppress(Exception):
13317
13754
  try:
13318
13755
  page_actions.hover_element(
13319
13756
  self.driver, dropdown
@@ -13335,8 +13772,6 @@ class BaseCase(unittest.TestCase):
13335
13772
  timeout=0.12,
13336
13773
  )
13337
13774
  return True
13338
- except Exception:
13339
- pass
13340
13775
  return False
13341
13776
 
13342
13777
  def __recalculate_selector(self, selector, by, xp_ok=True):
@@ -13360,7 +13795,8 @@ class BaseCase(unittest.TestCase):
13360
13795
  if self.get_current_url() == "about:blank":
13361
13796
  self.switch_to_window(current_window)
13362
13797
  except Exception:
13363
- self.switch_to_window(current_window)
13798
+ with suppress(Exception):
13799
+ self.switch_to_window(current_window)
13364
13800
 
13365
13801
  def __needs_minimum_wait(self):
13366
13802
  if (
@@ -13396,6 +13832,7 @@ class BaseCase(unittest.TestCase):
13396
13832
  self.slow_scroll_to(selector, by=by)
13397
13833
 
13398
13834
  def __demo_mode_highlight_if_active(self, selector, by):
13835
+ self.__skip_if_esc()
13399
13836
  if self.demo_mode:
13400
13837
  # Includes self.slow_scroll_to(selector, by=by) by default
13401
13838
  self.__highlight(selector, by=by)
@@ -13443,7 +13880,8 @@ class BaseCase(unittest.TestCase):
13443
13880
  js_utils.scroll_to_element(self.driver, element)
13444
13881
 
13445
13882
  def __highlight_with_js(self, selector, loops, o_bs):
13446
- self.wait_for_ready_state_complete()
13883
+ if not self.__is_cdp_swap_needed():
13884
+ self.wait_for_ready_state_complete()
13447
13885
  js_utils.highlight_with_js(self.driver, selector, loops, o_bs)
13448
13886
 
13449
13887
  def __highlight_element_with_js(self, element, loops, o_bs):
@@ -13558,23 +13996,112 @@ class BaseCase(unittest.TestCase):
13558
13996
  pass # JQuery probably couldn't load. Skip highlighting.
13559
13997
  time.sleep(0.065)
13560
13998
 
13999
+ def __activate_standard_virtual_display(self):
14000
+ from sbvirtualdisplay import Display
14001
+ width = settings.HEADLESS_START_WIDTH
14002
+ height = settings.HEADLESS_START_HEIGHT
14003
+ with suppress(Exception):
14004
+ self._xvfb_display = Display(
14005
+ visible=0, size=(width, height)
14006
+ )
14007
+ self._xvfb_display.start()
14008
+ self.headless_active = True
14009
+ if not self.undetectable:
14010
+ sb_config._virtual_display = self._xvfb_display
14011
+ sb_config.headless_active = True
14012
+
14013
+ def __activate_virtual_display(self):
14014
+ if self.undetectable and not (self.headless or self.headless2):
14015
+ from sbvirtualdisplay import Display
14016
+ import Xlib.display
14017
+ try:
14018
+ if not self._xvfb_width:
14019
+ self._xvfb_width = 1366
14020
+ if not self._xvfb_height:
14021
+ self._xvfb_height = 768
14022
+ self._xvfb_display = Display(
14023
+ visible=True,
14024
+ size=(self._xvfb_width, self._xvfb_height),
14025
+ backend="xvfb",
14026
+ use_xauth=True,
14027
+ )
14028
+ self._xvfb_display.start()
14029
+ if "DISPLAY" not in os.environ.keys():
14030
+ print(
14031
+ "\nX11 display failed! Will use regular xvfb!"
14032
+ )
14033
+ self.__activate_standard_virtual_display()
14034
+ else:
14035
+ self.headless_active = True
14036
+ except Exception as e:
14037
+ if hasattr(e, "msg"):
14038
+ print("\n" + str(e.msg))
14039
+ else:
14040
+ print(e)
14041
+ print("\nX11 display failed! Will use regular xvfb!")
14042
+ self.__activate_standard_virtual_display()
14043
+ return
14044
+ pyautogui_is_installed = False
14045
+ try:
14046
+ import pyautogui
14047
+ with suppress(Exception):
14048
+ use_pyautogui_ver = constants.PyAutoGUI.VER
14049
+ if pyautogui.__version__ != use_pyautogui_ver:
14050
+ del pyautogui # To get newer ver
14051
+ shared_utils.pip_install(
14052
+ "pyautogui", version=use_pyautogui_ver
14053
+ )
14054
+ import pyautogui
14055
+ pyautogui_is_installed = True
14056
+ except Exception:
14057
+ message = (
14058
+ "PyAutoGUI is required for UC Mode on Linux! "
14059
+ "Installing now..."
14060
+ )
14061
+ print("\n" + message)
14062
+ shared_utils.pip_install(
14063
+ "pyautogui", version=constants.PyAutoGUI.VER
14064
+ )
14065
+ import pyautogui
14066
+ pyautogui_is_installed = True
14067
+ if (
14068
+ pyautogui_is_installed
14069
+ and hasattr(pyautogui, "_pyautogui_x11")
14070
+ ):
14071
+ try:
14072
+ pyautogui._pyautogui_x11._display = (
14073
+ Xlib.display.Display(os.environ['DISPLAY'])
14074
+ )
14075
+ sb_config._pyautogui_x11_display = (
14076
+ pyautogui._pyautogui_x11._display
14077
+ )
14078
+ except Exception as e:
14079
+ if hasattr(e, "msg"):
14080
+ print("\n" + str(e.msg))
14081
+ else:
14082
+ print(e)
14083
+ else:
14084
+ self.__activate_standard_virtual_display()
14085
+
13561
14086
  def __activate_virtual_display_as_needed(self):
13562
- """Should be needed only on Linux.
14087
+ """This is only needed on Linux.
13563
14088
  The "--xvfb" arg is still useful, as it prevents headless mode,
13564
14089
  which is the default mode on Linux unless using another arg."""
13565
14090
  if "linux" in sys.platform and (not self.headed or self.xvfb):
13566
- width = settings.HEADLESS_START_WIDTH
13567
- height = settings.HEADLESS_START_HEIGHT
14091
+ pip_find_lock = fasteners.InterProcessLock(
14092
+ constants.PipInstall.FINDLOCK
14093
+ )
13568
14094
  try:
13569
- from sbvirtualdisplay import Display
13570
-
13571
- self._xvfb_display = Display(visible=0, size=(width, height))
13572
- self._xvfb_display.start()
13573
- sb_config._virtual_display = self._xvfb_display
13574
- self.headless_active = True
13575
- sb_config.headless_active = True
14095
+ with pip_find_lock:
14096
+ pass
13576
14097
  except Exception:
13577
- pass
14098
+ # Since missing permissions, skip the locks
14099
+ self.__activate_virtual_display()
14100
+ return
14101
+ with pip_find_lock: # Prevent issues with multiple processes
14102
+ with suppress(Exception):
14103
+ shared_utils.make_writable(constants.PipInstall.FINDLOCK)
14104
+ self.__activate_virtual_display()
13578
14105
 
13579
14106
  def __ad_block_as_needed(self):
13580
14107
  """This is an internal method for handling ad-blocking.
@@ -13796,12 +14323,10 @@ class BaseCase(unittest.TestCase):
13796
14323
  selector, timeout=timeout, must_be_visible=True
13797
14324
  )
13798
14325
  if clear_first:
13799
- try:
14326
+ with suppress(Exception):
13800
14327
  element.clear()
13801
14328
  backspaces = Keys.BACK_SPACE * 42 # Autofill Defense
13802
14329
  element.send_keys(backspaces)
13803
- except Exception:
13804
- pass
13805
14330
  text = self.__get_type_checked_text(text)
13806
14331
  if not text.endswith("\n"):
13807
14332
  element.send_keys(text)
@@ -13817,12 +14342,10 @@ class BaseCase(unittest.TestCase):
13817
14342
  element = self.__get_shadow_element(
13818
14343
  selector, timeout=timeout, must_be_visible=True
13819
14344
  )
13820
- try:
14345
+ with suppress(Exception):
13821
14346
  element.clear()
13822
14347
  backspaces = Keys.BACK_SPACE * 42 # Autofill Defense
13823
14348
  element.send_keys(backspaces)
13824
- except Exception:
13825
- pass
13826
14349
 
13827
14350
  def __get_shadow_text(self, selector, timeout):
13828
14351
  element = self.__get_shadow_element(
@@ -13942,19 +14465,13 @@ class BaseCase(unittest.TestCase):
13942
14465
  a_t = SD.translate_assert_text(self._language)
13943
14466
  i_n = SD.translate_in(self._language)
13944
14467
  messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
13945
- a_t,
13946
- text,
13947
- i_n,
13948
- by.upper(),
13949
- selector,
14468
+ a_t, text, i_n, by.upper(), selector
13950
14469
  )
13951
- try:
14470
+ with suppress(Exception):
13952
14471
  js_utils.activate_jquery(self.driver)
13953
14472
  js_utils.post_messenger_success_message(
13954
14473
  self.driver, messenger_post, self.message_duration
13955
14474
  )
13956
- except Exception:
13957
- pass
13958
14475
 
13959
14476
  def __assert_exact_shadow_text_visible(self, text, selector, timeout):
13960
14477
  self.__wait_for_exact_shadow_text_visible(text, selector, timeout)
@@ -13968,19 +14485,13 @@ class BaseCase(unittest.TestCase):
13968
14485
  a_t = SD.translate_assert_exact_text(self._language)
13969
14486
  i_n = SD.translate_in(self._language)
13970
14487
  messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
13971
- a_t,
13972
- text,
13973
- i_n,
13974
- by.upper(),
13975
- selector,
14488
+ a_t, text, i_n, by.upper(), selector
13976
14489
  )
13977
- try:
14490
+ with suppress(Exception):
13978
14491
  js_utils.activate_jquery(self.driver)
13979
14492
  js_utils.post_messenger_success_message(
13980
14493
  self.driver, messenger_post, self.message_duration
13981
14494
  )
13982
- except Exception:
13983
- pass
13984
14495
 
13985
14496
  def __assert_non_empty_shadow_text_visible(self, selector, timeout, strip):
13986
14497
  self.__wait_for_non_empty_shadow_text_visible(selector, timeout, strip)
@@ -13994,18 +14505,13 @@ class BaseCase(unittest.TestCase):
13994
14505
  a_t = SD.translate_assert_non_empty_text(self._language)
13995
14506
  i_n = SD.translate_in(self._language)
13996
14507
  messenger_post = "<b>%s</b> %s %s: %s" % (
13997
- a_t,
13998
- i_n,
13999
- by.upper(),
14000
- selector,
14508
+ a_t, i_n, by.upper(), selector
14001
14509
  )
14002
- try:
14510
+ with suppress(Exception):
14003
14511
  js_utils.activate_jquery(self.driver)
14004
14512
  js_utils.post_messenger_success_message(
14005
14513
  self.driver, messenger_post, self.message_duration
14006
14514
  )
14007
- except Exception:
14008
- pass
14009
14515
 
14010
14516
  def __is_shadow_element_present(self, selector):
14011
14517
  try:
@@ -14133,7 +14639,7 @@ class BaseCase(unittest.TestCase):
14133
14639
  message = (
14134
14640
  "Expected value {%s} for attribute {%s} of element "
14135
14641
  "{%s} was not present after %s second%s! "
14136
- "(The actual value was {%s})"
14642
+ "(Actual value was {%s})"
14137
14643
  % (
14138
14644
  value,
14139
14645
  attribute,
@@ -14157,13 +14663,11 @@ class BaseCase(unittest.TestCase):
14157
14663
 
14158
14664
  a_t = SD.translate_assert(self._language)
14159
14665
  messenger_post = "<b>%s %s</b>: %s" % (a_t, by.upper(), selector)
14160
- try:
14666
+ with suppress(Exception):
14161
14667
  js_utils.activate_jquery(self.driver)
14162
14668
  js_utils.post_messenger_success_message(
14163
14669
  self.driver, messenger_post, self.message_duration
14164
14670
  )
14165
- except Exception:
14166
- pass
14167
14671
 
14168
14672
  def __assert_shadow_element_visible(self, selector):
14169
14673
  element = self.__get_shadow_element(selector)
@@ -14178,13 +14682,11 @@ class BaseCase(unittest.TestCase):
14178
14682
 
14179
14683
  a_t = SD.translate_assert(self._language)
14180
14684
  messenger_post = "<b>%s %s</b>: %s" % (a_t, by.upper(), selector)
14181
- try:
14685
+ with suppress(Exception):
14182
14686
  js_utils.activate_jquery(self.driver)
14183
14687
  js_utils.post_messenger_success_message(
14184
14688
  self.driver, messenger_post, self.message_duration
14185
14689
  )
14186
- except Exception:
14187
- pass
14188
14690
 
14189
14691
  ############
14190
14692
 
@@ -14259,10 +14761,15 @@ class BaseCase(unittest.TestCase):
14259
14761
  self.env = self.environment # Add a shortened version
14260
14762
  self.with_selenium = sb_config.with_selenium # Should be True
14261
14763
  self.headless = sb_config.headless
14764
+ self.headless1 = sb_config.headless1
14765
+ if self.headless1:
14766
+ self.headless = True
14767
+ self.headless2 = sb_config.headless2
14262
14768
  self.headless_active = False
14263
14769
  sb_config.headless_active = False
14264
14770
  self.headed = sb_config.headed
14265
14771
  self.xvfb = sb_config.xvfb
14772
+ self.xvfb_metrics = sb_config.xvfb_metrics
14266
14773
  self.locale_code = sb_config.locale_code
14267
14774
  self.interval = sb_config.interval
14268
14775
  self.start_page = sb_config.start_page
@@ -14297,6 +14804,7 @@ class BaseCase(unittest.TestCase):
14297
14804
  self.firefox_arg = sb_config.firefox_arg
14298
14805
  self.firefox_pref = sb_config.firefox_pref
14299
14806
  self.verify_delay = sb_config.verify_delay
14807
+ self.esc_end = sb_config.esc_end
14300
14808
  self.recorder_mode = sb_config.recorder_mode
14301
14809
  self.recorder_ext = sb_config.recorder_mode
14302
14810
  self.rec_print = sb_config.rec_print
@@ -14311,6 +14819,7 @@ class BaseCase(unittest.TestCase):
14311
14819
  elif self.record_sleep and not self.recorder_mode:
14312
14820
  self.recorder_mode = True
14313
14821
  self.recorder_ext = True
14822
+ self.disable_cookies = sb_config.disable_cookies
14314
14823
  self.disable_js = sb_config.disable_js
14315
14824
  self.disable_csp = sb_config.disable_csp
14316
14825
  self.disable_ws = sb_config.disable_ws
@@ -14325,7 +14834,6 @@ class BaseCase(unittest.TestCase):
14325
14834
  self.log_cdp_events = sb_config.log_cdp_events
14326
14835
  self.no_sandbox = sb_config.no_sandbox
14327
14836
  self.disable_gpu = sb_config.disable_gpu
14328
- self.headless2 = sb_config.headless2
14329
14837
  self.incognito = sb_config.incognito
14330
14838
  self.guest_mode = sb_config.guest_mode
14331
14839
  self.dark_mode = sb_config.dark_mode
@@ -14353,31 +14861,8 @@ class BaseCase(unittest.TestCase):
14353
14861
  self.use_wire = sb_config.use_wire
14354
14862
  self.external_pdf = sb_config.external_pdf
14355
14863
  self._final_debug = sb_config.final_debug
14864
+ self.window_position = sb_config.window_position
14356
14865
  self.window_size = sb_config.window_size
14357
- window_size = self.window_size
14358
- if window_size:
14359
- if window_size.count(",") != 1:
14360
- message = (
14361
- '\n\n window_size expects a "width,height" string!'
14362
- '\n (Your input was: "%s")\n' % window_size
14363
- )
14364
- raise Exception(message)
14365
- window_size = window_size.replace(" ", "")
14366
- width = None
14367
- height = None
14368
- try:
14369
- width = int(window_size.split(",")[0])
14370
- height = int(window_size.split(",")[1])
14371
- except Exception:
14372
- message = (
14373
- '\n\n Expecting integer values for "width,height"!'
14374
- '\n (window_size input was: "%s")\n' % window_size
14375
- )
14376
- raise Exception(message)
14377
- settings.CHROME_START_WIDTH = width
14378
- settings.CHROME_START_HEIGHT = height
14379
- settings.HEADLESS_START_WIDTH = width
14380
- settings.HEADLESS_START_HEIGHT = height
14381
14866
  self.maximize_option = sb_config.maximize_option
14382
14867
  self.save_screenshot_after_test = sb_config.save_screenshot
14383
14868
  self.no_screenshot_after_test = sb_config.no_screenshot
@@ -14435,15 +14920,13 @@ class BaseCase(unittest.TestCase):
14435
14920
  self.__skip_reason = None
14436
14921
  self.testcase_manager.insert_testcase_data(data_payload)
14437
14922
  self.case_start_time = int(time.time() * 1000.0)
14438
- self.__activate_virtual_display_as_needed()
14439
14923
  elif hasattr(self, "is_behave") and self.is_behave:
14440
14924
  self.__initialize_variables()
14441
- self.__activate_virtual_display_as_needed()
14442
14925
  elif hasattr(self, "is_nosetest") and self.is_nosetest:
14443
14926
  pass # Setup performed in plugins for pynose
14444
14927
  else:
14445
- # Pure Python run. Eg. SB() Manager
14446
- self.__activate_virtual_display_as_needed()
14928
+ # Pure Python run. (Eg. SB() and Driver() Managers)
14929
+ pass # Variables initialized in respective plugins
14447
14930
 
14448
14931
  # Verify SeleniumBase is installed successfully, and used correctly
14449
14932
  if not hasattr(self, "browser"):
@@ -14528,8 +15011,8 @@ class BaseCase(unittest.TestCase):
14528
15011
  metrics_list = metrics_string.split(",")
14529
15012
  exception_string = (
14530
15013
  "Invalid input for Mobile Emulator device metrics!\n"
14531
- "Expecting a comma-separated string with three\n"
14532
- "integer values for Width, Height, and Pixel-Ratio.\n"
15014
+ "Expecting a comma-separated string with integer values\n"
15015
+ "for Width/Height, and an int or float for Pixel-Ratio.\n"
14533
15016
  'Example: --metrics="411,731,3" '
14534
15017
  )
14535
15018
  if len(metrics_list) != 3:
@@ -14537,13 +15020,91 @@ class BaseCase(unittest.TestCase):
14537
15020
  try:
14538
15021
  self.__device_width = int(metrics_list[0])
14539
15022
  self.__device_height = int(metrics_list[1])
14540
- self.__device_pixel_ratio = int(metrics_list[2])
15023
+ self.__device_pixel_ratio = float(metrics_list[2])
14541
15024
  self.mobile_emulator = True
14542
15025
  except Exception:
14543
15026
  raise Exception(exception_string)
15027
+
15028
+ window_position = self.window_position
15029
+ if window_position:
15030
+ if window_position.count(",") != 1:
15031
+ message = (
15032
+ '\n\n window_position expects an "x,y" string!'
15033
+ '\n (Your input was: "%s")\n' % window_position
15034
+ )
15035
+ raise Exception(message)
15036
+ window_position = window_position.replace(" ", "")
15037
+ win_x = None
15038
+ win_y = None
15039
+ try:
15040
+ win_x = int(window_position.split(",")[0])
15041
+ win_y = int(window_position.split(",")[1])
15042
+ except Exception:
15043
+ message = (
15044
+ '\n\n Expecting integer values for "x,y"!'
15045
+ '\n (window_position input was: "%s")\n'
15046
+ % window_position
15047
+ )
15048
+ raise Exception(message)
15049
+ settings.WINDOW_START_X = win_x
15050
+ settings.WINDOW_START_Y = win_y
15051
+
15052
+ window_size = self.window_size
15053
+ if window_size:
15054
+ if window_size.count(",") != 1:
15055
+ message = (
15056
+ '\n\n window_size expects a "width,height" string!'
15057
+ '\n (Your input was: "%s")\n' % window_size
15058
+ )
15059
+ raise Exception(message)
15060
+ window_size = window_size.replace(" ", "")
15061
+ width = None
15062
+ height = None
15063
+ try:
15064
+ width = int(window_size.split(",")[0])
15065
+ height = int(window_size.split(",")[1])
15066
+ except Exception:
15067
+ message = (
15068
+ '\n\n Expecting integer values for "width,height"!'
15069
+ '\n (window_size input was: "%s")\n' % window_size
15070
+ )
15071
+ raise Exception(message)
15072
+ settings.CHROME_START_WIDTH = width
15073
+ settings.CHROME_START_HEIGHT = height
15074
+ settings.HEADLESS_START_WIDTH = width
15075
+ settings.HEADLESS_START_HEIGHT = height
15076
+
15077
+ if self.xvfb_metrics:
15078
+ metrics_string = self.xvfb_metrics
15079
+ metrics_string = metrics_string.replace(" ", "")
15080
+ metrics_list = metrics_string.split(",")[0:2]
15081
+ exception_string = (
15082
+ "Invalid input for xvfb_metrics!\n"
15083
+ "Expecting a comma-separated string\n"
15084
+ "with integer values for Width/Height.\n"
15085
+ 'Eg. --xvfb-metrics="1920,1080".\n'
15086
+ "(Minimum: 1024,768) (Default: 1366,768)"
15087
+ )
15088
+ if len(metrics_list) != 2:
15089
+ raise Exception(exception_string)
15090
+ try:
15091
+ self._xvfb_width = int(metrics_list[0])
15092
+ self._xvfb_height = int(metrics_list[1])
15093
+ # The minimum width,height is: 1024,768
15094
+ if self._xvfb_width < 1024:
15095
+ self._xvfb_width = 1024
15096
+ sb_config._xvfb_width = self._xvfb_width
15097
+ if self._xvfb_height < 768:
15098
+ self._xvfb_height = 768
15099
+ sb_config._xvfb_height = self._xvfb_height
15100
+ self.xvfb = True
15101
+ except Exception:
15102
+ raise Exception(exception_string)
15103
+
14544
15104
  if self.mobile_emulator and not self.user_agent:
14545
15105
  # Use a Pixel user agent by default if not specified
14546
15106
  self.user_agent = constants.Mobile.AGENT
15107
+
14547
15108
  if self.browser in ["firefox", "ie", "safari"]:
14548
15109
  # The Recorder Mode browser extension is only for Chrome/Edge.
14549
15110
  if self.recorder_mode:
@@ -14553,10 +15114,18 @@ class BaseCase(unittest.TestCase):
14553
15114
  )
14554
15115
  raise Exception(message)
14555
15116
 
15117
+ if not hasattr(self, "is_nosetest") or not self.is_nosetest:
15118
+ # Xvfb Virtual Display activation for Linux
15119
+ self.__activate_virtual_display_as_needed()
15120
+
14556
15121
  # Dashboard pre-processing:
14557
15122
  if self.dashboard:
14558
15123
  if self._multithreaded:
14559
15124
  with self.dash_lock:
15125
+ with suppress(Exception):
15126
+ shared_utils.make_writable(
15127
+ constants.Dashboard.LOCKFILE
15128
+ )
14560
15129
  if not self._dash_initialized:
14561
15130
  sb_config._dashboard_initialized = True
14562
15131
  self._dash_initialized = True
@@ -14577,7 +15146,7 @@ class BaseCase(unittest.TestCase):
14577
15146
  if not hasattr(sb_config, "shared_driver"):
14578
15147
  sb_config.shared_driver = None
14579
15148
  if sb_config.shared_driver:
14580
- try:
15149
+ with suppress(Exception):
14581
15150
  self._default_driver = sb_config.shared_driver
14582
15151
  self.driver = sb_config.shared_driver
14583
15152
  self._drivers_list = [sb_config.shared_driver]
@@ -14591,12 +15160,8 @@ class BaseCase(unittest.TestCase):
14591
15160
  self.switch_to_window(0)
14592
15161
  if self._crumbs:
14593
15162
  self.wait_for_ready_state_complete()
14594
- try:
15163
+ with suppress(Exception):
14595
15164
  self.driver.delete_all_cookies()
14596
- except Exception:
14597
- pass
14598
- except Exception:
14599
- pass
14600
15165
  if self._reuse_session and sb_config.shared_driver and has_url:
14601
15166
  good_start_page = False
14602
15167
  if self.recorder_ext:
@@ -14639,6 +15204,7 @@ class BaseCase(unittest.TestCase):
14639
15204
  cap_file=self.cap_file,
14640
15205
  cap_string=self.cap_string,
14641
15206
  recorder_ext=self.recorder_ext,
15207
+ disable_cookies=self.disable_cookies,
14642
15208
  disable_js=self.disable_js,
14643
15209
  disable_csp=self.disable_csp,
14644
15210
  enable_ws=self.enable_ws,
@@ -14650,6 +15216,7 @@ class BaseCase(unittest.TestCase):
14650
15216
  log_cdp_events=self.log_cdp_events,
14651
15217
  no_sandbox=self.no_sandbox,
14652
15218
  disable_gpu=self.disable_gpu,
15219
+ headless1=self.headless1,
14653
15220
  headless2=self.headless2,
14654
15221
  incognito=self.incognito,
14655
15222
  guest_mode=self.guest_mode,
@@ -14683,10 +15250,8 @@ class BaseCase(unittest.TestCase):
14683
15250
  if self.driver.timeouts.implicit_wait > 0:
14684
15251
  self.driver.implicitly_wait(0)
14685
15252
  except Exception:
14686
- try:
15253
+ with suppress(Exception):
14687
15254
  self.driver.implicitly_wait(0)
14688
- except Exception:
14689
- pass
14690
15255
  self._default_driver = self.driver
14691
15256
  if self._reuse_session:
14692
15257
  sb_config.shared_driver = self.driver
@@ -14705,13 +15270,11 @@ class BaseCase(unittest.TestCase):
14705
15270
  self.set_time_limit(self.time_limit)
14706
15271
 
14707
15272
  # Configure the page load timeout
14708
- try:
15273
+ with suppress(Exception):
14709
15274
  if hasattr(settings, "PAGE_LOAD_TIMEOUT"):
14710
15275
  self.driver.set_page_load_timeout(settings.PAGE_LOAD_TIMEOUT)
14711
15276
  else:
14712
15277
  self.driver.set_page_load_timeout(120) # Selenium uses 300
14713
- except Exception:
14714
- pass
14715
15278
 
14716
15279
  # Set the start time for the test (in ms).
14717
15280
  # Although the pytest clock starts before setUp() begins,
@@ -14740,7 +15303,7 @@ class BaseCase(unittest.TestCase):
14740
15303
  not self.__last_page_screenshot
14741
15304
  and not self.__last_page_screenshot_png
14742
15305
  ):
14743
- try:
15306
+ with suppress(Exception):
14744
15307
  try:
14745
15308
  element = page_actions.wait_for_element_visible(
14746
15309
  self.driver,
@@ -14770,14 +15333,10 @@ class BaseCase(unittest.TestCase):
14770
15333
  element.screenshot_as_base64
14771
15334
  )
14772
15335
  except Exception:
14773
- try:
15336
+ with suppress(Exception):
14774
15337
  self.__last_page_screenshot = (
14775
15338
  self.driver.get_screenshot_as_base64()
14776
15339
  )
14777
- except Exception:
14778
- pass
14779
- except Exception:
14780
- pass
14781
15340
  if not self.__last_page_screenshot:
14782
15341
  self.__last_page_screenshot = SCREENSHOT_UNDEFINED
14783
15342
  self.__last_page_screenshot_png = SCREENSHOT_UNDEFINED
@@ -14787,12 +15346,10 @@ class BaseCase(unittest.TestCase):
14787
15346
  element.screenshot_as_png
14788
15347
  )
14789
15348
  except Exception:
14790
- try:
15349
+ with suppress(Exception):
14791
15350
  self.__last_page_screenshot_png = (
14792
15351
  self.driver.get_screenshot_as_png()
14793
15352
  )
14794
- except Exception:
14795
- pass
14796
15353
  else:
14797
15354
  import base64
14798
15355
 
@@ -14807,12 +15364,10 @@ class BaseCase(unittest.TestCase):
14807
15364
  element.screenshot_as_png
14808
15365
  )
14809
15366
  except Exception:
14810
- try:
15367
+ with suppress(Exception):
14811
15368
  self.__last_page_screenshot_png = (
14812
15369
  self.driver.get_screenshot_as_png()
14813
15370
  )
14814
- except Exception:
14815
- pass
14816
15371
  sb_config._last_page_screenshot_png = self.__last_page_screenshot_png
14817
15372
 
14818
15373
  def __set_last_page_url(self):
@@ -14864,7 +15419,6 @@ class BaseCase(unittest.TestCase):
14864
15419
  data_payload.state = state
14865
15420
  if err:
14866
15421
  import traceback
14867
-
14868
15422
  tb_string = traceback.format_exc()
14869
15423
  if "Message: " in tb_string:
14870
15424
  data_payload.message = (
@@ -14899,7 +15453,7 @@ class BaseCase(unittest.TestCase):
14899
15453
 
14900
15454
  def __add_pytest_html_extra(self):
14901
15455
  if not self.__added_pytest_html_extra:
14902
- try:
15456
+ with suppress(Exception):
14903
15457
  if self.with_selenium:
14904
15458
  if not self.__last_page_screenshot:
14905
15459
  self.__set_last_page_screenshot()
@@ -14926,8 +15480,6 @@ class BaseCase(unittest.TestCase):
14926
15480
  ):
14927
15481
  self._html_report_extra.append(extra_url)
14928
15482
  self._html_report_extra.append(extra_image)
14929
- except Exception:
14930
- pass
14931
15483
 
14932
15484
  def __delay_driver_quit(self):
14933
15485
  delay_driver_quit = False
@@ -15021,7 +15573,6 @@ class BaseCase(unittest.TestCase):
15021
15573
  context_id = None
15022
15574
  if filename == "base_case.py" or methodname == "runTest":
15023
15575
  import traceback
15024
-
15025
15576
  stack_base = traceback.format_stack()[0].split(", in ")[0]
15026
15577
  test_base = stack_base.split(", in ")[0].split(os.sep)[-1]
15027
15578
  if hasattr(self, "cm_filename") and self.cm_filename:
@@ -15041,7 +15592,8 @@ class BaseCase(unittest.TestCase):
15041
15592
  elif hasattr(self, "_using_sb_fixture") and self._using_sb_fixture:
15042
15593
  test_id = sb_config._latest_display_id
15043
15594
  test_id = test_id.replace(".py::", ".").replace("::", ".")
15044
- test_id = test_id.replace("/", ".").replace(" ", "_")
15595
+ test_id = test_id.replace("/", ".").replace("\\", ".")
15596
+ test_id = test_id.replace(" ", "_")
15045
15597
  # Linux filename length limit for `codecs.open(filename)` = 255
15046
15598
  # 255 - len("latest_logs/") - len("/basic_test_info.txt") = 223
15047
15599
  if len(test_id) <= 223:
@@ -15133,6 +15685,8 @@ class BaseCase(unittest.TestCase):
15133
15685
  constants.Dashboard.LOCKFILE
15134
15686
  )
15135
15687
  with self.dash_lock:
15688
+ with suppress(Exception):
15689
+ shared_utils.make_writable(constants.Dashboard.LOCKFILE)
15136
15690
  self.__process_dashboard(has_exception, init)
15137
15691
  else:
15138
15692
  self.__process_dashboard(has_exception, init)
@@ -15616,6 +16170,31 @@ class BaseCase(unittest.TestCase):
15616
16170
  else:
15617
16171
  return None
15618
16172
 
16173
+ def _get_num_handles(self):
16174
+ return len(self.driver.window_handles)
16175
+
16176
+ def _get_rec_shift_esc_script(self):
16177
+ return (
16178
+ """document.onkeydown = function(evt) {
16179
+ evt = evt || window.event;
16180
+ var isEscape = false;
16181
+ if ("key" in evt) {
16182
+ isEscape = (evt.key === "Escape" || evt.key === "Esc");
16183
+ last_key = evt.key;
16184
+ } else {
16185
+ isEscape = (evt.keyCode === 27);
16186
+ last_key = evt.keyCode;
16187
+ if (last_key === 16) {
16188
+ last_key = "Shift";
16189
+ }
16190
+ }
16191
+ if (isEscape && document.sb_last_key === "Shift") {
16192
+ document.sb_esc_end = "yes";
16193
+ }
16194
+ document.sb_last_key = last_key;
16195
+ };"""
16196
+ )
16197
+
15619
16198
  def _addSkip(self, result, test_case, reason):
15620
16199
  """This method should NOT be called directly from tests."""
15621
16200
  addSkip = getattr(result, 'addSkip', None)
@@ -15713,7 +16292,15 @@ class BaseCase(unittest.TestCase):
15713
16292
  # This test already called tearDown()
15714
16293
  return
15715
16294
  if hasattr(self, "recorder_mode") and self.recorder_mode:
15716
- self.__process_recorded_actions()
16295
+ page_actions._reconnect_if_disconnected(self.driver)
16296
+ try:
16297
+ self.__process_recorded_actions()
16298
+ except Exception as e:
16299
+ print("\n (Recorder) Code-generation exception:")
16300
+ if hasattr(e, "msg"):
16301
+ print("\n" + str(e.msg))
16302
+ else:
16303
+ print(e)
15717
16304
  self.__called_teardown = True
15718
16305
  self.__called_setup = False
15719
16306
  try:
@@ -15746,6 +16333,7 @@ class BaseCase(unittest.TestCase):
15746
16333
  )
15747
16334
  raise Exception(message)
15748
16335
  # *** Start tearDown() officially ***
16336
+ page_actions._reconnect_if_disconnected(self.driver)
15749
16337
  self.__slow_mode_pause_if_active()
15750
16338
  has_exception = self.__has_exception()
15751
16339
  sb_config._has_exception = has_exception
@@ -15868,6 +16456,10 @@ class BaseCase(unittest.TestCase):
15868
16456
  if self.dashboard:
15869
16457
  if self._multithreaded:
15870
16458
  with self.dash_lock:
16459
+ with suppress(Exception):
16460
+ shared_utils.make_writable(
16461
+ constants.Dashboard.LOCKFILE
16462
+ )
15871
16463
  self.__process_dashboard(has_exception)
15872
16464
  else:
15873
16465
  self.__process_dashboard(has_exception)
@@ -15935,7 +16527,6 @@ class BaseCase(unittest.TestCase):
15935
16527
  else:
15936
16528
  # (Pynose / Behave / Pure Python)
15937
16529
  if hasattr(self, "is_behave") and self.is_behave:
15938
- import colorama
15939
16530
  if sb_config.behave_scenario.status.name == "failed":
15940
16531
  has_exception = True
15941
16532
  sb_config._has_exception = True
@@ -15943,8 +16534,6 @@ class BaseCase(unittest.TestCase):
15943
16534
  if is_windows:
15944
16535
  c1 = colorama.Fore.RED + colorama.Back.LIGHTRED_EX
15945
16536
  cr = colorama.Style.RESET_ALL
15946
- if hasattr(colorama, "just_fix_windows_console"):
15947
- colorama.just_fix_windows_console()
15948
16537
  msg = msg.replace("❌", c1 + "><" + cr)
15949
16538
  print(msg)
15950
16539
  else:
@@ -15952,8 +16541,6 @@ class BaseCase(unittest.TestCase):
15952
16541
  if is_windows:
15953
16542
  c2 = colorama.Fore.GREEN + colorama.Back.LIGHTGREEN_EX
15954
16543
  cr = colorama.Style.RESET_ALL
15955
- if hasattr(colorama, "just_fix_windows_console"):
15956
- colorama.just_fix_windows_console()
15957
16544
  msg = msg.replace("✅", c2 + "<>" + cr)
15958
16545
  print(msg)
15959
16546
  if self.dashboard:
@@ -16018,6 +16605,7 @@ class BaseCase(unittest.TestCase):
16018
16605
  self.__quit_all_drivers()
16019
16606
  # Resume tearDown() for all test runners, (Pytest / Pynose / Behave)
16020
16607
  if hasattr(self, "_xvfb_display") and self._xvfb_display:
16608
+ # Stop the Xvfb virtual display launched from BaseCase
16021
16609
  try:
16022
16610
  if hasattr(self._xvfb_display, "stop"):
16023
16611
  self._xvfb_display.stop()
@@ -16027,6 +16615,20 @@ class BaseCase(unittest.TestCase):
16027
16615
  pass
16028
16616
  except Exception:
16029
16617
  pass
16618
+ if (
16619
+ hasattr(sb_config, "_virtual_display")
16620
+ and sb_config._virtual_display
16621
+ and hasattr(sb_config._virtual_display, "stop")
16622
+ ):
16623
+ # CDP Mode may launch a 2nd Xvfb virtual display
16624
+ try:
16625
+ sb_config._virtual_display.stop()
16626
+ sb_config._virtual_display = None
16627
+ sb_config.headless_active = False
16628
+ except AttributeError:
16629
+ pass
16630
+ except Exception:
16631
+ pass
16030
16632
  if self.__visual_baseline_copies:
16031
16633
  sb_config._visual_baseline_copies = True
16032
16634
  if has_exception: