seleniumbase 4.27.4__py3-none-any.whl → 4.28.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.
seleniumbase/__init__.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import collections
2
+ import os
2
3
  import pdb
3
4
  try:
4
5
  import pdbp # (Pdb+) --- Python Debugger Plus
@@ -34,11 +35,13 @@ if sys.version_info[0] < 3 and "pdbp" in locals():
34
35
  pdb.DefaultConfig.truncate_long_lines = False
35
36
  pdb.DefaultConfig.sticky_by_default = True
36
37
  colored_traceback.add_hook()
38
+ os.environ["SE_AVOID_STATS"] = "true" # Disable Selenium Manager stats
37
39
  if sys.version_info >= (3, 7):
38
40
  webdriver.TouchActions = None # Lifeline for past selenium-wire versions
39
41
  if sys.version_info >= (3, 10):
40
42
  collections.Callable = collections.abc.Callable # Lifeline for nosetests
41
43
  del collections # Undo "import collections" / Simplify "dir(seleniumbase)"
44
+ del os # Undo "import os" / Simplify "dir(seleniumbase)"
42
45
  del sys # Undo "import sys" / Simplify "dir(seleniumbase)"
43
46
  del webdriver # Undo "import webdriver" / Simplify "dir(seleniumbase)"
44
47
 
@@ -1,2 +1,2 @@
1
1
  # seleniumbase package
2
- __version__ = "4.27.4"
2
+ __version__ = "4.28.0"
@@ -862,14 +862,17 @@ def get_configured_sb(context):
862
862
  and not sb.headless2
863
863
  and not sb.xvfb
864
864
  ):
865
- print(
866
- '(Linux uses "-D headless" by default. '
867
- 'To override, use "-D headed" / "-D gui". '
868
- 'For Xvfb mode instead, use "-D xvfb". '
869
- "Or you can hide this info by using"
870
- '"-D headless" / "-D headless2".)'
871
- )
872
- sb.headless = True
865
+ if not sb.undetectable:
866
+ print(
867
+ '(Linux uses "-D headless" by default. '
868
+ 'To override, use "-D headed" / "-D gui". '
869
+ 'For Xvfb mode instead, use "-D xvfb". '
870
+ "Or you can hide this info by using"
871
+ '"-D headless" / "-D headless2" / "-D uc".)'
872
+ )
873
+ sb.headless = True
874
+ else:
875
+ sb.xvfb = True
873
876
  # Recorder Mode can still optimize scripts in --headless2 mode.
874
877
  if sb.recorder_mode and sb.headless:
875
878
  sb.headless = False
@@ -11,6 +11,7 @@ import urllib3
11
11
  import warnings
12
12
  from selenium import webdriver
13
13
  from selenium.common.exceptions import ElementClickInterceptedException
14
+ from selenium.common.exceptions import InvalidSessionIdException
14
15
  from selenium.webdriver.chrome.service import Service as ChromeService
15
16
  from selenium.webdriver.common.options import ArgOptions
16
17
  from selenium.webdriver.common.service import utils as service_utils
@@ -28,6 +29,7 @@ from seleniumbase.core import proxy_helper
28
29
  from seleniumbase.core import sb_driver
29
30
  from seleniumbase.fixtures import constants
30
31
  from seleniumbase.fixtures import js_utils
32
+ from seleniumbase.fixtures import page_actions
31
33
  from seleniumbase.fixtures import shared_utils
32
34
 
33
35
  urllib3.disable_warnings()
@@ -130,9 +132,13 @@ def extend_driver(driver):
130
132
  page.assert_element_not_visible = DM.assert_element_not_visible
131
133
  page.assert_text = DM.assert_text
132
134
  page.assert_exact_text = DM.assert_exact_text
135
+ page.assert_non_empty_text = DM.assert_non_empty_text
136
+ page.assert_text_not_visible = DM.assert_text_not_visible
133
137
  page.wait_for_element = DM.wait_for_element
134
138
  page.wait_for_text = DM.wait_for_text
135
139
  page.wait_for_exact_text = DM.wait_for_exact_text
140
+ page.wait_for_non_empty_text = DM.wait_for_non_empty_text
141
+ page.wait_for_text_not_visible = DM.wait_for_text_not_visible
136
142
  page.wait_for_and_accept_alert = DM.wait_for_and_accept_alert
137
143
  page.wait_for_and_dismiss_alert = DM.wait_for_and_dismiss_alert
138
144
  page.is_element_present = DM.is_element_present
@@ -140,12 +146,20 @@ def extend_driver(driver):
140
146
  page.is_text_visible = DM.is_text_visible
141
147
  page.is_exact_text_visible = DM.is_exact_text_visible
142
148
  page.is_attribute_present = DM.is_attribute_present
149
+ page.is_non_empty_text_visible = DM.is_non_empty_text_visible
143
150
  page.get_text = DM.get_text
144
151
  page.find_element = DM.find_element
145
152
  page.find_elements = DM.find_elements
146
153
  page.locator = DM.locator
147
154
  page.get_page_source = DM.get_page_source
148
155
  page.get_title = DM.get_title
156
+ page.switch_to_default_window = DM.switch_to_default_window
157
+ page.switch_to_newest_window = DM.switch_to_newest_window
158
+ page.open_new_window = DM.open_new_window
159
+ page.open_new_tab = DM.open_new_tab
160
+ page.switch_to_window = DM.switch_to_window
161
+ page.switch_to_tab = DM.switch_to_tab
162
+ page.switch_to_frame = DM.switch_to_frame
149
163
  driver.page = page
150
164
  js = types.SimpleNamespace()
151
165
  js.js_click = DM.js_click
@@ -169,12 +183,16 @@ def extend_driver(driver):
169
183
  driver.assert_element_not_visible = DM.assert_element_not_visible
170
184
  driver.assert_text = DM.assert_text
171
185
  driver.assert_exact_text = DM.assert_exact_text
186
+ driver.assert_non_empty_text = DM.assert_non_empty_text
187
+ driver.assert_text_not_visible = DM.assert_text_not_visible
172
188
  driver.wait_for_element = DM.wait_for_element
173
189
  driver.wait_for_element_visible = DM.wait_for_element_visible
174
190
  driver.wait_for_element_present = DM.wait_for_element_present
175
191
  driver.wait_for_selector = DM.wait_for_selector
176
192
  driver.wait_for_text = DM.wait_for_text
177
193
  driver.wait_for_exact_text = DM.wait_for_exact_text
194
+ driver.wait_for_non_empty_text = DM.wait_for_non_empty_text
195
+ driver.wait_for_text_not_visible = DM.wait_for_text_not_visible
178
196
  driver.wait_for_and_accept_alert = DM.wait_for_and_accept_alert
179
197
  driver.wait_for_and_dismiss_alert = DM.wait_for_and_dismiss_alert
180
198
  driver.is_element_present = DM.is_element_present
@@ -182,8 +200,10 @@ def extend_driver(driver):
182
200
  driver.is_text_visible = DM.is_text_visible
183
201
  driver.is_exact_text_visible = DM.is_exact_text_visible
184
202
  driver.is_attribute_present = DM.is_attribute_present
185
- driver.get_text = DM.get_text
203
+ driver.is_non_empty_text_visible = DM.is_non_empty_text_visible
204
+ driver.is_online = DM.is_online
186
205
  driver.js_click = DM.js_click
206
+ driver.get_text = DM.get_text
187
207
  driver.get_active_element_css = DM.get_active_element_css
188
208
  driver.get_locale_code = DM.get_locale_code
189
209
  driver.get_origin = DM.get_origin
@@ -195,6 +215,12 @@ def extend_driver(driver):
195
215
  driver.get_attribute = DM.get_attribute
196
216
  driver.get_page_source = DM.get_page_source
197
217
  driver.get_title = DM.get_title
218
+ driver.switch_to_default_window = DM.switch_to_default_window
219
+ driver.switch_to_newest_window = DM.switch_to_newest_window
220
+ driver.open_new_window = DM.open_new_window
221
+ driver.open_new_tab = DM.open_new_tab
222
+ driver.switch_to_window = DM.switch_to_window
223
+ driver.switch_to_tab = DM.switch_to_tab
198
224
  driver.switch_to_frame = DM.switch_to_frame
199
225
  if hasattr(driver, "proxy"):
200
226
  driver.set_wire_proxy = DM.set_wire_proxy
@@ -409,7 +435,7 @@ def uc_open(driver, url):
409
435
  if (url.startswith("http:") or url.startswith("https:")):
410
436
  with driver:
411
437
  script = 'window.location.href = "%s";' % url
412
- js_utils.call_me_later(driver, script, 33)
438
+ js_utils.call_me_later(driver, script, 5)
413
439
  else:
414
440
  driver.default_get(url) # The original one
415
441
  return None
@@ -440,22 +466,28 @@ def uc_open_with_reconnect(driver, url, reconnect_time=None):
440
466
  url = "https://" + url
441
467
  if (url.startswith("http:") or url.startswith("https:")):
442
468
  script = 'window.open("%s","_blank");' % url
443
- js_utils.call_me_later(driver, script, 3)
444
- time.sleep(0.007)
469
+ driver.execute_script(script)
470
+ time.sleep(0.05)
445
471
  driver.close()
446
472
  if reconnect_time == "disconnect":
447
473
  driver.disconnect()
448
- time.sleep(0.007)
474
+ time.sleep(0.008)
449
475
  else:
450
476
  driver.reconnect(reconnect_time)
451
- driver.switch_to.window(driver.window_handles[-1])
477
+ time.sleep(0.004)
478
+ try:
479
+ driver.switch_to.window(driver.window_handles[-1])
480
+ except InvalidSessionIdException:
481
+ time.sleep(0.05)
482
+ driver.switch_to.window(driver.window_handles[-1])
452
483
  else:
453
484
  driver.default_get(url) # The original one
454
485
  return None
455
486
 
456
487
 
457
- def uc_open_with_disconnect(driver, url):
488
+ def uc_open_with_disconnect(driver, url, timeout=None):
458
489
  """Open a url and disconnect chromedriver.
490
+ Then waits for the duration of the timeout.
459
491
  Note: You can't perform Selenium actions again
460
492
  until after you've called driver.connect()."""
461
493
  if url.startswith("//"):
@@ -464,11 +496,16 @@ def uc_open_with_disconnect(driver, url):
464
496
  url = "https://" + url
465
497
  if (url.startswith("http:") or url.startswith("https:")):
466
498
  script = 'window.open("%s","_blank");' % url
467
- js_utils.call_me_later(driver, script, 3)
468
- time.sleep(0.007)
499
+ driver.execute_script(script)
500
+ time.sleep(0.05)
469
501
  driver.close()
470
502
  driver.disconnect()
471
- time.sleep(0.007)
503
+ min_timeout = 0.008
504
+ if timeout and not str(timeout).replace(".", "", 1).isdigit():
505
+ timeout = min_timeout
506
+ if not timeout or timeout < min_timeout:
507
+ timeout = min_timeout
508
+ time.sleep(timeout)
472
509
  else:
473
510
  driver.default_get(url) # The original one
474
511
  return None
@@ -490,7 +527,7 @@ def uc_click(
490
527
  pass
491
528
  element = driver.wait_for_selector(selector, by=by, timeout=timeout)
492
529
  tag_name = element.tag_name
493
- if not tag_name == "span": # Element must be "visible"
530
+ if not tag_name == "span" and not tag_name == "input": # Must be "visible"
494
531
  element = driver.wait_for_element(selector, by=by, timeout=timeout)
495
532
  try:
496
533
  element.uc_click(
@@ -509,7 +546,154 @@ def uc_click(
509
546
  driver.reconnect(reconnect_time)
510
547
 
511
548
 
512
- def uc_switch_to_frame(driver, frame, reconnect_time=None):
549
+ def verify_pyautogui_has_a_headed_browser():
550
+ """PyAutoGUI requires a headed browser so that it can
551
+ focus on the correct element when performing actions."""
552
+ if sb_config.headless or sb_config.headless2:
553
+ raise Exception(
554
+ "PyAutoGUI can't be used in headless mode!"
555
+ )
556
+
557
+
558
+ def install_pyautogui_if_missing():
559
+ verify_pyautogui_has_a_headed_browser()
560
+ pip_find_lock = fasteners.InterProcessLock(
561
+ constants.PipInstall.FINDLOCK
562
+ )
563
+ with pip_find_lock: # Prevent issues with multiple processes
564
+ try:
565
+ import pyautogui
566
+ try:
567
+ use_pyautogui_ver = constants.PyAutoGUI.VER
568
+ if pyautogui.__version__ != use_pyautogui_ver:
569
+ del pyautogui
570
+ shared_utils.pip_install(
571
+ "pyautogui", version=use_pyautogui_ver
572
+ )
573
+ import pyautogui
574
+ except Exception:
575
+ pass
576
+ except Exception:
577
+ print("\nPyAutoGUI required! Installing now...")
578
+ shared_utils.pip_install(
579
+ "pyautogui", version=constants.PyAutoGUI.VER
580
+ )
581
+
582
+
583
+ def get_configured_pyautogui(pyautogui_copy):
584
+ if (
585
+ IS_LINUX
586
+ and hasattr(pyautogui_copy, "_pyautogui_x11")
587
+ and "DISPLAY" in os.environ.keys()
588
+ ):
589
+ if (
590
+ hasattr(sb_config, "_pyautogui_x11_display")
591
+ and sb_config._pyautogui_x11_display
592
+ and hasattr(pyautogui_copy._pyautogui_x11, "_display")
593
+ and (
594
+ sb_config._pyautogui_x11_display
595
+ == pyautogui_copy._pyautogui_x11._display
596
+ )
597
+ ):
598
+ pass
599
+ else:
600
+ import Xlib.display
601
+ pyautogui_copy._pyautogui_x11._display = (
602
+ Xlib.display.Display(os.environ['DISPLAY'])
603
+ )
604
+ sb_config._pyautogui_x11_display = (
605
+ pyautogui_copy._pyautogui_x11._display
606
+ )
607
+ return pyautogui_copy
608
+
609
+
610
+ def uc_gui_press_key(driver, key):
611
+ install_pyautogui_if_missing()
612
+ import pyautogui
613
+ pyautogui = get_configured_pyautogui(pyautogui)
614
+ gui_lock = fasteners.InterProcessLock(
615
+ constants.MultiBrowser.PYAUTOGUILOCK
616
+ )
617
+ with gui_lock:
618
+ pyautogui.press(key)
619
+
620
+
621
+ def uc_gui_press_keys(driver, keys):
622
+ install_pyautogui_if_missing()
623
+ import pyautogui
624
+ pyautogui = get_configured_pyautogui(pyautogui)
625
+ gui_lock = fasteners.InterProcessLock(
626
+ constants.MultiBrowser.PYAUTOGUILOCK
627
+ )
628
+ with gui_lock:
629
+ for key in keys:
630
+ pyautogui.press(key)
631
+
632
+
633
+ def uc_gui_write(driver, text):
634
+ install_pyautogui_if_missing()
635
+ import pyautogui
636
+ pyautogui = get_configured_pyautogui(pyautogui)
637
+ gui_lock = fasteners.InterProcessLock(
638
+ constants.MultiBrowser.PYAUTOGUILOCK
639
+ )
640
+ with gui_lock:
641
+ pyautogui.write(text)
642
+
643
+
644
+ def uc_gui_handle_cf(driver, frame="iframe"):
645
+ source = driver.get_page_source()
646
+ if (
647
+ "//challenges.cloudflare.com" not in source
648
+ and 'aria-label="Cloudflare"' not in source
649
+ ):
650
+ return
651
+ install_pyautogui_if_missing()
652
+ import pyautogui
653
+ pyautogui = get_configured_pyautogui(pyautogui)
654
+ gui_lock = fasteners.InterProcessLock(
655
+ constants.MultiBrowser.PYAUTOGUILOCK
656
+ )
657
+ with gui_lock: # Prevent issues with multiple processes
658
+ needs_switch = False
659
+ is_in_frame = js_utils.is_in_frame(driver)
660
+ if is_in_frame and driver.is_element_present("#challenge-stage"):
661
+ driver.switch_to.parent_frame()
662
+ needs_switch = True
663
+ is_in_frame = js_utils.is_in_frame(driver)
664
+ if not is_in_frame:
665
+ # Make sure the window is on top
666
+ page_actions.switch_to_window(
667
+ driver,
668
+ driver.current_window_handle,
669
+ timeout=settings.SMALL_TIMEOUT,
670
+ )
671
+ if not is_in_frame or needs_switch:
672
+ # Currently not in frame (or nested frame outside CF one)
673
+ try:
674
+ driver.switch_to_frame(frame)
675
+ except Exception:
676
+ if driver.is_element_present("iframe"):
677
+ driver.switch_to_frame("iframe")
678
+ else:
679
+ return
680
+ try:
681
+ driver.execute_script('document.querySelector("input").focus()')
682
+ except Exception:
683
+ try:
684
+ driver.switch_to.default_content()
685
+ except Exception:
686
+ return
687
+ driver.disconnect()
688
+ try:
689
+ pyautogui.press(" ")
690
+ except Exception:
691
+ pass
692
+ reconnect_time = (float(constants.UC.RECONNECT_TIME) / 2.0) + 0.5
693
+ driver.reconnect(reconnect_time)
694
+
695
+
696
+ def uc_switch_to_frame(driver, frame="iframe", reconnect_time=None):
513
697
  from selenium.webdriver.remote.webelement import WebElement
514
698
  if isinstance(frame, WebElement):
515
699
  if not reconnect_time:
@@ -847,7 +1031,7 @@ def _set_chrome_options(
847
1031
  prefs["download.prompt_for_download"] = False
848
1032
  prefs["credentials_enable_service"] = False
849
1033
  prefs["local_discovery.notifications_enabled"] = False
850
- prefs["safebrowsing.enabled"] = False
1034
+ prefs["safebrowsing.enabled"] = False # Prevent PW "data breach" pop-ups
851
1035
  prefs["safebrowsing.disable_download_protection"] = True
852
1036
  prefs["omnibox-max-zero-suggest-matches"] = 0
853
1037
  prefs["omnibox-use-existing-autocomplete-client"] = 0
@@ -1145,6 +1329,7 @@ def _set_chrome_options(
1145
1329
  chrome_options.add_argument("--auto-open-devtools-for-tabs")
1146
1330
  if user_agent:
1147
1331
  chrome_options.add_argument("--user-agent=%s" % user_agent)
1332
+ chrome_options.add_argument("--safebrowsing-disable-download-protection")
1148
1333
  chrome_options.add_argument("--disable-browser-side-navigation")
1149
1334
  chrome_options.add_argument("--disable-save-password-bubble")
1150
1335
  chrome_options.add_argument("--disable-single-click-autofill")
@@ -1165,6 +1350,14 @@ def _set_chrome_options(
1165
1350
  chrome_options.add_argument("--ash-no-nudges")
1166
1351
  chrome_options.add_argument("--no-crash-upload")
1167
1352
  chrome_options.add_argument("--deny-permission-prompts")
1353
+ chrome_options.add_argument(
1354
+ '--simulate-outdated-no-au="Tue, 31 Dec 2099 23:59:59 GMT"'
1355
+ )
1356
+ chrome_options.add_argument("--disable-ipc-flooding-protection")
1357
+ chrome_options.add_argument("--disable-password-generation")
1358
+ chrome_options.add_argument("--disable-domain-reliability")
1359
+ chrome_options.add_argument("--disable-component-update")
1360
+ chrome_options.add_argument("--disable-breakpad")
1168
1361
  included_disabled_features = []
1169
1362
  included_disabled_features.append("OptimizationHints")
1170
1363
  included_disabled_features.append("OptimizationHintsFetching")
@@ -1175,10 +1368,9 @@ def _set_chrome_options(
1175
1368
  included_disabled_features.append("DownloadBubbleV2")
1176
1369
  included_disabled_features.append("InsecureDownloadWarnings")
1177
1370
  included_disabled_features.append("InterestFeedContentSuggestions")
1178
- if user_data_dir:
1179
- included_disabled_features.append("PrivacySandboxSettings4")
1180
- if not is_using_uc(undetectable, browser_name) or user_data_dir:
1181
- included_disabled_features.append("SidePanelPinning")
1371
+ included_disabled_features.append("PrivacySandboxSettings4")
1372
+ included_disabled_features.append("SidePanelPinning")
1373
+ included_disabled_features.append("UserAgentClientHint")
1182
1374
  for item in extra_disabled_features:
1183
1375
  if item not in included_disabled_features:
1184
1376
  included_disabled_features.append(item)
@@ -1366,7 +1558,7 @@ def _set_firefox_options(
1366
1558
  f_pref_value = False
1367
1559
  elif f_pref_value.isdigit():
1368
1560
  f_pref_value = int(f_pref_value)
1369
- elif f_pref_value.isdecimal():
1561
+ elif f_pref_value.replace(".", "", 1).isdigit():
1370
1562
  f_pref_value = float(f_pref_value)
1371
1563
  else:
1372
1564
  pass # keep as string
@@ -2286,11 +2478,13 @@ def get_local_driver(
2286
2478
  or "Process unexpectedly closed" in str(e)
2287
2479
  or "Failed to read marionette port" in str(e)
2288
2480
  or "A connection attempt failed" in str(e)
2481
+ or "Expected browser binary" in str(e)
2289
2482
  or hasattr(e, "msg") and (
2290
2483
  "geckodriver unexpectedly exited" in e.msg
2291
2484
  or "Process unexpectedly closed" in e.msg
2292
2485
  or "Failed to read marionette port" in e.msg
2293
2486
  or "A connection attempt failed" in e.msg
2487
+ or "Expected browser binary" in e.msg
2294
2488
  )
2295
2489
  ):
2296
2490
  time.sleep(0.1)
@@ -2326,11 +2520,13 @@ def get_local_driver(
2326
2520
  or "Process unexpectedly closed" in str(e)
2327
2521
  or "Failed to read marionette port" in str(e)
2328
2522
  or "A connection attempt failed" in str(e)
2523
+ or "Expected browser binary" in str(e)
2329
2524
  or hasattr(e, "msg") and (
2330
2525
  "geckodriver unexpectedly exited" in e.msg
2331
2526
  or "Process unexpectedly closed" in e.msg
2332
2527
  or "Failed to read marionette port" in e.msg
2333
2528
  or "A connection attempt failed" in e.msg
2529
+ or "Expected browser binary" in e.msg
2334
2530
  )
2335
2531
  ):
2336
2532
  time.sleep(0.1)
@@ -2426,7 +2622,7 @@ def get_local_driver(
2426
2622
  "credentials_enable_service": False,
2427
2623
  "local_discovery.notifications_enabled": False,
2428
2624
  "safebrowsing.disable_download_protection": True,
2429
- "safebrowsing.enabled": False,
2625
+ "safebrowsing.enabled": False, # Prevent PW "data breach" pop-ups
2430
2626
  "omnibox-max-zero-suggest-matches": 0,
2431
2627
  "omnibox-use-existing-autocomplete-client": 0,
2432
2628
  "omnibox-trending-zero-prefix-suggestions-on-ntp": 0,
@@ -2695,6 +2891,7 @@ def get_local_driver(
2695
2891
  edge_options.add_argument(
2696
2892
  "--disable-autofill-keyboard-accessory-view[8]"
2697
2893
  )
2894
+ edge_options.add_argument("--safebrowsing-disable-download-protection")
2698
2895
  edge_options.add_argument("--disable-browser-side-navigation")
2699
2896
  edge_options.add_argument("--disable-translate")
2700
2897
  if not enable_ws:
@@ -2820,6 +3017,14 @@ def get_local_driver(
2820
3017
  edge_options.add_argument(chromium_arg_item)
2821
3018
  if disable_features:
2822
3019
  extra_disabled_features.extend(disable_features.split(","))
3020
+ edge_options.add_argument(
3021
+ '--simulate-outdated-no-au="Tue, 31 Dec 2099 23:59:59 GMT"'
3022
+ )
3023
+ edge_options.add_argument("--disable-ipc-flooding-protection")
3024
+ edge_options.add_argument("--disable-password-generation")
3025
+ edge_options.add_argument("--disable-domain-reliability")
3026
+ edge_options.add_argument("--disable-component-update")
3027
+ edge_options.add_argument("--disable-breakpad")
2823
3028
  included_disabled_features = []
2824
3029
  included_disabled_features.append("OptimizationHints")
2825
3030
  included_disabled_features.append("OptimizationHintsFetching")
@@ -2828,10 +3033,9 @@ def get_local_driver(
2828
3033
  included_disabled_features.append("OptimizationGuideModelDownloading")
2829
3034
  included_disabled_features.append("InsecureDownloadWarnings")
2830
3035
  included_disabled_features.append("InterestFeedContentSuggestions")
2831
- if user_data_dir:
2832
- included_disabled_features.append("PrivacySandboxSettings4")
2833
- if not is_using_uc(undetectable, browser_name) or user_data_dir:
2834
- included_disabled_features.append("SidePanelPinning")
3036
+ included_disabled_features.append("PrivacySandboxSettings4")
3037
+ included_disabled_features.append("SidePanelPinning")
3038
+ included_disabled_features.append("UserAgentClientHint")
2835
3039
  for item in extra_disabled_features:
2836
3040
  if item not in included_disabled_features:
2837
3041
  included_disabled_features.append(item)
@@ -3802,6 +4006,26 @@ def get_local_driver(
3802
4006
  driver.uc_click = lambda *args, **kwargs: uc_click(
3803
4007
  driver, *args, **kwargs
3804
4008
  )
4009
+ driver.uc_gui_press_key = (
4010
+ lambda *args, **kwargs: uc_gui_press_key(
4011
+ driver, *args, **kwargs
4012
+ )
4013
+ )
4014
+ driver.uc_gui_press_keys = (
4015
+ lambda *args, **kwargs: uc_gui_press_keys(
4016
+ driver, *args, **kwargs
4017
+ )
4018
+ )
4019
+ driver.uc_gui_write = (
4020
+ lambda *args, **kwargs: uc_gui_write(
4021
+ driver, *args, **kwargs
4022
+ )
4023
+ )
4024
+ driver.uc_gui_handle_cf = (
4025
+ lambda *args, **kwargs: uc_gui_handle_cf(
4026
+ driver, *args, **kwargs
4027
+ )
4028
+ )
3805
4029
  driver.uc_switch_to_frame = (
3806
4030
  lambda *args, **kwargs: uc_switch_to_frame(
3807
4031
  driver, *args, **kwargs
@@ -94,6 +94,16 @@ class DriverMethods():
94
94
  def assert_exact_text(self, *args, **kwargs):
95
95
  page_actions.assert_exact_text(self.driver, *args, **kwargs)
96
96
 
97
+ def assert_non_empty_text(self, *args, **kwargs):
98
+ return page_actions.assert_non_empty_text(
99
+ self.driver, *args, **kwargs
100
+ )
101
+
102
+ def assert_text_not_visible(self, *args, **kwargs):
103
+ return page_actions.assert_text_not_visible(
104
+ self.driver, *args, **kwargs
105
+ )
106
+
97
107
  def wait_for_element(self, *args, **kwargs):
98
108
  return page_actions.wait_for_element(self.driver, *args, **kwargs)
99
109
 
@@ -112,6 +122,16 @@ class DriverMethods():
112
122
  def wait_for_exact_text(self, *args, **kwargs):
113
123
  return page_actions.wait_for_exact_text(self.driver, *args, **kwargs)
114
124
 
125
+ def wait_for_non_empty_text(self, *args, **kwargs):
126
+ return page_actions.wait_for_non_empty_text(
127
+ self.driver, *args, **kwargs
128
+ )
129
+
130
+ def wait_for_text_not_visible(self, *args, **kwargs):
131
+ return page_actions.wait_for_text_not_visible(
132
+ self.driver, *args, **kwargs
133
+ )
134
+
115
135
  def wait_for_and_accept_alert(self, *args, **kwargs):
116
136
  return page_actions.wait_for_and_accept_alert(
117
137
  self.driver, *args, **kwargs
@@ -134,14 +154,22 @@ class DriverMethods():
134
154
  def is_exact_text_visible(self, *args, **kwargs):
135
155
  return page_actions.is_exact_text_visible(self.driver, *args, **kwargs)
136
156
 
137
- def get_text(self, *args, **kwargs):
138
- return page_actions.get_text(self.driver, *args, **kwargs)
157
+ def is_attribute_present(self, *args, **kwargs):
158
+ return page_actions.has_attribute(self.driver, *args, **kwargs)
159
+
160
+ def is_non_empty_text_visible(self, *args, **kwargs):
161
+ return page_actions.is_non_empty_text_visible(
162
+ self.driver, *args, **kwargs
163
+ )
164
+
165
+ def is_online(self):
166
+ return self.driver.execute_script("return navigator.onLine;")
139
167
 
140
168
  def js_click(self, *args, **kwargs):
141
169
  return page_actions.js_click(self.driver, *args, **kwargs)
142
170
 
143
- def is_attribute_present(self, *args, **kwargs):
144
- return page_actions.has_attribute(self.driver, *args, **kwargs)
171
+ def get_text(self, *args, **kwargs):
172
+ return page_actions.get_text(self.driver, *args, **kwargs)
145
173
 
146
174
  def get_active_element_css(self, *args, **kwargs):
147
175
  return js_utils.get_active_element_css(self.driver, *args, **kwargs)
@@ -182,7 +210,32 @@ class DriverMethods():
182
210
  if self.is_element_visible(selector, by=by):
183
211
  self.highlight(selector, by=by, loops=loops, scroll=scroll)
184
212
 
185
- def switch_to_frame(self, frame):
213
+ def switch_to_default_window(self):
214
+ self.driver.switch_to.window(self.driver.window_handles[0])
215
+
216
+ def switch_to_newest_window(self):
217
+ self.driver.switch_to.window(self.driver.window_handles[-1])
218
+
219
+ def open_new_window(self, switch_to=True):
220
+ if switch_to:
221
+ try:
222
+ self.driver.switch_to.new_window("tab")
223
+ except Exception:
224
+ self.driver.execute_script("window.open('');")
225
+ self.switch_to_newest_window()
226
+ else:
227
+ self.driver.execute_script("window.open('');")
228
+
229
+ def open_new_tab(self, switch_to=True):
230
+ self.open_new_window(switch_to=switch_to)
231
+
232
+ def switch_to_window(self, *args, **kwargs):
233
+ page_actions.switch_to_window(self.driver, *args, **kwargs)
234
+
235
+ def switch_to_tab(self, *args, **kwargs):
236
+ self.switch_to_window(*args, **kwargs)
237
+
238
+ def switch_to_frame(self, frame="iframe"):
186
239
  if isinstance(frame, WebElement):
187
240
  self.driver.switch_to.frame(frame)
188
241
  else:
Binary file