seleniumbase 4.31.6a4__py3-none-any.whl → 4.32.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,12 +4,17 @@ from selenium.webdriver.remote.webelement import WebElement
4
4
  from seleniumbase.fixtures import js_utils
5
5
  from seleniumbase.fixtures import page_actions
6
6
  from seleniumbase.fixtures import page_utils
7
+ from seleniumbase.fixtures import shared_utils
7
8
 
8
9
 
9
10
  class DriverMethods():
10
11
  def __init__(self, driver):
11
12
  self.driver = driver
12
13
 
14
+ def __is_cdp_swap_needed(self):
15
+ """If the driver is disconnected, use a CDP method when available."""
16
+ return shared_utils.is_cdp_swap_needed(self.driver)
17
+
13
18
  def find_element(self, by=None, value=None):
14
19
  if not value:
15
20
  value = by
@@ -45,10 +50,21 @@ class DriverMethods():
45
50
  element = self.locator(selector, by=by)
46
51
  return element.get_attribute(attribute)
47
52
 
53
+ def get_current_url(self):
54
+ if self.__is_cdp_swap_needed():
55
+ current_url = self.driver.cdp.get_current_url()
56
+ else:
57
+ current_url = self.driver.current_url
58
+ return current_url
59
+
48
60
  def get_page_source(self):
61
+ if self.__is_cdp_swap_needed():
62
+ return self.driver.cdp.get_page_source()
49
63
  return self.driver.page_source
50
64
 
51
65
  def get_title(self):
66
+ if self.__is_cdp_swap_needed():
67
+ return self.driver.cdp.get_title()
52
68
  return self.driver.title
53
69
 
54
70
  def open_url(self, *args, **kwargs):
@@ -175,6 +191,34 @@ class DriverMethods():
175
191
  def is_online(self):
176
192
  return self.driver.execute_script("return navigator.onLine;")
177
193
 
194
+ def is_connected(self):
195
+ """
196
+ Return True if WebDriver is connected to the browser.
197
+ Note that the stealthy CDP-Driver isn't a WebDriver.
198
+ In CDP Mode, the CDP-Driver controls the web browser.
199
+ The CDP-Driver can be connected while WebDriver isn't.
200
+ """
201
+ try:
202
+ self.driver.window_handles
203
+ return True
204
+ except Exception:
205
+ return False
206
+
207
+ def is_uc_mode_active(self):
208
+ """Return True if the driver is using UC Mode. False otherwise."""
209
+ return (
210
+ hasattr(self.driver, "_is_using_uc")
211
+ and self.driver._is_using_uc
212
+ )
213
+
214
+ def is_cdp_mode_active(self):
215
+ """CDP Mode is a special mode within UC Mode. Activated separately.
216
+ Return True if CDP Mode is loaded in the driver. False otherwise."""
217
+ return (
218
+ hasattr(self.driver, "_is_using_cdp")
219
+ and self.driver._is_using_cdp
220
+ )
221
+
178
222
  def js_click(self, *args, **kwargs):
179
223
  return page_actions.js_click(self.driver, *args, **kwargs)
180
224
 
@@ -223,6 +223,9 @@ class BaseCase(unittest.TestCase):
223
223
  def open(self, url):
224
224
  """Navigates the current browser window to the specified page."""
225
225
  self.__check_scope()
226
+ if self.__is_cdp_swap_needed():
227
+ self.cdp.open(url)
228
+ return
226
229
  self._check_browser()
227
230
  if self.__needs_minimum_wait():
228
231
  time.sleep(0.04)
@@ -388,6 +391,9 @@ class BaseCase(unittest.TestCase):
388
391
  original_selector = selector
389
392
  original_by = by
390
393
  selector, by = self.__recalculate_selector(selector, by)
394
+ if self.__is_cdp_swap_needed():
395
+ self.cdp.click(selector)
396
+ return
391
397
  if delay and (type(delay) in [int, float]) and delay > 0:
392
398
  time.sleep(delay)
393
399
  if page_utils.is_link_text_selector(selector) or by == By.LINK_TEXT:
@@ -878,6 +884,9 @@ class BaseCase(unittest.TestCase):
878
884
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
879
885
  timeout = self.__get_new_timeout(timeout)
880
886
  selector, by = self.__recalculate_selector(selector, by)
887
+ if self.__is_cdp_swap_needed():
888
+ self.cdp.type(selector, text)
889
+ return
881
890
  if self.__is_shadow_selector(selector):
882
891
  self.__shadow_type(selector, text, timeout)
883
892
  return
@@ -991,6 +1000,9 @@ class BaseCase(unittest.TestCase):
991
1000
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
992
1001
  timeout = self.__get_new_timeout(timeout)
993
1002
  selector, by = self.__recalculate_selector(selector, by)
1003
+ if self.__is_cdp_swap_needed():
1004
+ self.cdp.send_keys(selector, text)
1005
+ return
994
1006
  if self.__is_shadow_selector(selector):
995
1007
  self.__shadow_type(selector, text, timeout, clear_first=False)
996
1008
  return
@@ -1099,6 +1111,9 @@ class BaseCase(unittest.TestCase):
1099
1111
 
1100
1112
  def press_keys(self, selector, text, by="css selector", timeout=None):
1101
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)
1116
+ return
1102
1117
  self.wait_for_ready_state_complete()
1103
1118
  element = self.wait_for_element_present(
1104
1119
  selector, by=by, timeout=timeout
@@ -1207,6 +1222,9 @@ class BaseCase(unittest.TestCase):
1207
1222
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
1208
1223
  timeout = self.__get_new_timeout(timeout)
1209
1224
  selector, by = self.__recalculate_selector(selector, by)
1225
+ if self.__is_cdp_swap_needed():
1226
+ self.cdp.focus(selector)
1227
+ return
1210
1228
  element = self.wait_for_element_present(
1211
1229
  selector, by=by, timeout=timeout
1212
1230
  )
@@ -1237,6 +1255,9 @@ class BaseCase(unittest.TestCase):
1237
1255
  def refresh_page(self):
1238
1256
  self.__check_scope()
1239
1257
  self.__last_page_load_url = None
1258
+ if self.__is_cdp_swap_needed():
1259
+ self.cdp.reload()
1260
+ return
1240
1261
  js_utils.clear_out_console_logs(self.driver)
1241
1262
  self.driver.refresh()
1242
1263
  self.wait_for_ready_state_complete()
@@ -1247,7 +1268,11 @@ class BaseCase(unittest.TestCase):
1247
1268
 
1248
1269
  def get_current_url(self):
1249
1270
  self.__check_scope()
1250
- 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
1251
1276
  if "%" in current_url:
1252
1277
  try:
1253
1278
  from urllib.parse import unquote
@@ -1262,15 +1287,22 @@ class BaseCase(unittest.TestCase):
1262
1287
  return self.execute_script("return window.location.origin;")
1263
1288
 
1264
1289
  def get_page_source(self):
1290
+ if self.__is_cdp_swap_needed():
1291
+ return self.cdp.get_page_source()
1265
1292
  self.wait_for_ready_state_complete()
1266
1293
  if self.__needs_minimum_wait:
1267
- time.sleep(0.02)
1294
+ time.sleep(0.025)
1268
1295
  return self.driver.page_source
1269
1296
 
1270
1297
  def get_page_title(self):
1298
+ if self.__is_cdp_swap_needed():
1299
+ return self.cdp.get_title()
1271
1300
  self.wait_for_ready_state_complete()
1272
- self.wait_for_element_present("title", timeout=settings.SMALL_TIMEOUT)
1273
- 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)
1274
1306
  return self.driver.title
1275
1307
 
1276
1308
  def get_title(self):
@@ -1365,7 +1397,7 @@ class BaseCase(unittest.TestCase):
1365
1397
  to convert the open() action into open_if_not_url() so that the
1366
1398
  same page isn't opened again if the user is already on the page."""
1367
1399
  self.__check_scope()
1368
- current_url = self.driver.current_url
1400
+ current_url = self.get_current_url()
1369
1401
  if current_url != url:
1370
1402
  if (
1371
1403
  "?q=" not in current_url
@@ -1377,6 +1409,8 @@ class BaseCase(unittest.TestCase):
1377
1409
 
1378
1410
  def is_element_present(self, selector, by="css selector"):
1379
1411
  """Returns whether the element exists in the HTML."""
1412
+ if self.__is_cdp_swap_needed():
1413
+ return self.cdp.is_element_present(selector)
1380
1414
  self.wait_for_ready_state_complete()
1381
1415
  selector, by = self.__recalculate_selector(selector, by)
1382
1416
  if self.__is_shadow_selector(selector):
@@ -1385,6 +1419,8 @@ class BaseCase(unittest.TestCase):
1385
1419
 
1386
1420
  def is_element_visible(self, selector, by="css selector"):
1387
1421
  """Returns whether the element is visible on the page."""
1422
+ if self.__is_cdp_swap_needed():
1423
+ return self.cdp.is_element_visible(selector)
1388
1424
  self.wait_for_ready_state_complete()
1389
1425
  selector, by = self.__recalculate_selector(selector, by)
1390
1426
  if self.__is_shadow_selector(selector):
@@ -1562,6 +1598,9 @@ class BaseCase(unittest.TestCase):
1562
1598
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
1563
1599
  timeout = self.__get_new_timeout(timeout)
1564
1600
  link_text = self.__get_type_checked_text(link_text)
1601
+ if self.__is_cdp_swap_needed():
1602
+ self.cdp.click_link(link_text)
1603
+ return
1565
1604
  if self.browser == "safari":
1566
1605
  if self.demo_mode:
1567
1606
  self.wait_for_link_text_present(link_text, timeout=timeout)
@@ -1794,6 +1833,8 @@ class BaseCase(unittest.TestCase):
1794
1833
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
1795
1834
  timeout = self.__get_new_timeout(timeout)
1796
1835
  selector, by = self.__recalculate_selector(selector, by)
1836
+ if self.__is_cdp_swap_needed():
1837
+ return self.cdp.get_text(selector)
1797
1838
  if self.__is_shadow_selector(selector):
1798
1839
  return self.__get_shadow_text(selector, timeout)
1799
1840
  self.wait_for_ready_state_complete()
@@ -1921,6 +1962,9 @@ class BaseCase(unittest.TestCase):
1921
1962
  self.set_attributes("a", "href", "https://google.com")"""
1922
1963
  self.__check_scope()
1923
1964
  selector, by = self.__recalculate_selector(selector, by)
1965
+ if self.__is_cdp_swap_needed():
1966
+ self.cdp.set_attributes(selector, attribute, value)
1967
+ return
1924
1968
  original_attribute = attribute
1925
1969
  original_value = value
1926
1970
  attribute = re.escape(attribute)
@@ -2001,6 +2045,14 @@ class BaseCase(unittest.TestCase):
2001
2045
  with suppress(Exception):
2002
2046
  self.execute_script(script)
2003
2047
 
2048
+ def internalize_links(self):
2049
+ """All `target="_blank"` links become `target="_self"`.
2050
+ This prevents those links from opening in a new tab."""
2051
+ if self.__is_cdp_swap_needed():
2052
+ self.cdp.internalize_links()
2053
+ return
2054
+ self.set_attributes('[target="_blank"]', "target", "_self")
2055
+
2004
2056
  def get_property(
2005
2057
  self, selector, property, by="css selector", timeout=None
2006
2058
  ):
@@ -2104,6 +2156,12 @@ class BaseCase(unittest.TestCase):
2104
2156
  Elements could be either hidden or visible on the page.
2105
2157
  If "limit" is set and > 0, will only return that many elements."""
2106
2158
  selector, by = self.__recalculate_selector(selector, by)
2159
+ if self.__is_cdp_swap_needed():
2160
+ elements = self.cdp.select_all(selector)
2161
+ if limit and limit > 0 and len(elements) > limit:
2162
+ elements = elements[:limit]
2163
+ return elements
2164
+
2107
2165
  self.wait_for_ready_state_complete()
2108
2166
  time.sleep(0.05)
2109
2167
  elements = self.driver.find_elements(by=by, value=selector)
@@ -2277,6 +2335,9 @@ class BaseCase(unittest.TestCase):
2277
2335
  Use click_visible_elements() to click all matching elements.
2278
2336
  If a "timeout" is provided, waits that long for the element
2279
2337
  to appear before giving up and returning without a click()."""
2338
+ if self.__is_cdp_swap_needed():
2339
+ self.cdp.click_if_visible(selector)
2340
+ return
2280
2341
  self.wait_for_ready_state_complete()
2281
2342
  if self.is_element_visible(selector, by=by):
2282
2343
  self.click(selector, by=by)
@@ -2289,6 +2350,9 @@ class BaseCase(unittest.TestCase):
2289
2350
  self.click(selector, by=by)
2290
2351
 
2291
2352
  def click_active_element(self):
2353
+ if self.__is_cdp_swap_needed():
2354
+ self.cdp.click_active_element()
2355
+ return
2292
2356
  self.wait_for_ready_state_complete()
2293
2357
  pre_action_url = None
2294
2358
  with suppress(Exception):
@@ -3311,6 +3375,8 @@ class BaseCase(unittest.TestCase):
3311
3375
  relative to the entire screen, rather than the browser window.
3312
3376
  This is specifically for PyAutoGUI actions on the full screen.
3313
3377
  (Note: There may be complications if iframes are involved.)"""
3378
+ if self.__is_cdp_swap_needed():
3379
+ return self.cdp.get_gui_element_rect(selector)
3314
3380
  element = self.wait_for_element_present(selector, by=by, timeout=1)
3315
3381
  element_rect = element.rect
3316
3382
  e_width = element_rect["width"]
@@ -3344,6 +3410,8 @@ class BaseCase(unittest.TestCase):
3344
3410
  on the entire GUI / screen, rather than on the browser window.
3345
3411
  This is specifically for PyAutoGUI actions on the full screen.
3346
3412
  (Note: There may be complications if iframes are involved.)"""
3413
+ if self.__is_cdp_swap_needed():
3414
+ return self.cdp.get_gui_element_center(selector)
3347
3415
  element_rect = self.get_gui_element_rect(selector, by=by)
3348
3416
  x = int(element_rect["x"]) + int(element_rect["width"] / 2) + 1
3349
3417
  y = int(element_rect["y"]) + int(element_rect["height"] / 2) + 1
@@ -3351,16 +3419,22 @@ class BaseCase(unittest.TestCase):
3351
3419
 
3352
3420
  def get_window_rect(self):
3353
3421
  self.__check_scope()
3422
+ if self.__is_cdp_swap_needed():
3423
+ return self.cdp.get_window_rect()
3354
3424
  self._check_browser()
3355
3425
  return self.driver.get_window_rect()
3356
3426
 
3357
3427
  def get_window_size(self):
3358
3428
  self.__check_scope()
3429
+ if self.__is_cdp_swap_needed():
3430
+ return self.cdp.get_window_size()
3359
3431
  self._check_browser()
3360
3432
  return self.driver.get_window_size()
3361
3433
 
3362
3434
  def get_window_position(self):
3363
3435
  self.__check_scope()
3436
+ if self.__is_cdp_swap_needed():
3437
+ return self.cdp.get_window_position()
3364
3438
  self._check_browser()
3365
3439
  return self.driver.get_window_position()
3366
3440
 
@@ -4138,12 +4212,16 @@ class BaseCase(unittest.TestCase):
4138
4212
  self.open(new_start_page)
4139
4213
  self.__dont_record_open = False
4140
4214
  if undetectable:
4215
+ if hasattr(new_driver, "cdp"):
4216
+ self.cdp = new_driver.cdp
4141
4217
  if hasattr(new_driver, "uc_open"):
4142
4218
  self.uc_open = new_driver.uc_open
4143
4219
  if hasattr(new_driver, "uc_open_with_tab"):
4144
4220
  self.uc_open_with_tab = new_driver.uc_open_with_tab
4145
4221
  if hasattr(new_driver, "uc_open_with_reconnect"):
4146
4222
  self.uc_open_with_reconnect = new_driver.uc_open_with_reconnect
4223
+ if hasattr(new_driver, "uc_open_with_cdp_mode"):
4224
+ self.uc_open_with_cdp_mode = new_driver.uc_open_with_cdp_mode
4147
4225
  if hasattr(new_driver, "uc_open_with_disconnect"):
4148
4226
  self.uc_open_with_disconnect = (
4149
4227
  new_driver.uc_open_with_disconnect
@@ -4207,6 +4285,9 @@ class BaseCase(unittest.TestCase):
4207
4285
  If a provided selector is not found, then takes a full-page screenshot.
4208
4286
  If the folder provided doesn't exist, it will get created.
4209
4287
  The screenshot will be in PNG format: (*.png)"""
4288
+ if self.__is_cdp_swap_needed():
4289
+ self.cdp.save_screenshot(name, folder=folder, selector=selector)
4290
+ return
4210
4291
  self.wait_for_ready_state_complete()
4211
4292
  if selector and by:
4212
4293
  selector, by = self.__recalculate_selector(selector, by)
@@ -4565,12 +4646,44 @@ class BaseCase(unittest.TestCase):
4565
4646
  script = """document.designMode = 'on';"""
4566
4647
  self.execute_script(script)
4567
4648
 
4568
- def deactivate_design_mode(self):
4649
+ def deactivate_design_mode(self, url=None):
4569
4650
  # Deactivate Chrome's Design Mode.
4570
4651
  self.wait_for_ready_state_complete()
4571
4652
  script = """document.designMode = 'off';"""
4572
4653
  self.execute_script(script)
4573
4654
 
4655
+ def activate_cdp_mode(self, url=None):
4656
+ if hasattr(self.driver, "_is_using_uc") and self.driver._is_using_uc:
4657
+ self.driver.uc_open_with_cdp_mode(url)
4658
+ else:
4659
+ # Fix Chrome-130 issues by creating a user-data-dir in advance
4660
+ if (
4661
+ (
4662
+ not self.user_data_dir
4663
+ or not os.path.exists(self.user_data_dir)
4664
+ )
4665
+ and self.browser == "chrome"
4666
+ ):
4667
+ import tempfile
4668
+ user_data_dir = os.path.normpath(tempfile.mkdtemp())
4669
+ self.user_data_dir = user_data_dir
4670
+ sb_config.user_data_dir = user_data_dir
4671
+ try:
4672
+ driver = self.get_new_driver(
4673
+ user_data_dir=user_data_dir,
4674
+ undetectable=True,
4675
+ headless2=True,
4676
+ )
4677
+ time.sleep(0.555)
4678
+ except Exception:
4679
+ pass
4680
+ finally:
4681
+ with suppress(Exception):
4682
+ driver.quit()
4683
+ self.get_new_driver(undetectable=True)
4684
+ self.driver.uc_open_with_cdp_mode(url)
4685
+ self.cdp = self.driver.cdp
4686
+
4574
4687
  def activate_recorder(self):
4575
4688
  from seleniumbase.js_code.recorder_js import recorder_js
4576
4689
 
@@ -5589,6 +5702,9 @@ class BaseCase(unittest.TestCase):
5589
5702
  """Brings the active browser window to the front (on top).
5590
5703
  Useful when multiple drivers are being used at the same time."""
5591
5704
  self.__check_scope()
5705
+ if self.__is_cdp_swap_needed():
5706
+ self.cdp.bring_active_window_to_front()
5707
+ return
5592
5708
  with suppress(Exception):
5593
5709
  if not self.__is_in_frame():
5594
5710
  # Only bring the window to the front if not in a frame
@@ -5804,6 +5920,7 @@ class BaseCase(unittest.TestCase):
5804
5920
  scroll - the option to scroll to the element first (Default: True)
5805
5921
  timeout - the time to wait for the element to appear """
5806
5922
  self.__check_scope()
5923
+ self._check_browser()
5807
5924
  self.__skip_if_esc()
5808
5925
  if isinstance(selector, WebElement):
5809
5926
  self.__highlight_element(selector, loops=loops, scroll=scroll)
@@ -6004,6 +6121,9 @@ class BaseCase(unittest.TestCase):
6004
6121
  timeout = settings.SMALL_TIMEOUT
6005
6122
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
6006
6123
  timeout = self.__get_new_timeout(timeout)
6124
+ if self.__is_cdp_swap_needed():
6125
+ self.cdp.scroll_into_view(selector)
6126
+ return
6007
6127
  element = self.wait_for_element_visible(selector, by, timeout=timeout)
6008
6128
  self.execute_script("arguments[0].scrollIntoView();", element)
6009
6129
 
@@ -6046,6 +6166,9 @@ class BaseCase(unittest.TestCase):
6046
6166
  Can be used to click hidden / invisible elements.
6047
6167
  If "all_matches" is False, only the first match is clicked.
6048
6168
  If "scroll" is False, won't scroll unless running in Demo Mode."""
6169
+ if self.__is_cdp_swap_needed():
6170
+ self.cdp.click(selector)
6171
+ return
6049
6172
  self.wait_for_ready_state_complete()
6050
6173
  if not timeout or timeout is True:
6051
6174
  timeout = settings.SMALL_TIMEOUT
@@ -6414,6 +6537,9 @@ class BaseCase(unittest.TestCase):
6414
6537
  def remove_element(self, selector, by="css selector"):
6415
6538
  """Remove the first element on the page that matches the selector."""
6416
6539
  self.__check_scope()
6540
+ if self.__is_cdp_swap_needed():
6541
+ self.cdp.remove_element(selector)
6542
+ return
6417
6543
  element = None
6418
6544
  with suppress(Exception):
6419
6545
  self.wait_for_element_visible("body", timeout=1.5)
@@ -6445,6 +6571,9 @@ class BaseCase(unittest.TestCase):
6445
6571
  def remove_elements(self, selector, by="css selector"):
6446
6572
  """Remove all elements on the page that match the selector."""
6447
6573
  self.__check_scope()
6574
+ if self.__is_cdp_swap_needed():
6575
+ self.cdp.remove_elements(selector)
6576
+ return
6448
6577
  with suppress(Exception):
6449
6578
  self.wait_for_element_visible("body", timeout=1.5)
6450
6579
  selector, by = self.__recalculate_selector(selector, by)
@@ -7829,6 +7958,15 @@ class BaseCase(unittest.TestCase):
7829
7958
  """Return True if connected to the Internet."""
7830
7959
  return self.execute_script("return navigator.onLine;")
7831
7960
 
7961
+ def is_connected(self):
7962
+ """
7963
+ Return True if WebDriver is connected to the browser.
7964
+ Note that the stealthy CDP-Driver isn't a WebDriver.
7965
+ In CDP Mode, the CDP-Driver controls the web browser.
7966
+ The CDP-Driver can be connected while WebDriver isn't.
7967
+ """
7968
+ return self.driver.is_connected()
7969
+
7832
7970
  def is_chromium(self):
7833
7971
  """Return True if the browser is Chrome or Edge."""
7834
7972
  self.__check_scope()
@@ -7944,6 +8082,10 @@ class BaseCase(unittest.TestCase):
7944
8082
  self.__check_scope()
7945
8083
  if not timeout:
7946
8084
  timeout = settings.SMALL_TIMEOUT
8085
+ if self.__is_cdp_swap_needed():
8086
+ mfa_code = self.get_mfa_code(totp_key)
8087
+ self.cdp.type(selector, mfa_code + "\n")
8088
+ return
7947
8089
  self.wait_for_element_visible(selector, by=by, timeout=timeout)
7948
8090
  if self.recorder_mode and self.__current_url_is_recordable():
7949
8091
  if self.get_session_storage_item("pause_recorder") == "no":
@@ -7981,6 +8123,9 @@ class BaseCase(unittest.TestCase):
7981
8123
  if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
7982
8124
  timeout = self.__get_new_timeout(timeout)
7983
8125
  selector, by = self.__recalculate_selector(selector, by, xp_ok=False)
8126
+ if self.__is_cdp_swap_needed():
8127
+ self.cdp.type(selector, text)
8128
+ return
7984
8129
  self.wait_for_ready_state_complete()
7985
8130
  self.wait_for_element_present(selector, by=by, timeout=timeout)
7986
8131
  original_selector = selector
@@ -8696,6 +8841,8 @@ class BaseCase(unittest.TestCase):
8696
8841
  timeout = self.__get_new_timeout(timeout)
8697
8842
  original_selector = selector
8698
8843
  selector, by = self.__recalculate_selector(selector, by)
8844
+ if self.__is_cdp_swap_needed():
8845
+ return self.cdp.select(selector)
8699
8846
  if self.__is_shadow_selector(selector):
8700
8847
  return self.__get_shadow_element(selector, timeout)
8701
8848
  return page_actions.wait_for_element_visible(
@@ -8751,6 +8898,9 @@ class BaseCase(unittest.TestCase):
8751
8898
  original_selector=original_selector,
8752
8899
  )
8753
8900
 
8901
+ def select_all(self, selector, by="css selector", limit=0):
8902
+ return self.find_elements(selector, by=by, limit=limit)
8903
+
8754
8904
  def assert_link(self, link_text, timeout=None):
8755
8905
  """Same as self.assert_link_text()"""
8756
8906
  self.__check_scope()
@@ -8825,6 +8975,7 @@ class BaseCase(unittest.TestCase):
8825
8975
  def _check_browser(self):
8826
8976
  """This method raises an exception if the active window is closed.
8827
8977
  (This provides a much cleaner exception message in this situation.)"""
8978
+ page_actions._reconnect_if_disconnected(self.driver)
8828
8979
  active_window = None
8829
8980
  with suppress(Exception):
8830
8981
  active_window = self.driver.current_window_handle # Fails if None
@@ -9109,6 +9260,8 @@ class BaseCase(unittest.TestCase):
9109
9260
  timeout = self.__get_new_timeout(timeout)
9110
9261
  original_selector = selector
9111
9262
  selector, by = self.__recalculate_selector(selector, by)
9263
+ if self.__is_cdp_swap_needed():
9264
+ return self.cdp.select(selector)
9112
9265
  if self.__is_shadow_selector(selector):
9113
9266
  return self.__wait_for_shadow_element_present(selector, timeout)
9114
9267
  return page_actions.wait_for_element_present(
@@ -9129,6 +9282,8 @@ class BaseCase(unittest.TestCase):
9129
9282
  timeout = self.__get_new_timeout(timeout)
9130
9283
  original_selector = selector
9131
9284
  selector, by = self.__recalculate_selector(selector, by)
9285
+ if self.__is_cdp_swap_needed():
9286
+ return self.cdp.select(selector)
9132
9287
  if self.recorder_mode and self.__current_url_is_recordable():
9133
9288
  if self.get_session_storage_item("pause_recorder") == "no":
9134
9289
  if by == By.XPATH:
@@ -9189,6 +9344,9 @@ class BaseCase(unittest.TestCase):
9189
9344
  if isinstance(selector, list):
9190
9345
  self.assert_elements_present(selector, by=by, timeout=timeout)
9191
9346
  return True
9347
+ if self.__is_cdp_swap_needed():
9348
+ self.cdp.assert_element_present(selector)
9349
+ return True
9192
9350
  if self.__is_shadow_selector(selector):
9193
9351
  self.__assert_shadow_element_present(selector)
9194
9352
  return True
@@ -9263,6 +9421,9 @@ class BaseCase(unittest.TestCase):
9263
9421
  timeout = settings.SMALL_TIMEOUT
9264
9422
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
9265
9423
  timeout = self.__get_new_timeout(timeout)
9424
+ if self.__is_cdp_swap_needed():
9425
+ self.cdp.assert_element(selector)
9426
+ return True
9266
9427
  if isinstance(selector, list):
9267
9428
  self.assert_elements(selector, by=by, timeout=timeout)
9268
9429
  return True
@@ -9383,6 +9544,8 @@ class BaseCase(unittest.TestCase):
9383
9544
  timeout = self.__get_new_timeout(timeout)
9384
9545
  text = self.__get_type_checked_text(text)
9385
9546
  selector, by = self.__recalculate_selector(selector, by)
9547
+ if self.__is_cdp_swap_needed():
9548
+ return self.cdp.find_element(selector)
9386
9549
  if self.__is_shadow_selector(selector):
9387
9550
  return self.__wait_for_shadow_text_visible(text, selector, timeout)
9388
9551
  return page_actions.wait_for_text_visible(
@@ -9551,6 +9714,11 @@ class BaseCase(unittest.TestCase):
9551
9714
  self.__highlight_with_assert_success(
9552
9715
  messenger_post, selector, by
9553
9716
  )
9717
+ elif self.__is_cdp_swap_needed():
9718
+ self.cdp.assert_text(text, selector)
9719
+ return True
9720
+ elif not self.is_connected():
9721
+ self.connect()
9554
9722
  elif self.__is_shadow_selector(selector):
9555
9723
  self.__assert_shadow_text_visible(text, selector, timeout)
9556
9724
  return True
@@ -9596,6 +9764,9 @@ class BaseCase(unittest.TestCase):
9596
9764
  timeout = self.__get_new_timeout(timeout)
9597
9765
  original_selector = selector
9598
9766
  selector, by = self.__recalculate_selector(selector, by)
9767
+ if self.__is_cdp_swap_needed():
9768
+ self.cdp.assert_exact_text(text, selector)
9769
+ return True
9599
9770
  if self.__is_shadow_selector(selector):
9600
9771
  self.__assert_exact_shadow_text_visible(text, selector, timeout)
9601
9772
  return True
@@ -10578,6 +10749,12 @@ class BaseCase(unittest.TestCase):
10578
10749
 
10579
10750
  ############
10580
10751
 
10752
+ def __is_cdp_swap_needed(self):
10753
+ """If the driver is disconnected, use a CDP method when available."""
10754
+ return shared_utils.is_cdp_swap_needed(self.driver)
10755
+
10756
+ ############
10757
+
10581
10758
  def __check_scope(self):
10582
10759
  if hasattr(self, "browser"): # self.browser stores the type of browser
10583
10760
  return # All good: setUp() already initialized variables in "self"
@@ -14764,6 +14941,31 @@ class BaseCase(unittest.TestCase):
14764
14941
  self.__js_start_time = int(time.time() * 1000.0)
14765
14942
  else:
14766
14943
  # Launch WebDriver for both pytest and pynose
14944
+
14945
+ # Fix Chrome-130 issues by creating a user-data-dir in advance
14946
+ if (
14947
+ self.undetectable
14948
+ and (
14949
+ not self.user_data_dir
14950
+ or not os.path.exists(self.user_data_dir)
14951
+ )
14952
+ and self.browser == "chrome"
14953
+ ):
14954
+ import tempfile
14955
+ user_data_dir = os.path.normpath(tempfile.mkdtemp())
14956
+ self.user_data_dir = user_data_dir
14957
+ sb_config.user_data_dir = user_data_dir
14958
+ try:
14959
+ driver = self.get_new_driver(
14960
+ user_data_dir=user_data_dir,
14961
+ headless2=True,
14962
+ )
14963
+ time.sleep(0.555)
14964
+ except Exception:
14965
+ pass
14966
+ finally:
14967
+ with suppress(Exception):
14968
+ driver.quit()
14767
14969
  self.driver = self.get_new_driver(
14768
14970
  browser=self.browser,
14769
14971
  headless=self.headless,
@@ -375,6 +375,7 @@ class Mobile:
375
375
 
376
376
  class UC:
377
377
  RECONNECT_TIME = 2.4 # Seconds
378
+ CDP_MODE_OPEN_WAIT = 0.9 # Seconds
378
379
 
379
380
 
380
381
  class ValidBrowsers:
@@ -243,6 +243,10 @@ def escape_quotes_if_needed(string):
243
243
  def is_in_frame(driver):
244
244
  # Returns True if the driver has switched to a frame.
245
245
  # Returns False if the driver was on default content.
246
+ from seleniumbase.fixtures import shared_utils
247
+
248
+ if shared_utils.is_cdp_swap_needed(driver):
249
+ return False
246
250
  in_basic_frame = driver.execute_script(
247
251
  """
248
252
  var frame = window.frameElement;