seleniumbase 4.32.10a3__py3-none-any.whl → 4.32.11__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.
@@ -1,2 +1,2 @@
1
1
  # seleniumbase package
2
- __version__ = "4.32.10a3"
2
+ __version__ = "4.32.11"
@@ -544,6 +544,8 @@ def uc_open_with_cdp_mode(driver, url=None):
544
544
  )
545
545
  loop.run_until_complete(driver.cdp_base.wait(0))
546
546
 
547
+ gui_lock = fasteners.InterProcessLock(constants.MultiBrowser.PYAUTOGUILOCK)
548
+
547
549
  if (
548
550
  "chrome-extension://" in str(driver.cdp_base.main_tab)
549
551
  and len(driver.cdp_base.tabs) >= 2
@@ -553,7 +555,8 @@ def uc_open_with_cdp_mode(driver, url=None):
553
555
 
554
556
  for tab in driver.cdp_base.tabs[-1::-1]:
555
557
  if "chrome-extension://" not in str(tab):
556
- loop.run_until_complete(tab.activate())
558
+ with gui_lock:
559
+ loop.run_until_complete(tab.activate())
557
560
  break
558
561
 
559
562
  page_tab = None
@@ -566,14 +569,20 @@ def uc_open_with_cdp_mode(driver, url=None):
566
569
  break
567
570
  if page_tab:
568
571
  loop.run_until_complete(page_tab.aopen())
569
- loop.run_until_complete(page_tab.activate())
572
+ with gui_lock:
573
+ loop.run_until_complete(page_tab.activate())
570
574
 
571
575
  loop.run_until_complete(driver.cdp_base.update_targets())
572
576
  page = loop.run_until_complete(driver.cdp_base.get(url))
573
- loop.run_until_complete(page.activate())
577
+ with gui_lock:
578
+ loop.run_until_complete(page.activate())
574
579
  loop.run_until_complete(page.wait())
575
580
  if not safe_url:
576
581
  time.sleep(constants.UC.CDP_MODE_OPEN_WAIT)
582
+ if IS_WINDOWS:
583
+ time.sleep(constants.UC.EXTRA_WINDOWS_WAIT)
584
+ else:
585
+ time.sleep(0.012)
577
586
  cdp = types.SimpleNamespace()
578
587
  CDPM = sb_cdp.CDPMethods(loop, page, driver)
579
588
  cdp.get = CDPM.get
@@ -590,6 +599,9 @@ def uc_open_with_cdp_mode(driver, url=None):
590
599
  cdp.select = CDPM.select
591
600
  cdp.select_all = CDPM.select_all
592
601
  cdp.find_elements = CDPM.find_elements
602
+ cdp.find_visible_elements = CDPM.find_visible_elements
603
+ cdp.click_nth_element = CDPM.click_nth_element
604
+ cdp.click_nth_visible_element = CDPM.click_nth_visible_element
593
605
  cdp.click_link = CDPM.click_link
594
606
  cdp.tile_windows = CDPM.tile_windows
595
607
  cdp.get_all_cookies = CDPM.get_all_cookies
@@ -609,7 +621,6 @@ def uc_open_with_cdp_mode(driver, url=None):
609
621
  cdp.remove_element = CDPM.remove_element
610
622
  cdp.remove_from_dom = CDPM.remove_from_dom
611
623
  cdp.remove_elements = CDPM.remove_elements
612
- cdp.scroll_into_view = CDPM.scroll_into_view
613
624
  cdp.send_keys = CDPM.send_keys
614
625
  cdp.press_keys = CDPM.press_keys
615
626
  cdp.type = CDPM.type
@@ -680,8 +691,12 @@ def uc_open_with_cdp_mode(driver, url=None):
680
691
  cdp.assert_title = CDPM.assert_title
681
692
  cdp.assert_text = CDPM.assert_text
682
693
  cdp.assert_exact_text = CDPM.assert_exact_text
683
- cdp.scroll_down = CDPM.scroll_down
694
+ cdp.scroll_into_view = CDPM.scroll_into_view
695
+ cdp.scroll_to_y = CDPM.scroll_to_y
696
+ cdp.scroll_to_top = CDPM.scroll_to_top
697
+ cdp.scroll_to_bottom = CDPM.scroll_to_bottom
684
698
  cdp.scroll_up = CDPM.scroll_up
699
+ cdp.scroll_down = CDPM.scroll_down
685
700
  cdp.save_screenshot = CDPM.save_screenshot
686
701
  cdp.page = page # async world
687
702
  cdp.driver = driver.cdp_base # async world
@@ -1255,6 +1270,7 @@ def _uc_gui_click_captcha(
1255
1270
  with suppress(Exception):
1256
1271
  _uc_gui_click_x_y(driver, x, y, timeframe=0.32)
1257
1272
  if __is_cdp_swap_needed(driver):
1273
+ time.sleep(float(constants.UC.RECONNECT_TIME) / 2.0)
1258
1274
  return
1259
1275
  reconnect_time = (float(constants.UC.RECONNECT_TIME) / 2.0) + 0.6
1260
1276
  if IS_LINUX:
@@ -3,6 +3,7 @@ import os
3
3
  import shutil
4
4
  import sys
5
5
  import time
6
+ from contextlib import suppress
6
7
  from seleniumbase import config as sb_config
7
8
  from seleniumbase.config import settings
8
9
  from seleniumbase.fixtures import constants
@@ -281,14 +282,13 @@ def log_test_failure_data(test, test_logpath, driver, browser, url=None):
281
282
  sb_config._report_time = the_time
282
283
  sb_config._report_traceback = traceback_message
283
284
  sb_config._report_exception = exc_message
284
- try:
285
+ with suppress(Exception):
285
286
  if not os.path.exists(test_logpath):
286
287
  os.makedirs(test_logpath)
287
- except Exception:
288
- pass
289
- log_file = codecs.open(basic_file_path, "w+", "utf-8")
290
- log_file.writelines("\r\n".join(data_to_save))
291
- log_file.close()
288
+ with suppress(Exception):
289
+ log_file = codecs.open(basic_file_path, "w+", encoding="utf-8")
290
+ log_file.writelines("\r\n".join(data_to_save))
291
+ log_file.close()
292
292
 
293
293
 
294
294
  def log_skipped_test_data(test, test_logpath, driver, browser, reason):
@@ -297,16 +297,12 @@ def log_skipped_test_data(test, test_logpath, driver, browser, reason):
297
297
  browser_version = None
298
298
  driver_version = None
299
299
  driver_name = None
300
- try:
300
+ with suppress(Exception):
301
301
  browser_version = get_browser_version(driver)
302
- except Exception:
303
- pass
304
- try:
302
+ with suppress(Exception):
305
303
  driver_name, driver_version = get_driver_name_and_version(
306
304
  driver, browser
307
305
  )
308
- except Exception:
309
- pass
310
306
  if browser_version:
311
307
  headless = ""
312
308
  if test.headless and browser in ["chrome", "edge", "firefox"]:
@@ -368,13 +364,11 @@ def log_page_source(test_logpath, driver, source=None):
368
364
  "unresponsive, or closed prematurely!</h4>"
369
365
  )
370
366
  )
371
- try:
367
+ with suppress(Exception):
372
368
  if not os.path.exists(test_logpath):
373
369
  os.makedirs(test_logpath)
374
- except Exception:
375
- pass
376
370
  html_file_path = os.path.join(test_logpath, html_file_name)
377
- html_file = codecs.open(html_file_path, "w+", "utf-8")
371
+ html_file = codecs.open(html_file_path, "w+", encoding="utf-8")
378
372
  html_file.write(page_source)
379
373
  html_file.close()
380
374
 
@@ -543,7 +537,7 @@ def log_folder_setup(log_path, archive_logs=False):
543
537
  try:
544
538
  os.makedirs(log_path)
545
539
  except Exception:
546
- pass # Should only be reachable during multi-threaded runs
540
+ pass # Only reachable during multi-threaded runs
547
541
  else:
548
542
  saved_folder = "%s/../%s/" % (log_path, constants.Logs.SAVED)
549
543
  archived_folder = os.path.realpath(saved_folder) + "/"
@@ -551,7 +545,7 @@ def log_folder_setup(log_path, archive_logs=False):
551
545
  try:
552
546
  os.makedirs(archived_folder)
553
547
  except Exception:
554
- pass # Should only be reachable during multi-threaded runs
548
+ pass # Only reachable during multi-threaded runs
555
549
  archived_logs = "%slogs_%s" % (archived_folder, int(time.time()))
556
550
  if len(os.listdir(log_path)) > 0:
557
551
  try:
@@ -89,6 +89,10 @@ class CDPMethods():
89
89
  safe_url = False
90
90
  if not safe_url:
91
91
  time.sleep(constants.UC.CDP_MODE_OPEN_WAIT)
92
+ if shared_utils.is_windows():
93
+ time.sleep(constants.UC.EXTRA_WINDOWS_WAIT)
94
+ else:
95
+ time.sleep(0.012)
92
96
  self.__slow_mode_pause_if_set()
93
97
  self.loop.run_until_complete(self.page.wait())
94
98
 
@@ -248,6 +252,45 @@ class CDPMethods():
248
252
  def find_elements(self, selector, timeout=settings.SMALL_TIMEOUT):
249
253
  return self.select_all(selector, timeout=timeout)
250
254
 
255
+ def find_visible_elements(self, selector, timeout=settings.SMALL_TIMEOUT):
256
+ visible_elements = []
257
+ elements = self.select_all(selector, timeout=timeout)
258
+ for element in elements:
259
+ with suppress(Exception):
260
+ position = element.get_position()
261
+ if (position.width != 0 or position.height != 0):
262
+ visible_elements.append(element)
263
+ return visible_elements
264
+
265
+ def click_nth_element(self, selector, number):
266
+ elements = self.select_all(selector)
267
+ if len(elements) < number:
268
+ raise Exception(
269
+ "Not enough matching {%s} elements to "
270
+ "click number %s!" % (selector, number)
271
+ )
272
+ number = number - 1
273
+ if number < 0:
274
+ number = 0
275
+ element = elements[number]
276
+ element.click()
277
+
278
+ def click_nth_visible_element(self, selector, number):
279
+ """Finds all matching page elements and clicks the nth visible one.
280
+ Example: self.click_nth_visible_element('[type="checkbox"]', 5)
281
+ (Clicks the 5th visible checkbox on the page.)"""
282
+ elements = self.find_visible_elements(selector)
283
+ if len(elements) < number:
284
+ raise Exception(
285
+ "Not enough matching {%s} elements to "
286
+ "click number %s!" % (selector, number)
287
+ )
288
+ number = number - 1
289
+ if number < 0:
290
+ number = 0
291
+ element = elements[number]
292
+ element.click()
293
+
251
294
  def click_link(self, link_text):
252
295
  self.find_elements_by_text(link_text, "a")[0].click()
253
296
 
@@ -475,18 +518,36 @@ class CDPMethods():
475
518
  self.__slow_mode_pause_if_set()
476
519
  self.loop.run_until_complete(self.page.wait())
477
520
 
478
- def click_visible_elements(self, selector):
521
+ def click_visible_elements(self, selector, limit=0):
522
+ """Finds all matching page elements and clicks visible ones in order.
523
+ If a click reloads or opens a new page, the clicking will stop.
524
+ If no matching elements appear, an Exception will be raised.
525
+ If "limit" is set and > 0, will only click that many elements.
526
+ Also clicks elements that become visible from previous clicks.
527
+ Works best for actions such as clicking all checkboxes on a page.
528
+ Example: self.click_visible_elements('input[type="checkbox"]')"""
479
529
  elements = self.select_all(selector)
530
+ click_count = 0
480
531
  for element in elements:
532
+ if limit and limit > 0 and click_count >= limit:
533
+ return
481
534
  try:
482
- position = element.get_position()
483
- if (position.width != 0 or position.height != 0):
535
+ width = 0
536
+ height = 0
537
+ try:
538
+ position = element.get_position()
539
+ width = position.width
540
+ height = position.height
541
+ except Exception:
542
+ continue
543
+ if (width != 0 or height != 0):
484
544
  element.click()
545
+ click_count += 1
485
546
  time.sleep(0.0375)
486
547
  self.__slow_mode_pause_if_set()
487
548
  self.loop.run_until_complete(self.page.wait())
488
549
  except Exception:
489
- pass
550
+ break
490
551
 
491
552
  def mouse_click(self, selector, timeout=settings.SMALL_TIMEOUT):
492
553
  """(Attempt simulating a mouse click)"""
@@ -578,9 +639,6 @@ class CDPMethods():
578
639
  with suppress(Exception):
579
640
  self.loop.run_until_complete(self.page.evaluate(js_code))
580
641
 
581
- def scroll_into_view(self, selector):
582
- self.find_element(selector).scroll_into_view()
583
-
584
642
  def send_keys(self, selector, text, timeout=settings.SMALL_TIMEOUT):
585
643
  self.__slow_mode_pause_if_set()
586
644
  element = self.select(selector, timeout=timeout)
@@ -1237,6 +1295,7 @@ class CDPMethods():
1237
1295
 
1238
1296
  def gui_drag_and_drop(self, drag_selector, drop_selector, timeframe=0.35):
1239
1297
  self.__slow_mode_pause_if_set()
1298
+ self.bring_active_window_to_front()
1240
1299
  x1, y1 = self.get_gui_element_center(drag_selector)
1241
1300
  self.__add_light_pause()
1242
1301
  x2, y2 = self.get_gui_element_center(drop_selector)
@@ -1326,10 +1385,14 @@ class CDPMethods():
1326
1385
 
1327
1386
  def gui_hover_element(self, selector, timeframe=0.25):
1328
1387
  self.__slow_mode_pause_if_set()
1329
- x, y = self.get_gui_element_center(selector)
1330
- self.__add_light_pause()
1331
- self.__gui_hover_x_y(x, y, timeframe=timeframe)
1332
- self.__slow_mode_pause_if_set()
1388
+ element_rect = self.get_gui_element_rect(selector)
1389
+ width = element_rect["width"]
1390
+ height = element_rect["height"]
1391
+ if width > 0 and height > 0:
1392
+ x, y = self.get_gui_element_center(selector)
1393
+ self.bring_active_window_to_front()
1394
+ self.__gui_hover_x_y(x, y, timeframe=timeframe)
1395
+ self.__slow_mode_pause_if_set()
1333
1396
  self.loop.run_until_complete(self.page.wait())
1334
1397
 
1335
1398
  def gui_hover_and_click(self, hover_selector, click_selector):
@@ -1337,6 +1400,7 @@ class CDPMethods():
1337
1400
  constants.MultiBrowser.PYAUTOGUILOCK
1338
1401
  )
1339
1402
  with gui_lock:
1403
+ self.bring_active_window_to_front()
1340
1404
  self.gui_hover_element(hover_selector)
1341
1405
  time.sleep(0.15)
1342
1406
  self.gui_hover_element(click_selector)
@@ -1521,15 +1585,36 @@ class CDPMethods():
1521
1585
  % (text, element.text_all, selector)
1522
1586
  )
1523
1587
 
1524
- def scroll_down(self, amount=25):
1525
- self.loop.run_until_complete(
1526
- self.page.scroll_down(amount)
1527
- )
1588
+ def scroll_into_view(self, selector):
1589
+ self.find_element(selector).scroll_into_view()
1590
+ self.loop.run_until_complete(self.page.wait())
1591
+
1592
+ def scroll_to_y(self, y):
1593
+ y = int(y)
1594
+ js_code = "window.scrollTo(0, %s);" % y
1595
+ with suppress(Exception):
1596
+ self.loop.run_until_complete(self.page.evaluate(js_code))
1597
+ self.loop.run_until_complete(self.page.wait())
1598
+
1599
+ def scroll_to_top(self):
1600
+ js_code = "window.scrollTo(0, 0);"
1601
+ with suppress(Exception):
1602
+ self.loop.run_until_complete(self.page.evaluate(js_code))
1603
+ self.loop.run_until_complete(self.page.wait())
1604
+
1605
+ def scroll_to_bottom(self):
1606
+ js_code = "window.scrollTo(0, 10000);"
1607
+ with suppress(Exception):
1608
+ self.loop.run_until_complete(self.page.evaluate(js_code))
1609
+ self.loop.run_until_complete(self.page.wait())
1528
1610
 
1529
1611
  def scroll_up(self, amount=25):
1530
- self.loop.run_until_complete(
1531
- self.page.scroll_up(amount)
1532
- )
1612
+ self.loop.run_until_complete(self.page.scroll_up(amount))
1613
+ self.loop.run_until_complete(self.page.wait())
1614
+
1615
+ def scroll_down(self, amount=25):
1616
+ self.loop.run_until_complete(self.page.scroll_down(amount))
1617
+ self.loop.run_until_complete(self.page.wait())
1533
1618
 
1534
1619
  def save_screenshot(self, name, folder=None, selector=None):
1535
1620
  filename = name
@@ -249,8 +249,11 @@ class DriverMethods():
249
249
  selector = kwargs["selector"]
250
250
  else:
251
251
  selector = args[0]
252
- self.driver.cdp.highlight(selector)
253
- return
252
+ if ":contains(" not in selector:
253
+ self.driver.cdp.highlight(selector)
254
+ return
255
+ else:
256
+ self.driver.connect()
254
257
  if "scroll" in kwargs:
255
258
  kwargs.pop("scroll")
256
259
  w_args = kwargs.copy()
@@ -2166,7 +2166,6 @@ class BaseCase(unittest.TestCase):
2166
2166
  if limit and limit > 0 and len(elements) > limit:
2167
2167
  elements = elements[:limit]
2168
2168
  return elements
2169
-
2170
2169
  self.wait_for_ready_state_complete()
2171
2170
  time.sleep(0.05)
2172
2171
  elements = self.driver.find_elements(by=by, value=selector)
@@ -2178,6 +2177,11 @@ class BaseCase(unittest.TestCase):
2178
2177
  """Returns a list of matching WebElements that are visible.
2179
2178
  If "limit" is set and > 0, will only return that many elements."""
2180
2179
  selector, by = self.__recalculate_selector(selector, by)
2180
+ if self.__is_cdp_swap_needed():
2181
+ elements = self.cdp.find_visible_elements(selector)
2182
+ if limit and limit > 0 and len(elements) > limit:
2183
+ elements = elements[:limit]
2184
+ return elements
2181
2185
  self.wait_for_ready_state_complete()
2182
2186
  time.sleep(0.05)
2183
2187
  return page_actions.find_visible_elements(
@@ -2201,7 +2205,7 @@ class BaseCase(unittest.TestCase):
2201
2205
  timeout = self.__get_new_timeout(timeout)
2202
2206
  selector, by = self.__recalculate_selector(selector, by)
2203
2207
  if self.__is_cdp_swap_needed():
2204
- self.cdp.click_visible_elements(selector)
2208
+ self.cdp.click_visible_elements(selector, limit)
2205
2209
  return
2206
2210
  self.wait_for_ready_state_complete()
2207
2211
  if self.__needs_minimum_wait():
@@ -2283,13 +2287,16 @@ class BaseCase(unittest.TestCase):
2283
2287
  ):
2284
2288
  """Finds all matching page elements and clicks the nth visible one.
2285
2289
  Example: self.click_nth_visible_element('[type="checkbox"]', 5)
2286
- (Clicks the 5th visible checkbox on the page.)"""
2290
+ (Clicks the 5th visible checkbox on the page.)"""
2287
2291
  self.__check_scope()
2288
2292
  if not timeout:
2289
2293
  timeout = settings.SMALL_TIMEOUT
2290
2294
  if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
2291
2295
  timeout = self.__get_new_timeout(timeout)
2292
2296
  selector, by = self.__recalculate_selector(selector, by)
2297
+ if self.__is_cdp_swap_needed():
2298
+ self.cdp.click_nth_visible_element(selector, number)
2299
+ return
2293
2300
  self.wait_for_ready_state_complete()
2294
2301
  self.wait_for_element_present(selector, by=by, timeout=timeout)
2295
2302
  elements = self.find_visible_elements(selector, by=by)
@@ -2897,6 +2904,9 @@ class BaseCase(unittest.TestCase):
2897
2904
  drop_selector, drop_by = self.__recalculate_selector(
2898
2905
  drop_selector, drop_by
2899
2906
  )
2907
+ if self.__is_cdp_swap_needed():
2908
+ self.cdp.gui_drag_and_drop(drag_selector, drop_selector)
2909
+ return
2900
2910
  drag_element = self.wait_for_element_clickable(
2901
2911
  drag_selector, by=drag_by, timeout=timeout
2902
2912
  )
@@ -6144,6 +6154,9 @@ class BaseCase(unittest.TestCase):
6144
6154
  original_selector = selector
6145
6155
  original_by = by
6146
6156
  selector, by = self.__recalculate_selector(selector, by)
6157
+ if self.__is_cdp_swap_needed() and ":contains(" not in selector:
6158
+ self.cdp.scroll_into_view(selector)
6159
+ return
6147
6160
  element = self.wait_for_element_visible(
6148
6161
  original_selector, by=original_by, timeout=timeout
6149
6162
  )
@@ -6190,24 +6203,36 @@ class BaseCase(unittest.TestCase):
6190
6203
  def scroll_to_top(self):
6191
6204
  """Scroll to the top of the page."""
6192
6205
  self.__check_scope()
6206
+ if self.__is_cdp_swap_needed():
6207
+ self.cdp.scroll_to_top()
6208
+ return
6193
6209
  scroll_script = "window.scrollTo(0, 0);"
6194
- try:
6210
+ with suppress(Exception):
6195
6211
  self.execute_script(scroll_script)
6196
6212
  time.sleep(0.012)
6197
- return True
6198
- except Exception:
6199
- return False
6200
6213
 
6201
6214
  def scroll_to_bottom(self):
6202
6215
  """Scroll to the bottom of the page."""
6203
6216
  self.__check_scope()
6217
+ if self.__is_cdp_swap_needed():
6218
+ self.cdp.scroll_to_bottom()
6219
+ return
6204
6220
  scroll_script = "window.scrollTo(0, 10000);"
6205
- try:
6221
+ with suppress(Exception):
6222
+ self.execute_script(scroll_script)
6223
+ time.sleep(0.012)
6224
+
6225
+ def scroll_to_y(self, y):
6226
+ """Scroll to y position on the page."""
6227
+ self.__check_scope()
6228
+ y = int(y)
6229
+ if self.__is_cdp_swap_needed():
6230
+ self.cdp.scroll_to_y(y)
6231
+ return
6232
+ scroll_script = "window.scrollTo(0, %s);" % y
6233
+ with suppress(Exception):
6206
6234
  self.execute_script(scroll_script)
6207
6235
  time.sleep(0.012)
6208
- return True
6209
- except Exception:
6210
- return False
6211
6236
 
6212
6237
  def click_xpath(self, xpath):
6213
6238
  """Technically, self.click() automatically detects xpath selectors,
@@ -15420,7 +15445,8 @@ class BaseCase(unittest.TestCase):
15420
15445
  elif hasattr(self, "_using_sb_fixture") and self._using_sb_fixture:
15421
15446
  test_id = sb_config._latest_display_id
15422
15447
  test_id = test_id.replace(".py::", ".").replace("::", ".")
15423
- test_id = test_id.replace("/", ".").replace(" ", "_")
15448
+ test_id = test_id.replace("/", ".").replace("\\", ".")
15449
+ test_id = test_id.replace(" ", "_")
15424
15450
  # Linux filename length limit for `codecs.open(filename)` = 255
15425
15451
  # 255 - len("latest_logs/") - len("/basic_test_info.txt") = 223
15426
15452
  if len(test_id) <= 223:
@@ -16117,11 +16143,7 @@ class BaseCase(unittest.TestCase):
16117
16143
  # This test already called tearDown()
16118
16144
  return
16119
16145
  if hasattr(self, "recorder_mode") and self.recorder_mode:
16120
- if self.undetectable:
16121
- try:
16122
- self.driver.window_handles
16123
- except Exception:
16124
- self.driver.connect()
16146
+ page_actions._reconnect_if_disconnected(self.driver)
16125
16147
  try:
16126
16148
  self.__process_recorded_actions()
16127
16149
  except Exception as e:
@@ -16162,12 +16184,7 @@ class BaseCase(unittest.TestCase):
16162
16184
  )
16163
16185
  raise Exception(message)
16164
16186
  # *** Start tearDown() officially ***
16165
- if self.undetectable:
16166
- try:
16167
- self.driver.window_handles
16168
- except Exception:
16169
- with suppress(Exception):
16170
- self.driver.connect()
16187
+ page_actions._reconnect_if_disconnected(self.driver)
16171
16188
  self.__slow_mode_pause_if_active()
16172
16189
  has_exception = self.__has_exception()
16173
16190
  sb_config._has_exception = has_exception
@@ -376,6 +376,7 @@ class Mobile:
376
376
  class UC:
377
377
  RECONNECT_TIME = 2.4 # Seconds
378
378
  CDP_MODE_OPEN_WAIT = 0.9 # Seconds
379
+ EXTRA_WINDOWS_WAIT = 0.3 # Seconds
379
380
 
380
381
 
381
382
  class ValidBrowsers:
@@ -10,6 +10,7 @@ from seleniumbase import config as sb_config
10
10
  from seleniumbase.config import settings
11
11
  from seleniumbase.fixtures import constants
12
12
  from seleniumbase.fixtures import css_to_xpath
13
+ from seleniumbase.fixtures import shared_utils
13
14
  from seleniumbase.fixtures import xpath_to_css
14
15
 
15
16
 
@@ -24,9 +25,6 @@ def wait_for_ready_state_complete(driver, timeout=settings.LARGE_TIMEOUT):
24
25
  (Previously, tests would fail immediately if exceeding the timeout.)"""
25
26
  if hasattr(settings, "SKIP_JS_WAITS") and settings.SKIP_JS_WAITS:
26
27
  return
27
- if sb_config.time_limit and not sb_config.recorder_mode:
28
- from seleniumbase.fixtures import shared_utils
29
-
30
28
  start_ms = time.time() * 1000.0
31
29
  stop_ms = start_ms + (timeout * 1000.0)
32
30
  for x in range(int(timeout * 10)):
@@ -243,8 +241,6 @@ def escape_quotes_if_needed(string):
243
241
  def is_in_frame(driver):
244
242
  # Returns True if the driver has switched to a frame.
245
243
  # Returns False if the driver was on default content.
246
- from seleniumbase.fixtures import shared_utils
247
-
248
244
  if shared_utils.is_cdp_swap_needed(driver):
249
245
  return False
250
246
  in_basic_frame = driver.execute_script(
@@ -1555,8 +1555,6 @@ def _reconnect_if_disconnected(driver):
1555
1555
  if (
1556
1556
  hasattr(driver, "_is_using_uc")
1557
1557
  and driver._is_using_uc
1558
- and hasattr(driver, "_is_connected")
1559
- and not driver._is_connected
1560
1558
  and hasattr(driver, "is_connected")
1561
1559
  and not driver.is_connected()
1562
1560
  ):
@@ -84,6 +84,17 @@ def fix_url_as_needed(url):
84
84
  return url
85
85
 
86
86
 
87
+ def reconnect_if_disconnected(driver):
88
+ if (
89
+ hasattr(driver, "_is_using_uc")
90
+ and driver._is_using_uc
91
+ and hasattr(driver, "is_connected")
92
+ and not driver.is_connected()
93
+ ):
94
+ with suppress(Exception):
95
+ driver.connect()
96
+
97
+
87
98
  def is_cdp_swap_needed(driver):
88
99
  """
89
100
  When someone is using CDP Mode with a disconnected webdriver,
@@ -1202,7 +1202,7 @@ def SB(
1202
1202
  from seleniumbase.core import download_helper
1203
1203
  from seleniumbase.core import proxy_helper
1204
1204
 
1205
- log_helper.log_folder_setup(constants.Logs.LATEST + "/")
1205
+ log_helper.log_folder_setup(constants.Logs.LATEST + os.sep)
1206
1206
  log_helper.clear_empty_logs()
1207
1207
  download_helper.reset_downloads_folder()
1208
1208
  if not sb_config.multi_proxy:
@@ -1228,7 +1228,7 @@ def SB(
1228
1228
  the_traceback = traceback.format_exc().strip()
1229
1229
  try:
1230
1230
  p2 = the_traceback.split(', in ')[1].split('", line ')[0]
1231
- filename = p2.split("/")[-1]
1231
+ filename = p2.split(os.sep)[-1]
1232
1232
  sb.cm_filename = filename
1233
1233
  except Exception:
1234
1234
  sb.cm_filename = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: seleniumbase
3
- Version: 4.32.10a3
3
+ Version: 4.32.11
4
4
  Summary: A complete web automation framework for end-to-end testing.
5
5
  Home-page: https://github.com/seleniumbase/SeleniumBase
6
6
  Author: Michael Mintz
@@ -127,7 +127,7 @@ Requires-Dist: allure-behave>=2.13.5; extra == "allure"
127
127
  Provides-Extra: coverage
128
128
  Requires-Dist: coverage>=7.6.1; python_version < "3.9" and extra == "coverage"
129
129
  Requires-Dist: pytest-cov>=5.0.0; python_version < "3.9" and extra == "coverage"
130
- Requires-Dist: coverage>=7.6.4; python_version >= "3.9" and extra == "coverage"
130
+ Requires-Dist: coverage>=7.6.5; python_version >= "3.9" and extra == "coverage"
131
131
  Requires-Dist: pytest-cov>=6.0.0; python_version >= "3.9" and extra == "coverage"
132
132
  Provides-Extra: flake8
133
133
  Requires-Dist: mccabe==0.7.0; extra == "flake8"
@@ -3,7 +3,7 @@ sbase/__main__.py,sha256=G0bVB1-DM4PGwQ1KyOupaWCs4ePbChZNNWuX2htim5U,647
3
3
  sbase/steps.py,sha256=bKT_u5bJkKzYWEuAXi9NVVRYYxQRCM1_YJUrNFFRVPY,42865
4
4
  seleniumbase/__init__.py,sha256=OtJh8nGKL4xtZpw8KPqmn7Q6R-86t4cWUDyVF5MbMTo,2398
5
5
  seleniumbase/__main__.py,sha256=dn1p6dgCchmcH1zzTzzQvFwwdQQqnTGH6ULV9m4hv24,654
6
- seleniumbase/__version__.py,sha256=14fllQeteOT_Suz0vgP14dq-Lmrkoig_p-X-_kTOUzg,49
6
+ seleniumbase/__version__.py,sha256=0NN9rH4ffocZPC19OF8zCT06wDT8muncnxK87-frKM8,47
7
7
  seleniumbase/behave/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  seleniumbase/behave/behave_helper.py,sha256=elkl8P9eLulRAioLstE9baYNM9N_PHBmAOcajX-pH_Y,24198
9
9
  seleniumbase/behave/behave_sb.py,sha256=-hza7Nx2U41mSObYiPMi48v3JlPh3sJO3yzP0kqZ1Gk,59174
@@ -36,7 +36,7 @@ seleniumbase/console_scripts/sb_print.py,sha256=tNy-bMDgwHJO3bZxMpmo9weSE8uhbH0C
36
36
  seleniumbase/console_scripts/sb_recorder.py,sha256=1oAA4wFzVboNhIFDwJLD3jgy9RuoavywKQG7R67bNZE,10908
37
37
  seleniumbase/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
38
  seleniumbase/core/application_manager.py,sha256=e_0sjtI8cjY5BNyZj1QBR0j6_oCScxGmSXYEpcYwuZE,576
39
- seleniumbase/core/browser_launcher.py,sha256=spXqxLljEovT48O0zbKWuTfG1OS4y9VjYKI8pufQIkk,219268
39
+ seleniumbase/core/browser_launcher.py,sha256=Lo-R29qNyhNw2mTjm1I8JkwqIVchEHQeJTiE8JVdATE,219934
40
40
  seleniumbase/core/capabilities_parser.py,sha256=meIS2uHapTCq2ldfNAToC7r0cKmZDRXuYNKExM1GHDY,6038
41
41
  seleniumbase/core/colored_traceback.py,sha256=DrRWfg7XEnKcgY59Xj7Jdk09H-XqHYBSUpB-DiZt6iY,2020
42
42
  seleniumbase/core/create_db_tables.sql,sha256=VWPtrdiW_HQ6yETHjqTu-VIrTwvd8I8o1NfBeaVSHpU,972
@@ -44,14 +44,14 @@ seleniumbase/core/detect_b_ver.py,sha256=RxeGRMbBUTMrXh5KsS1P1SH7eEKYbzL1vQw1gTd
44
44
  seleniumbase/core/download_helper.py,sha256=qSR54kQISucF4RQaLCOuuerSu6DR41juGi_30HVvWYY,2943
45
45
  seleniumbase/core/encoded_images.py,sha256=rDKJ4cNJSuKiRcFViYU7bjyTS9_moI57gUPRXVg3u2k,14209
46
46
  seleniumbase/core/jqc_helper.py,sha256=2DDQr9Q2jSSZqFzX588jLlUM9oJvyrRWq2aORSIPUdI,10322
47
- seleniumbase/core/log_helper.py,sha256=c4gWI_spHF0N9co2W0-eR_s3y20v9FrQH8c9Vb76BXU,22593
47
+ seleniumbase/core/log_helper.py,sha256=T_nPPSRSjhqt6TTzVE6pN1owVvIeRBNF5pWK6sl4dMY,22609
48
48
  seleniumbase/core/mysql.py,sha256=8Fzj3p5dhtDWfMpFqFYxpSwa9s1UltiHsWJ56_aPOqk,3993
49
49
  seleniumbase/core/proxy_helper.py,sha256=cXhu8ErK9Vjdm82RMaQj7hEq_yUWizSp6LyiD50Ieu4,8020
50
50
  seleniumbase/core/recorder_helper.py,sha256=fNGjbapXmEsht54x1o6Igk198QdnPxDDnjUOzQxNhNQ,25055
51
51
  seleniumbase/core/report_helper.py,sha256=AIl6Qava2yW1uSzbLpJBlPlYDz0KE-rVhogh8hsGWBo,12201
52
52
  seleniumbase/core/s3_manager.py,sha256=bkeI8I4y19ebWuQG1oEZV5qJbotC6eN8vin31OCNWJk,3521
53
- seleniumbase/core/sb_cdp.py,sha256=CPQvyJ8v_xozVdGt5g9JFjo0aYsLaOEm9gnthpysrOc,59586
54
- seleniumbase/core/sb_driver.py,sha256=Yd9BpjnOUuZqYRGmsERVKc1W-e8qwTt7SAytLatkXPA,12070
53
+ seleniumbase/core/sb_cdp.py,sha256=zisjMDPULeGZQ48Cdqpa1JE41NYsoR1dVS8OJB2yHZA,63278
54
+ seleniumbase/core/sb_driver.py,sha256=xMgtvBitEMr73RkqgQLT-3IvkP6sh7cJv-caCUPoO-o,12179
55
55
  seleniumbase/core/session_helper.py,sha256=s9zD3PVZEWVzG2h81cCUskbNWLfdjC_LwwQjKptHCak,558
56
56
  seleniumbase/core/settings_parser.py,sha256=KokVXpCiGZhJ-D4Bo-hizPz5r-iefzWoiTANu9zNaq4,7504
57
57
  seleniumbase/core/style_sheet.py,sha256=tPpJ1xl6Kuw425Z-3Y0OgVRLGXk_ciBDREZjXk_NuPE,11395
@@ -65,14 +65,14 @@ seleniumbase/extensions/disable_csp.zip,sha256=YMifIIgEBiLrEFrS1sfW4Exh4br1V4oK1
65
65
  seleniumbase/extensions/recorder.zip,sha256=OOyzF-Ize2cSRu1CqhzSAq5vusI9hqLLd2OIApUHesI,11918
66
66
  seleniumbase/extensions/sbase_ext.zip,sha256=3s1N8zrVaMz8RQEOIoBzC3KDjtmHwVZRvVsX25Odr_s,8175
67
67
  seleniumbase/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
- seleniumbase/fixtures/base_case.py,sha256=ad--jkCZk2CTzXXk4_ncrI8nqWgHhGPjVmS3vHhnplQ,712849
69
- seleniumbase/fixtures/constants.py,sha256=XYYMpB-ZDI756LvfhSK9RxdqQ_qO9fJVXgBqBYlQNkk,13609
68
+ seleniumbase/fixtures/base_case.py,sha256=4NIR3rsLRqLtDLoe67SsLnB6ln3q2ycjyXL5QqboT8Y,713744
69
+ seleniumbase/fixtures/constants.py,sha256=e1LppavlrAcI4XBJMq7u5j8SffaQ7SPQps1y0YvZYfY,13649
70
70
  seleniumbase/fixtures/css_to_xpath.py,sha256=9ouDB1xl4MJ2os6JOgTIAyHKOQfuxtxvXC3O5hSnEKA,1954
71
71
  seleniumbase/fixtures/errors.py,sha256=KyxuEVx_e3MPhVrJfNIa_3ltMpbCFxfy_jxK8RFNTns,555
72
- seleniumbase/fixtures/js_utils.py,sha256=5o4CTLcCyd717lJ_atOYcC6kPRiZFx-LJIlixRrP_cE,51061
73
- seleniumbase/fixtures/page_actions.py,sha256=fOCb2NB2PpEaE8gpAVu-73VjwLzfwP1R9HsRkix_z6s,66634
72
+ seleniumbase/fixtures/js_utils.py,sha256=2l4UY_zUBsMviRoJpLA0z3XxhGeLMWj0Mv07FUR_jzg,50939
73
+ seleniumbase/fixtures/page_actions.py,sha256=dbp63c-7asYZyd8aOu57Y3dxQQozp_VJsP5h74s1kBA,66552
74
74
  seleniumbase/fixtures/page_utils.py,sha256=5m7iXpikLs80TJoRO6_gEfXE1AKeQgcH1aFbR8o1C9A,12034
75
- seleniumbase/fixtures/shared_utils.py,sha256=MwCrt58YAv_XrfNfYjo_quUTWfYArlnf-aexSZGIyRs,7271
75
+ seleniumbase/fixtures/shared_utils.py,sha256=WbPb15IvIWzRtMInKG8DUzJ26UZU-PixdOwTCjXQirU,7545
76
76
  seleniumbase/fixtures/unittest_helper.py,sha256=sfZ92rZeBAn_sF_yQ3I6_I7h3lyU5-cV_UMegBNoEm8,1294
77
77
  seleniumbase/fixtures/words.py,sha256=FOA4mAYvl3EPVpBTvgvK6YwCL8BdlRCmed685kEe7Vg,7827
78
78
  seleniumbase/fixtures/xpath_to_css.py,sha256=lML56k656fElXJ4NJF07r35FjctrbgQkXUotNk7A-as,8876
@@ -90,7 +90,7 @@ seleniumbase/plugins/driver_manager.py,sha256=s20s0pJYaNrG0WNwyIC04oUMRVFjtm6V_n
90
90
  seleniumbase/plugins/page_source.py,sha256=loTnXxOj4kxEukuTZEiGyvKBhY3KDVDMnNlHHheTBDE,1889
91
91
  seleniumbase/plugins/pytest_plugin.py,sha256=Up96HY6q3hcPo4LQoEcKqt1hm2OmY5GZz_nMXTqDSXQ,97185
92
92
  seleniumbase/plugins/s3_logging_plugin.py,sha256=WDfertQgGOW_SRJpFMaekYD6vBVW9VO62POtXXy2HCM,2319
93
- seleniumbase/plugins/sb_manager.py,sha256=_Uefqpopw6M5NZq7WRi5sXyPMSyaCtBA7oSXObhlvM8,54250
93
+ seleniumbase/plugins/sb_manager.py,sha256=lVCPDL0Y1ig2TAOZUlJmMZs2ij-SqhYhaEd_SYZyRfQ,54256
94
94
  seleniumbase/plugins/screen_shots.py,sha256=1hrXw-hzuZ1BR6Yh7AyWX2ABnvnP73-RCbwdz958gj4,1127
95
95
  seleniumbase/plugins/selenium_plugin.py,sha256=GhGW2ATy2kM7UH7NrZ2je402nN2LMlVHpM-yxlU3I9E,59069
96
96
  seleniumbase/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -135,9 +135,9 @@ seleniumbase/utilities/selenium_grid/start-grid-hub.bat,sha256=Ftq-GrAKRYH2ssDPr
135
135
  seleniumbase/utilities/selenium_grid/start-grid-hub.sh,sha256=KADv0RUHONLL2_I443QFK8PryBpDmKn5Gy0s4o0vDSM,106
136
136
  seleniumbase/utilities/selenium_ide/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
137
137
  seleniumbase/utilities/selenium_ide/convert_ide.py,sha256=pZFnqEJQEKZPyNFjkLD29s2HPQgCrWW9XJWpCPhWOoM,31691
138
- seleniumbase-4.32.10a3.dist-info/LICENSE,sha256=odSYtWibXBnQ1gBg6CnDZ82n8kLF_if5-2nbqnEyD8k,1085
139
- seleniumbase-4.32.10a3.dist-info/METADATA,sha256=cV0euSriQjApI1C02faR-StIhkJ_d4wgmZGaTcuTDl0,86464
140
- seleniumbase-4.32.10a3.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
141
- seleniumbase-4.32.10a3.dist-info/entry_points.txt,sha256=CNrh2EKNaHYEhO6pP1RJyVLB99LkDDYX7TnUK8xfjqk,623
142
- seleniumbase-4.32.10a3.dist-info/top_level.txt,sha256=4N97aBOQ8ETCnDnokBsWb07lJfTaq3C1ZzYRxvLMxqU,19
143
- seleniumbase-4.32.10a3.dist-info/RECORD,,
138
+ seleniumbase-4.32.11.dist-info/LICENSE,sha256=odSYtWibXBnQ1gBg6CnDZ82n8kLF_if5-2nbqnEyD8k,1085
139
+ seleniumbase-4.32.11.dist-info/METADATA,sha256=VuRR7rY9QmKSwRL8cbN6el6Vrw4NFcJ_qYpkxWg_22o,86462
140
+ seleniumbase-4.32.11.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
141
+ seleniumbase-4.32.11.dist-info/entry_points.txt,sha256=CNrh2EKNaHYEhO6pP1RJyVLB99LkDDYX7TnUK8xfjqk,623
142
+ seleniumbase-4.32.11.dist-info/top_level.txt,sha256=4N97aBOQ8ETCnDnokBsWb07lJfTaq3C1ZzYRxvLMxqU,19
143
+ seleniumbase-4.32.11.dist-info/RECORD,,