seleniumbase 4.24.11__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 (78) 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/log_helper.py +42 -27
  25. seleniumbase/core/mysql.py +1 -4
  26. seleniumbase/core/proxy_helper.py +35 -30
  27. seleniumbase/core/recorder_helper.py +24 -5
  28. seleniumbase/core/sb_cdp.py +1951 -0
  29. seleniumbase/core/sb_driver.py +162 -8
  30. seleniumbase/core/settings_parser.py +6 -0
  31. seleniumbase/core/style_sheet.py +10 -0
  32. seleniumbase/extensions/recorder.zip +0 -0
  33. seleniumbase/fixtures/base_case.py +1225 -614
  34. seleniumbase/fixtures/constants.py +10 -1
  35. seleniumbase/fixtures/js_utils.py +171 -144
  36. seleniumbase/fixtures/page_actions.py +177 -13
  37. seleniumbase/fixtures/page_utils.py +25 -53
  38. seleniumbase/fixtures/shared_utils.py +97 -11
  39. seleniumbase/js_code/active_css_js.py +1 -1
  40. seleniumbase/js_code/recorder_js.py +1 -1
  41. seleniumbase/plugins/base_plugin.py +2 -3
  42. seleniumbase/plugins/driver_manager.py +340 -65
  43. seleniumbase/plugins/pytest_plugin.py +276 -47
  44. seleniumbase/plugins/sb_manager.py +412 -99
  45. seleniumbase/plugins/selenium_plugin.py +122 -17
  46. seleniumbase/translate/translator.py +0 -7
  47. seleniumbase/undetected/__init__.py +59 -52
  48. seleniumbase/undetected/cdp.py +0 -1
  49. seleniumbase/undetected/cdp_driver/__init__.py +1 -0
  50. seleniumbase/undetected/cdp_driver/_contradict.py +110 -0
  51. seleniumbase/undetected/cdp_driver/browser.py +829 -0
  52. seleniumbase/undetected/cdp_driver/cdp_util.py +458 -0
  53. seleniumbase/undetected/cdp_driver/config.py +334 -0
  54. seleniumbase/undetected/cdp_driver/connection.py +639 -0
  55. seleniumbase/undetected/cdp_driver/element.py +1168 -0
  56. seleniumbase/undetected/cdp_driver/tab.py +1323 -0
  57. seleniumbase/undetected/dprocess.py +4 -7
  58. seleniumbase/undetected/options.py +6 -8
  59. seleniumbase/undetected/patcher.py +11 -13
  60. seleniumbase/undetected/reactor.py +0 -1
  61. seleniumbase/undetected/webelement.py +16 -3
  62. {seleniumbase-4.24.11.dist-info → seleniumbase-4.33.15.dist-info}/LICENSE +1 -1
  63. {seleniumbase-4.24.11.dist-info → seleniumbase-4.33.15.dist-info}/METADATA +299 -252
  64. {seleniumbase-4.24.11.dist-info → seleniumbase-4.33.15.dist-info}/RECORD +67 -69
  65. {seleniumbase-4.24.11.dist-info → seleniumbase-4.33.15.dist-info}/WHEEL +1 -1
  66. sbase/ReadMe.txt +0 -2
  67. seleniumbase/ReadMe.md +0 -25
  68. seleniumbase/common/ReadMe.md +0 -71
  69. seleniumbase/console_scripts/ReadMe.md +0 -731
  70. seleniumbase/drivers/ReadMe.md +0 -27
  71. seleniumbase/extensions/ReadMe.md +0 -12
  72. seleniumbase/masterqa/ReadMe.md +0 -61
  73. seleniumbase/resources/ReadMe.md +0 -31
  74. seleniumbase/resources/favicon.ico +0 -0
  75. seleniumbase/utilities/selenium_grid/ReadMe.md +0 -84
  76. seleniumbase/utilities/selenium_ide/ReadMe.md +0 -111
  77. {seleniumbase-4.24.11.dist-info → seleniumbase-4.33.15.dist-info}/entry_points.txt +0 -0
  78. {seleniumbase-4.24.11.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,29 +1310,32 @@ class BaseCase(unittest.TestCase):
1310
1310
  return self.get_page_title()
1311
1311
 
1312
1312
  def get_user_agent(self):
1313
+ if self.__is_cdp_swap_needed():
1314
+ return self.cdp.get_user_agent()
1313
1315
  return self.execute_script("return navigator.userAgent;")
1314
1316
 
1315
1317
  def get_locale_code(self):
1318
+ if self.__is_cdp_swap_needed():
1319
+ return self.cdp.get_locale_code()
1316
1320
  return self.execute_script(
1317
1321
  "return navigator.language || navigator.languages[0];"
1318
1322
  )
1319
1323
 
1320
1324
  def go_back(self):
1321
1325
  self.__check_scope()
1326
+ if self.__is_cdp_swap_needed():
1327
+ self.cdp.go_back()
1328
+ return
1322
1329
  if hasattr(self, "recorder_mode") and self.recorder_mode:
1323
1330
  self.save_recorded_actions()
1324
1331
  pre_action_url = None
1325
- try:
1332
+ with suppress(Exception):
1326
1333
  pre_action_url = self.driver.current_url
1327
- except Exception:
1328
- pass
1329
1334
  self.__last_page_load_url = None
1330
1335
  self.driver.back()
1331
- try:
1336
+ with suppress(Exception):
1332
1337
  if pre_action_url == self.driver.current_url:
1333
1338
  self.driver.back() # Again because the page was redirected
1334
- except Exception:
1335
- pass
1336
1339
  if self.recorder_mode:
1337
1340
  time_stamp = self.execute_script("return Date.now();")
1338
1341
  origin = self.get_origin()
@@ -1348,6 +1351,9 @@ class BaseCase(unittest.TestCase):
1348
1351
 
1349
1352
  def go_forward(self):
1350
1353
  self.__check_scope()
1354
+ if self.__is_cdp_swap_needed():
1355
+ self.cdp.go_forward()
1356
+ return
1351
1357
  if hasattr(self, "recorder_mode") and self.recorder_mode:
1352
1358
  self.save_recorded_actions()
1353
1359
  self.__last_page_load_url = None
@@ -1401,7 +1407,7 @@ class BaseCase(unittest.TestCase):
1401
1407
  to convert the open() action into open_if_not_url() so that the
1402
1408
  same page isn't opened again if the user is already on the page."""
1403
1409
  self.__check_scope()
1404
- current_url = self.driver.current_url
1410
+ current_url = self.get_current_url()
1405
1411
  if current_url != url:
1406
1412
  if (
1407
1413
  "?q=" not in current_url
@@ -1412,6 +1418,9 @@ class BaseCase(unittest.TestCase):
1412
1418
  self.open(url)
1413
1419
 
1414
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)
1415
1424
  self.wait_for_ready_state_complete()
1416
1425
  selector, by = self.__recalculate_selector(selector, by)
1417
1426
  if self.__is_shadow_selector(selector):
@@ -1419,6 +1428,9 @@ class BaseCase(unittest.TestCase):
1419
1428
  return page_actions.is_element_present(self.driver, selector, by)
1420
1429
 
1421
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)
1422
1434
  self.wait_for_ready_state_complete()
1423
1435
  selector, by = self.__recalculate_selector(selector, by)
1424
1436
  if self.__is_shadow_selector(selector):
@@ -1439,7 +1451,8 @@ class BaseCase(unittest.TestCase):
1439
1451
  return self.__is_shadow_element_enabled(selector)
1440
1452
  return page_actions.is_element_enabled(self.driver, selector, by)
1441
1453
 
1442
- 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."""
1443
1456
  self.wait_for_ready_state_complete()
1444
1457
  time.sleep(0.01)
1445
1458
  selector, by = self.__recalculate_selector(selector, by)
@@ -1447,7 +1460,9 @@ class BaseCase(unittest.TestCase):
1447
1460
  return self.__is_shadow_text_visible(text, selector)
1448
1461
  return page_actions.is_text_visible(self.driver, text, selector, by)
1449
1462
 
1450
- 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.)"""
1451
1466
  self.wait_for_ready_state_complete()
1452
1467
  time.sleep(0.01)
1453
1468
  selector, by = self.__recalculate_selector(selector, by)
@@ -1457,7 +1472,7 @@ class BaseCase(unittest.TestCase):
1457
1472
  self.driver, text, selector, by
1458
1473
  )
1459
1474
 
1460
- 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"):
1461
1476
  """Returns whether the element has any non-empty text visible.
1462
1477
  Whitespace-only text is considered empty text."""
1463
1478
  self.wait_for_ready_state_complete()
@@ -1486,6 +1501,7 @@ class BaseCase(unittest.TestCase):
1486
1501
  )
1487
1502
 
1488
1503
  def is_link_text_visible(self, link_text):
1504
+ """Returns whether there's an exact match for the link text."""
1489
1505
  self.wait_for_ready_state_complete()
1490
1506
  time.sleep(0.01)
1491
1507
  return page_actions.is_element_visible(
@@ -1493,6 +1509,7 @@ class BaseCase(unittest.TestCase):
1493
1509
  )
1494
1510
 
1495
1511
  def is_partial_link_text_visible(self, partial_link_text):
1512
+ """Returns whether there's a substring match for the link text."""
1496
1513
  self.wait_for_ready_state_complete()
1497
1514
  time.sleep(0.01)
1498
1515
  return page_actions.is_element_visible(
@@ -1585,11 +1602,18 @@ class BaseCase(unittest.TestCase):
1585
1602
  def click_link_text(self, link_text, timeout=None):
1586
1603
  """This method clicks link text on a page."""
1587
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()
1588
1609
  if not timeout:
1589
1610
  timeout = settings.SMALL_TIMEOUT
1590
1611
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
1591
1612
  timeout = self.__get_new_timeout(timeout)
1592
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
1593
1617
  if self.browser == "safari":
1594
1618
  if self.demo_mode:
1595
1619
  self.wait_for_link_text_present(link_text, timeout=timeout)
@@ -1620,10 +1644,8 @@ class BaseCase(unittest.TestCase):
1620
1644
  if self.__needs_minimum_wait():
1621
1645
  time.sleep(0.04)
1622
1646
  pre_action_url = None
1623
- try:
1647
+ with suppress(Exception):
1624
1648
  pre_action_url = self.driver.current_url
1625
- except Exception:
1626
- pass
1627
1649
  pre_window_count = len(self.driver.window_handles)
1628
1650
  try:
1629
1651
  element = self.wait_for_link_text_visible(link_text, timeout=0.2)
@@ -1694,10 +1716,8 @@ class BaseCase(unittest.TestCase):
1694
1716
  # switch to the last one if it exists.
1695
1717
  self.switch_to_window(-1)
1696
1718
  if settings.WAIT_FOR_RSC_ON_PAGE_LOADS:
1697
- try:
1719
+ with suppress(Exception):
1698
1720
  self.wait_for_ready_state_complete()
1699
- except Exception:
1700
- pass
1701
1721
  if self.demo_mode:
1702
1722
  if self.driver.current_url != pre_action_url:
1703
1723
  if not js_utils.is_jquery_activated(self.driver):
@@ -1718,15 +1738,16 @@ class BaseCase(unittest.TestCase):
1718
1738
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
1719
1739
  timeout = self.__get_new_timeout(timeout)
1720
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
1721
1744
  if not self.is_partial_link_text_present(partial_link_text):
1722
1745
  self.wait_for_partial_link_text_present(
1723
1746
  partial_link_text, timeout=timeout
1724
1747
  )
1725
1748
  pre_action_url = None
1726
- try:
1749
+ with suppress(Exception):
1727
1750
  pre_action_url = self.driver.current_url
1728
- except Exception:
1729
- pass
1730
1751
  pre_window_count = len(self.driver.window_handles)
1731
1752
  try:
1732
1753
  element = self.wait_for_partial_link_text(
@@ -1809,10 +1830,8 @@ class BaseCase(unittest.TestCase):
1809
1830
  # switch to the last one if it exists.
1810
1831
  self.switch_to_window(-1)
1811
1832
  if settings.WAIT_FOR_RSC_ON_PAGE_LOADS:
1812
- try:
1833
+ with suppress(Exception):
1813
1834
  self.wait_for_ready_state_complete()
1814
- except Exception:
1815
- pass
1816
1835
  if self.demo_mode:
1817
1836
  if self.driver.current_url != pre_action_url:
1818
1837
  if not js_utils.is_jquery_activated(self.driver):
@@ -1823,13 +1842,15 @@ class BaseCase(unittest.TestCase):
1823
1842
  elif self.slow_mode:
1824
1843
  self.__slow_mode_pause_if_active()
1825
1844
 
1826
- def get_text(self, selector, by="css selector", timeout=None):
1845
+ def get_text(self, selector="body", by="css selector", timeout=None):
1827
1846
  self.__check_scope()
1828
1847
  if not timeout:
1829
1848
  timeout = settings.LARGE_TIMEOUT
1830
1849
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
1831
1850
  timeout = self.__get_new_timeout(timeout)
1832
1851
  selector, by = self.__recalculate_selector(selector, by)
1852
+ if self.__is_cdp_swap_needed():
1853
+ return self.cdp.get_text(selector)
1833
1854
  if self.__is_shadow_selector(selector):
1834
1855
  return self.__get_shadow_text(selector, timeout)
1835
1856
  self.wait_for_ready_state_complete()
@@ -1879,6 +1900,8 @@ class BaseCase(unittest.TestCase):
1879
1900
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
1880
1901
  timeout = self.__get_new_timeout(timeout)
1881
1902
  selector, by = self.__recalculate_selector(selector, by)
1903
+ if self.__is_cdp_swap_needed():
1904
+ return self.cdp.get_element_attribute(selector, attribute)
1882
1905
  self.wait_for_ready_state_complete()
1883
1906
  time.sleep(0.01)
1884
1907
  if self.__is_shadow_selector(selector):
@@ -1928,10 +1951,8 @@ class BaseCase(unittest.TestCase):
1928
1951
  original_attribute = attribute
1929
1952
  original_value = value
1930
1953
  if scroll and self.is_element_visible(selector, by=by):
1931
- try:
1954
+ with suppress(Exception):
1932
1955
  self.scroll_to(selector, by=by, timeout=timeout)
1933
- except Exception:
1934
- pass
1935
1956
  attribute = re.escape(attribute)
1936
1957
  attribute = self.__escape_quotes_if_needed(attribute)
1937
1958
  value = re.escape(value)
@@ -1959,6 +1980,9 @@ class BaseCase(unittest.TestCase):
1959
1980
  self.set_attributes("a", "href", "https://google.com")"""
1960
1981
  self.__check_scope()
1961
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
1962
1986
  original_attribute = attribute
1963
1987
  original_value = value
1964
1988
  attribute = re.escape(attribute)
@@ -1976,10 +2000,8 @@ class BaseCase(unittest.TestCase):
1976
2000
  attribute,
1977
2001
  value,
1978
2002
  )
1979
- try:
2003
+ with suppress(Exception):
1980
2004
  self.execute_script(script)
1981
- except Exception:
1982
- pass
1983
2005
  if self.recorder_mode and self.__current_url_is_recordable():
1984
2006
  if self.get_session_storage_item("pause_recorder") == "no":
1985
2007
  time_stamp = self.execute_script("return Date.now();")
@@ -2008,10 +2030,8 @@ class BaseCase(unittest.TestCase):
2008
2030
  timeout = self.__get_new_timeout(timeout)
2009
2031
  selector, by = self.__recalculate_selector(selector, by)
2010
2032
  if self.is_element_visible(selector, by=by):
2011
- try:
2033
+ with suppress(Exception):
2012
2034
  self.scroll_to(selector, by=by, timeout=timeout)
2013
- except Exception:
2014
- pass
2015
2035
  attribute = re.escape(attribute)
2016
2036
  attribute = self.__escape_quotes_if_needed(attribute)
2017
2037
  css_selector = self.convert_to_css_selector(selector, by=by)
@@ -2040,10 +2060,16 @@ class BaseCase(unittest.TestCase):
2040
2060
  css_selector,
2041
2061
  attribute,
2042
2062
  )
2043
- try:
2063
+ with suppress(Exception):
2044
2064
  self.execute_script(script)
2045
- except Exception:
2046
- 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")
2047
2073
 
2048
2074
  def get_property(
2049
2075
  self, selector, property, by="css selector", timeout=None
@@ -2078,7 +2104,9 @@ class BaseCase(unittest.TestCase):
2078
2104
  return ""
2079
2105
  return property_value
2080
2106
 
2081
- 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
+ ):
2082
2110
  """Returns the text that appears in the HTML for an element.
2083
2111
  This is different from "self.get_text(selector, by="css selector")"
2084
2112
  because that only returns the visible text on a page for an element,
@@ -2146,6 +2174,11 @@ class BaseCase(unittest.TestCase):
2146
2174
  Elements could be either hidden or visible on the page.
2147
2175
  If "limit" is set and > 0, will only return that many elements."""
2148
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
2149
2182
  self.wait_for_ready_state_complete()
2150
2183
  time.sleep(0.05)
2151
2184
  elements = self.driver.find_elements(by=by, value=selector)
@@ -2157,6 +2190,11 @@ class BaseCase(unittest.TestCase):
2157
2190
  """Returns a list of matching WebElements that are visible.
2158
2191
  If "limit" is set and > 0, will only return that many elements."""
2159
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
2160
2198
  self.wait_for_ready_state_complete()
2161
2199
  time.sleep(0.05)
2162
2200
  return page_actions.find_visible_elements(
@@ -2179,6 +2217,9 @@ class BaseCase(unittest.TestCase):
2179
2217
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
2180
2218
  timeout = self.__get_new_timeout(timeout)
2181
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
2182
2223
  self.wait_for_ready_state_complete()
2183
2224
  if self.__needs_minimum_wait():
2184
2225
  time.sleep(0.12)
@@ -2187,20 +2228,16 @@ class BaseCase(unittest.TestCase):
2187
2228
  element = self.wait_for_element_present(
2188
2229
  selector, by=by, timeout=timeout
2189
2230
  )
2190
- try:
2231
+ with suppress(Exception):
2191
2232
  # If the first element isn't visible, wait a little.
2192
2233
  if not element.is_displayed():
2193
2234
  time.sleep(0.16)
2194
2235
  if self.undetectable:
2195
2236
  time.sleep(0.06)
2196
- except Exception:
2197
- pass
2198
2237
  elements = self.find_elements(selector, by=by)
2199
2238
  pre_action_url = None
2200
- try:
2239
+ with suppress(Exception):
2201
2240
  pre_action_url = self.driver.current_url
2202
- except Exception:
2203
- pass
2204
2241
  pre_window_count = len(self.driver.window_handles)
2205
2242
  click_count = 0
2206
2243
  for element in elements:
@@ -2263,13 +2300,16 @@ class BaseCase(unittest.TestCase):
2263
2300
  ):
2264
2301
  """Finds all matching page elements and clicks the nth visible one.
2265
2302
  Example: self.click_nth_visible_element('[type="checkbox"]', 5)
2266
- (Clicks the 5th visible checkbox on the page.)"""
2303
+ (Clicks the 5th visible checkbox on the page.)"""
2267
2304
  self.__check_scope()
2268
2305
  if not timeout:
2269
2306
  timeout = settings.SMALL_TIMEOUT
2270
2307
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
2271
2308
  timeout = self.__get_new_timeout(timeout)
2272
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
2273
2313
  self.wait_for_ready_state_complete()
2274
2314
  self.wait_for_element_present(selector, by=by, timeout=timeout)
2275
2315
  elements = self.find_visible_elements(selector, by=by)
@@ -2283,10 +2323,8 @@ class BaseCase(unittest.TestCase):
2283
2323
  number = 0
2284
2324
  element = elements[number]
2285
2325
  pre_action_url = None
2286
- try:
2326
+ with suppress(Exception):
2287
2327
  pre_action_url = self.driver.current_url
2288
- except Exception:
2289
- pass
2290
2328
  pre_window_count = len(self.driver.window_handles)
2291
2329
  try:
2292
2330
  self.__scroll_to_element(element)
@@ -2325,26 +2363,28 @@ class BaseCase(unittest.TestCase):
2325
2363
  Use click_visible_elements() to click all matching elements.
2326
2364
  If a "timeout" is provided, waits that long for the element
2327
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
2328
2369
  self.wait_for_ready_state_complete()
2329
2370
  if self.is_element_visible(selector, by=by):
2330
2371
  self.click(selector, by=by)
2331
2372
  elif timeout > 0:
2332
- try:
2373
+ with suppress(Exception):
2333
2374
  self.wait_for_element_visible(
2334
2375
  selector, by=by, timeout=timeout
2335
2376
  )
2336
- except Exception:
2337
- pass
2338
2377
  if self.is_element_visible(selector, by=by):
2339
2378
  self.click(selector, by=by)
2340
2379
 
2341
2380
  def click_active_element(self):
2381
+ if self.__is_cdp_swap_needed():
2382
+ self.cdp.click_active_element()
2383
+ return
2342
2384
  self.wait_for_ready_state_complete()
2343
2385
  pre_action_url = None
2344
- try:
2386
+ with suppress(Exception):
2345
2387
  pre_action_url = self.driver.current_url
2346
- except Exception:
2347
- pass
2348
2388
  pre_window_count = len(self.driver.window_handles)
2349
2389
  if self.recorder_mode:
2350
2390
  selector = js_utils.get_active_element_css(self.driver)
@@ -2448,16 +2488,14 @@ class BaseCase(unittest.TestCase):
2448
2488
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
2449
2489
  timeout = self.__get_new_timeout(timeout)
2450
2490
  selector, by = self.__recalculate_selector(selector, by)
2491
+ if self.__is_cdp_swap_needed():
2492
+ return self.cdp.is_checked(selector)
2451
2493
  kind = self.get_attribute(selector, "type", by=by, timeout=timeout)
2452
2494
  if kind != "checkbox" and kind != "radio":
2453
2495
  raise Exception("Expecting a checkbox or a radio button element!")
2454
- is_checked = self.get_attribute(
2496
+ return self.get_attribute(
2455
2497
  selector, "checked", by=by, timeout=timeout, hard_fail=False
2456
2498
  )
2457
- if is_checked:
2458
- return True
2459
- else: # (NoneType)
2460
- return False
2461
2499
 
2462
2500
  def is_selected(self, selector, by="css selector", timeout=None):
2463
2501
  """Same as is_checked()"""
@@ -2467,6 +2505,9 @@ class BaseCase(unittest.TestCase):
2467
2505
  """If a checkbox or radio button is not checked, will check it."""
2468
2506
  self.__check_scope()
2469
2507
  selector, by = self.__recalculate_selector(selector, by)
2508
+ if self.__is_cdp_swap_needed():
2509
+ self.cdp.check_if_unchecked(selector)
2510
+ return
2470
2511
  if not self.is_checked(selector, by=by):
2471
2512
  if self.is_element_visible(selector, by=by):
2472
2513
  self.click(selector, by=by)
@@ -2477,12 +2518,10 @@ class BaseCase(unittest.TestCase):
2477
2518
  )
2478
2519
  # Handle switches that sit on checkboxes with zero opacity:
2479
2520
  # Change the opacity a bit to allow the click to succeed.
2480
- try:
2521
+ with suppress(Exception):
2481
2522
  self.execute_script(
2482
2523
  'arguments[0].style.opacity="0.001";', element
2483
2524
  )
2484
- except Exception:
2485
- pass
2486
2525
  if self.is_element_visible(selector, by=by):
2487
2526
  self.click(selector, by=by)
2488
2527
  else:
@@ -2490,14 +2529,12 @@ class BaseCase(unittest.TestCase):
2490
2529
  self.__dont_record_js_click = True
2491
2530
  self.js_click(selector, by="css selector")
2492
2531
  self.__dont_record_js_click = False
2493
- try:
2532
+ with suppress(Exception):
2494
2533
  self.execute_script(
2495
2534
  'arguments[0].style.opacity="arguments[1]";',
2496
2535
  element,
2497
2536
  opacity,
2498
2537
  )
2499
- except Exception:
2500
- pass
2501
2538
 
2502
2539
  def select_if_unselected(self, selector, by="css selector"):
2503
2540
  """Same as check_if_unchecked()"""
@@ -2507,6 +2544,9 @@ class BaseCase(unittest.TestCase):
2507
2544
  """If a checkbox is checked, will uncheck it."""
2508
2545
  self.__check_scope()
2509
2546
  selector, by = self.__recalculate_selector(selector, by)
2547
+ if self.__is_cdp_swap_needed():
2548
+ self.cdp.uncheck_if_checked(selector)
2549
+ return
2510
2550
  if self.is_checked(selector, by=by):
2511
2551
  if self.is_element_visible(selector, by=by):
2512
2552
  self.click(selector, by=by)
@@ -2517,12 +2557,10 @@ class BaseCase(unittest.TestCase):
2517
2557
  )
2518
2558
  # Handle switches that sit on checkboxes with zero opacity:
2519
2559
  # Change the opacity a bit to allow the click to succeed.
2520
- try:
2560
+ with suppress(Exception):
2521
2561
  self.execute_script(
2522
2562
  'arguments[0].style.opacity="0.001";', element
2523
2563
  )
2524
- except Exception:
2525
- pass
2526
2564
  if self.is_element_visible(selector, by=by):
2527
2565
  self.click(selector, by=by)
2528
2566
  else:
@@ -2530,14 +2568,12 @@ class BaseCase(unittest.TestCase):
2530
2568
  self.__dont_record_js_click = True
2531
2569
  self.js_click(selector, by="css selector")
2532
2570
  self.__dont_record_js_click = False
2533
- try:
2571
+ with suppress(Exception):
2534
2572
  self.execute_script(
2535
2573
  'arguments[0].style.opacity="arguments[1]";',
2536
2574
  element,
2537
2575
  opacity,
2538
2576
  )
2539
- except Exception:
2540
- pass
2541
2577
 
2542
2578
  def unselect_if_selected(self, selector, by="css selector"):
2543
2579
  """Same as uncheck_if_checked()"""
@@ -2596,14 +2632,12 @@ class BaseCase(unittest.TestCase):
2596
2632
  iframe_identifier = '[class="%s"]' % iframe_class
2597
2633
  else:
2598
2634
  continue
2599
- try:
2635
+ with suppress(Exception):
2600
2636
  self.switch_to_frame(iframe_identifier, timeout=1)
2601
2637
  if self.__needs_minimum_wait():
2602
2638
  time.sleep(0.02)
2603
2639
  if self.is_element_present(selector, by=by):
2604
2640
  return iframe_identifier
2605
- except Exception:
2606
- pass
2607
2641
  self.switch_to_default_content()
2608
2642
  if self.__needs_minimum_wait():
2609
2643
  time.sleep(0.02)
@@ -2629,6 +2663,9 @@ class BaseCase(unittest.TestCase):
2629
2663
  original_selector = selector
2630
2664
  original_by = by
2631
2665
  selector, by = self.__recalculate_selector(selector, by)
2666
+ if self.__is_cdp_swap_needed():
2667
+ self.cdp.gui_hover_element(selector)
2668
+ return
2632
2669
  self.wait_for_element_visible(
2633
2670
  original_selector, by=original_by, timeout=timeout
2634
2671
  )
@@ -2671,16 +2708,17 @@ class BaseCase(unittest.TestCase):
2671
2708
  click_selector, click_by = self.__recalculate_selector(
2672
2709
  click_selector, click_by
2673
2710
  )
2711
+ if self.__is_cdp_swap_needed():
2712
+ self.cdp.gui_hover_and_click(hover_selector, click_selector)
2713
+ return
2674
2714
  dropdown_element = self.wait_for_element_visible(
2675
2715
  original_selector, by=original_by, timeout=timeout
2676
2716
  )
2677
2717
  self.__demo_mode_highlight_if_active(original_selector, original_by)
2678
2718
  self.scroll_to(hover_selector, by=hover_by)
2679
2719
  pre_action_url = None
2680
- try:
2720
+ with suppress(Exception):
2681
2721
  pre_action_url = self.driver.current_url
2682
- except Exception:
2683
- pass
2684
2722
  pre_window_count = len(self.driver.window_handles)
2685
2723
  if self.recorder_mode and self.__current_url_is_recordable():
2686
2724
  if self.get_session_storage_item("pause_recorder") == "no":
@@ -2744,10 +2782,8 @@ class BaseCase(unittest.TestCase):
2744
2782
  self.__switch_to_newest_window_if_not_blank()
2745
2783
  elif self.browser == "safari":
2746
2784
  # Release the hover by hovering elsewhere
2747
- try:
2785
+ with suppress(Exception):
2748
2786
  page_actions.hover_on_element(self.driver, "body")
2749
- except Exception:
2750
- pass
2751
2787
  if self.demo_mode:
2752
2788
  if self.driver.current_url != pre_action_url:
2753
2789
  if not js_utils.is_jquery_activated(self.driver):
@@ -2807,10 +2843,8 @@ class BaseCase(unittest.TestCase):
2807
2843
  self.__demo_mode_highlight_if_active(original_selector, original_by)
2808
2844
  self.scroll_to(hover_selector, by=hover_by)
2809
2845
  pre_action_url = None
2810
- try:
2846
+ with suppress(Exception):
2811
2847
  pre_action_url = self.driver.current_url
2812
- except Exception:
2813
- pass
2814
2848
  pre_window_count = len(self.driver.window_handles)
2815
2849
  outdated_driver = False
2816
2850
  element = None
@@ -2871,7 +2905,7 @@ class BaseCase(unittest.TestCase):
2871
2905
  timeout=None,
2872
2906
  jquery=False,
2873
2907
  ):
2874
- """Drag and drop an element from one selector to another."""
2908
+ """Drag-and-drop an element from one selector to another."""
2875
2909
  self.__check_scope()
2876
2910
  if not timeout:
2877
2911
  timeout = settings.SMALL_TIMEOUT
@@ -2883,6 +2917,9 @@ class BaseCase(unittest.TestCase):
2883
2917
  drop_selector, drop_by = self.__recalculate_selector(
2884
2918
  drop_selector, drop_by
2885
2919
  )
2920
+ if self.__is_cdp_swap_needed():
2921
+ self.cdp.gui_drag_and_drop(drag_selector, drop_selector)
2922
+ return
2886
2923
  drag_element = self.wait_for_element_clickable(
2887
2924
  drag_selector, by=drag_by, timeout=timeout
2888
2925
  )
@@ -2918,7 +2955,7 @@ class BaseCase(unittest.TestCase):
2918
2955
  def drag_and_drop_with_offset(
2919
2956
  self, selector, x, y, by="css selector", timeout=None
2920
2957
  ):
2921
- """Drag and drop an element to an {X,Y}-offset location."""
2958
+ """Drag-and-drop an element to an {X,Y}-offset location."""
2922
2959
  self.__check_scope()
2923
2960
  if not timeout:
2924
2961
  timeout = settings.SMALL_TIMEOUT
@@ -2998,10 +3035,8 @@ class BaseCase(unittest.TestCase):
2998
3035
  dropdown_selector, dropdown_by
2999
3036
  )
3000
3037
  pre_action_url = None
3001
- try:
3038
+ with suppress(Exception):
3002
3039
  pre_action_url = self.driver.current_url
3003
- except Exception:
3004
- pass
3005
3040
  pre_window_count = len(self.driver.window_handles)
3006
3041
  try:
3007
3042
  if option_by == "index":
@@ -3105,6 +3140,9 @@ class BaseCase(unittest.TestCase):
3105
3140
  timeout = settings.SMALL_TIMEOUT
3106
3141
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
3107
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
3108
3146
  self.__select_option(
3109
3147
  dropdown_selector,
3110
3148
  option,
@@ -3276,10 +3314,8 @@ class BaseCase(unittest.TestCase):
3276
3314
  self.open("data:text/html,<head></head><body><div></div></body>")
3277
3315
  inner_head = """document.getElementsByTagName("head")[0].innerHTML"""
3278
3316
  inner_body = """document.getElementsByTagName("body")[0].innerHTML"""
3279
- try:
3317
+ with suppress(Exception):
3280
3318
  self.wait_for_element_present("body", timeout=1)
3281
- except Exception:
3282
- pass
3283
3319
  if not found_body:
3284
3320
  self.execute_script('''%s = \"%s\"''' % (inner_body, html_string))
3285
3321
  elif found_body and not found_head:
@@ -3353,6 +3389,8 @@ class BaseCase(unittest.TestCase):
3353
3389
 
3354
3390
  def execute_script(self, script, *args, **kwargs):
3355
3391
  self.__check_scope()
3392
+ if self.__is_cdp_swap_needed():
3393
+ return self.cdp.evaluate(script)
3356
3394
  self._check_browser()
3357
3395
  return self.driver.execute_script(script, *args, **kwargs)
3358
3396
 
@@ -3378,25 +3416,142 @@ class BaseCase(unittest.TestCase):
3378
3416
  self.activate_jquery()
3379
3417
  return self.driver.execute_script(script, *args, **kwargs)
3380
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
+
3381
3502
  def set_window_rect(self, x, y, width, height):
3382
3503
  self.__check_scope()
3504
+ if self.__is_cdp_swap_needed():
3505
+ self.cdp.set_window_rect(x, y, width, height)
3506
+ return
3383
3507
  self._check_browser()
3384
3508
  self.driver.set_window_rect(x, y, width, height)
3385
- self.__demo_mode_pause_if_active()
3509
+ self.__demo_mode_pause_if_active(tiny=True)
3386
3510
 
3387
3511
  def set_window_size(self, width, height):
3388
3512
  self.__check_scope()
3389
3513
  self._check_browser()
3390
3514
  self.driver.set_window_size(width, height)
3391
- 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)
3392
3522
 
3393
3523
  def maximize_window(self):
3394
3524
  self.__check_scope()
3525
+ if self.__is_cdp_swap_needed():
3526
+ self.cdp.maximize()
3527
+ return
3395
3528
  self._check_browser()
3396
3529
  self.driver.maximize_window()
3397
- self.__demo_mode_pause_if_active()
3530
+ self.__demo_mode_pause_if_active(tiny=True)
3398
3531
 
3399
- def switch_to_frame(self, frame, timeout=None):
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)
3553
+
3554
+ def switch_to_frame(self, frame="iframe", timeout=None):
3400
3555
  """Wait for an iframe to appear, and switch to it. This should be
3401
3556
  usable as a drop-in replacement for driver.switch_to.frame().
3402
3557
  The iframe identifier can be a selector, an index, an id, a name,
@@ -3723,7 +3878,11 @@ class BaseCase(unittest.TestCase):
3723
3878
  """Opens a new browser tab/window and switches to it by default."""
3724
3879
  self.wait_for_ready_state_complete()
3725
3880
  if switch_to:
3726
- 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()
3727
3886
  else:
3728
3887
  self.driver.execute_script("window.open('');")
3729
3888
  time.sleep(0.01)
@@ -3764,6 +3923,7 @@ class BaseCase(unittest.TestCase):
3764
3923
  cap_file=None,
3765
3924
  cap_string=None,
3766
3925
  recorder_ext=None,
3926
+ disable_cookies=None,
3767
3927
  disable_js=None,
3768
3928
  disable_csp=None,
3769
3929
  enable_ws=None,
@@ -3775,6 +3935,7 @@ class BaseCase(unittest.TestCase):
3775
3935
  log_cdp_events=None,
3776
3936
  no_sandbox=None,
3777
3937
  disable_gpu=None,
3938
+ headless1=None,
3778
3939
  headless2=None,
3779
3940
  incognito=None,
3780
3941
  guest_mode=None,
@@ -3823,6 +3984,7 @@ class BaseCase(unittest.TestCase):
3823
3984
  cap_file - the file containing desired capabilities for the browser
3824
3985
  cap_string - the string with desired capabilities for the browser
3825
3986
  recorder_ext - the option to enable the SBase Recorder extension
3987
+ disable_cookies - the option to disable Cookies (May break things!)
3826
3988
  disable_js - the option to disable JavaScript (May break websites!)
3827
3989
  disable_csp - an option to disable Chrome's Content Security Policy
3828
3990
  enable_ws - the option to enable the Web Security feature (Chrome)
@@ -3834,6 +3996,7 @@ class BaseCase(unittest.TestCase):
3834
3996
  log_cdp_events - capture {"performance": "ALL", "browser": "ALL"})
3835
3997
  no_sandbox - the option to enable the "No-Sandbox" feature (Chrome)
3836
3998
  disable_gpu - the option to enable Chrome's "Disable GPU" feature
3999
+ headless1 - the option to use the older headless mode (Chromium)
3837
4000
  headless2 - the option to use the newer headless mode (Chromium)
3838
4001
  incognito - the option to enable Chrome's Incognito mode (Chrome)
3839
4002
  guest_mode - the option to enable Chrome's Guest mode (Chrome)
@@ -3920,6 +4083,8 @@ class BaseCase(unittest.TestCase):
3920
4083
  user_agent = self.user_agent
3921
4084
  if recorder_ext is None:
3922
4085
  recorder_ext = self.recorder_ext
4086
+ if disable_cookies is None:
4087
+ disable_cookies = self.disable_cookies
3923
4088
  if disable_js is None:
3924
4089
  disable_js = self.disable_js
3925
4090
  if disable_csp is None:
@@ -3942,6 +4107,8 @@ class BaseCase(unittest.TestCase):
3942
4107
  no_sandbox = self.no_sandbox
3943
4108
  if disable_gpu is None:
3944
4109
  disable_gpu = self.disable_gpu
4110
+ if headless1 is None:
4111
+ headless1 = self.headless1
3945
4112
  if headless2 is None:
3946
4113
  headless2 = self.headless2
3947
4114
  if incognito is None:
@@ -4013,8 +4180,6 @@ class BaseCase(unittest.TestCase):
4013
4180
  "Valid options = {%s}" % (browser, valid_browsers)
4014
4181
  )
4015
4182
  # Launch a web browser
4016
- from seleniumbase.core import browser_launcher
4017
-
4018
4183
  new_driver = browser_launcher.get_driver(
4019
4184
  browser_name=browser_name,
4020
4185
  headless=headless,
@@ -4031,6 +4196,7 @@ class BaseCase(unittest.TestCase):
4031
4196
  cap_file=cap_file,
4032
4197
  cap_string=cap_string,
4033
4198
  recorder_ext=recorder_ext,
4199
+ disable_cookies=disable_cookies,
4034
4200
  disable_js=disable_js,
4035
4201
  disable_csp=disable_csp,
4036
4202
  enable_ws=enable_ws,
@@ -4042,6 +4208,7 @@ class BaseCase(unittest.TestCase):
4042
4208
  log_cdp_events=log_cdp_events,
4043
4209
  no_sandbox=no_sandbox,
4044
4210
  disable_gpu=disable_gpu,
4211
+ headless1=headless1,
4045
4212
  headless2=headless2,
4046
4213
  incognito=incognito,
4047
4214
  guest_mode=guest_mode,
@@ -4110,7 +4277,8 @@ class BaseCase(unittest.TestCase):
4110
4277
  self.driver.maximize_window()
4111
4278
  self.wait_for_ready_state_complete()
4112
4279
  else:
4113
- self.driver.set_window_size(width, height)
4280
+ with suppress(Exception):
4281
+ self.driver.set_window_size(width, height)
4114
4282
  except Exception:
4115
4283
  pass # Keep existing browser resolution
4116
4284
  elif self.browser == "safari":
@@ -4121,10 +4289,8 @@ class BaseCase(unittest.TestCase):
4121
4289
  except Exception:
4122
4290
  pass # Keep existing browser resolution
4123
4291
  else:
4124
- try:
4125
- self.driver.set_window_rect(10, 20, width, height)
4126
- except Exception:
4127
- pass
4292
+ with suppress(Exception):
4293
+ self.driver.set_window_rect(10, 46, width, height)
4128
4294
  if self.start_page and len(self.start_page) >= 4:
4129
4295
  if page_utils.is_valid_url(self.start_page):
4130
4296
  self.open(self.start_page)
@@ -4134,6 +4300,51 @@ class BaseCase(unittest.TestCase):
4134
4300
  self.__dont_record_open = True
4135
4301
  self.open(new_start_page)
4136
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
4137
4348
  return new_driver
4138
4349
 
4139
4350
  def switch_to_driver(self, driver):
@@ -4163,6 +4374,9 @@ class BaseCase(unittest.TestCase):
4163
4374
  If a provided selector is not found, then takes a full-page screenshot.
4164
4375
  If the folder provided doesn't exist, it will get created.
4165
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
4166
4380
  self.wait_for_ready_state_complete()
4167
4381
  if selector and by:
4168
4382
  selector, by = self.__recalculate_selector(selector, by)
@@ -4278,7 +4492,8 @@ class BaseCase(unittest.TestCase):
4278
4492
  @Params
4279
4493
  name - The file name to save the current page's HTML to.
4280
4494
  folder - The folder to save the file to. (Default = current folder)"""
4281
- self.wait_for_ready_state_complete()
4495
+ if not self.__is_cdp_swap_needed():
4496
+ self.wait_for_ready_state_complete()
4282
4497
  return page_actions.save_page_source(self.driver, name, folder)
4283
4498
 
4284
4499
  def save_cookies(self, name="cookies.txt"):
@@ -4306,35 +4521,39 @@ class BaseCase(unittest.TestCase):
4306
4521
  cookies_file.writelines(json_cookies)
4307
4522
  cookies_file.close()
4308
4523
 
4309
- def load_cookies(self, name="cookies.txt"):
4310
- """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)
4311
4534
  self.wait_for_ready_state_complete()
4312
- if name.endswith("/"):
4313
- raise Exception("Invalid filename for Cookies!")
4314
- if "/" in name:
4315
- name = name.split("/")[-1]
4316
- if "\\" in name:
4317
- name = name.split("\\")[-1]
4318
- if len(name) < 1:
4319
- raise Exception("Filename for Cookies is too short!")
4320
- if not name.endswith(".txt"):
4321
- name = name + ".txt"
4322
- folder = constants.SavedCookies.STORAGE_FOLDER
4323
- abs_path = os.path.abspath(".")
4324
- file_path = os.path.join(abs_path, folder)
4325
- cookies_file_path = os.path.join(file_path, name)
4326
- json_cookies = None
4327
- with open(cookies_file_path, "r") as f:
4328
- json_cookies = f.read().strip()
4329
- cookies = json.loads(json_cookies)
4535
+ origin = self.get_origin()
4536
+ trim_origin = origin.split("://")[-1]
4330
4537
  for cookie in cookies:
4331
- 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):
4332
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
4333
4549
  self.driver.add_cookie(cookie)
4334
4550
 
4335
4551
  def delete_all_cookies(self):
4336
4552
  """Deletes all cookies in the web browser.
4337
4553
  Does NOT delete the saved cookies file."""
4554
+ if self.__is_cdp_swap_needed():
4555
+ self.cdp.clear_cookies()
4556
+ return
4338
4557
  self.wait_for_ready_state_complete()
4339
4558
  self.driver.delete_all_cookies()
4340
4559
  if self.recorder_mode:
@@ -4346,7 +4565,6 @@ class BaseCase(unittest.TestCase):
4346
4565
  def delete_saved_cookies(self, name="cookies.txt"):
4347
4566
  """Deletes the cookies file from the "saved_cookies" folder.
4348
4567
  Does NOT delete the cookies from the web browser."""
4349
- self.wait_for_ready_state_complete()
4350
4568
  if name.endswith("/"):
4351
4569
  raise Exception("Invalid filename for Cookies!")
4352
4570
  if "/" in name:
@@ -4363,11 +4581,129 @@ class BaseCase(unittest.TestCase):
4363
4581
  if cookies_file_path.endswith(".txt"):
4364
4582
  os.remove(cookies_file_path)
4365
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
+
4366
4701
  def wait_for_ready_state_complete(self, timeout=None):
4367
4702
  """Waits for the "readyState" of the page to be "complete".
4368
4703
  Returns True when the method completes."""
4369
4704
  self.__check_scope()
4370
4705
  self._check_browser()
4706
+ self.__skip_if_esc()
4371
4707
  if not timeout:
4372
4708
  timeout = settings.EXTREME_TIMEOUT
4373
4709
  if self.timeout_multiplier and timeout == settings.EXTREME_TIMEOUT:
@@ -4386,6 +4722,7 @@ class BaseCase(unittest.TestCase):
4386
4722
  time.sleep(0.01)
4387
4723
  if self.undetectable:
4388
4724
  time.sleep(0.035)
4725
+ self.__set_esc_skip()
4389
4726
  return True
4390
4727
 
4391
4728
  def wait_for_angularjs(self, timeout=None, **kwargs):
@@ -4473,24 +4810,35 @@ class BaseCase(unittest.TestCase):
4473
4810
  script = """document.designMode = 'on';"""
4474
4811
  self.execute_script(script)
4475
4812
 
4476
- def deactivate_design_mode(self):
4813
+ def deactivate_design_mode(self, url=None):
4477
4814
  # Deactivate Chrome's Design Mode.
4478
4815
  self.wait_for_ready_state_complete()
4479
4816
  script = """document.designMode = 'off';"""
4480
4817
  self.execute_script(script)
4481
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
+
4482
4827
  def activate_recorder(self):
4483
4828
  from seleniumbase.js_code.recorder_js import recorder_js
4484
4829
 
4485
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
4486
4836
  raise Exception(
4487
- "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
4488
4839
  )
4489
4840
  url = self.driver.current_url
4490
- if (
4491
- url.startswith("data:") or url.startswith("about:")
4492
- or url.startswith("chrome:") or url.startswith("edge:")
4493
- ):
4841
+ if url.startswith(("data:", "about:", "chrome:", "edge:")):
4494
4842
  message = (
4495
4843
  "The URL in Recorder-Mode cannot start with: "
4496
4844
  '"data:", "about:", "chrome:", or "edge:"!'
@@ -4499,7 +4847,7 @@ class BaseCase(unittest.TestCase):
4499
4847
  return
4500
4848
  if self.recorder_ext:
4501
4849
  return # The Recorder extension is already active
4502
- try:
4850
+ with suppress(Exception):
4503
4851
  recorder_on = self.get_session_storage_item("recorder_activated")
4504
4852
  if not recorder_on == "yes":
4505
4853
  self.execute_script(recorder_js)
@@ -4508,8 +4856,6 @@ class BaseCase(unittest.TestCase):
4508
4856
  print("\n" + message)
4509
4857
  p_msg = "Recorder Mode ACTIVE.<br>[ESC]: Pause. [~`]: Resume."
4510
4858
  self.post_message(p_msg, pause=False, style="error")
4511
- except Exception:
4512
- pass
4513
4859
 
4514
4860
  def __current_url_is_recordable(self):
4515
4861
  url = self.get_current_url()
@@ -4549,10 +4895,7 @@ class BaseCase(unittest.TestCase):
4549
4895
 
4550
4896
  def __get_recorded_actions_on_active_tab(self):
4551
4897
  url = self.driver.current_url
4552
- if (
4553
- url.startswith("data:") or url.startswith("about:")
4554
- or url.startswith("chrome:") or url.startswith("edge:")
4555
- ):
4898
+ if url.startswith(("data:", "about:", "chrome:", "edge:")):
4556
4899
  return []
4557
4900
  self.__origins_to_save.append(self.get_origin())
4558
4901
  actions = self.get_session_storage_item("recorded_actions")
@@ -4563,9 +4906,9 @@ class BaseCase(unittest.TestCase):
4563
4906
  return []
4564
4907
 
4565
4908
  def __process_recorded_actions(self):
4909
+ """Generates code after the SeleniumBase Recorder runs."""
4566
4910
  if self.driver is None:
4567
4911
  return
4568
- import colorama
4569
4912
  from seleniumbase.core import recorder_helper
4570
4913
 
4571
4914
  raw_actions = [] # All raw actions from sessionStorage
@@ -4767,10 +5110,7 @@ class BaseCase(unittest.TestCase):
4767
5110
  or srt_actions[n - 1][0] == "jq_cl"
4768
5111
  or srt_actions[n - 1][0] == "jq_ca"
4769
5112
  ):
4770
- if (
4771
- srt_actions[n - 1][1].startswith("input")
4772
- or srt_actions[n - 1][1].startswith("button")
4773
- ):
5113
+ if srt_actions[n - 1][1].startswith(("input", "button")):
4774
5114
  srt_actions[n][0] = "f_url"
4775
5115
  elif srt_actions[n - 1][0] == "input":
4776
5116
  if srt_actions[n - 1][2].endswith("\n"):
@@ -5118,7 +5458,6 @@ class BaseCase(unittest.TestCase):
5118
5458
  and (filename == "base_case.py" or methodname == "runTest")
5119
5459
  ):
5120
5460
  import traceback
5121
-
5122
5461
  stack_base = traceback.format_stack()[0].split(os.sep)[-1]
5123
5462
  test_base = stack_base.split(", in ")[0]
5124
5463
  if hasattr(self, "cm_filename") and self.cm_filename:
@@ -5166,7 +5505,10 @@ class BaseCase(unittest.TestCase):
5166
5505
  new_file = True
5167
5506
  sb_config._recorded_actions[filename] = []
5168
5507
  data.append("from seleniumbase import BaseCase")
5169
- 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__)")
5170
5512
  data.append("")
5171
5513
  data.append("")
5172
5514
  data.append("class %s(BaseCase):" % classname)
@@ -5176,7 +5518,13 @@ class BaseCase(unittest.TestCase):
5176
5518
  data.append("class %s(BaseCase):" % classname)
5177
5519
  data.append(" def %s(self):" % methodname)
5178
5520
  if len(sb_actions) > 0:
5521
+ if "--uc" in sys.argv:
5522
+ data.append(" self.activate_cdp_mode()")
5179
5523
  for action in sb_actions:
5524
+ if "--uc" in sys.argv:
5525
+ action = action.replace(
5526
+ "self.type(", "self.press_keys("
5527
+ )
5180
5528
  data.append(" " + action)
5181
5529
  else:
5182
5530
  data.append(" pass")
@@ -5188,11 +5536,9 @@ class BaseCase(unittest.TestCase):
5188
5536
  if recordings_folder.endswith("/"):
5189
5537
  recordings_folder = recordings_folder[:-1]
5190
5538
  if not os.path.exists(recordings_folder):
5191
- try:
5539
+ with suppress(Exception):
5192
5540
  os.makedirs(recordings_folder)
5193
5541
  sys.stdout.write("\nCreated recordings%s" % os.sep)
5194
- except Exception:
5195
- pass
5196
5542
 
5197
5543
  data = []
5198
5544
  data.append("")
@@ -5293,12 +5639,10 @@ class BaseCase(unittest.TestCase):
5293
5639
  if not new_file:
5294
5640
  rec_message = ">>> RECORDING ADDED to: "
5295
5641
  star_len = len(rec_message) + len(file_path)
5296
- try:
5642
+ with suppress(Exception):
5297
5643
  terminal_size = os.get_terminal_size().columns
5298
5644
  if terminal_size > 30 and star_len > terminal_size:
5299
5645
  star_len = terminal_size
5300
- except Exception:
5301
- pass
5302
5646
  spc = "\n\n"
5303
5647
  if hasattr(self, "rec_print") and self.rec_print:
5304
5648
  spc = ""
@@ -5358,6 +5702,9 @@ class BaseCase(unittest.TestCase):
5358
5702
  data.append(" Scenario: %s" % scenario_test)
5359
5703
  if len(behave_actions) > 0:
5360
5704
  count = 0
5705
+ if "--uc" in sys.argv:
5706
+ data.append(" Given Activate CDP Mode")
5707
+ count += 1
5361
5708
  for action in behave_actions:
5362
5709
  if count == 0:
5363
5710
  data.append(" Given " + action)
@@ -5371,22 +5718,16 @@ class BaseCase(unittest.TestCase):
5371
5718
  if recordings_folder.endswith("/"):
5372
5719
  recordings_folder = recordings_folder[:-1]
5373
5720
  if not os.path.exists(recordings_folder):
5374
- try:
5721
+ with suppress(Exception):
5375
5722
  os.makedirs(recordings_folder)
5376
- except Exception:
5377
- pass
5378
5723
  features_folder = os.path.join(recordings_folder, "features")
5379
5724
  if not os.path.exists(features_folder):
5380
- try:
5725
+ with suppress(Exception):
5381
5726
  os.makedirs(features_folder)
5382
- except Exception:
5383
- pass
5384
5727
  steps_folder = os.path.join(features_folder, "steps")
5385
5728
  if not os.path.exists(steps_folder):
5386
- try:
5729
+ with suppress(Exception):
5387
5730
  os.makedirs(steps_folder)
5388
- except Exception:
5389
- pass
5390
5731
 
5391
5732
  file_name = filename.split(".")[0]
5392
5733
  if hasattr(self, "is_behave") and self.is_behave:
@@ -5401,12 +5742,10 @@ class BaseCase(unittest.TestCase):
5401
5742
  if not new_file:
5402
5743
  rec_message = ">>> RECORDING ADDED to: "
5403
5744
  star_len = len(rec_message) + len(file_path)
5404
- try:
5745
+ with suppress(Exception):
5405
5746
  terminal_size = os.get_terminal_size().columns
5406
5747
  if terminal_size > 30 and star_len > terminal_size:
5407
5748
  star_len = terminal_size
5408
- except Exception:
5409
- pass
5410
5749
  spc = "\n"
5411
5750
  if hasattr(self, "rec_print") and self.rec_print:
5412
5751
  spc = ""
@@ -5512,16 +5851,17 @@ class BaseCase(unittest.TestCase):
5512
5851
  print("Created recordings/features/steps/imported.py")
5513
5852
 
5514
5853
  def bring_active_window_to_front(self):
5515
- """Brings the active browser window to the front.
5516
- 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."""
5517
5856
  self.__check_scope()
5518
- try:
5857
+ if self.__is_cdp_swap_needed():
5858
+ self.cdp.bring_active_window_to_front()
5859
+ return
5860
+ with suppress(Exception):
5519
5861
  if not self.__is_in_frame():
5520
5862
  # Only bring the window to the front if not in a frame
5521
5863
  # because the driver resets itself to default content.
5522
5864
  self.switch_to_window(self.driver.current_window_handle)
5523
- except Exception:
5524
- pass
5525
5865
 
5526
5866
  def bring_to_front(self, selector, by="css selector"):
5527
5867
  """Updates the Z-index of a page element to bring it into view.
@@ -5551,7 +5891,7 @@ class BaseCase(unittest.TestCase):
5551
5891
  def highlight_click(
5552
5892
  self, selector, by="css selector", loops=3, scroll=True, timeout=None,
5553
5893
  ):
5554
- """Highlights the element and then clicks it."""
5894
+ """Highlights the element, and then clicks it."""
5555
5895
  self.__check_scope()
5556
5896
  if not timeout:
5557
5897
  timeout = settings.SMALL_TIMEOUT
@@ -5605,11 +5945,43 @@ class BaseCase(unittest.TestCase):
5605
5945
  if self.is_element_visible(selector, by=by):
5606
5946
  self.__highlight(selector, by=by, loops=loops, scroll=scroll)
5607
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
+
5608
5980
  def __highlight(
5609
5981
  self, selector, by="css selector", loops=None, scroll=True
5610
5982
  ):
5611
5983
  """This method uses fancy JavaScript to highlight an element.
5612
- (Commonly used during Demo Mode automatically)"""
5984
+ (Automatically using in S_e_l_e_n_i_u_m_B_a_s_e Demo Mode)"""
5613
5985
  self.__check_scope()
5614
5986
  selector, by = self.__recalculate_selector(selector, by, xp_ok=False)
5615
5987
  element = self.wait_for_element_visible(
@@ -5693,13 +6065,19 @@ class BaseCase(unittest.TestCase):
5693
6065
  ):
5694
6066
  """This method uses fancy JavaScript to highlight an element.
5695
6067
  @Params
5696
- selector - the selector of the element to find
6068
+ selector - the selector of the element to find (Accepts WebElement)
5697
6069
  by - the type of selector to search by (Default: CSS)
5698
6070
  loops - # of times to repeat the highlight animation
5699
6071
  (Default: 4. Each loop lasts for about 0.2s)
5700
6072
  scroll - the option to scroll to the element first (Default: True)
5701
6073
  timeout - the time to wait for the element to appear """
5702
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
5703
6081
  if not timeout:
5704
6082
  timeout = settings.SMALL_TIMEOUT
5705
6083
  self.wait_for_element_visible(selector, by=by, timeout=timeout)
@@ -5711,7 +6089,30 @@ class BaseCase(unittest.TestCase):
5711
6089
  action = ["hi_li", selector, origin, time_stamp]
5712
6090
  self.__extra_actions.append(action)
5713
6091
 
5714
- 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"):
5715
6116
  """Simulates pressing the UP Arrow on the keyboard.
5716
6117
  By default, "html" will be used as the CSS Selector target.
5717
6118
  You can specify how many times in-a-row the action happens."""
@@ -5733,7 +6134,7 @@ class BaseCase(unittest.TestCase):
5733
6134
  if self.slow_mode:
5734
6135
  time.sleep(0.1)
5735
6136
 
5736
- 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"):
5737
6138
  """Simulates pressing the DOWN Arrow on the keyboard.
5738
6139
  By default, "html" will be used as the CSS Selector target.
5739
6140
  You can specify how many times in-a-row the action happens."""
@@ -5755,7 +6156,7 @@ class BaseCase(unittest.TestCase):
5755
6156
  if self.slow_mode:
5756
6157
  time.sleep(0.1)
5757
6158
 
5758
- 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"):
5759
6160
  """Simulates pressing the LEFT Arrow on the keyboard.
5760
6161
  By default, "html" will be used as the CSS Selector target.
5761
6162
  You can specify how many times in-a-row the action happens."""
@@ -5777,7 +6178,7 @@ class BaseCase(unittest.TestCase):
5777
6178
  if self.slow_mode:
5778
6179
  time.sleep(0.1)
5779
6180
 
5780
- 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"):
5781
6182
  """Simulates pressing the RIGHT Arrow on the keyboard.
5782
6183
  By default, "html" will be used as the CSS Selector target.
5783
6184
  You can specify how many times in-a-row the action happens."""
@@ -5806,6 +6207,9 @@ class BaseCase(unittest.TestCase):
5806
6207
  timeout = settings.SMALL_TIMEOUT
5807
6208
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
5808
6209
  timeout = self.__get_new_timeout(timeout)
6210
+ if self.__is_cdp_swap_needed():
6211
+ self.cdp.scroll_into_view(selector)
6212
+ return
5809
6213
  if self.demo_mode or self.slow_mode:
5810
6214
  self.slow_scroll_to(selector, by=by, timeout=timeout)
5811
6215
  return
@@ -5836,6 +6240,9 @@ class BaseCase(unittest.TestCase):
5836
6240
  original_selector = selector
5837
6241
  original_by = by
5838
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
5839
6246
  element = self.wait_for_element_visible(
5840
6247
  original_selector, by=original_by, timeout=timeout
5841
6248
  )
@@ -5873,30 +6280,45 @@ class BaseCase(unittest.TestCase):
5873
6280
  timeout = settings.SMALL_TIMEOUT
5874
6281
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
5875
6282
  timeout = self.__get_new_timeout(timeout)
6283
+ if self.__is_cdp_swap_needed():
6284
+ self.cdp.scroll_into_view(selector)
6285
+ return
5876
6286
  element = self.wait_for_element_visible(selector, by, timeout=timeout)
5877
6287
  self.execute_script("arguments[0].scrollIntoView();", element)
5878
6288
 
5879
6289
  def scroll_to_top(self):
5880
6290
  """Scroll to the top of the page."""
5881
6291
  self.__check_scope()
6292
+ if self.__is_cdp_swap_needed():
6293
+ self.cdp.scroll_to_top()
6294
+ return
5882
6295
  scroll_script = "window.scrollTo(0, 0);"
5883
- try:
6296
+ with suppress(Exception):
5884
6297
  self.execute_script(scroll_script)
5885
6298
  time.sleep(0.012)
5886
- return True
5887
- except Exception:
5888
- return False
5889
6299
 
5890
6300
  def scroll_to_bottom(self):
5891
6301
  """Scroll to the bottom of the page."""
5892
6302
  self.__check_scope()
6303
+ if self.__is_cdp_swap_needed():
6304
+ self.cdp.scroll_to_bottom()
6305
+ return
5893
6306
  scroll_script = "window.scrollTo(0, 10000);"
5894
- 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):
5895
6320
  self.execute_script(scroll_script)
5896
6321
  time.sleep(0.012)
5897
- return True
5898
- except Exception:
5899
- return False
5900
6322
 
5901
6323
  def click_xpath(self, xpath):
5902
6324
  """Technically, self.click() automatically detects xpath selectors,
@@ -5915,6 +6337,9 @@ class BaseCase(unittest.TestCase):
5915
6337
  Can be used to click hidden / invisible elements.
5916
6338
  If "all_matches" is False, only the first match is clicked.
5917
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
5918
6343
  self.wait_for_ready_state_complete()
5919
6344
  if not timeout or timeout is True:
5920
6345
  timeout = settings.SMALL_TIMEOUT
@@ -5954,10 +6379,8 @@ class BaseCase(unittest.TestCase):
5954
6379
  time_stamp = 0
5955
6380
  action = ["", "", "", time_stamp]
5956
6381
  pre_action_url = None
5957
- try:
6382
+ with suppress(Exception):
5958
6383
  pre_action_url = self.driver.current_url
5959
- except Exception:
5960
- pass
5961
6384
  pre_window_count = len(self.driver.window_handles)
5962
6385
  if self.recorder_mode and not self.__dont_record_js_click:
5963
6386
  time_stamp = self.execute_script("return Date.now();")
@@ -6059,10 +6482,8 @@ class BaseCase(unittest.TestCase):
6059
6482
  # If a click closes the active window,
6060
6483
  # switch to the last one if it exists.
6061
6484
  self.switch_to_window(-1)
6062
- try:
6485
+ with suppress(Exception):
6063
6486
  self.wait_for_ready_state_complete()
6064
- except Exception:
6065
- pass
6066
6487
  self.__demo_mode_pause_if_active()
6067
6488
 
6068
6489
  def js_click_if_present(self, selector, by="css selector", timeout=0):
@@ -6074,10 +6495,8 @@ class BaseCase(unittest.TestCase):
6074
6495
  if self.is_element_present(selector, by=by):
6075
6496
  self.js_click(selector, by=by)
6076
6497
  elif timeout > 0:
6077
- try:
6498
+ with suppress(Exception):
6078
6499
  self.wait_for_element_present(selector, by=by, timeout=timeout)
6079
- except Exception:
6080
- pass
6081
6500
  if self.is_element_present(selector, by=by):
6082
6501
  self.js_click(selector, by=by)
6083
6502
 
@@ -6090,10 +6509,8 @@ class BaseCase(unittest.TestCase):
6090
6509
  if self.is_element_visible(selector, by=by):
6091
6510
  self.js_click(selector, by=by)
6092
6511
  elif timeout > 0:
6093
- try:
6512
+ with suppress(Exception):
6094
6513
  self.wait_for_element_visible(selector, by=by, timeout=timeout)
6095
- except Exception:
6096
- pass
6097
6514
  if self.is_element_visible(selector, by=by):
6098
6515
  self.js_click(selector, by=by)
6099
6516
 
@@ -6186,13 +6603,11 @@ class BaseCase(unittest.TestCase):
6186
6603
  """Hide the first element on the page that matches the selector."""
6187
6604
  self.__check_scope()
6188
6605
  element = None
6189
- try:
6606
+ with suppress(Exception):
6190
6607
  self.wait_for_element_visible("body", timeout=1.5)
6191
6608
  element = self.wait_for_element_present(
6192
6609
  selector, by=by, timeout=0.5
6193
6610
  )
6194
- except Exception:
6195
- pass
6196
6611
  selector, by = self.__recalculate_selector(selector, by)
6197
6612
  css_selector = self.convert_to_css_selector(selector, by=by)
6198
6613
  if ":contains(" in css_selector and element:
@@ -6218,10 +6633,8 @@ class BaseCase(unittest.TestCase):
6218
6633
  def hide_elements(self, selector, by="css selector"):
6219
6634
  """Hide all elements on the page that match the selector."""
6220
6635
  self.__check_scope()
6221
- try:
6636
+ with suppress(Exception):
6222
6637
  self.wait_for_element_visible("body", timeout=1.5)
6223
- except Exception:
6224
- pass
6225
6638
  selector, by = self.__recalculate_selector(selector, by)
6226
6639
  css_selector = self.convert_to_css_selector(selector, by=by)
6227
6640
  if ":contains(" in css_selector:
@@ -6244,11 +6657,9 @@ class BaseCase(unittest.TestCase):
6244
6657
  """Show the first element on the page that matches the selector."""
6245
6658
  self.__check_scope()
6246
6659
  element = None
6247
- try:
6660
+ with suppress(Exception):
6248
6661
  self.wait_for_element_visible("body", timeout=1.5)
6249
6662
  element = self.wait_for_element_present(selector, by=by, timeout=1)
6250
- except Exception:
6251
- pass
6252
6663
  selector, by = self.__recalculate_selector(selector, by)
6253
6664
  css_selector = self.convert_to_css_selector(selector, by=by)
6254
6665
  if ":contains(" in css_selector and element:
@@ -6274,10 +6685,8 @@ class BaseCase(unittest.TestCase):
6274
6685
  def show_elements(self, selector, by="css selector"):
6275
6686
  """Show all elements on the page that match the selector."""
6276
6687
  self.__check_scope()
6277
- try:
6688
+ with suppress(Exception):
6278
6689
  self.wait_for_element_visible("body", timeout=1.5)
6279
- except Exception:
6280
- pass
6281
6690
  selector, by = self.__recalculate_selector(selector, by)
6282
6691
  css_selector = self.convert_to_css_selector(selector, by=by)
6283
6692
  if ":contains(" in css_selector:
@@ -6299,14 +6708,15 @@ class BaseCase(unittest.TestCase):
6299
6708
  def remove_element(self, selector, by="css selector"):
6300
6709
  """Remove the first element on the page that matches the selector."""
6301
6710
  self.__check_scope()
6711
+ if self.__is_cdp_swap_needed():
6712
+ self.cdp.remove_element(selector)
6713
+ return
6302
6714
  element = None
6303
- try:
6715
+ with suppress(Exception):
6304
6716
  self.wait_for_element_visible("body", timeout=1.5)
6305
6717
  element = self.wait_for_element_present(
6306
6718
  selector, by=by, timeout=0.5
6307
6719
  )
6308
- except Exception:
6309
- pass
6310
6720
  selector, by = self.__recalculate_selector(selector, by)
6311
6721
  css_selector = self.convert_to_css_selector(selector, by=by)
6312
6722
  if ":contains(" in css_selector and element:
@@ -6332,10 +6742,11 @@ class BaseCase(unittest.TestCase):
6332
6742
  def remove_elements(self, selector, by="css selector"):
6333
6743
  """Remove all elements on the page that match the selector."""
6334
6744
  self.__check_scope()
6335
- try:
6745
+ if self.__is_cdp_swap_needed():
6746
+ self.cdp.remove_elements(selector)
6747
+ return
6748
+ with suppress(Exception):
6336
6749
  self.wait_for_element_visible("body", timeout=1.5)
6337
- except Exception:
6338
- pass
6339
6750
  selector, by = self.__recalculate_selector(selector, by)
6340
6751
  css_selector = self.convert_to_css_selector(selector, by=by)
6341
6752
  if ":contains(" in css_selector:
@@ -6400,10 +6811,8 @@ class BaseCase(unittest.TestCase):
6400
6811
  $elements[index].setAttribute('class', new_class);}"""
6401
6812
  % css_selector
6402
6813
  )
6403
- try:
6814
+ with suppress(Exception):
6404
6815
  self.execute_script(script)
6405
- except Exception:
6406
- pass
6407
6816
  if self.recorder_mode and self.__current_url_is_recordable():
6408
6817
  if self.get_session_storage_item("pause_recorder") == "no":
6409
6818
  time_stamp = self.execute_script("return Date.now();")
@@ -6421,10 +6830,8 @@ class BaseCase(unittest.TestCase):
6421
6830
  self.is_chromium()
6422
6831
  and self.driver.current_url.startswith("http")
6423
6832
  ):
6424
- try:
6833
+ with suppress(Exception):
6425
6834
  self.driver.execute_script("window.onbeforeunload=null;")
6426
- except Exception:
6427
- pass
6428
6835
 
6429
6836
  def get_domain_url(self, url):
6430
6837
  self.__check_scope()
@@ -6440,12 +6847,10 @@ class BaseCase(unittest.TestCase):
6440
6847
  from bs4 import BeautifulSoup
6441
6848
 
6442
6849
  if not source:
6443
- try:
6850
+ with suppress(Exception):
6444
6851
  self.wait_for_element_visible(
6445
6852
  "body", timeout=settings.MINI_TIMEOUT
6446
6853
  )
6447
- except Exception:
6448
- pass
6449
6854
  source = self.get_page_source()
6450
6855
  return BeautifulSoup(source, "html.parser")
6451
6856
 
@@ -6458,11 +6863,9 @@ class BaseCase(unittest.TestCase):
6458
6863
  time.sleep(0.08)
6459
6864
  if self.undetectable:
6460
6865
  time.sleep(0.02)
6461
- try:
6866
+ with suppress(Exception):
6462
6867
  self.wait_for_element_present("body", timeout=1.5)
6463
6868
  self.wait_for_element_visible("body", timeout=1.5)
6464
- except Exception:
6465
- pass
6466
6869
  if self.__needs_minimum_wait():
6467
6870
  time.sleep(0.25)
6468
6871
  if self.undetectable:
@@ -6524,6 +6927,7 @@ class BaseCase(unittest.TestCase):
6524
6927
  for link in all_links:
6525
6928
  if (
6526
6929
  "data:" not in link
6930
+ and "tel:" not in link
6527
6931
  and "mailto:" not in link
6528
6932
  and "javascript:" not in link
6529
6933
  and "://fonts.gstatic.com" not in link
@@ -6657,18 +7061,19 @@ class BaseCase(unittest.TestCase):
6657
7061
  constants.PipInstall.FINDLOCK
6658
7062
  )
6659
7063
  with pip_find_lock:
6660
- if (
6661
- sys.version_info >= (3, 7)
6662
- and sys.version_info < (3, 9)
6663
- ):
7064
+ with suppress(Exception):
7065
+ shared_utils.make_writable(constants.PipInstall.FINDLOCK)
7066
+ if sys.version_info < (3, 9):
6664
7067
  # Fix bug in newer cryptography for Python 3.7 and 3.8:
6665
7068
  # "pyo3_runtime.PanicException: Python API call failed"
6666
7069
  try:
6667
7070
  import cryptography
6668
7071
  if cryptography.__version__ != "39.0.2":
7072
+ del cryptography # To get newer ver
6669
7073
  shared_utils.pip_install(
6670
7074
  "cryptography", version="39.0.2"
6671
7075
  )
7076
+ import cryptography
6672
7077
  except Exception:
6673
7078
  shared_utils.pip_install(
6674
7079
  "cryptography", version="39.0.2"
@@ -6676,12 +7081,7 @@ class BaseCase(unittest.TestCase):
6676
7081
  try:
6677
7082
  from pdfminer.high_level import extract_text
6678
7083
  except Exception:
6679
- if not sys.version_info >= (3, 8):
6680
- shared_utils.pip_install(
6681
- "pdfminer.six", version="20221105"
6682
- )
6683
- else:
6684
- shared_utils.pip_install("pdfminer.six")
7084
+ shared_utils.pip_install("pdfminer.six")
6685
7085
  from pdfminer.high_level import extract_text
6686
7086
  if not password:
6687
7087
  password = ""
@@ -6801,10 +7201,8 @@ class BaseCase(unittest.TestCase):
6801
7201
  if len(folder) < 1:
6802
7202
  raise Exception("Minimum folder name length = 1.")
6803
7203
  if not os.path.exists(folder):
6804
- try:
7204
+ with suppress(Exception):
6805
7205
  os.makedirs(folder)
6806
- except Exception:
6807
- pass
6808
7206
 
6809
7207
  def choose_file(
6810
7208
  self, selector, file_path, by="css selector", timeout=None
@@ -6844,10 +7242,8 @@ class BaseCase(unittest.TestCase):
6844
7242
  self.__scroll_to_element(element, selector, by)
6845
7243
  pre_action_url = None
6846
7244
  if self.demo_mode:
6847
- try:
7245
+ with suppress(Exception):
6848
7246
  pre_action_url = self.driver.current_url
6849
- except Exception:
6850
- pass
6851
7247
  if self.recorder_mode and self.__current_url_is_recordable():
6852
7248
  if self.get_session_storage_item("pause_recorder") == "no":
6853
7249
  time_stamp = self.execute_script("return Date.now();")
@@ -6917,6 +7313,8 @@ class BaseCase(unittest.TestCase):
6917
7313
  constants.PipInstall.FINDLOCK
6918
7314
  )
6919
7315
  with pip_find_lock:
7316
+ with suppress(Exception):
7317
+ shared_utils.make_writable(constants.PipInstall.FINDLOCK)
6920
7318
  try:
6921
7319
  from PIL import Image, ImageDraw
6922
7320
  except Exception:
@@ -6962,6 +7360,10 @@ class BaseCase(unittest.TestCase):
6962
7360
  constants.MultiBrowser.DOWNLOAD_FILE_LOCK
6963
7361
  )
6964
7362
  with download_file_lock:
7363
+ with suppress(Exception):
7364
+ shared_utils.make_writable(
7365
+ constants.MultiBrowser.DOWNLOAD_FILE_LOCK
7366
+ )
6965
7367
  if not destination_folder:
6966
7368
  destination_folder = constants.Files.DOWNLOADS_FOLDER
6967
7369
  if not os.path.exists(destination_folder):
@@ -6982,6 +7384,10 @@ class BaseCase(unittest.TestCase):
6982
7384
  constants.MultiBrowser.DOWNLOAD_FILE_LOCK
6983
7385
  )
6984
7386
  with download_file_lock:
7387
+ with suppress(Exception):
7388
+ shared_utils.make_writable(
7389
+ constants.MultiBrowser.DOWNLOAD_FILE_LOCK
7390
+ )
6985
7391
  if not destination_folder:
6986
7392
  destination_folder = constants.Files.DOWNLOADS_FOLDER
6987
7393
  if not os.path.exists(destination_folder):
@@ -7087,6 +7493,8 @@ class BaseCase(unittest.TestCase):
7087
7493
  constants.MultiBrowser.FILE_IO_LOCK
7088
7494
  )
7089
7495
  with file_io_lock:
7496
+ with suppress(Exception):
7497
+ shared_utils.make_writable(constants.MultiBrowser.FILE_IO_LOCK)
7090
7498
  with open(fpath, "r") as f:
7091
7499
  data = f.read().strip()
7092
7500
  return data
@@ -7135,10 +7543,8 @@ class BaseCase(unittest.TestCase):
7135
7543
  Those paths are usually the same. (browser-dependent)."""
7136
7544
  if self.is_downloaded_file_present(file, browser=browser):
7137
7545
  file_path = self.get_path_of_downloaded_file(file, browser=browser)
7138
- try:
7546
+ with suppress(Exception):
7139
7547
  os.remove(file_path)
7140
- except Exception:
7141
- pass
7142
7548
 
7143
7549
  def delete_downloaded_file(self, file, browser=False):
7144
7550
  """Same as self.delete_downloaded_file_if_present()
@@ -7155,10 +7561,8 @@ class BaseCase(unittest.TestCase):
7155
7561
  Those paths are usually the same. (browser-dependent)."""
7156
7562
  if self.is_downloaded_file_present(file, browser=browser):
7157
7563
  file_path = self.get_path_of_downloaded_file(file, browser=browser)
7158
- try:
7564
+ with suppress(Exception):
7159
7565
  os.remove(file_path)
7160
- except Exception:
7161
- pass
7162
7566
 
7163
7567
  def assert_downloaded_file(self, file, timeout=None, browser=False):
7164
7568
  """Asserts that the file exists in SeleniumBase's [Downloads Folder].
@@ -7215,13 +7619,11 @@ class BaseCase(unittest.TestCase):
7215
7619
  self.__extra_actions.append(action)
7216
7620
  if self.demo_mode:
7217
7621
  messenger_post = "<b>ASSERT DOWNLOADED FILE</b>: [%s]" % file
7218
- try:
7622
+ with suppress(Exception):
7219
7623
  js_utils.activate_jquery(self.driver)
7220
7624
  js_utils.post_messenger_success_message(
7221
7625
  self.driver, messenger_post, self.message_duration
7222
7626
  )
7223
- except Exception:
7224
- pass
7225
7627
 
7226
7628
  def assert_downloaded_file_regex(self, regex, timeout=None, browser=False):
7227
7629
  """Assert the filename regex exists in SeleniumBase's Downloads Folder.
@@ -7270,13 +7672,11 @@ class BaseCase(unittest.TestCase):
7270
7672
  messenger_post = (
7271
7673
  "<b>ASSERT DOWNLOADED FILE REGEX</b>: [%s]" % regex
7272
7674
  )
7273
- try:
7675
+ with suppress(Exception):
7274
7676
  js_utils.activate_jquery(self.driver)
7275
7677
  js_utils.post_messenger_success_message(
7276
7678
  self.driver, messenger_post, self.message_duration
7277
7679
  )
7278
- except Exception:
7279
- pass
7280
7680
 
7281
7681
  def assert_data_in_downloaded_file(
7282
7682
  self, data, file, timeout=None, browser=False
@@ -7295,37 +7695,37 @@ class BaseCase(unittest.TestCase):
7295
7695
 
7296
7696
  def assert_true(self, expr, msg=None):
7297
7697
  """Asserts that the expression is True.
7298
- Will raise an exception if the statement if False."""
7698
+ Raises an exception if the statement if False."""
7299
7699
  self.assertTrue(expr, msg=msg)
7300
7700
 
7301
7701
  def assert_false(self, expr, msg=None):
7302
7702
  """Asserts that the expression is False.
7303
- Will raise an exception if the statement if True."""
7703
+ Raises an exception if the statement if True."""
7304
7704
  self.assertFalse(expr, msg=msg)
7305
7705
 
7306
7706
  def assert_equal(self, first, second, msg=None):
7307
7707
  """Asserts that the two values are equal.
7308
- Will raise an exception if the values are not equal."""
7708
+ Raises an exception if the values are not equal."""
7309
7709
  self.assertEqual(first, second, msg=msg)
7310
7710
 
7311
7711
  def assert_not_equal(self, first, second, msg=None):
7312
7712
  """Asserts that the two values are not equal.
7313
- Will raise an exception if the values are equal."""
7713
+ Raises an exception if the values are equal."""
7314
7714
  self.assertNotEqual(first, second, msg=msg)
7315
7715
 
7316
7716
  def assert_in(self, first, second, msg=None):
7317
7717
  """Asserts that the first string is in the second string.
7318
- 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."""
7319
7719
  self.assertIn(first, second, msg=msg)
7320
7720
 
7321
7721
  def assert_not_in(self, first, second, msg=None):
7322
7722
  """Asserts that the first string is not in the second string.
7323
- 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."""
7324
7724
  self.assertNotIn(first, second, msg=msg)
7325
7725
 
7326
7726
  def assert_raises(self, *args, **kwargs):
7327
7727
  """Asserts that the following block of code raises an exception.
7328
- Will raise an exception if the block of code has no exception.
7728
+ Raises an exception if the block of code has no exception.
7329
7729
  Usage Example =>
7330
7730
  # Verify that the expected exception is raised.
7331
7731
  with self.assert_raises(Exception):
@@ -7345,7 +7745,10 @@ class BaseCase(unittest.TestCase):
7345
7745
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
7346
7746
  timeout = self.__get_new_timeout(timeout)
7347
7747
  selector, by = self.__recalculate_selector(selector, by)
7348
- 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):
7349
7752
  return self.__wait_for_shadow_attribute_present(
7350
7753
  selector, attribute, value=value, timeout=timeout
7351
7754
  )
@@ -7370,6 +7773,9 @@ class BaseCase(unittest.TestCase):
7370
7773
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
7371
7774
  timeout = self.__get_new_timeout(timeout)
7372
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
7373
7779
  self.wait_for_attribute(
7374
7780
  selector, attribute, value=value, by=by, timeout=timeout
7375
7781
  )
@@ -7419,6 +7825,9 @@ class BaseCase(unittest.TestCase):
7419
7825
  but then the title switches over to the actual page title.
7420
7826
  In Recorder Mode, this assertion is skipped because the Recorder
7421
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
7422
7831
  self.wait_for_ready_state_complete()
7423
7832
  expected = title.strip()
7424
7833
  actual = self.get_page_title().strip()
@@ -7465,6 +7874,9 @@ class BaseCase(unittest.TestCase):
7465
7874
  but then the title switches over to the actual page title.
7466
7875
  In Recorder Mode, this assertion is skipped because the Recorder
7467
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
7468
7880
  self.wait_for_ready_state_complete()
7469
7881
  expected = substring.strip()
7470
7882
  actual = self.get_page_title().strip()
@@ -7508,6 +7920,9 @@ class BaseCase(unittest.TestCase):
7508
7920
 
7509
7921
  def assert_url(self, url):
7510
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
7511
7926
  self.wait_for_ready_state_complete()
7512
7927
  expected = url.strip()
7513
7928
  actual = self.get_current_url().strip()
@@ -7543,6 +7958,9 @@ class BaseCase(unittest.TestCase):
7543
7958
 
7544
7959
  def assert_url_contains(self, substring):
7545
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
7546
7964
  self.wait_for_ready_state_complete()
7547
7965
  expected = substring.strip()
7548
7966
  actual = self.get_current_url().strip()
@@ -7732,13 +8150,33 @@ class BaseCase(unittest.TestCase):
7732
8150
  """Return True if the url is a valid url."""
7733
8151
  return page_utils.is_valid_url(url)
7734
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
+
7735
8160
  def is_online(self):
7736
8161
  """Return True if connected to the Internet."""
8162
+ if self.__is_cdp_swap_needed():
8163
+ return self.cdp.evaluate("navigator.onLine;")
7737
8164
  return self.execute_script("return navigator.onLine;")
7738
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()
8174
+
7739
8175
  def is_chromium(self):
7740
8176
  """Return True if the browser is Chrome or Edge."""
7741
8177
  self.__check_scope()
8178
+ if self.__is_cdp_swap_needed():
8179
+ return True
7742
8180
  chromium = False
7743
8181
  if (
7744
8182
  "chrome" in self.driver.capabilities
@@ -7851,6 +8289,10 @@ class BaseCase(unittest.TestCase):
7851
8289
  self.__check_scope()
7852
8290
  if not timeout:
7853
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
7854
8296
  self.wait_for_element_visible(selector, by=by, timeout=timeout)
7855
8297
  if self.recorder_mode and self.__current_url_is_recordable():
7856
8298
  if self.get_session_storage_item("pause_recorder") == "no":
@@ -7876,27 +8318,7 @@ class BaseCase(unittest.TestCase):
7876
8318
  jQuery commands require a CSS_SELECTOR for finding elements.
7877
8319
  This method should only be used for jQuery/JavaScript actions.
7878
8320
  Pure JavaScript doesn't support using a:contains("LINK_TEXT")."""
7879
- if by == By.CSS_SELECTOR:
7880
- return selector
7881
- elif by == By.ID:
7882
- return "#%s" % selector
7883
- elif by == By.CLASS_NAME:
7884
- return ".%s" % selector
7885
- elif by == By.NAME:
7886
- return '[name="%s"]' % selector
7887
- elif by == By.TAG_NAME:
7888
- return selector
7889
- elif by == By.XPATH:
7890
- return self.convert_xpath_to_css(selector)
7891
- elif by == By.LINK_TEXT:
7892
- return 'a:contains("%s")' % selector
7893
- elif by == By.PARTIAL_LINK_TEXT:
7894
- return 'a:contains("%s")' % selector
7895
- else:
7896
- raise Exception(
7897
- "Exception: Could not convert {%s}(by=%s) to CSS_SELECTOR!"
7898
- % (selector, by)
7899
- )
8321
+ return js_utils.convert_to_css_selector(selector, by)
7900
8322
 
7901
8323
  def set_value(
7902
8324
  self, selector, text, by="css selector", timeout=None, scroll=True
@@ -7908,6 +8330,9 @@ class BaseCase(unittest.TestCase):
7908
8330
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
7909
8331
  timeout = self.__get_new_timeout(timeout)
7910
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
7911
8336
  self.wait_for_ready_state_complete()
7912
8337
  self.wait_for_element_present(selector, by=by, timeout=timeout)
7913
8338
  original_selector = selector
@@ -7965,17 +8390,15 @@ class BaseCase(unittest.TestCase):
7965
8390
  else:
7966
8391
  if the_type == "range" and ":contains\\(" not in css_selector:
7967
8392
  # Some input sliders need a mouse event to trigger listeners.
7968
- try:
8393
+ with suppress(Exception):
7969
8394
  mouse_move_script = (
7970
8395
  """m_elm = document.querySelector('%s');"""
7971
8396
  """m_evt = new Event('mousemove');"""
7972
8397
  """m_elm.dispatchEvent(m_evt);""" % css_selector
7973
8398
  )
7974
8399
  self.execute_script(mouse_move_script)
7975
- except Exception:
7976
- pass
7977
8400
  elif the_type == "range" and ":contains\\(" in css_selector:
7978
- try:
8401
+ with suppress(Exception):
7979
8402
  element = self.wait_for_element_present(
7980
8403
  original_selector, by=by, timeout=1
7981
8404
  )
@@ -7985,8 +8408,6 @@ class BaseCase(unittest.TestCase):
7985
8408
  """m_elm.dispatchEvent(m_evt);"""
7986
8409
  )
7987
8410
  self.execute_script(mouse_move_script, element)
7988
- except Exception:
7989
- pass
7990
8411
  self.__demo_mode_pause_if_active()
7991
8412
  if not self.demo_mode and not self.slow_mode:
7992
8413
  if self.__needs_minimum_wait():
@@ -8006,13 +8427,11 @@ class BaseCase(unittest.TestCase):
8006
8427
  text = self.__get_type_checked_text(text)
8007
8428
  self.set_value(selector, text, by=by, timeout=timeout)
8008
8429
  if not text.endswith("\n"):
8009
- try:
8430
+ with suppress(Exception):
8010
8431
  element = page_actions.wait_for_element_present(
8011
8432
  self.driver, selector, by, timeout=0.2
8012
8433
  )
8013
8434
  element.send_keys(" " + Keys.BACK_SPACE)
8014
- except Exception:
8015
- pass
8016
8435
 
8017
8436
  def js_type(self, selector, text, by="css selector", timeout=None):
8018
8437
  """Same as self.js_update_text()
@@ -8132,13 +8551,11 @@ class BaseCase(unittest.TestCase):
8132
8551
  )
8133
8552
  element.send_keys(Keys.RETURN)
8134
8553
  else:
8135
- try:
8554
+ with suppress(Exception):
8136
8555
  element = self.wait_for_element_present(
8137
8556
  original_selector, by=original_by, timeout=0.2
8138
8557
  )
8139
8558
  element.send_keys(" " + Keys.BACK_SPACE)
8140
- except Exception:
8141
- pass
8142
8559
  self.__demo_mode_pause_if_active()
8143
8560
 
8144
8561
  def jquery_type(self, selector, text, by="css selector", timeout=None):
@@ -8315,10 +8732,8 @@ class BaseCase(unittest.TestCase):
8315
8732
  def get_recorded_console_logs(self):
8316
8733
  """Get console logs recorded after "start_recording_console_logs()"."""
8317
8734
  logs = []
8318
- try:
8735
+ with suppress(Exception):
8319
8736
  logs = self.execute_script("return console.logs;")
8320
- except Exception:
8321
- pass
8322
8737
  return logs
8323
8738
 
8324
8739
  ############
@@ -8626,12 +9041,15 @@ class BaseCase(unittest.TestCase):
8626
9041
  ):
8627
9042
  """Same as self.wait_for_element()"""
8628
9043
  self.__check_scope()
9044
+ self.__skip_if_esc()
8629
9045
  if not timeout:
8630
9046
  timeout = settings.LARGE_TIMEOUT
8631
9047
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
8632
9048
  timeout = self.__get_new_timeout(timeout)
8633
9049
  original_selector = selector
8634
9050
  selector, by = self.__recalculate_selector(selector, by)
9051
+ if self.__is_cdp_swap_needed():
9052
+ return self.cdp.select(selector, timeout=timeout)
8635
9053
  if self.__is_shadow_selector(selector):
8636
9054
  return self.__get_shadow_element(selector, timeout)
8637
9055
  return page_actions.wait_for_element_visible(
@@ -8653,7 +9071,9 @@ class BaseCase(unittest.TestCase):
8653
9071
  timeout = self.__get_new_timeout(timeout)
8654
9072
  original_selector = selector
8655
9073
  selector, by = self.__recalculate_selector(selector, by)
8656
- 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):
8657
9077
  # If a shadow selector, use visible instead of clickable
8658
9078
  return self.__wait_for_shadow_element_visible(selector, timeout)
8659
9079
  return page_actions.wait_for_element_clickable(
@@ -8679,6 +9099,9 @@ class BaseCase(unittest.TestCase):
8679
9099
  timeout = self.__get_new_timeout(timeout)
8680
9100
  original_selector = selector
8681
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
8682
9105
  return page_actions.wait_for_element_absent(
8683
9106
  self.driver,
8684
9107
  selector,
@@ -8687,6 +9110,9 @@ class BaseCase(unittest.TestCase):
8687
9110
  original_selector=original_selector,
8688
9111
  )
8689
9112
 
9113
+ def select_all(self, selector, by="css selector", limit=0):
9114
+ return self.find_elements(selector, by=by, limit=limit)
9115
+
8690
9116
  def assert_link(self, link_text, timeout=None):
8691
9117
  """Same as self.assert_link_text()"""
8692
9118
  self.__check_scope()
@@ -8700,7 +9126,7 @@ class BaseCase(unittest.TestCase):
8700
9126
  self, selector, by="css selector", timeout=None
8701
9127
  ):
8702
9128
  """Same as self.assert_element_absent()
8703
- Will raise an exception if the element stays present.
9129
+ Raises an exception if the element stays present.
8704
9130
  A hidden element counts as a present element, which fails this assert.
8705
9131
  If you want to assert that elements are hidden instead of nonexistent,
8706
9132
  use assert_element_not_visible() instead.
@@ -8738,6 +9164,14 @@ class BaseCase(unittest.TestCase):
8738
9164
  """Same as self.delete_all_cookies()"""
8739
9165
  self.delete_all_cookies()
8740
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
+
8741
9175
  def assert_no_broken_links(self, multithreaded=True):
8742
9176
  """Same as self.assert_no_404_errors()"""
8743
9177
  self.assert_no_404_errors(multithreaded=multithreaded)
@@ -8753,11 +9187,10 @@ class BaseCase(unittest.TestCase):
8753
9187
  def _check_browser(self):
8754
9188
  """This method raises an exception if the active window is closed.
8755
9189
  (This provides a much cleaner exception message in this situation.)"""
9190
+ page_actions._reconnect_if_disconnected(self.driver)
8756
9191
  active_window = None
8757
- try:
9192
+ with suppress(Exception):
8758
9193
  active_window = self.driver.current_window_handle # Fails if None
8759
- except Exception:
8760
- pass
8761
9194
  if not active_window:
8762
9195
  raise NoSuchWindowException("Active window was already closed!")
8763
9196
 
@@ -8771,10 +9204,8 @@ class BaseCase(unittest.TestCase):
8771
9204
  """
8772
9205
  if hasattr(sb_config, "_multithreaded") and sb_config._multithreaded:
8773
9206
  if not isinstance(msg, str):
8774
- try:
9207
+ with suppress(Exception):
8775
9208
  msg = str(msg)
8776
- except Exception:
8777
- pass
8778
9209
  sys.stderr.write(msg + "\n")
8779
9210
  else:
8780
9211
  print(msg)
@@ -9041,7 +9472,9 @@ class BaseCase(unittest.TestCase):
9041
9472
  timeout = self.__get_new_timeout(timeout)
9042
9473
  original_selector = selector
9043
9474
  selector, by = self.__recalculate_selector(selector, by)
9044
- 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):
9045
9478
  return self.__wait_for_shadow_element_present(selector, timeout)
9046
9479
  return page_actions.wait_for_element_present(
9047
9480
  self.driver,
@@ -9061,6 +9494,8 @@ class BaseCase(unittest.TestCase):
9061
9494
  timeout = self.__get_new_timeout(timeout)
9062
9495
  original_selector = selector
9063
9496
  selector, by = self.__recalculate_selector(selector, by)
9497
+ if self.__is_cdp_swap_needed():
9498
+ return self.cdp.select(selector, timeout=timeout)
9064
9499
  if self.recorder_mode and self.__current_url_is_recordable():
9065
9500
  if self.get_session_storage_item("pause_recorder") == "no":
9066
9501
  if by == By.XPATH:
@@ -9102,6 +9537,8 @@ class BaseCase(unittest.TestCase):
9102
9537
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
9103
9538
  timeout = self.__get_new_timeout(timeout)
9104
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)
9105
9542
  return js_utils.wait_for_css_query_selector(
9106
9543
  self.driver, css_selector, timeout
9107
9544
  )
@@ -9121,6 +9558,9 @@ class BaseCase(unittest.TestCase):
9121
9558
  if isinstance(selector, list):
9122
9559
  self.assert_elements_present(selector, by=by, timeout=timeout)
9123
9560
  return True
9561
+ if self.__is_cdp_swap_needed():
9562
+ self.cdp.assert_element_present(selector)
9563
+ return True
9124
9564
  if self.__is_shadow_selector(selector):
9125
9565
  self.__assert_shadow_element_present(selector)
9126
9566
  return True
@@ -9188,13 +9628,16 @@ class BaseCase(unittest.TestCase):
9188
9628
 
9189
9629
  def assert_element(self, selector, by="css selector", timeout=None):
9190
9630
  """Similar to wait_for_element_visible(), but returns nothing.
9191
- As above, will raise an exception if nothing can be found.
9631
+ As above, raises an exception if nothing can be found.
9192
9632
  Returns True if successful. Default timeout = SMALL_TIMEOUT."""
9193
9633
  self.__check_scope()
9194
9634
  if not timeout:
9195
9635
  timeout = settings.SMALL_TIMEOUT
9196
9636
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
9197
9637
  timeout = self.__get_new_timeout(timeout)
9638
+ if self.__is_cdp_swap_needed():
9639
+ self.cdp.assert_element(selector)
9640
+ return True
9198
9641
  if isinstance(selector, list):
9199
9642
  self.assert_elements(selector, by=by, timeout=timeout)
9200
9643
  return True
@@ -9228,7 +9671,7 @@ class BaseCase(unittest.TestCase):
9228
9671
  self, selector, by="css selector", timeout=None
9229
9672
  ):
9230
9673
  """Same as self.assert_element()
9231
- As above, will raise an exception if nothing can be found."""
9674
+ As above, raises an exception if nothing can be found."""
9232
9675
  self.__check_scope()
9233
9676
  if not timeout:
9234
9677
  timeout = settings.SMALL_TIMEOUT
@@ -9306,7 +9749,7 @@ class BaseCase(unittest.TestCase):
9306
9749
  ############
9307
9750
 
9308
9751
  def wait_for_text_visible(
9309
- self, text, selector="html", by="css selector", timeout=None
9752
+ self, text, selector="body", by="css selector", timeout=None
9310
9753
  ):
9311
9754
  self.__check_scope()
9312
9755
  if not timeout:
@@ -9315,14 +9758,16 @@ class BaseCase(unittest.TestCase):
9315
9758
  timeout = self.__get_new_timeout(timeout)
9316
9759
  text = self.__get_type_checked_text(text)
9317
9760
  selector, by = self.__recalculate_selector(selector, by)
9318
- 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):
9319
9764
  return self.__wait_for_shadow_text_visible(text, selector, timeout)
9320
9765
  return page_actions.wait_for_text_visible(
9321
9766
  self.driver, text, selector, by, timeout
9322
9767
  )
9323
9768
 
9324
9769
  def wait_for_exact_text_visible(
9325
- self, text, selector="html", by="css selector", timeout=None
9770
+ self, text, selector="body", by="css selector", timeout=None
9326
9771
  ):
9327
9772
  self.__check_scope()
9328
9773
  if not timeout:
@@ -9339,7 +9784,7 @@ class BaseCase(unittest.TestCase):
9339
9784
  )
9340
9785
 
9341
9786
  def wait_for_non_empty_text_visible(
9342
- self, selector="html", by="css selector", timeout=None
9787
+ self, selector="body", by="css selector", timeout=None
9343
9788
  ):
9344
9789
  """Searches for any text in the element of the given selector.
9345
9790
  Returns the element if it has visible text within the timeout.
@@ -9360,7 +9805,7 @@ class BaseCase(unittest.TestCase):
9360
9805
  )
9361
9806
 
9362
9807
  def wait_for_text(
9363
- self, text, selector="html", by="css selector", timeout=None
9808
+ self, text, selector="body", by="css selector", timeout=None
9364
9809
  ):
9365
9810
  """The shorter version of wait_for_text_visible()"""
9366
9811
  self.__check_scope()
@@ -9373,7 +9818,7 @@ class BaseCase(unittest.TestCase):
9373
9818
  )
9374
9819
 
9375
9820
  def wait_for_exact_text(
9376
- self, text, selector="html", by="css selector", timeout=None
9821
+ self, text, selector="body", by="css selector", timeout=None
9377
9822
  ):
9378
9823
  """The shorter version of wait_for_exact_text_visible()"""
9379
9824
  self.__check_scope()
@@ -9386,7 +9831,7 @@ class BaseCase(unittest.TestCase):
9386
9831
  )
9387
9832
 
9388
9833
  def wait_for_non_empty_text(
9389
- self, selector="html", by="css selector", timeout=None
9834
+ self, selector="body", by="css selector", timeout=None
9390
9835
  ):
9391
9836
  """The shorter version of wait_for_non_empty_text_visible()"""
9392
9837
  self.__check_scope()
@@ -9399,7 +9844,7 @@ class BaseCase(unittest.TestCase):
9399
9844
  )
9400
9845
 
9401
9846
  def find_text(
9402
- self, text, selector="html", by="css selector", timeout=None
9847
+ self, text, selector="body", by="css selector", timeout=None
9403
9848
  ):
9404
9849
  """Same as wait_for_text_visible() - returns the element"""
9405
9850
  self.__check_scope()
@@ -9412,7 +9857,7 @@ class BaseCase(unittest.TestCase):
9412
9857
  )
9413
9858
 
9414
9859
  def find_exact_text(
9415
- self, text, selector="html", by="css selector", timeout=None
9860
+ self, text, selector="body", by="css selector", timeout=None
9416
9861
  ):
9417
9862
  """Same as wait_for_exact_text_visible() - returns the element"""
9418
9863
  self.__check_scope()
@@ -9425,7 +9870,7 @@ class BaseCase(unittest.TestCase):
9425
9870
  )
9426
9871
 
9427
9872
  def find_non_empty_text(
9428
- self, selector="html", by="css selector", timeout=None
9873
+ self, selector="body", by="css selector", timeout=None
9429
9874
  ):
9430
9875
  """Same as wait_for_non_empty_text_visible() - returns the element"""
9431
9876
  self.__check_scope()
@@ -9438,7 +9883,7 @@ class BaseCase(unittest.TestCase):
9438
9883
  )
9439
9884
 
9440
9885
  def assert_text_visible(
9441
- self, text, selector="html", by="css selector", timeout=None
9886
+ self, text, selector="body", by="css selector", timeout=None
9442
9887
  ):
9443
9888
  """Same as assert_text()"""
9444
9889
  self.__check_scope()
@@ -9449,11 +9894,12 @@ class BaseCase(unittest.TestCase):
9449
9894
  return self.assert_text(text, selector, by=by, timeout=timeout)
9450
9895
 
9451
9896
  def assert_text(
9452
- self, text, selector="html", by="css selector", timeout=None
9897
+ self, text, selector="body", by="css selector", timeout=None
9453
9898
  ):
9454
9899
  """Similar to wait_for_text_visible()
9455
9900
  Raises an exception if the element or the text is not found.
9456
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.
9457
9903
  Returns True if successful. Default timeout = SMALL_TIMEOUT."""
9458
9904
  self.__check_scope()
9459
9905
  if not timeout:
@@ -9462,26 +9908,50 @@ class BaseCase(unittest.TestCase):
9462
9908
  timeout = self.__get_new_timeout(timeout)
9463
9909
  original_selector = selector
9464
9910
  selector, by = self.__recalculate_selector(selector, by)
9465
- 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):
9466
9937
  self.__assert_shadow_text_visible(text, selector, timeout)
9467
9938
  return True
9468
- self.wait_for_text_visible(text, selector, by=by, timeout=timeout)
9469
- if self.demo_mode:
9470
- a_t = "ASSERT TEXT"
9471
- i_n = "in"
9472
- if self._language != "English":
9473
- 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
9474
9946
 
9475
- a_t = SD.translate_assert_text(self._language)
9476
- i_n = SD.translate_in(self._language)
9477
- messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
9478
- a_t,
9479
- text,
9480
- i_n,
9481
- by.upper(),
9482
- selector,
9483
- )
9484
- 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
+ )
9485
9955
  if self.recorder_mode and self.__current_url_is_recordable():
9486
9956
  if self.get_session_storage_item("pause_recorder") == "no":
9487
9957
  if by == By.XPATH:
@@ -9494,7 +9964,7 @@ class BaseCase(unittest.TestCase):
9494
9964
  return True
9495
9965
 
9496
9966
  def assert_exact_text(
9497
- self, text, selector="html", by="css selector", timeout=None
9967
+ self, text, selector="body", by="css selector", timeout=None
9498
9968
  ):
9499
9969
  """Similar to assert_text(), but the text must be exact,
9500
9970
  rather than exist as a subset of the full text.
@@ -9508,6 +9978,9 @@ class BaseCase(unittest.TestCase):
9508
9978
  timeout = self.__get_new_timeout(timeout)
9509
9979
  original_selector = selector
9510
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
9511
9984
  if self.__is_shadow_selector(selector):
9512
9985
  self.__assert_exact_shadow_text_visible(text, selector, timeout)
9513
9986
  return True
@@ -9523,11 +9996,7 @@ class BaseCase(unittest.TestCase):
9523
9996
  a_t = SD.translate_assert_exact_text(self._language)
9524
9997
  i_n = SD.translate_in(self._language)
9525
9998
  messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
9526
- a_t,
9527
- text,
9528
- i_n,
9529
- by.upper(),
9530
- selector,
9999
+ a_t, text, i_n, by.upper(), selector
9531
10000
  )
9532
10001
  self.__highlight_with_assert_success(messenger_post, selector, by)
9533
10002
  if self.recorder_mode and self.__current_url_is_recordable():
@@ -9542,7 +10011,7 @@ class BaseCase(unittest.TestCase):
9542
10011
  return True
9543
10012
 
9544
10013
  def assert_non_empty_text(
9545
- self, selector="html", by="css selector", timeout=None
10014
+ self, selector="body", by="css selector", timeout=None
9546
10015
  ):
9547
10016
  """Assert that the element has any non-empty text visible.
9548
10017
  Raises an exception if the element has no text within the timeout.
@@ -9567,10 +10036,7 @@ class BaseCase(unittest.TestCase):
9567
10036
  a_t = SD.translate_assert_non_empty_text(self._language)
9568
10037
  i_n = SD.translate_in(self._language)
9569
10038
  messenger_post = "<b>%s</b> %s %s: %s" % (
9570
- a_t,
9571
- i_n,
9572
- by.upper(),
9573
- selector,
10039
+ a_t, i_n, by.upper(), selector
9574
10040
  )
9575
10041
  self.__highlight_with_assert_success(messenger_post, selector, by)
9576
10042
  if self.recorder_mode and self.__current_url_is_recordable():
@@ -9665,13 +10131,16 @@ class BaseCase(unittest.TestCase):
9665
10131
 
9666
10132
  def assert_link_text(self, link_text, timeout=None):
9667
10133
  """Similar to wait_for_link_text_visible(), but returns nothing.
9668
- As above, will raise an exception if nothing can be found.
10134
+ As above, raises an exception if nothing can be found.
9669
10135
  Returns True if successful. Default timeout = SMALL_TIMEOUT."""
9670
10136
  self.__check_scope()
9671
10137
  if not timeout:
9672
10138
  timeout = settings.SMALL_TIMEOUT
9673
10139
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
9674
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
9675
10144
  self.wait_for_link_text_visible(link_text, timeout=timeout)
9676
10145
  if self.demo_mode:
9677
10146
  a_t = "ASSERT LINK TEXT"
@@ -9714,7 +10183,7 @@ class BaseCase(unittest.TestCase):
9714
10183
 
9715
10184
  def assert_partial_link_text(self, partial_link_text, timeout=None):
9716
10185
  """Similar to wait_for_partial_link_text(), but returns nothing.
9717
- As above, will raise an exception if nothing can be found.
10186
+ As above, raises an exception if nothing can be found.
9718
10187
  Returns True if successful. Default timeout = SMALL_TIMEOUT."""
9719
10188
  self.__check_scope()
9720
10189
  if not timeout:
@@ -9760,7 +10229,7 @@ class BaseCase(unittest.TestCase):
9760
10229
 
9761
10230
  def assert_element_absent(self, selector, by="css selector", timeout=None):
9762
10231
  """Similar to wait_for_element_absent()
9763
- As above, will raise an exception if the element stays present.
10232
+ As above, raises an exception if the element stays present.
9764
10233
  A hidden element counts as a present element, which fails this assert.
9765
10234
  If you want to assert that elements are hidden instead of nonexistent,
9766
10235
  use assert_element_not_visible() instead.
@@ -9771,6 +10240,9 @@ class BaseCase(unittest.TestCase):
9771
10240
  timeout = settings.SMALL_TIMEOUT
9772
10241
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
9773
10242
  timeout = self.__get_new_timeout(timeout)
10243
+ if self.__is_cdp_swap_needed():
10244
+ self.cdp.assert_element_absent(selector)
10245
+ return True
9774
10246
  self.wait_for_element_absent(selector, by=by, timeout=timeout)
9775
10247
  return True
9776
10248
 
@@ -9789,6 +10261,9 @@ class BaseCase(unittest.TestCase):
9789
10261
  timeout = self.__get_new_timeout(timeout)
9790
10262
  original_selector = selector
9791
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
9792
10267
  return page_actions.wait_for_element_not_visible(
9793
10268
  self.driver,
9794
10269
  selector,
@@ -9801,13 +10276,16 @@ class BaseCase(unittest.TestCase):
9801
10276
  self, selector, by="css selector", timeout=None
9802
10277
  ):
9803
10278
  """Similar to wait_for_element_not_visible()
9804
- As above, will raise an exception if the element stays visible.
10279
+ As above, raises an exception if the element stays visible.
9805
10280
  Returns True if successful. Default timeout = SMALL_TIMEOUT."""
9806
10281
  self.__check_scope()
9807
10282
  if not timeout:
9808
10283
  timeout = settings.SMALL_TIMEOUT
9809
10284
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
9810
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
9811
10289
  self.wait_for_element_not_visible(selector, by=by, timeout=timeout)
9812
10290
  if self.recorder_mode and self.__current_url_is_recordable():
9813
10291
  if self.get_session_storage_item("pause_recorder") == "no":
@@ -9820,7 +10298,7 @@ class BaseCase(unittest.TestCase):
9820
10298
  ############
9821
10299
 
9822
10300
  def wait_for_text_not_visible(
9823
- self, text, selector="html", by="css selector", timeout=None
10301
+ self, text, selector="body", by="css selector", timeout=None
9824
10302
  ):
9825
10303
  self.__check_scope()
9826
10304
  if not timeout:
@@ -9833,7 +10311,7 @@ class BaseCase(unittest.TestCase):
9833
10311
  )
9834
10312
 
9835
10313
  def wait_for_exact_text_not_visible(
9836
- self, text, selector="html", by="css selector", timeout=None
10314
+ self, text, selector="body", by="css selector", timeout=None
9837
10315
  ):
9838
10316
  self.__check_scope()
9839
10317
  if not timeout:
@@ -9846,7 +10324,7 @@ class BaseCase(unittest.TestCase):
9846
10324
  )
9847
10325
 
9848
10326
  def assert_text_not_visible(
9849
- self, text, selector="html", by="css selector", timeout=None
10327
+ self, text, selector="body", by="css selector", timeout=None
9850
10328
  ):
9851
10329
  """Similar to wait_for_text_not_visible()
9852
10330
  Raises an exception if the text is still visible after timeout.
@@ -9867,7 +10345,7 @@ class BaseCase(unittest.TestCase):
9867
10345
  return True
9868
10346
 
9869
10347
  def assert_exact_text_not_visible(
9870
- self, text, selector="html", by="css selector", timeout=None
10348
+ self, text, selector="body", by="css selector", timeout=None
9871
10349
  ):
9872
10350
  """Similar to wait_for_exact_text_not_visible()
9873
10351
  Raises an exception if the exact text is still visible after timeout.
@@ -10117,7 +10595,7 @@ class BaseCase(unittest.TestCase):
10117
10595
  countdown_on = True
10118
10596
  countdown = 3
10119
10597
  minified_exception += line + "\n"
10120
- elif line.startswith("+") or line.startswith("-"):
10598
+ elif line.startswith(("+", "-")):
10121
10599
  minified_exception += line + "\n"
10122
10600
  elif line.startswith("?"):
10123
10601
  minified_exception += line + "\n"
@@ -10166,8 +10644,6 @@ class BaseCase(unittest.TestCase):
10166
10644
  shutil.copy(latest_png_path, latest_copy_path)
10167
10645
  if len(self.__visual_baseline_copies) != 1:
10168
10646
  return # Skip the rest when deferred visual asserts are used
10169
- from seleniumbase.core import visual_helper
10170
-
10171
10647
  the_html = visual_helper.get_sbs_html()
10172
10648
  file_path = os.path.join(test_logpath, constants.SideBySide.HTML_FILE)
10173
10649
  out_file = codecs.open(file_path, "w+", encoding="utf-8")
@@ -10254,12 +10730,10 @@ class BaseCase(unittest.TestCase):
10254
10730
  self.check_window(name="github_page", level=2)
10255
10731
  self.check_window(name="wikipedia_page", level=3) """
10256
10732
  self.wait_for_ready_state_complete()
10257
- try:
10733
+ with suppress(Exception):
10258
10734
  self.wait_for_element_visible(
10259
10735
  "body", timeout=settings.MINI_TIMEOUT
10260
10736
  )
10261
- except Exception:
10262
- pass
10263
10737
  if self.__needs_minimum_wait():
10264
10738
  time.sleep(0.08)
10265
10739
  if level == "0":
@@ -10285,7 +10759,6 @@ class BaseCase(unittest.TestCase):
10285
10759
  if not name or len(name) < 1:
10286
10760
  name = "default"
10287
10761
  name = str(name)
10288
- from seleniumbase.core import visual_helper
10289
10762
 
10290
10763
  visual_helper.visual_baseline_folder_setup()
10291
10764
  baseline_dir = constants.VisualBaseline.STORAGE_FOLDER
@@ -10502,6 +10975,12 @@ class BaseCase(unittest.TestCase):
10502
10975
 
10503
10976
  ############
10504
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
+
10505
10984
  def __check_scope(self):
10506
10985
  if hasattr(self, "browser"): # self.browser stores the type of browser
10507
10986
  return # All good: setUp() already initialized variables in "self"
@@ -10568,14 +11047,12 @@ class BaseCase(unittest.TestCase):
10568
11047
  if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
10569
11048
  timeout = self.__get_new_timeout(timeout)
10570
11049
  self.__deferred_assert_count += 1
10571
- try:
11050
+ with suppress(Exception):
10572
11051
  url = self.get_current_url()
10573
11052
  if url == self.__last_url_of_deferred_assert:
10574
11053
  timeout = 0.6 # Was already on page (full wait not needed)
10575
11054
  else:
10576
11055
  self.__last_url_of_deferred_assert = url
10577
- except Exception:
10578
- pass
10579
11056
  if self.recorder_mode and self.__current_url_is_recordable():
10580
11057
  if self.get_session_storage_item("pause_recorder") == "no":
10581
11058
  time_stamp = self.execute_script("return Date.now();")
@@ -10605,14 +11082,12 @@ class BaseCase(unittest.TestCase):
10605
11082
  if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
10606
11083
  timeout = self.__get_new_timeout(timeout)
10607
11084
  self.__deferred_assert_count += 1
10608
- try:
11085
+ with suppress(Exception):
10609
11086
  url = self.get_current_url()
10610
11087
  if url == self.__last_url_of_deferred_assert:
10611
11088
  timeout = 0.6 # Was already on page (full wait not needed)
10612
11089
  else:
10613
11090
  self.__last_url_of_deferred_assert = url
10614
- except Exception:
10615
- pass
10616
11091
  if self.recorder_mode and self.__current_url_is_recordable():
10617
11092
  if self.get_session_storage_item("pause_recorder") == "no":
10618
11093
  time_stamp = self.execute_script("return Date.now();")
@@ -10627,7 +11102,7 @@ class BaseCase(unittest.TestCase):
10627
11102
  return False
10628
11103
 
10629
11104
  def deferred_assert_text(
10630
- self, text, selector="html", by="css selector", timeout=None, fs=False
11105
+ self, text, selector="body", by="css selector", timeout=None, fs=False
10631
11106
  ):
10632
11107
  """A non-terminating assertion for text from an element on a page.
10633
11108
  Failures will be saved until the process_deferred_asserts()
@@ -10642,14 +11117,12 @@ class BaseCase(unittest.TestCase):
10642
11117
  if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
10643
11118
  timeout = self.__get_new_timeout(timeout)
10644
11119
  self.__deferred_assert_count += 1
10645
- try:
11120
+ with suppress(Exception):
10646
11121
  url = self.get_current_url()
10647
11122
  if url == self.__last_url_of_deferred_assert:
10648
11123
  timeout = 0.6 # Was already on page (full wait not needed)
10649
11124
  else:
10650
11125
  self.__last_url_of_deferred_assert = url
10651
- except Exception:
10652
- pass
10653
11126
  if self.recorder_mode and self.__current_url_is_recordable():
10654
11127
  if self.get_session_storage_item("pause_recorder") == "no":
10655
11128
  time_stamp = self.execute_script("return Date.now();")
@@ -10665,7 +11138,7 @@ class BaseCase(unittest.TestCase):
10665
11138
  return False
10666
11139
 
10667
11140
  def deferred_assert_exact_text(
10668
- self, text, selector="html", by="css selector", timeout=None, fs=False
11141
+ self, text, selector="body", by="css selector", timeout=None, fs=False
10669
11142
  ):
10670
11143
  """A non-terminating assertion for exact text from an element.
10671
11144
  Failures will be saved until the process_deferred_asserts()
@@ -10680,14 +11153,12 @@ class BaseCase(unittest.TestCase):
10680
11153
  if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
10681
11154
  timeout = self.__get_new_timeout(timeout)
10682
11155
  self.__deferred_assert_count += 1
10683
- try:
11156
+ with suppress(Exception):
10684
11157
  url = self.get_current_url()
10685
11158
  if url == self.__last_url_of_deferred_assert:
10686
11159
  timeout = 0.6 # Was already on page (full wait not needed)
10687
11160
  else:
10688
11161
  self.__last_url_of_deferred_assert = url
10689
- except Exception:
10690
- pass
10691
11162
  if self.recorder_mode and self.__current_url_is_recordable():
10692
11163
  if self.get_session_storage_item("pause_recorder") == "no":
10693
11164
  time_stamp = self.execute_script("return Date.now();")
@@ -10706,7 +11177,7 @@ class BaseCase(unittest.TestCase):
10706
11177
 
10707
11178
  def deferred_assert_non_empty_text(
10708
11179
  self,
10709
- selector="html",
11180
+ selector="body",
10710
11181
  by="css selector",
10711
11182
  timeout=None,
10712
11183
  fs=False,
@@ -10724,14 +11195,12 @@ class BaseCase(unittest.TestCase):
10724
11195
  if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
10725
11196
  timeout = self.__get_new_timeout(timeout)
10726
11197
  self.__deferred_assert_count += 1
10727
- try:
11198
+ with suppress(Exception):
10728
11199
  url = self.get_current_url()
10729
11200
  if url == self.__last_url_of_deferred_assert:
10730
11201
  timeout = 0.6 # Was already on page (full wait not needed)
10731
11202
  else:
10732
11203
  self.__last_url_of_deferred_assert = url
10733
- except Exception:
10734
- pass
10735
11204
  if self.recorder_mode and self.__current_url_is_recordable():
10736
11205
  if self.get_session_storage_item("pause_recorder") == "no":
10737
11206
  time_stamp = self.execute_script("return Date.now();")
@@ -10828,7 +11297,7 @@ class BaseCase(unittest.TestCase):
10828
11297
  )
10829
11298
 
10830
11299
  def delayed_assert_text(
10831
- self, text, selector="html", by="css selector", timeout=None, fs=False
11300
+ self, text, selector="body", by="css selector", timeout=None, fs=False
10832
11301
  ):
10833
11302
  """Same as self.deferred_assert_text()"""
10834
11303
  return self.deferred_assert_text(
@@ -10836,7 +11305,7 @@ class BaseCase(unittest.TestCase):
10836
11305
  )
10837
11306
 
10838
11307
  def delayed_assert_exact_text(
10839
- self, text, selector="html", by="css selector", timeout=None, fs=False
11308
+ self, text, selector="body", by="css selector", timeout=None, fs=False
10840
11309
  ):
10841
11310
  """Same as self.deferred_assert_exact_text()"""
10842
11311
  return self.deferred_assert_exact_text(
@@ -10845,7 +11314,7 @@ class BaseCase(unittest.TestCase):
10845
11314
 
10846
11315
  def delayed_assert_non_empty_text(
10847
11316
  self,
10848
- selector="html",
11317
+ selector="body",
10849
11318
  by="css selector",
10850
11319
  timeout=None,
10851
11320
  fs=False,
@@ -11167,10 +11636,8 @@ class BaseCase(unittest.TestCase):
11167
11636
  if saved_presentations_folder.endswith("/"):
11168
11637
  saved_presentations_folder = saved_presentations_folder[:-1]
11169
11638
  if not os.path.exists(saved_presentations_folder):
11170
- try:
11639
+ with suppress(Exception):
11171
11640
  os.makedirs(saved_presentations_folder)
11172
- except Exception:
11173
- pass
11174
11641
  file_path = os.path.join(saved_presentations_folder, filename)
11175
11642
  out_file = codecs.open(file_path, "w+", encoding="utf-8")
11176
11643
  out_file.writelines(the_html)
@@ -11224,7 +11691,7 @@ class BaseCase(unittest.TestCase):
11224
11691
  self._presentation_slides[name].pop()
11225
11692
  self.open_html_file(file_path)
11226
11693
  presentation_folder = constants.Presentations.SAVED_FOLDER
11227
- try:
11694
+ with suppress(Exception):
11228
11695
  while (
11229
11696
  len(self.driver.window_handles) > 0
11230
11697
  and presentation_folder in self.get_current_url()
@@ -11235,8 +11702,6 @@ class BaseCase(unittest.TestCase):
11235
11702
  ):
11236
11703
  break
11237
11704
  time.sleep(0.05)
11238
- except Exception:
11239
- pass
11240
11705
 
11241
11706
  ############
11242
11707
 
@@ -11866,10 +12331,8 @@ class BaseCase(unittest.TestCase):
11866
12331
  if saved_charts_folder.endswith("/"):
11867
12332
  saved_charts_folder = saved_charts_folder[:-1]
11868
12333
  if not os.path.exists(saved_charts_folder):
11869
- try:
12334
+ with suppress(Exception):
11870
12335
  os.makedirs(saved_charts_folder)
11871
- except Exception:
11872
- pass
11873
12336
  file_path = os.path.join(saved_charts_folder, filename)
11874
12337
  out_file = codecs.open(file_path, "w+", encoding="utf-8")
11875
12338
  out_file.writelines(the_html)
@@ -11909,17 +12372,15 @@ class BaseCase(unittest.TestCase):
11909
12372
  self.open_html_file(file_path)
11910
12373
  chart_folder = constants.Charts.SAVED_FOLDER
11911
12374
  if interval == 0:
11912
- try:
12375
+ with suppress(Exception):
11913
12376
  print("\n*** Close the browser window to continue ***")
11914
12377
  # Will also continue if manually navigating to a new page
11915
12378
  while len(self.driver.window_handles) > 0 and (
11916
12379
  chart_folder in self.get_current_url()
11917
12380
  ):
11918
12381
  time.sleep(0.05)
11919
- except Exception:
11920
- pass
11921
12382
  else:
11922
- try:
12383
+ with suppress(Exception):
11923
12384
  start_ms = time.time() * 1000.0
11924
12385
  stop_ms = start_ms + (interval * 1000.0)
11925
12386
  for x in range(int(interval * 10)):
@@ -11931,8 +12392,6 @@ class BaseCase(unittest.TestCase):
11931
12392
  if chart_folder not in self.get_current_url():
11932
12393
  break
11933
12394
  time.sleep(0.1)
11934
- except Exception:
11935
- pass
11936
12395
 
11937
12396
  def extract_chart(self, chart_name=None):
11938
12397
  """Extracts the HTML from a SeleniumBase-generated chart.
@@ -12744,10 +13203,8 @@ class BaseCase(unittest.TestCase):
12744
13203
  )
12745
13204
  time.sleep(0.02)
12746
13205
  jf = "document.querySelector('.jconfirm-box').focus();"
12747
- try:
13206
+ with suppress(Exception):
12748
13207
  self.execute_script(jf)
12749
- except Exception:
12750
- pass
12751
13208
  waiting_for_response = True
12752
13209
  while waiting_for_response:
12753
13210
  time.sleep(0.05)
@@ -12819,10 +13276,8 @@ class BaseCase(unittest.TestCase):
12819
13276
  )
12820
13277
  time.sleep(0.02)
12821
13278
  jf = "document.querySelector('.jconfirm-box input.jqc_input').focus();"
12822
- try:
13279
+ with suppress(Exception):
12823
13280
  self.execute_script(jf)
12824
- except Exception:
12825
- pass
12826
13281
  waiting_for_response = True
12827
13282
  while waiting_for_response:
12828
13283
  time.sleep(0.05)
@@ -12883,10 +13338,8 @@ class BaseCase(unittest.TestCase):
12883
13338
  )
12884
13339
  time.sleep(0.02)
12885
13340
  jf = "document.querySelector('.jconfirm-box input.jqc_input').focus();"
12886
- try:
13341
+ with suppress(Exception):
12887
13342
  self.execute_script(jf)
12888
- except Exception:
12889
- pass
12890
13343
  waiting_for_response = True
12891
13344
  while waiting_for_response:
12892
13345
  time.sleep(0.05)
@@ -12961,12 +13414,10 @@ class BaseCase(unittest.TestCase):
12961
13414
  if not page_actions.is_element_clickable(
12962
13415
  self.driver, selector, by
12963
13416
  ):
12964
- try:
13417
+ with suppress(Exception):
12965
13418
  self.wait_for_element_clickable(
12966
13419
  selector, by, timeout=1.8
12967
13420
  )
12968
- except Exception:
12969
- pass
12970
13421
  # If the regular mouse-simulated click fails, do a basic JS click
12971
13422
  script = (
12972
13423
  """document.querySelector('%s').click();"""
@@ -13042,8 +13493,6 @@ class BaseCase(unittest.TestCase):
13042
13493
  timeout=None,
13043
13494
  center=None,
13044
13495
  ):
13045
- from selenium.webdriver.common.action_chains import ActionChains
13046
-
13047
13496
  self.wait_for_ready_state_complete()
13048
13497
  if self.__needs_minimum_wait():
13049
13498
  time.sleep(0.14)
@@ -13240,7 +13689,7 @@ class BaseCase(unittest.TestCase):
13240
13689
  for dropdown in matching_dropdowns:
13241
13690
  # The same class names might be used for multiple dropdowns
13242
13691
  if dropdown.is_displayed():
13243
- try:
13692
+ with suppress(Exception):
13244
13693
  try:
13245
13694
  page_actions.hover_element(
13246
13695
  self.driver,
@@ -13261,9 +13710,6 @@ class BaseCase(unittest.TestCase):
13261
13710
  timeout=0.12,
13262
13711
  )
13263
13712
  return True
13264
- except Exception:
13265
- pass
13266
-
13267
13713
  return False
13268
13714
 
13269
13715
  def __get_href_from_partial_link_text(self, link_text, hard_fail=True):
@@ -13304,7 +13750,7 @@ class BaseCase(unittest.TestCase):
13304
13750
  for dropdown in matching_dropdowns:
13305
13751
  # The same class names might be used for multiple dropdowns
13306
13752
  if dropdown.is_displayed():
13307
- try:
13753
+ with suppress(Exception):
13308
13754
  try:
13309
13755
  page_actions.hover_element(
13310
13756
  self.driver, dropdown
@@ -13326,8 +13772,6 @@ class BaseCase(unittest.TestCase):
13326
13772
  timeout=0.12,
13327
13773
  )
13328
13774
  return True
13329
- except Exception:
13330
- pass
13331
13775
  return False
13332
13776
 
13333
13777
  def __recalculate_selector(self, selector, by, xp_ok=True):
@@ -13351,7 +13795,8 @@ class BaseCase(unittest.TestCase):
13351
13795
  if self.get_current_url() == "about:blank":
13352
13796
  self.switch_to_window(current_window)
13353
13797
  except Exception:
13354
- self.switch_to_window(current_window)
13798
+ with suppress(Exception):
13799
+ self.switch_to_window(current_window)
13355
13800
 
13356
13801
  def __needs_minimum_wait(self):
13357
13802
  if (
@@ -13387,6 +13832,7 @@ class BaseCase(unittest.TestCase):
13387
13832
  self.slow_scroll_to(selector, by=by)
13388
13833
 
13389
13834
  def __demo_mode_highlight_if_active(self, selector, by):
13835
+ self.__skip_if_esc()
13390
13836
  if self.demo_mode:
13391
13837
  # Includes self.slow_scroll_to(selector, by=by) by default
13392
13838
  self.__highlight(selector, by=by)
@@ -13434,7 +13880,8 @@ class BaseCase(unittest.TestCase):
13434
13880
  js_utils.scroll_to_element(self.driver, element)
13435
13881
 
13436
13882
  def __highlight_with_js(self, selector, loops, o_bs):
13437
- self.wait_for_ready_state_complete()
13883
+ if not self.__is_cdp_swap_needed():
13884
+ self.wait_for_ready_state_complete()
13438
13885
  js_utils.highlight_with_js(self.driver, selector, loops, o_bs)
13439
13886
 
13440
13887
  def __highlight_element_with_js(self, element, loops, o_bs):
@@ -13549,23 +13996,112 @@ class BaseCase(unittest.TestCase):
13549
13996
  pass # JQuery probably couldn't load. Skip highlighting.
13550
13997
  time.sleep(0.065)
13551
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
+
13552
14086
  def __activate_virtual_display_as_needed(self):
13553
- """Should be needed only on Linux.
14087
+ """This is only needed on Linux.
13554
14088
  The "--xvfb" arg is still useful, as it prevents headless mode,
13555
14089
  which is the default mode on Linux unless using another arg."""
13556
14090
  if "linux" in sys.platform and (not self.headed or self.xvfb):
13557
- width = settings.HEADLESS_START_WIDTH
13558
- height = settings.HEADLESS_START_HEIGHT
14091
+ pip_find_lock = fasteners.InterProcessLock(
14092
+ constants.PipInstall.FINDLOCK
14093
+ )
13559
14094
  try:
13560
- from sbvirtualdisplay import Display
13561
-
13562
- self._xvfb_display = Display(visible=0, size=(width, height))
13563
- self._xvfb_display.start()
13564
- sb_config._virtual_display = self._xvfb_display
13565
- self.headless_active = True
13566
- sb_config.headless_active = True
14095
+ with pip_find_lock:
14096
+ pass
13567
14097
  except Exception:
13568
- 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()
13569
14105
 
13570
14106
  def __ad_block_as_needed(self):
13571
14107
  """This is an internal method for handling ad-blocking.
@@ -13787,12 +14323,10 @@ class BaseCase(unittest.TestCase):
13787
14323
  selector, timeout=timeout, must_be_visible=True
13788
14324
  )
13789
14325
  if clear_first:
13790
- try:
14326
+ with suppress(Exception):
13791
14327
  element.clear()
13792
14328
  backspaces = Keys.BACK_SPACE * 42 # Autofill Defense
13793
14329
  element.send_keys(backspaces)
13794
- except Exception:
13795
- pass
13796
14330
  text = self.__get_type_checked_text(text)
13797
14331
  if not text.endswith("\n"):
13798
14332
  element.send_keys(text)
@@ -13808,12 +14342,10 @@ class BaseCase(unittest.TestCase):
13808
14342
  element = self.__get_shadow_element(
13809
14343
  selector, timeout=timeout, must_be_visible=True
13810
14344
  )
13811
- try:
14345
+ with suppress(Exception):
13812
14346
  element.clear()
13813
14347
  backspaces = Keys.BACK_SPACE * 42 # Autofill Defense
13814
14348
  element.send_keys(backspaces)
13815
- except Exception:
13816
- pass
13817
14349
 
13818
14350
  def __get_shadow_text(self, selector, timeout):
13819
14351
  element = self.__get_shadow_element(
@@ -13933,19 +14465,13 @@ class BaseCase(unittest.TestCase):
13933
14465
  a_t = SD.translate_assert_text(self._language)
13934
14466
  i_n = SD.translate_in(self._language)
13935
14467
  messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
13936
- a_t,
13937
- text,
13938
- i_n,
13939
- by.upper(),
13940
- selector,
14468
+ a_t, text, i_n, by.upper(), selector
13941
14469
  )
13942
- try:
14470
+ with suppress(Exception):
13943
14471
  js_utils.activate_jquery(self.driver)
13944
14472
  js_utils.post_messenger_success_message(
13945
14473
  self.driver, messenger_post, self.message_duration
13946
14474
  )
13947
- except Exception:
13948
- pass
13949
14475
 
13950
14476
  def __assert_exact_shadow_text_visible(self, text, selector, timeout):
13951
14477
  self.__wait_for_exact_shadow_text_visible(text, selector, timeout)
@@ -13959,19 +14485,13 @@ class BaseCase(unittest.TestCase):
13959
14485
  a_t = SD.translate_assert_exact_text(self._language)
13960
14486
  i_n = SD.translate_in(self._language)
13961
14487
  messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
13962
- a_t,
13963
- text,
13964
- i_n,
13965
- by.upper(),
13966
- selector,
14488
+ a_t, text, i_n, by.upper(), selector
13967
14489
  )
13968
- try:
14490
+ with suppress(Exception):
13969
14491
  js_utils.activate_jquery(self.driver)
13970
14492
  js_utils.post_messenger_success_message(
13971
14493
  self.driver, messenger_post, self.message_duration
13972
14494
  )
13973
- except Exception:
13974
- pass
13975
14495
 
13976
14496
  def __assert_non_empty_shadow_text_visible(self, selector, timeout, strip):
13977
14497
  self.__wait_for_non_empty_shadow_text_visible(selector, timeout, strip)
@@ -13985,18 +14505,13 @@ class BaseCase(unittest.TestCase):
13985
14505
  a_t = SD.translate_assert_non_empty_text(self._language)
13986
14506
  i_n = SD.translate_in(self._language)
13987
14507
  messenger_post = "<b>%s</b> %s %s: %s" % (
13988
- a_t,
13989
- i_n,
13990
- by.upper(),
13991
- selector,
14508
+ a_t, i_n, by.upper(), selector
13992
14509
  )
13993
- try:
14510
+ with suppress(Exception):
13994
14511
  js_utils.activate_jquery(self.driver)
13995
14512
  js_utils.post_messenger_success_message(
13996
14513
  self.driver, messenger_post, self.message_duration
13997
14514
  )
13998
- except Exception:
13999
- pass
14000
14515
 
14001
14516
  def __is_shadow_element_present(self, selector):
14002
14517
  try:
@@ -14124,7 +14639,7 @@ class BaseCase(unittest.TestCase):
14124
14639
  message = (
14125
14640
  "Expected value {%s} for attribute {%s} of element "
14126
14641
  "{%s} was not present after %s second%s! "
14127
- "(The actual value was {%s})"
14642
+ "(Actual value was {%s})"
14128
14643
  % (
14129
14644
  value,
14130
14645
  attribute,
@@ -14148,13 +14663,11 @@ class BaseCase(unittest.TestCase):
14148
14663
 
14149
14664
  a_t = SD.translate_assert(self._language)
14150
14665
  messenger_post = "<b>%s %s</b>: %s" % (a_t, by.upper(), selector)
14151
- try:
14666
+ with suppress(Exception):
14152
14667
  js_utils.activate_jquery(self.driver)
14153
14668
  js_utils.post_messenger_success_message(
14154
14669
  self.driver, messenger_post, self.message_duration
14155
14670
  )
14156
- except Exception:
14157
- pass
14158
14671
 
14159
14672
  def __assert_shadow_element_visible(self, selector):
14160
14673
  element = self.__get_shadow_element(selector)
@@ -14169,13 +14682,11 @@ class BaseCase(unittest.TestCase):
14169
14682
 
14170
14683
  a_t = SD.translate_assert(self._language)
14171
14684
  messenger_post = "<b>%s %s</b>: %s" % (a_t, by.upper(), selector)
14172
- try:
14685
+ with suppress(Exception):
14173
14686
  js_utils.activate_jquery(self.driver)
14174
14687
  js_utils.post_messenger_success_message(
14175
14688
  self.driver, messenger_post, self.message_duration
14176
14689
  )
14177
- except Exception:
14178
- pass
14179
14690
 
14180
14691
  ############
14181
14692
 
@@ -14250,10 +14761,15 @@ class BaseCase(unittest.TestCase):
14250
14761
  self.env = self.environment # Add a shortened version
14251
14762
  self.with_selenium = sb_config.with_selenium # Should be True
14252
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
14253
14768
  self.headless_active = False
14254
14769
  sb_config.headless_active = False
14255
14770
  self.headed = sb_config.headed
14256
14771
  self.xvfb = sb_config.xvfb
14772
+ self.xvfb_metrics = sb_config.xvfb_metrics
14257
14773
  self.locale_code = sb_config.locale_code
14258
14774
  self.interval = sb_config.interval
14259
14775
  self.start_page = sb_config.start_page
@@ -14288,6 +14804,7 @@ class BaseCase(unittest.TestCase):
14288
14804
  self.firefox_arg = sb_config.firefox_arg
14289
14805
  self.firefox_pref = sb_config.firefox_pref
14290
14806
  self.verify_delay = sb_config.verify_delay
14807
+ self.esc_end = sb_config.esc_end
14291
14808
  self.recorder_mode = sb_config.recorder_mode
14292
14809
  self.recorder_ext = sb_config.recorder_mode
14293
14810
  self.rec_print = sb_config.rec_print
@@ -14302,6 +14819,7 @@ class BaseCase(unittest.TestCase):
14302
14819
  elif self.record_sleep and not self.recorder_mode:
14303
14820
  self.recorder_mode = True
14304
14821
  self.recorder_ext = True
14822
+ self.disable_cookies = sb_config.disable_cookies
14305
14823
  self.disable_js = sb_config.disable_js
14306
14824
  self.disable_csp = sb_config.disable_csp
14307
14825
  self.disable_ws = sb_config.disable_ws
@@ -14316,7 +14834,6 @@ class BaseCase(unittest.TestCase):
14316
14834
  self.log_cdp_events = sb_config.log_cdp_events
14317
14835
  self.no_sandbox = sb_config.no_sandbox
14318
14836
  self.disable_gpu = sb_config.disable_gpu
14319
- self.headless2 = sb_config.headless2
14320
14837
  self.incognito = sb_config.incognito
14321
14838
  self.guest_mode = sb_config.guest_mode
14322
14839
  self.dark_mode = sb_config.dark_mode
@@ -14344,31 +14861,8 @@ class BaseCase(unittest.TestCase):
14344
14861
  self.use_wire = sb_config.use_wire
14345
14862
  self.external_pdf = sb_config.external_pdf
14346
14863
  self._final_debug = sb_config.final_debug
14864
+ self.window_position = sb_config.window_position
14347
14865
  self.window_size = sb_config.window_size
14348
- window_size = self.window_size
14349
- if window_size:
14350
- if window_size.count(",") != 1:
14351
- message = (
14352
- '\n\n window_size expects a "width,height" string!'
14353
- '\n (Your input was: "%s")\n' % window_size
14354
- )
14355
- raise Exception(message)
14356
- window_size = window_size.replace(" ", "")
14357
- width = None
14358
- height = None
14359
- try:
14360
- width = int(window_size.split(",")[0])
14361
- height = int(window_size.split(",")[1])
14362
- except Exception:
14363
- message = (
14364
- '\n\n Expecting integer values for "width,height"!'
14365
- '\n (window_size input was: "%s")\n' % window_size
14366
- )
14367
- raise Exception(message)
14368
- settings.CHROME_START_WIDTH = width
14369
- settings.CHROME_START_HEIGHT = height
14370
- settings.HEADLESS_START_WIDTH = width
14371
- settings.HEADLESS_START_HEIGHT = height
14372
14866
  self.maximize_option = sb_config.maximize_option
14373
14867
  self.save_screenshot_after_test = sb_config.save_screenshot
14374
14868
  self.no_screenshot_after_test = sb_config.no_screenshot
@@ -14426,15 +14920,13 @@ class BaseCase(unittest.TestCase):
14426
14920
  self.__skip_reason = None
14427
14921
  self.testcase_manager.insert_testcase_data(data_payload)
14428
14922
  self.case_start_time = int(time.time() * 1000.0)
14429
- self.__activate_virtual_display_as_needed()
14430
14923
  elif hasattr(self, "is_behave") and self.is_behave:
14431
14924
  self.__initialize_variables()
14432
- self.__activate_virtual_display_as_needed()
14433
14925
  elif hasattr(self, "is_nosetest") and self.is_nosetest:
14434
14926
  pass # Setup performed in plugins for pynose
14435
14927
  else:
14436
- # Pure Python run. Eg. SB() Manager
14437
- self.__activate_virtual_display_as_needed()
14928
+ # Pure Python run. (Eg. SB() and Driver() Managers)
14929
+ pass # Variables initialized in respective plugins
14438
14930
 
14439
14931
  # Verify SeleniumBase is installed successfully, and used correctly
14440
14932
  if not hasattr(self, "browser"):
@@ -14519,8 +15011,8 @@ class BaseCase(unittest.TestCase):
14519
15011
  metrics_list = metrics_string.split(",")
14520
15012
  exception_string = (
14521
15013
  "Invalid input for Mobile Emulator device metrics!\n"
14522
- "Expecting a comma-separated string with three\n"
14523
- "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"
14524
15016
  'Example: --metrics="411,731,3" '
14525
15017
  )
14526
15018
  if len(metrics_list) != 3:
@@ -14528,13 +15020,91 @@ class BaseCase(unittest.TestCase):
14528
15020
  try:
14529
15021
  self.__device_width = int(metrics_list[0])
14530
15022
  self.__device_height = int(metrics_list[1])
14531
- self.__device_pixel_ratio = int(metrics_list[2])
15023
+ self.__device_pixel_ratio = float(metrics_list[2])
14532
15024
  self.mobile_emulator = True
14533
15025
  except Exception:
14534
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
+
14535
15104
  if self.mobile_emulator and not self.user_agent:
14536
15105
  # Use a Pixel user agent by default if not specified
14537
15106
  self.user_agent = constants.Mobile.AGENT
15107
+
14538
15108
  if self.browser in ["firefox", "ie", "safari"]:
14539
15109
  # The Recorder Mode browser extension is only for Chrome/Edge.
14540
15110
  if self.recorder_mode:
@@ -14544,10 +15114,18 @@ class BaseCase(unittest.TestCase):
14544
15114
  )
14545
15115
  raise Exception(message)
14546
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
+
14547
15121
  # Dashboard pre-processing:
14548
15122
  if self.dashboard:
14549
15123
  if self._multithreaded:
14550
15124
  with self.dash_lock:
15125
+ with suppress(Exception):
15126
+ shared_utils.make_writable(
15127
+ constants.Dashboard.LOCKFILE
15128
+ )
14551
15129
  if not self._dash_initialized:
14552
15130
  sb_config._dashboard_initialized = True
14553
15131
  self._dash_initialized = True
@@ -14568,7 +15146,7 @@ class BaseCase(unittest.TestCase):
14568
15146
  if not hasattr(sb_config, "shared_driver"):
14569
15147
  sb_config.shared_driver = None
14570
15148
  if sb_config.shared_driver:
14571
- try:
15149
+ with suppress(Exception):
14572
15150
  self._default_driver = sb_config.shared_driver
14573
15151
  self.driver = sb_config.shared_driver
14574
15152
  self._drivers_list = [sb_config.shared_driver]
@@ -14582,12 +15160,8 @@ class BaseCase(unittest.TestCase):
14582
15160
  self.switch_to_window(0)
14583
15161
  if self._crumbs:
14584
15162
  self.wait_for_ready_state_complete()
14585
- try:
15163
+ with suppress(Exception):
14586
15164
  self.driver.delete_all_cookies()
14587
- except Exception:
14588
- pass
14589
- except Exception:
14590
- pass
14591
15165
  if self._reuse_session and sb_config.shared_driver and has_url:
14592
15166
  good_start_page = False
14593
15167
  if self.recorder_ext:
@@ -14630,6 +15204,7 @@ class BaseCase(unittest.TestCase):
14630
15204
  cap_file=self.cap_file,
14631
15205
  cap_string=self.cap_string,
14632
15206
  recorder_ext=self.recorder_ext,
15207
+ disable_cookies=self.disable_cookies,
14633
15208
  disable_js=self.disable_js,
14634
15209
  disable_csp=self.disable_csp,
14635
15210
  enable_ws=self.enable_ws,
@@ -14641,6 +15216,7 @@ class BaseCase(unittest.TestCase):
14641
15216
  log_cdp_events=self.log_cdp_events,
14642
15217
  no_sandbox=self.no_sandbox,
14643
15218
  disable_gpu=self.disable_gpu,
15219
+ headless1=self.headless1,
14644
15220
  headless2=self.headless2,
14645
15221
  incognito=self.incognito,
14646
15222
  guest_mode=self.guest_mode,
@@ -14674,10 +15250,8 @@ class BaseCase(unittest.TestCase):
14674
15250
  if self.driver.timeouts.implicit_wait > 0:
14675
15251
  self.driver.implicitly_wait(0)
14676
15252
  except Exception:
14677
- try:
15253
+ with suppress(Exception):
14678
15254
  self.driver.implicitly_wait(0)
14679
- except Exception:
14680
- pass
14681
15255
  self._default_driver = self.driver
14682
15256
  if self._reuse_session:
14683
15257
  sb_config.shared_driver = self.driver
@@ -14696,13 +15270,11 @@ class BaseCase(unittest.TestCase):
14696
15270
  self.set_time_limit(self.time_limit)
14697
15271
 
14698
15272
  # Configure the page load timeout
14699
- try:
15273
+ with suppress(Exception):
14700
15274
  if hasattr(settings, "PAGE_LOAD_TIMEOUT"):
14701
15275
  self.driver.set_page_load_timeout(settings.PAGE_LOAD_TIMEOUT)
14702
15276
  else:
14703
15277
  self.driver.set_page_load_timeout(120) # Selenium uses 300
14704
- except Exception:
14705
- pass
14706
15278
 
14707
15279
  # Set the start time for the test (in ms).
14708
15280
  # Although the pytest clock starts before setUp() begins,
@@ -14731,7 +15303,7 @@ class BaseCase(unittest.TestCase):
14731
15303
  not self.__last_page_screenshot
14732
15304
  and not self.__last_page_screenshot_png
14733
15305
  ):
14734
- try:
15306
+ with suppress(Exception):
14735
15307
  try:
14736
15308
  element = page_actions.wait_for_element_visible(
14737
15309
  self.driver,
@@ -14761,14 +15333,10 @@ class BaseCase(unittest.TestCase):
14761
15333
  element.screenshot_as_base64
14762
15334
  )
14763
15335
  except Exception:
14764
- try:
15336
+ with suppress(Exception):
14765
15337
  self.__last_page_screenshot = (
14766
15338
  self.driver.get_screenshot_as_base64()
14767
15339
  )
14768
- except Exception:
14769
- pass
14770
- except Exception:
14771
- pass
14772
15340
  if not self.__last_page_screenshot:
14773
15341
  self.__last_page_screenshot = SCREENSHOT_UNDEFINED
14774
15342
  self.__last_page_screenshot_png = SCREENSHOT_UNDEFINED
@@ -14778,12 +15346,10 @@ class BaseCase(unittest.TestCase):
14778
15346
  element.screenshot_as_png
14779
15347
  )
14780
15348
  except Exception:
14781
- try:
15349
+ with suppress(Exception):
14782
15350
  self.__last_page_screenshot_png = (
14783
15351
  self.driver.get_screenshot_as_png()
14784
15352
  )
14785
- except Exception:
14786
- pass
14787
15353
  else:
14788
15354
  import base64
14789
15355
 
@@ -14798,12 +15364,10 @@ class BaseCase(unittest.TestCase):
14798
15364
  element.screenshot_as_png
14799
15365
  )
14800
15366
  except Exception:
14801
- try:
15367
+ with suppress(Exception):
14802
15368
  self.__last_page_screenshot_png = (
14803
15369
  self.driver.get_screenshot_as_png()
14804
15370
  )
14805
- except Exception:
14806
- pass
14807
15371
  sb_config._last_page_screenshot_png = self.__last_page_screenshot_png
14808
15372
 
14809
15373
  def __set_last_page_url(self):
@@ -14855,7 +15419,6 @@ class BaseCase(unittest.TestCase):
14855
15419
  data_payload.state = state
14856
15420
  if err:
14857
15421
  import traceback
14858
-
14859
15422
  tb_string = traceback.format_exc()
14860
15423
  if "Message: " in tb_string:
14861
15424
  data_payload.message = (
@@ -14890,7 +15453,7 @@ class BaseCase(unittest.TestCase):
14890
15453
 
14891
15454
  def __add_pytest_html_extra(self):
14892
15455
  if not self.__added_pytest_html_extra:
14893
- try:
15456
+ with suppress(Exception):
14894
15457
  if self.with_selenium:
14895
15458
  if not self.__last_page_screenshot:
14896
15459
  self.__set_last_page_screenshot()
@@ -14917,8 +15480,6 @@ class BaseCase(unittest.TestCase):
14917
15480
  ):
14918
15481
  self._html_report_extra.append(extra_url)
14919
15482
  self._html_report_extra.append(extra_image)
14920
- except Exception:
14921
- pass
14922
15483
 
14923
15484
  def __delay_driver_quit(self):
14924
15485
  delay_driver_quit = False
@@ -15012,7 +15573,6 @@ class BaseCase(unittest.TestCase):
15012
15573
  context_id = None
15013
15574
  if filename == "base_case.py" or methodname == "runTest":
15014
15575
  import traceback
15015
-
15016
15576
  stack_base = traceback.format_stack()[0].split(", in ")[0]
15017
15577
  test_base = stack_base.split(", in ")[0].split(os.sep)[-1]
15018
15578
  if hasattr(self, "cm_filename") and self.cm_filename:
@@ -15032,7 +15592,8 @@ class BaseCase(unittest.TestCase):
15032
15592
  elif hasattr(self, "_using_sb_fixture") and self._using_sb_fixture:
15033
15593
  test_id = sb_config._latest_display_id
15034
15594
  test_id = test_id.replace(".py::", ".").replace("::", ".")
15035
- test_id = test_id.replace("/", ".").replace(" ", "_")
15595
+ test_id = test_id.replace("/", ".").replace("\\", ".")
15596
+ test_id = test_id.replace(" ", "_")
15036
15597
  # Linux filename length limit for `codecs.open(filename)` = 255
15037
15598
  # 255 - len("latest_logs/") - len("/basic_test_info.txt") = 223
15038
15599
  if len(test_id) <= 223:
@@ -15124,6 +15685,8 @@ class BaseCase(unittest.TestCase):
15124
15685
  constants.Dashboard.LOCKFILE
15125
15686
  )
15126
15687
  with self.dash_lock:
15688
+ with suppress(Exception):
15689
+ shared_utils.make_writable(constants.Dashboard.LOCKFILE)
15127
15690
  self.__process_dashboard(has_exception, init)
15128
15691
  else:
15129
15692
  self.__process_dashboard(has_exception, init)
@@ -15607,6 +16170,31 @@ class BaseCase(unittest.TestCase):
15607
16170
  else:
15608
16171
  return None
15609
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
+
15610
16198
  def _addSkip(self, result, test_case, reason):
15611
16199
  """This method should NOT be called directly from tests."""
15612
16200
  addSkip = getattr(result, 'addSkip', None)
@@ -15704,7 +16292,15 @@ class BaseCase(unittest.TestCase):
15704
16292
  # This test already called tearDown()
15705
16293
  return
15706
16294
  if hasattr(self, "recorder_mode") and self.recorder_mode:
15707
- 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)
15708
16304
  self.__called_teardown = True
15709
16305
  self.__called_setup = False
15710
16306
  try:
@@ -15737,6 +16333,7 @@ class BaseCase(unittest.TestCase):
15737
16333
  )
15738
16334
  raise Exception(message)
15739
16335
  # *** Start tearDown() officially ***
16336
+ page_actions._reconnect_if_disconnected(self.driver)
15740
16337
  self.__slow_mode_pause_if_active()
15741
16338
  has_exception = self.__has_exception()
15742
16339
  sb_config._has_exception = has_exception
@@ -15859,6 +16456,10 @@ class BaseCase(unittest.TestCase):
15859
16456
  if self.dashboard:
15860
16457
  if self._multithreaded:
15861
16458
  with self.dash_lock:
16459
+ with suppress(Exception):
16460
+ shared_utils.make_writable(
16461
+ constants.Dashboard.LOCKFILE
16462
+ )
15862
16463
  self.__process_dashboard(has_exception)
15863
16464
  else:
15864
16465
  self.__process_dashboard(has_exception)
@@ -15926,7 +16527,6 @@ class BaseCase(unittest.TestCase):
15926
16527
  else:
15927
16528
  # (Pynose / Behave / Pure Python)
15928
16529
  if hasattr(self, "is_behave") and self.is_behave:
15929
- import colorama
15930
16530
  if sb_config.behave_scenario.status.name == "failed":
15931
16531
  has_exception = True
15932
16532
  sb_config._has_exception = True
@@ -15934,8 +16534,6 @@ class BaseCase(unittest.TestCase):
15934
16534
  if is_windows:
15935
16535
  c1 = colorama.Fore.RED + colorama.Back.LIGHTRED_EX
15936
16536
  cr = colorama.Style.RESET_ALL
15937
- if hasattr(colorama, "just_fix_windows_console"):
15938
- colorama.just_fix_windows_console()
15939
16537
  msg = msg.replace("❌", c1 + "><" + cr)
15940
16538
  print(msg)
15941
16539
  else:
@@ -15943,8 +16541,6 @@ class BaseCase(unittest.TestCase):
15943
16541
  if is_windows:
15944
16542
  c2 = colorama.Fore.GREEN + colorama.Back.LIGHTGREEN_EX
15945
16543
  cr = colorama.Style.RESET_ALL
15946
- if hasattr(colorama, "just_fix_windows_console"):
15947
- colorama.just_fix_windows_console()
15948
16544
  msg = msg.replace("✅", c2 + "<>" + cr)
15949
16545
  print(msg)
15950
16546
  if self.dashboard:
@@ -16009,6 +16605,7 @@ class BaseCase(unittest.TestCase):
16009
16605
  self.__quit_all_drivers()
16010
16606
  # Resume tearDown() for all test runners, (Pytest / Pynose / Behave)
16011
16607
  if hasattr(self, "_xvfb_display") and self._xvfb_display:
16608
+ # Stop the Xvfb virtual display launched from BaseCase
16012
16609
  try:
16013
16610
  if hasattr(self._xvfb_display, "stop"):
16014
16611
  self._xvfb_display.stop()
@@ -16018,6 +16615,20 @@ class BaseCase(unittest.TestCase):
16018
16615
  pass
16019
16616
  except Exception:
16020
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
16021
16632
  if self.__visual_baseline_copies:
16022
16633
  sb_config._visual_baseline_copies = True
16023
16634
  if has_exception: