seleniumbase 4.49.8__tar.gz → 4.49.10__tar.gz

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.
Files changed (164) hide show
  1. {seleniumbase-4.49.8/seleniumbase.egg-info → seleniumbase-4.49.10}/PKG-INFO +10 -9
  2. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/README.md +8 -7
  3. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/requirements.txt +1 -1
  4. seleniumbase-4.49.10/seleniumbase/__version__.py +2 -0
  5. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/browser_launcher.py +16 -10
  6. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/sb_cdp.py +116 -4
  7. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/fixtures/base_case.py +54 -0
  8. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/undetected/cdp_driver/browser.py +6 -0
  9. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/undetected/cdp_driver/cdp_util.py +2 -0
  10. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/undetected/cdp_driver/connection.py +13 -0
  11. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/undetected/cdp_driver/element.py +9 -3
  12. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/undetected/cdp_driver/tab.py +25 -36
  13. {seleniumbase-4.49.8 → seleniumbase-4.49.10/seleniumbase.egg-info}/PKG-INFO +10 -9
  14. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase.egg-info/requires.txt +1 -1
  15. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/setup.py +1 -1
  16. seleniumbase-4.49.8/seleniumbase/__version__.py +0 -2
  17. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/.gitignore +0 -0
  18. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/LICENSE +0 -0
  19. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/MANIFEST.in +0 -0
  20. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/install.sh +0 -0
  21. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/pyproject.toml +0 -0
  22. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/pytest.ini +0 -0
  23. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/sbase/__init__.py +0 -0
  24. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/sbase/__main__.py +0 -0
  25. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/sbase/steps.py +0 -0
  26. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/__init__.py +0 -0
  27. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/__main__.py +0 -0
  28. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/behave/__init__.py +0 -0
  29. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/behave/behave_helper.py +0 -0
  30. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/behave/behave_sb.py +0 -0
  31. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/behave/steps.py +0 -0
  32. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/common/__init__.py +0 -0
  33. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/common/decorators.py +0 -0
  34. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/common/encryption.py +0 -0
  35. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/common/exceptions.py +0 -0
  36. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/common/obfuscate.py +0 -0
  37. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/common/unobfuscate.py +0 -0
  38. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/config/__init__.py +0 -0
  39. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/config/ad_block_list.py +0 -0
  40. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/config/proxy_list.py +0 -0
  41. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/config/settings.py +0 -0
  42. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/console_scripts/__init__.py +0 -0
  43. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/console_scripts/logo_helper.py +0 -0
  44. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/console_scripts/rich_helper.py +0 -0
  45. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/console_scripts/run.py +0 -0
  46. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/console_scripts/sb_behave_gui.py +0 -0
  47. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/console_scripts/sb_caseplans.py +0 -0
  48. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/console_scripts/sb_commander.py +0 -0
  49. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/console_scripts/sb_install.py +0 -0
  50. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/console_scripts/sb_mkchart.py +0 -0
  51. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/console_scripts/sb_mkdir.py +0 -0
  52. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/console_scripts/sb_mkfile.py +0 -0
  53. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/console_scripts/sb_mkpres.py +0 -0
  54. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/console_scripts/sb_mkrec.py +0 -0
  55. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/console_scripts/sb_objectify.py +0 -0
  56. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/console_scripts/sb_print.py +0 -0
  57. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/console_scripts/sb_recorder.py +0 -0
  58. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/__init__.py +0 -0
  59. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/application_manager.py +0 -0
  60. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/capabilities_parser.py +0 -0
  61. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/colored_traceback.py +0 -0
  62. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/create_db_tables.sql +0 -0
  63. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/detect_b_ver.py +0 -0
  64. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/download_helper.py +0 -0
  65. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/encoded_images.py +0 -0
  66. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/jqc_helper.py +0 -0
  67. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/log_helper.py +0 -0
  68. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/mysql.py +0 -0
  69. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/nest_asyncio.py +0 -0
  70. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/proxy_helper.py +0 -0
  71. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/recorder_helper.py +0 -0
  72. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/report_helper.py +0 -0
  73. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/s3_manager.py +0 -0
  74. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/sb_driver.py +0 -0
  75. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/session_helper.py +0 -0
  76. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/settings_parser.py +0 -0
  77. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/style_sheet.py +0 -0
  78. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/testcase_manager.py +0 -0
  79. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/tour_helper.py +0 -0
  80. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/core/visual_helper.py +0 -0
  81. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/drivers/__init__.py +0 -0
  82. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/drivers/atlas_drivers/__init__.py +0 -0
  83. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/drivers/brave_drivers/__init__.py +0 -0
  84. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/drivers/cft_drivers/__init__.py +0 -0
  85. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/drivers/chromium_drivers/__init__.py +0 -0
  86. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/drivers/chs_drivers/__init__.py +0 -0
  87. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/drivers/comet_drivers/__init__.py +0 -0
  88. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/drivers/opera_drivers/__init__.py +0 -0
  89. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/extensions/__init__.py +0 -0
  90. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/extensions/ad_block.zip +0 -0
  91. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/extensions/disable_csp.zip +0 -0
  92. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/extensions/recorder.zip +0 -0
  93. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/extensions/sbase_ext.zip +0 -0
  94. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/fixtures/__init__.py +0 -0
  95. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/fixtures/constants.py +0 -0
  96. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/fixtures/css_to_xpath.py +0 -0
  97. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/fixtures/errors.py +0 -0
  98. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/fixtures/js_utils.py +0 -0
  99. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/fixtures/page_actions.py +0 -0
  100. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/fixtures/page_utils.py +0 -0
  101. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/fixtures/shared_utils.py +0 -0
  102. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/fixtures/unittest_helper.py +0 -0
  103. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/fixtures/words.py +0 -0
  104. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/fixtures/xpath_to_css.py +0 -0
  105. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/js_code/__init__.py +0 -0
  106. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/js_code/active_css_js.py +0 -0
  107. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/js_code/live_js.py +0 -0
  108. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/js_code/recorder_js.py +0 -0
  109. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/masterqa/__init__.py +0 -0
  110. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/masterqa/master_qa.py +0 -0
  111. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/plugins/__init__.py +0 -0
  112. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/plugins/base_plugin.py +0 -0
  113. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/plugins/basic_test_info.py +0 -0
  114. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/plugins/db_reporting_plugin.py +0 -0
  115. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/plugins/driver_manager.py +0 -0
  116. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/plugins/page_source.py +0 -0
  117. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/plugins/pytest_plugin.py +0 -0
  118. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/plugins/s3_logging_plugin.py +0 -0
  119. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/plugins/sb_manager.py +0 -0
  120. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/plugins/screen_shots.py +0 -0
  121. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/plugins/selenium_plugin.py +0 -0
  122. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/resources/__init__.py +0 -0
  123. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/translate/__init__.py +0 -0
  124. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/translate/chinese.py +0 -0
  125. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/translate/dutch.py +0 -0
  126. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/translate/french.py +0 -0
  127. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/translate/italian.py +0 -0
  128. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/translate/japanese.py +0 -0
  129. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/translate/korean.py +0 -0
  130. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/translate/master_dict.py +0 -0
  131. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/translate/portuguese.py +0 -0
  132. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/translate/russian.py +0 -0
  133. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/translate/spanish.py +0 -0
  134. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/translate/translator.py +0 -0
  135. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/undetected/__init__.py +0 -0
  136. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/undetected/cdp.py +0 -0
  137. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/undetected/cdp_driver/__init__.py +0 -0
  138. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/undetected/cdp_driver/_contradict.py +0 -0
  139. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/undetected/cdp_driver/config.py +0 -0
  140. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/undetected/dprocess.py +0 -0
  141. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/undetected/options.py +0 -0
  142. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/undetected/patcher.py +0 -0
  143. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/undetected/reactor.py +0 -0
  144. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/undetected/webelement.py +0 -0
  145. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/utilities/__init__.py +0 -0
  146. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/utilities/selenium_grid/__init__.py +0 -0
  147. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/utilities/selenium_grid/download_selenium_server.py +0 -0
  148. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/utilities/selenium_grid/font_color +0 -0
  149. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/utilities/selenium_grid/grid-hub +0 -0
  150. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/utilities/selenium_grid/grid-node +0 -0
  151. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/utilities/selenium_grid/grid_hub.py +0 -0
  152. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/utilities/selenium_grid/grid_node.py +0 -0
  153. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/utilities/selenium_grid/register-grid-node.bat +0 -0
  154. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/utilities/selenium_grid/register-grid-node.sh +0 -0
  155. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/utilities/selenium_grid/start-grid-hub.bat +0 -0
  156. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/utilities/selenium_grid/start-grid-hub.sh +0 -0
  157. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/utilities/selenium_ide/__init__.py +0 -0
  158. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase/utilities/selenium_ide/convert_ide.py +0 -0
  159. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase.egg-info/SOURCES.txt +0 -0
  160. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase.egg-info/dependency_links.txt +0 -0
  161. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase.egg-info/entry_points.txt +0 -0
  162. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/seleniumbase.egg-info/top_level.txt +0 -0
  163. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/setup.cfg +0 -0
  164. {seleniumbase-4.49.8 → seleniumbase-4.49.10}/virtualenv_install.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: seleniumbase
3
- Version: 4.49.8
3
+ Version: 4.49.10
4
4
  Summary: SeleniumBase is a framework for web crawling, scraping, and testing. Supports pytest. CDP Mode adds stealth. Includes many tools.
5
5
  Home-page: https://github.com/seleniumbase/SeleniumBase
6
6
  Author: Michael Mintz
@@ -71,7 +71,7 @@ Requires-Dist: exceptiongroup>=1.3.1
71
71
  Requires-Dist: websockets~=15.0.1; python_version < "3.10"
72
72
  Requires-Dist: websockets>=16.0; python_version >= "3.10"
73
73
  Requires-Dist: filelock~=3.19.1; python_version < "3.10"
74
- Requires-Dist: filelock>=3.29.1; python_version >= "3.10"
74
+ Requires-Dist: filelock>=3.29.3; python_version >= "3.10"
75
75
  Requires-Dist: fasteners>=0.20
76
76
  Requires-Dist: mycdp>=1.3.7
77
77
  Requires-Dist: pynose>=1.5.5
@@ -187,8 +187,8 @@ Dynamic: summary
187
187
  <!-- SeleniumBase Docs -->
188
188
 
189
189
  <meta property="og:site_name" content="SeleniumBase">
190
- <meta property="og:title" content="SeleniumBase: Stealthy Chromium Automation and E2E Testing with Python." />
191
- <meta property="og:description" content="Stealthy Chromium Automation and E2E Testing with Python." />
190
+ <meta property="og:title" content="SeleniumBase: Stealthy Chromium Automation with Python; and E2E Testing." />
191
+ <meta property="og:description" content="Stealthy Chromium Automation, including fast, easy, and reliable Web/UI testing with Python." />
192
192
  <meta property="og:keywords" content="Python, pytest, selenium, webdriver, testing, automation, seleniumbase, framework, dashboard, recorder, reports, screenshots, playwright, stealth, CAPTCHA">
193
193
  <meta property="og:image" content="https://seleniumbase.github.io/cdn/img/mac_sb_logo_5b.png" />
194
194
  <link rel="icon" href="https://seleniumbase.github.io/img/logo6.png" />
@@ -306,8 +306,8 @@ sb.quit()
306
306
  ```python
307
307
  from seleniumbase import sb_cdp
308
308
 
309
- url = "https://news.ycombinator.com/submitted?id=seleniumbase"
310
- sb = sb_cdp.Chrome(url)
309
+ sb = sb_cdp.Chrome()
310
+ sb.goto("https://news.ycombinator.com/submitted?id=seleniumbase")
311
311
  elements = sb.find_elements("span.titleline > a")
312
312
  for element in elements:
313
313
  print("* " + element.text)
@@ -346,7 +346,7 @@ Google Chrome is the default browser. Only unbranded Chromium and Chrome-for-Tes
346
346
  The Chromium browser can also be set via method args, eg: `cft=True`, `use_chromium=True`, `browser="edge"`, `browser="brave"`, etc. Eg:
347
347
 
348
348
  ```python
349
- sb = sb_cdp.Chrome(url, use_chromium=True)
349
+ sb = sb_cdp.Chrome(use_chromium=True)
350
350
  ```
351
351
 
352
352
  --------
@@ -404,12 +404,13 @@ with SB(uc=True, test=True, locale="en") as sb:
404
404
  ```python
405
405
  from seleniumbase import sb_cdp
406
406
 
407
- url = "https://gitlab.com/users/sign_in"
408
- sb = sb_cdp.Chrome(url, incognito=True)
407
+ sb = sb_cdp.Chrome(incognito=True)
408
+ sb.goto("https://gitlab.com/users/sign_in")
409
409
  sb.sleep(2)
410
410
  sb.solve_captcha()
411
411
  sb.highlight('h1:contains("GitLab")')
412
412
  sb.highlight('button:contains("Sign in")')
413
+ sb.quit()
413
414
  ```
414
415
 
415
416
  --------
@@ -1,8 +1,8 @@
1
1
  <!-- SeleniumBase Docs -->
2
2
 
3
3
  <meta property="og:site_name" content="SeleniumBase">
4
- <meta property="og:title" content="SeleniumBase: Stealthy Chromium Automation and E2E Testing with Python." />
5
- <meta property="og:description" content="Stealthy Chromium Automation and E2E Testing with Python." />
4
+ <meta property="og:title" content="SeleniumBase: Stealthy Chromium Automation with Python; and E2E Testing." />
5
+ <meta property="og:description" content="Stealthy Chromium Automation, including fast, easy, and reliable Web/UI testing with Python." />
6
6
  <meta property="og:keywords" content="Python, pytest, selenium, webdriver, testing, automation, seleniumbase, framework, dashboard, recorder, reports, screenshots, playwright, stealth, CAPTCHA">
7
7
  <meta property="og:image" content="https://seleniumbase.github.io/cdn/img/mac_sb_logo_5b.png" />
8
8
  <link rel="icon" href="https://seleniumbase.github.io/img/logo6.png" />
@@ -120,8 +120,8 @@ sb.quit()
120
120
  ```python
121
121
  from seleniumbase import sb_cdp
122
122
 
123
- url = "https://news.ycombinator.com/submitted?id=seleniumbase"
124
- sb = sb_cdp.Chrome(url)
123
+ sb = sb_cdp.Chrome()
124
+ sb.goto("https://news.ycombinator.com/submitted?id=seleniumbase")
125
125
  elements = sb.find_elements("span.titleline > a")
126
126
  for element in elements:
127
127
  print("* " + element.text)
@@ -160,7 +160,7 @@ Google Chrome is the default browser. Only unbranded Chromium and Chrome-for-Tes
160
160
  The Chromium browser can also be set via method args, eg: `cft=True`, `use_chromium=True`, `browser="edge"`, `browser="brave"`, etc. Eg:
161
161
 
162
162
  ```python
163
- sb = sb_cdp.Chrome(url, use_chromium=True)
163
+ sb = sb_cdp.Chrome(use_chromium=True)
164
164
  ```
165
165
 
166
166
  --------
@@ -218,12 +218,13 @@ with SB(uc=True, test=True, locale="en") as sb:
218
218
  ```python
219
219
  from seleniumbase import sb_cdp
220
220
 
221
- url = "https://gitlab.com/users/sign_in"
222
- sb = sb_cdp.Chrome(url, incognito=True)
221
+ sb = sb_cdp.Chrome(incognito=True)
222
+ sb.goto("https://gitlab.com/users/sign_in")
223
223
  sb.sleep(2)
224
224
  sb.solve_captcha()
225
225
  sb.highlight('h1:contains("GitLab")')
226
226
  sb.highlight('button:contains("Sign in")')
227
+ sb.quit()
227
228
  ```
228
229
 
229
230
  --------
@@ -10,7 +10,7 @@ exceptiongroup>=1.3.1
10
10
  websockets~=15.0.1;python_version<"3.10"
11
11
  websockets>=16.0;python_version>="3.10"
12
12
  filelock~=3.19.1;python_version<"3.10"
13
- filelock>=3.29.1;python_version>="3.10"
13
+ filelock>=3.29.3;python_version>="3.10"
14
14
  fasteners>=0.20
15
15
  mycdp>=1.3.7
16
16
  pynose>=1.5.5
@@ -0,0 +1,2 @@
1
+ # seleniumbase package
2
+ __version__ = "4.49.10"
@@ -18,11 +18,7 @@ from selenium.common.exceptions import ElementClickInterceptedException
18
18
  from selenium.common.exceptions import InvalidSessionIdException
19
19
  from selenium.common.exceptions import SessionNotCreatedException
20
20
  from selenium.webdriver.chrome.service import Service as ChromeService
21
- from selenium.webdriver.common.options import ArgOptions
22
- from selenium.webdriver.common.service import utils as service_utils
23
- from selenium.webdriver.edge.service import Service as EdgeService
24
- from selenium.webdriver.firefox.service import Service as FirefoxService
25
- from selenium.webdriver.safari.service import Service as SafariService
21
+ from selenium.webdriver.common import utils as common_utils
26
22
  from seleniumbase import config as sb_config
27
23
  from seleniumbase import decorators
28
24
  from seleniumbase import drivers # webdriver storage folder for SeleniumBase
@@ -793,6 +789,7 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
793
789
  cdp.grant_permissions = CDPM.grant_permissions
794
790
  cdp.grant_all_permissions = CDPM.grant_all_permissions
795
791
  cdp.reset_permissions = CDPM.reset_permissions
792
+ cdp.get_all_urls = CDPM.get_all_urls
796
793
  cdp.get_all_cookies = CDPM.get_all_cookies
797
794
  cdp.set_all_cookies = CDPM.set_all_cookies
798
795
  cdp.save_cookies = CDPM.save_cookies
@@ -831,6 +828,11 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
831
828
  cdp.activate_messenger = CDPM.activate_messenger
832
829
  cdp.set_messenger_theme = CDPM.set_messenger_theme
833
830
  cdp.post_message = CDPM.post_message
831
+ cdp.download_file = CDPM.download_file
832
+ cdp.save_file_as = CDPM.save_file_as
833
+ cdp.assert_downloaded_file = CDPM.assert_downloaded_file
834
+ cdp.get_path_of_downloaded_file = CDPM.get_path_of_downloaded_file
835
+ cdp.set_download_path = CDPM.set_download_path
834
836
  cdp.set_locale = CDPM.set_locale
835
837
  cdp.set_local_storage_item = CDPM.set_local_storage_item
836
838
  cdp.set_session_storage_item = CDPM.set_session_storage_item
@@ -2668,7 +2670,7 @@ def _set_chrome_options(
2668
2670
  args = " ".join(sys.argv)
2669
2671
  debug_port = 9222
2670
2672
  if ("-n" in sys.argv or " -n=" in args or args == "-c"):
2671
- debug_port = service_utils.free_port()
2673
+ debug_port = common_utils.free_port()
2672
2674
  chrome_options.add_argument("--remote-debugging-port=%s" % debug_port)
2673
2675
  if swiftshader:
2674
2676
  chrome_options.add_argument("--use-gl=angle")
@@ -3672,6 +3674,7 @@ def get_remote_driver(
3672
3674
  device_height,
3673
3675
  device_pixel_ratio,
3674
3676
  ):
3677
+ from selenium.webdriver.common.options import ArgOptions
3675
3678
  # Construct the address for connecting to a Selenium Grid
3676
3679
  if servername.startswith("https://"):
3677
3680
  protocol = "https"
@@ -4130,6 +4133,7 @@ def get_local_driver(
4130
4133
  b_path = binary_location
4131
4134
  use_uc = is_using_uc(undetectable, browser_name)
4132
4135
  if browser_name == constants.Browser.FIREFOX:
4136
+ from selenium.webdriver.firefox.service import Service as FFService
4133
4137
  firefox_options = _set_firefox_options(
4134
4138
  downloads_path,
4135
4139
  headless,
@@ -4184,7 +4188,7 @@ def get_local_driver(
4184
4188
  sys.argv = sys_args # Put back original sys args
4185
4189
  # Launch Firefox
4186
4190
  if os.path.exists(local_geckodriver):
4187
- service = FirefoxService(
4191
+ service = FFService(
4188
4192
  executable_path=local_geckodriver,
4189
4193
  log_output=os.devnull,
4190
4194
  )
@@ -4229,7 +4233,7 @@ def get_local_driver(
4229
4233
  else:
4230
4234
  raise # Not an obvious fix.
4231
4235
  else:
4232
- service = FirefoxService(log_output=os.devnull)
4236
+ service = FFService(log_output=os.devnull)
4233
4237
  try:
4234
4238
  driver = webdriver.Firefox(
4235
4239
  service=service,
@@ -4337,6 +4341,7 @@ def get_local_driver(
4337
4341
  driver = webdriver.Ie(service=service, options=ie_options)
4338
4342
  return extend_driver(driver)
4339
4343
  elif browser_name == constants.Browser.EDGE:
4344
+ from selenium.webdriver.edge.service import Service as EdgeService
4340
4345
  prefs = {
4341
4346
  "download.default_directory": downloads_path,
4342
4347
  "download.directory_upgrade": True,
@@ -4756,7 +4761,7 @@ def get_local_driver(
4756
4761
  args = " ".join(sys.argv)
4757
4762
  free_port = 9222
4758
4763
  if ("-n" in sys.argv or " -n=" in args or args == "-c"):
4759
- free_port = service_utils.free_port()
4764
+ free_port = common_utils.free_port()
4760
4765
  edge_options.add_argument("--remote-debugging-port=%s" % free_port)
4761
4766
  if swiftshader:
4762
4767
  edge_options.add_argument("--use-gl=angle")
@@ -4866,7 +4871,7 @@ def get_local_driver(
4866
4871
  args = " ".join(sys.argv)
4867
4872
  free_port = 9222
4868
4873
  if ("-n" in sys.argv or " -n=" in args or args == "-c"):
4869
- free_port = service_utils.free_port()
4874
+ free_port = common_utils.free_port()
4870
4875
  edge_options.add_argument(
4871
4876
  "--remote-debugging-port=%s" % free_port
4872
4877
  )
@@ -4904,6 +4909,7 @@ def get_local_driver(
4904
4909
  raise Exception("Can't run Safari tests in multithreaded mode!")
4905
4910
  warnings.simplefilter("ignore", category=DeprecationWarning)
4906
4911
  from selenium.webdriver.safari.options import Options as SafariOptions
4912
+ from selenium.webdriver.safari.service import Service as SafariService
4907
4913
  service = SafariService(quiet=False)
4908
4914
  options = SafariOptions()
4909
4915
  if (
@@ -152,6 +152,17 @@ class CDPMethods():
152
152
  except Exception:
153
153
  pass
154
154
 
155
+ def activate_cdp_mode(self, url=None, **kwargs):
156
+ """If calling this method from here, then it was likely done
157
+ by accident because CDP Mode is already active at this point.
158
+ If URL, then navigate there with any kwargs that were passed.
159
+ If no URL (but kwargs are included) then refresh with kwargs.
160
+ If no URL and no kwargs either, then do nothing."""
161
+ if url:
162
+ self.get(url, **kwargs)
163
+ elif kwargs:
164
+ self.get(self.get_current_url(), **kwargs)
165
+
155
166
  def open(self, url, **kwargs):
156
167
  self.get(url, **kwargs)
157
168
 
@@ -752,6 +763,18 @@ class CDPMethods():
752
763
  driver = driver.cdp_base
753
764
  return self.loop.run_until_complete(driver.reset_permissions())
754
765
 
766
+ def get_all_urls(self, absolute=True):
767
+ """
768
+ Convenience function that returns all links (a,link,img,script,meta).
769
+ :param absolute:
770
+ Try to build all the links in absolute form
771
+ instead of "as is", often relative.
772
+ :return: List of URLs.
773
+ """
774
+ return self.loop.run_until_complete(
775
+ self.page.get_all_urls(absolute=absolute)
776
+ )
777
+
755
778
  def get_all_cookies(self, *args, **kwargs):
756
779
  driver = self.driver
757
780
  if hasattr(driver, "cdp_base"):
@@ -1374,10 +1397,15 @@ class CDPMethods():
1374
1397
  return self.find_element(selector).text_all
1375
1398
 
1376
1399
  def get_title(self):
1400
+ """Returns the title of the current web page."""
1377
1401
  return self.loop.run_until_complete(
1378
1402
  self.page.evaluate("document.title")
1379
1403
  )
1380
1404
 
1405
+ def get_page_title(self):
1406
+ """Same as get_title(), which returns the current page title."""
1407
+ return self.get_title()
1408
+
1381
1409
  def get_current_url(self):
1382
1410
  return self.loop.run_until_complete(
1383
1411
  self.page.evaluate("window.location.href")
@@ -1725,6 +1753,80 @@ class CDPMethods():
1725
1753
  duration = float(duration) + 0.15
1726
1754
  time.sleep(float(duration))
1727
1755
 
1756
+ def download_file(self, file_url):
1757
+ """Download a file from a URL.
1758
+ The default download location is: "./downloaded_files/"."""
1759
+ self.loop.run_until_complete(
1760
+ self.page.download_file(file_url)
1761
+ )
1762
+
1763
+ def save_file_as(self, file_url, new_file_name):
1764
+ """Download a file from a URL and rename it.
1765
+ The default download location is: "./downloaded_files/"."""
1766
+ self.loop.run_until_complete(
1767
+ self.page.download_file(file_url, new_file_name)
1768
+ )
1769
+
1770
+ def assert_downloaded_file(self, file, timeout=None):
1771
+ """Asserts that the file exists in SeleniumBase's [Downloads Folder].
1772
+ For browser click-initiated downloads, SeleniumBase will override
1773
+ the system [Downloads Folder] to be "./downloaded_files/".
1774
+ @Params
1775
+ file - The filename of the downloaded file.
1776
+ timeout - The time (seconds) to wait for the download to complete.
1777
+ browser - If True, uses the path set by click-initiated downloads."""
1778
+ downloads_folder = constants.Files.DOWNLOADS_FOLDER
1779
+ abs_path = os.path.abspath(".")
1780
+ downloads_path = os.path.join(abs_path, downloads_folder)
1781
+ if not timeout:
1782
+ timeout = settings.LARGE_TIMEOUT
1783
+ start_ms = time.time() * 1000.0
1784
+ stop_ms = start_ms + (timeout * 1000.0)
1785
+ downloaded_file_path = os.path.join(downloads_path, file)
1786
+ found = False
1787
+ for x in range(int(timeout)):
1788
+ shared_utils.check_if_time_limit_exceeded()
1789
+ try:
1790
+ self.assert_true(
1791
+ os.path.exists(downloaded_file_path),
1792
+ "File [%s] was not found in the downloads folder [%s]!"
1793
+ % (file, downloads_path),
1794
+ )
1795
+ found = True
1796
+ break
1797
+ except Exception:
1798
+ now_ms = time.time() * 1000.0
1799
+ if now_ms >= stop_ms:
1800
+ break
1801
+ time.sleep(1)
1802
+ if not found and not os.path.exists(downloaded_file_path):
1803
+ plural = "s"
1804
+ if timeout == 1:
1805
+ plural = ""
1806
+ message = (
1807
+ "File {%s} was not found in the downloads folder {%s} "
1808
+ "after %s second%s! (Or the download didn't complete!)"
1809
+ % (file, downloads_path, timeout, plural)
1810
+ )
1811
+ from seleniumbase.common.exceptions import NoSuchFileException
1812
+ raise NoSuchFileException(message)
1813
+
1814
+ def get_path_of_downloaded_file(self, file):
1815
+ """This assumes the default location of SeleniumBase downloads,
1816
+ which is the "./downloaded_files/" folder where scripts run."""
1817
+ downloads_folder = constants.Files.DOWNLOADS_FOLDER
1818
+ abs_path = os.path.abspath(".")
1819
+ downloads_path = os.path.join(abs_path, downloads_folder)
1820
+ return os.path.join(downloads_path, file)
1821
+
1822
+ def set_download_path(self, path):
1823
+ """Set a new download path for click-initiated downloads.
1824
+ (For Pure CDP Mode sync format only! -> sb_cdp.)
1825
+ The default download location is: "./downloaded_files/".
1826
+ Convenience methods such as assert_downloaded_file(file)
1827
+ will still expect the default location."""
1828
+ self.loop.run_until_complete(self.page.set_download_path(path))
1829
+
1728
1830
  def set_locale(self, locale):
1729
1831
  """(Settings will take effect on the next page load)"""
1730
1832
  self.loop.run_until_complete(self.page.set_locale(locale))
@@ -3233,13 +3335,23 @@ class CDPMethods():
3233
3335
  )
3234
3336
  return True
3235
3337
 
3236
- def assert_true(self, expression):
3338
+ def assert_true(self, expression, msg=None):
3237
3339
  if not expression:
3238
- raise AssertionError("%s is not true" % expression)
3340
+ if not msg:
3341
+ raise AssertionError("%s is not true" % expression)
3342
+ else:
3343
+ raise AssertionError(
3344
+ "%s is not true. (%s)" % (expression, msg)
3345
+ )
3239
3346
 
3240
- def assert_false(self, expression):
3347
+ def assert_false(self, expression, msg=None):
3241
3348
  if expression:
3242
- raise AssertionError("%s is not false" % expression)
3349
+ if not msg:
3350
+ raise AssertionError("%s is not false" % expression)
3351
+ else:
3352
+ raise AssertionError(
3353
+ "%s is not false. (%s)" % (expression, msg)
3354
+ )
3243
3355
 
3244
3356
  def assert_equal(self, first, second):
3245
3357
  if first != second:
@@ -5101,14 +5101,48 @@ class BaseCase(unittest.TestCase):
5101
5101
  self.close_active_tab = self.cdp.close_active_tab
5102
5102
  if hasattr(self.cdp, "find_element_by_text"):
5103
5103
  self.find_element_by_text = self.cdp.find_element_by_text
5104
+ if hasattr(self.cdp, "find_elements_by_text"):
5105
+ self.find_elements_by_text = self.cdp.find_elements_by_text
5104
5106
  if hasattr(self.cdp, "get_active_tab"):
5105
5107
  self.get_active_tab = self.cdp.get_active_tab
5108
+ if hasattr(self.cdp, "get_all_cookies"):
5109
+ self.get_all_cookies = self.cdp.get_all_cookies
5110
+ if hasattr(self.cdp, "get_all_urls"):
5111
+ self.get_all_urls = self.cdp.get_all_urls
5112
+ if hasattr(self.cdp, "get_document"):
5113
+ self.get_document = self.cdp.get_document
5114
+ if hasattr(self.cdp, "get_element_attribute"):
5115
+ self.get_element_attribute = self.cdp.get_element_attribute
5116
+ if hasattr(self.cdp, "get_element_attributes"):
5117
+ self.get_element_attributes = self.cdp.get_element_attributes
5118
+ if hasattr(self.cdp, "get_element_html"):
5119
+ self.get_element_html = self.cdp.get_element_html
5106
5120
  if hasattr(self.cdp, "get_endpoint_url"):
5107
5121
  self.get_endpoint_url = self.cdp.get_endpoint_url
5108
5122
  if hasattr(self.cdp, "get_event_loop"):
5109
5123
  self.get_event_loop = self.cdp.get_event_loop
5124
+ if hasattr(self.cdp, "get_flattened_document"):
5125
+ self.get_flattened_document = self.cdp.get_flattened_document
5126
+ if hasattr(self.cdp, "get_navigation_history"):
5127
+ self.get_navigation_history = self.cdp.get_navigation_history
5128
+ if hasattr(self.cdp, "get_nested_element"):
5129
+ self.get_nested_element = self.cdp.get_nested_element
5130
+ if hasattr(self.cdp, "get_port"):
5131
+ self.get_port = self.cdp.get_port
5132
+ if hasattr(self.cdp, "get_rd_host"):
5133
+ self.get_rd_host = self.cdp.get_rd_host
5134
+ if hasattr(self.cdp, "get_rd_port"):
5135
+ self.get_rd_port = self.cdp.get_rd_port
5136
+ if hasattr(self.cdp, "get_rd_url"):
5137
+ self.get_rd_url = self.cdp.get_rd_url
5110
5138
  if hasattr(self.cdp, "get_tabs"):
5111
5139
  self.get_tabs = self.cdp.get_tabs
5140
+ if hasattr(self.cdp, "get_websocket_url"):
5141
+ self.get_websocket_url = self.cdp.get_websocket_url
5142
+ if hasattr(self.cdp, "grant_all_permissions"):
5143
+ self.grant_all_permissions = self.cdp.grant_all_permissions
5144
+ if hasattr(self.cdp, "grant_permissions"):
5145
+ self.grant_permissions = self.cdp.grant_permissions
5112
5146
  if hasattr(self.cdp, "gui_click_and_hold"):
5113
5147
  self.gui_click_and_hold = self.cdp.gui_click_and_hold
5114
5148
  if hasattr(self.cdp, "gui_click_element"):
@@ -5119,6 +5153,26 @@ class BaseCase(unittest.TestCase):
5119
5153
  self.gui_drag_drop_points = self.cdp.gui_drag_drop_points
5120
5154
  if hasattr(self.cdp, "highlight_overlay"):
5121
5155
  self.highlight_overlay = self.cdp.highlight_overlay
5156
+ if hasattr(self.cdp, "js_dumps"):
5157
+ self.js_dumps = self.cdp.js_dumps
5158
+ if hasattr(self.cdp, "js_scroll_into_view"):
5159
+ self.js_scroll_into_view = self.cdp.js_scroll_into_view
5160
+ if hasattr(self.cdp, "medimize"):
5161
+ self.medimize = self.cdp.medimize
5162
+ if hasattr(self.cdp, "mouse_click"):
5163
+ self.mouse_click = self.cdp.mouse_click
5164
+ if hasattr(self.cdp, "nested_click"):
5165
+ self.nested_click = self.cdp.nested_click
5166
+ if hasattr(self.cdp, "remove_from_dom"):
5167
+ self.remove_from_dom = self.cdp.remove_from_dom
5168
+ if hasattr(self.cdp, "reset_permissions"):
5169
+ self.reset_permissions = self.cdp.reset_permissions
5170
+ if hasattr(self.cdp, "set_all_cookies"):
5171
+ self.set_all_cookies = self.cdp.set_all_cookies
5172
+ if hasattr(self.cdp, "tile_windows"):
5173
+ self.tile_windows = self.cdp.tile_windows
5174
+ if hasattr(self.cdp, "get_window"):
5175
+ self.get_window = self.cdp.get_window
5122
5176
  if getattr(self.driver, "_is_using_auth", None):
5123
5177
  with suppress(Exception):
5124
5178
  self.cdp.loop.run_until_complete(self.cdp.page.wait(0.25))
@@ -380,6 +380,7 @@ class Browser:
380
380
  filter(lambda item: item.type_ == "page", self.targets)
381
381
  )
382
382
  await connection.sleep(0.005)
383
+ _cdp_downloads_path = None
383
384
  _cdp_timezone = None
384
385
  _cdp_user_agent = ""
385
386
  _cdp_locale = None
@@ -389,6 +390,8 @@ class Browser:
389
390
  _cdp_mobile_mode = None
390
391
  _cdp_recorder = None
391
392
  _cdp_ad_block = None
393
+ if getattr(sb_config, "_cdp_downloads_path", None):
394
+ _cdp_downloads_path = sb_config._cdp_downloads_path
392
395
  if getattr(sb_config, "_cdp_timezone", None):
393
396
  _cdp_timezone = sb_config._cdp_timezone
394
397
  if getattr(sb_config, "_cdp_user_agent", None):
@@ -405,6 +408,8 @@ class Browser:
405
408
  _cdp_ad_block = sb_config.ad_block_on
406
409
  if getattr(sb_config, "disable_csp", None):
407
410
  _cdp_disable_csp = sb_config.disable_csp
411
+ if "downloads_path" in kwargs:
412
+ _cdp_downloads_path = kwargs["downloads_path"]
408
413
  if "timezone" in kwargs:
409
414
  _cdp_timezone = kwargs["timezone"]
410
415
  elif "tzone" in kwargs:
@@ -439,6 +444,7 @@ class Browser:
439
444
  await connection.sleep(0.01)
440
445
  await connection.send(cdp.network.enable())
441
446
  await connection.sleep(0.01)
447
+ await connection.set_downloads_folder(_cdp_downloads_path)
442
448
  if _cdp_timezone:
443
449
  await connection.set_timezone(_cdp_timezone)
444
450
  if _cdp_locale:
@@ -744,6 +744,8 @@ async def start(
744
744
  sb_config._cdp_user_agent = kwargs["user_agent"]
745
745
  else:
746
746
  sb_config._cdp_user_agent = None
747
+ if "downloads_path" in kwargs:
748
+ sb_config._cdp_downloads_path = kwargs["downloads_path"]
747
749
  if "platform" in kwargs:
748
750
  sb_config._cdp_platform = kwargs["platform"]
749
751
  elif "plat" in kwargs:
@@ -5,6 +5,7 @@ import inspect
5
5
  import itertools
6
6
  import json
7
7
  import logging
8
+ import os
8
9
  import sys
9
10
  import types
10
11
  import warnings
@@ -19,6 +20,7 @@ from typing import (
19
20
  )
20
21
  import websockets
21
22
  from websockets.protocol import State
23
+ from seleniumbase.fixtures import constants
22
24
  from . import cdp_util as util
23
25
  import mycdp as cdp
24
26
  import mycdp.network
@@ -335,6 +337,17 @@ class Connection(metaclass=CantTouchThis):
335
337
  # No listener created yet.
336
338
  pass
337
339
 
340
+ async def set_downloads_folder(self, downloads_path):
341
+ if not downloads_path:
342
+ downloads_dir = constants.Files.DOWNLOADS_FOLDER
343
+ abs_path = os.path.abspath(".")
344
+ downloads_path = os.path.join(abs_path, downloads_dir)
345
+ await self.send(
346
+ cdp.browser.set_download_behavior(
347
+ behavior="allow", download_path=str(downloads_path)
348
+ )
349
+ )
350
+
338
351
  async def set_locale(self, locale: Optional[str] = None):
339
352
  """Sets the Language Locale code via set_user_agent_override."""
340
353
  await self.set_user_agent(user_agent="", accept_language=locale)
@@ -373,7 +373,9 @@ class Element:
373
373
  object_id=self._remote_object.object_id
374
374
  )]
375
375
  script = 'sessionStorage.getItem("pxsid") !== null;'
376
- using_px = await self.tab.evaluate(script)
376
+ using_px = True
377
+ with suppress(Exception):
378
+ using_px = await self.tab.evaluate(script)
377
379
  if not using_px:
378
380
  await self.flash_async(0.25)
379
381
  await self._tab.send(
@@ -505,7 +507,9 @@ class Element:
505
507
  return
506
508
  logger.debug("Clicking on location: %.2f, %.2f" % center)
507
509
  script = 'sessionStorage.getItem("pxsid") !== null;'
508
- using_px = await self.tab.evaluate(script)
510
+ using_px = True
511
+ with suppress(Exception):
512
+ using_px = await self.tab.evaluate(script)
509
513
  if not using_px:
510
514
  asyncio.create_task(self.flash_async(0.25))
511
515
  asyncio.create_task(
@@ -567,7 +571,9 @@ class Element:
567
571
  else:
568
572
  logger.debug("Clicking on location: %.2f, %.2f" % (x_pos, y_pos))
569
573
  script = 'sessionStorage.getItem("pxsid") !== null;'
570
- using_px = await self.tab.evaluate(script)
574
+ using_px = True
575
+ with suppress(Exception):
576
+ using_px = await self.tab.evaluate(script)
571
577
  if not using_px:
572
578
  asyncio.create_task(
573
579
  self.flash_async(