seleniumbase 4.41.3__py3-none-any.whl → 4.45.10__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.
Files changed (64) hide show
  1. sbase/steps.py +9 -0
  2. seleniumbase/__version__.py +1 -1
  3. seleniumbase/behave/behave_helper.py +2 -0
  4. seleniumbase/behave/behave_sb.py +21 -8
  5. seleniumbase/common/decorators.py +3 -1
  6. seleniumbase/console_scripts/run.py +1 -0
  7. seleniumbase/console_scripts/sb_caseplans.py +3 -4
  8. seleniumbase/console_scripts/sb_install.py +142 -11
  9. seleniumbase/console_scripts/sb_mkchart.py +1 -2
  10. seleniumbase/console_scripts/sb_mkdir.py +99 -29
  11. seleniumbase/console_scripts/sb_mkfile.py +1 -2
  12. seleniumbase/console_scripts/sb_mkpres.py +1 -2
  13. seleniumbase/console_scripts/sb_mkrec.py +26 -2
  14. seleniumbase/console_scripts/sb_objectify.py +4 -5
  15. seleniumbase/console_scripts/sb_print.py +1 -1
  16. seleniumbase/console_scripts/sb_recorder.py +40 -3
  17. seleniumbase/core/browser_launcher.py +474 -151
  18. seleniumbase/core/detect_b_ver.py +258 -16
  19. seleniumbase/core/log_helper.py +15 -21
  20. seleniumbase/core/mysql.py +1 -1
  21. seleniumbase/core/recorder_helper.py +3 -0
  22. seleniumbase/core/report_helper.py +9 -12
  23. seleniumbase/core/sb_cdp.py +734 -215
  24. seleniumbase/core/sb_driver.py +46 -5
  25. seleniumbase/core/session_helper.py +2 -4
  26. seleniumbase/core/tour_helper.py +1 -2
  27. seleniumbase/drivers/atlas_drivers/__init__.py +0 -0
  28. seleniumbase/drivers/brave_drivers/__init__.py +0 -0
  29. seleniumbase/drivers/chromium_drivers/__init__.py +0 -0
  30. seleniumbase/drivers/comet_drivers/__init__.py +0 -0
  31. seleniumbase/drivers/opera_drivers/__init__.py +0 -0
  32. seleniumbase/fixtures/base_case.py +448 -251
  33. seleniumbase/fixtures/constants.py +36 -9
  34. seleniumbase/fixtures/js_utils.py +77 -18
  35. seleniumbase/fixtures/page_actions.py +41 -13
  36. seleniumbase/fixtures/page_utils.py +19 -12
  37. seleniumbase/fixtures/shared_utils.py +64 -6
  38. seleniumbase/masterqa/master_qa.py +16 -2
  39. seleniumbase/plugins/base_plugin.py +8 -0
  40. seleniumbase/plugins/basic_test_info.py +2 -3
  41. seleniumbase/plugins/driver_manager.py +131 -5
  42. seleniumbase/plugins/page_source.py +2 -3
  43. seleniumbase/plugins/pytest_plugin.py +244 -79
  44. seleniumbase/plugins/sb_manager.py +143 -20
  45. seleniumbase/plugins/selenium_plugin.py +144 -12
  46. seleniumbase/translate/translator.py +2 -3
  47. seleniumbase/undetected/__init__.py +17 -13
  48. seleniumbase/undetected/cdp.py +1 -12
  49. seleniumbase/undetected/cdp_driver/browser.py +330 -129
  50. seleniumbase/undetected/cdp_driver/cdp_util.py +328 -61
  51. seleniumbase/undetected/cdp_driver/config.py +110 -14
  52. seleniumbase/undetected/cdp_driver/connection.py +18 -48
  53. seleniumbase/undetected/cdp_driver/element.py +105 -33
  54. seleniumbase/undetected/cdp_driver/tab.py +414 -39
  55. seleniumbase/utilities/selenium_grid/download_selenium_server.py +1 -1
  56. seleniumbase/utilities/selenium_grid/grid_hub.py +1 -2
  57. seleniumbase/utilities/selenium_grid/grid_node.py +2 -3
  58. seleniumbase/utilities/selenium_ide/convert_ide.py +2 -3
  59. {seleniumbase-4.41.3.dist-info → seleniumbase-4.45.10.dist-info}/METADATA +193 -166
  60. {seleniumbase-4.41.3.dist-info → seleniumbase-4.45.10.dist-info}/RECORD +64 -59
  61. {seleniumbase-4.41.3.dist-info → seleniumbase-4.45.10.dist-info}/licenses/LICENSE +1 -1
  62. {seleniumbase-4.41.3.dist-info → seleniumbase-4.45.10.dist-info}/WHEEL +0 -0
  63. {seleniumbase-4.41.3.dist-info → seleniumbase-4.45.10.dist-info}/entry_points.txt +0 -0
  64. {seleniumbase-4.41.3.dist-info → seleniumbase-4.45.10.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: seleniumbase
3
- Version: 4.41.3
3
+ Version: 4.45.10
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
@@ -28,13 +28,11 @@ Classifier: Environment :: Web Environment
28
28
  Classifier: Framework :: Pytest
29
29
  Classifier: Intended Audience :: Developers
30
30
  Classifier: Intended Audience :: Information Technology
31
- Classifier: License :: OSI Approved :: MIT License
32
31
  Classifier: Operating System :: MacOS :: MacOS X
33
32
  Classifier: Operating System :: Microsoft :: Windows
34
33
  Classifier: Operating System :: POSIX :: Linux
35
34
  Classifier: Programming Language :: Python
36
35
  Classifier: Programming Language :: Python :: 3
37
- Classifier: Programming Language :: Python :: 3.8
38
36
  Classifier: Programming Language :: Python :: 3.9
39
37
  Classifier: Programming Language :: Python :: 3.10
40
38
  Classifier: Programming Language :: Python :: 3.11
@@ -57,132 +55,124 @@ Classifier: Topic :: Software Development :: Testing
57
55
  Classifier: Topic :: Software Development :: Testing :: Acceptance
58
56
  Classifier: Topic :: Software Development :: Testing :: Traffic Generation
59
57
  Classifier: Topic :: Utilities
60
- Requires-Python: >=3.8
58
+ Requires-Python: >=3.9
61
59
  Description-Content-Type: text/markdown
62
60
  License-File: LICENSE
63
- Requires-Dist: pip>=25.0.1; python_version < "3.9"
64
- Requires-Dist: pip>=25.2; python_version >= "3.9"
61
+ Requires-Dist: pip>=25.3
65
62
  Requires-Dist: packaging>=25.0
66
63
  Requires-Dist: setuptools~=70.2; python_version < "3.10"
67
64
  Requires-Dist: setuptools>=80.9.0; python_version >= "3.10"
68
65
  Requires-Dist: wheel>=0.45.1
69
- Requires-Dist: attrs>=25.3.0
70
- Requires-Dist: certifi>=2025.8.3
71
- Requires-Dist: exceptiongroup>=1.3.0
72
- Requires-Dist: websockets~=13.1; python_version < "3.9"
73
- Requires-Dist: websockets>=15.0.1; python_version >= "3.9"
74
- Requires-Dist: filelock~=3.16.1; python_version < "3.9"
75
- Requires-Dist: filelock>=3.19.1; python_version >= "3.9"
66
+ Requires-Dist: attrs>=25.4.0
67
+ Requires-Dist: certifi>=2026.1.4
68
+ Requires-Dist: exceptiongroup>=1.3.1
69
+ Requires-Dist: websockets>=15.0.1
70
+ Requires-Dist: filelock~=3.19.1; python_version < "3.10"
71
+ Requires-Dist: filelock>=3.20.2; python_version >= "3.10"
76
72
  Requires-Dist: fasteners>=0.20
77
- Requires-Dist: mycdp>=1.2.0
78
- Requires-Dist: pynose>=1.5.4
79
- Requires-Dist: platformdirs>=4.3.6; python_version < "3.9"
80
- Requires-Dist: platformdirs>=4.4.0; python_version >= "3.9"
81
- Requires-Dist: typing-extensions>=4.13.2
73
+ Requires-Dist: mycdp>=1.3.2
74
+ Requires-Dist: pynose>=1.5.5
75
+ Requires-Dist: platformdirs~=4.4.0; python_version < "3.10"
76
+ Requires-Dist: platformdirs>=4.5.1; python_version >= "3.10"
77
+ Requires-Dist: typing-extensions>=4.15.0
82
78
  Requires-Dist: sbvirtualdisplay>=1.4.0
83
- Requires-Dist: MarkupSafe==2.1.5; python_version < "3.9"
84
- Requires-Dist: MarkupSafe>=3.0.2; python_version >= "3.9"
79
+ Requires-Dist: MarkupSafe>=3.0.3
85
80
  Requires-Dist: Jinja2>=3.1.6
86
81
  Requires-Dist: six>=1.17.0
87
82
  Requires-Dist: parse>=1.20.2
88
83
  Requires-Dist: parse-type>=0.6.6
89
84
  Requires-Dist: colorama>=0.4.6
90
- Requires-Dist: pyyaml>=6.0.2
85
+ Requires-Dist: pyyaml>=6.0.3
91
86
  Requires-Dist: pygments>=2.19.2
92
- Requires-Dist: pyreadline3>=3.5.3; platform_system == "Windows"
87
+ Requires-Dist: pyreadline3>=3.5.4; platform_system == "Windows"
93
88
  Requires-Dist: tabcompleter>=1.4.0
94
- Requires-Dist: pdbp>=1.7.1
95
- Requires-Dist: idna==3.10
89
+ Requires-Dist: pdbp>=1.8.1
90
+ Requires-Dist: idna>=3.11
96
91
  Requires-Dist: chardet==5.2.0
97
- Requires-Dist: charset-normalizer<4,>=3.4.3
92
+ Requires-Dist: charset-normalizer<4,>=3.4.4
98
93
  Requires-Dist: urllib3<2,>=1.26.20; python_version < "3.10"
99
- Requires-Dist: urllib3<2.6.0,>=1.26.20; python_version >= "3.10"
100
- Requires-Dist: requests==2.32.4; python_version < "3.9"
101
- Requires-Dist: requests<2.33,>=2.32.5; python_version >= "3.9"
94
+ Requires-Dist: urllib3<3,>=1.26.20; python_version >= "3.10"
95
+ Requires-Dist: requests~=2.32.5
102
96
  Requires-Dist: sniffio==1.3.1
103
97
  Requires-Dist: h11==0.16.0
104
98
  Requires-Dist: outcome==1.3.0.post0
105
- Requires-Dist: trio==0.27.0; python_version < "3.9"
106
- Requires-Dist: trio==0.30.0; python_version >= "3.9"
107
- Requires-Dist: trio-websocket==0.12.2
108
- Requires-Dist: wsproto==1.2.0
109
- Requires-Dist: websocket-client==1.8.0
110
- Requires-Dist: selenium==4.27.1; python_version < "3.9"
111
- Requires-Dist: selenium==4.32.0; python_version >= "3.9" and python_version < "3.10"
112
- Requires-Dist: selenium==4.35.0; python_version >= "3.10"
113
- Requires-Dist: cssselect==1.2.0; python_version < "3.9"
114
- Requires-Dist: cssselect==1.3.0; python_version >= "3.9"
99
+ Requires-Dist: trio<1,>=0.31.0; python_version < "3.10"
100
+ Requires-Dist: trio<1,>=0.32.0; python_version >= "3.10"
101
+ Requires-Dist: trio-websocket~=0.12.2
102
+ Requires-Dist: wsproto==1.2.0; python_version < "3.10"
103
+ Requires-Dist: wsproto~=1.3.2; python_version >= "3.10"
104
+ Requires-Dist: websocket-client~=1.9.0
105
+ Requires-Dist: selenium==4.32.0; python_version < "3.10"
106
+ Requires-Dist: selenium==4.39.0; python_version >= "3.10"
107
+ Requires-Dist: cssselect==1.3.0
108
+ Requires-Dist: nest-asyncio==1.6.0
115
109
  Requires-Dist: sortedcontainers==2.4.0
116
- Requires-Dist: execnet==2.1.1
117
- Requires-Dist: iniconfig==2.1.0
118
- Requires-Dist: pluggy==1.5.0; python_version < "3.9"
119
- Requires-Dist: pluggy==1.6.0; python_version >= "3.9"
120
- Requires-Dist: pytest==8.3.5; python_version < "3.9"
121
- Requires-Dist: pytest==8.4.1; python_version >= "3.9"
110
+ Requires-Dist: execnet==2.1.1; python_version < "3.10"
111
+ Requires-Dist: execnet==2.1.2; python_version >= "3.10"
112
+ Requires-Dist: iniconfig==2.1.0; python_version < "3.10"
113
+ Requires-Dist: iniconfig==2.3.0; python_version >= "3.10"
114
+ Requires-Dist: pluggy==1.6.0
115
+ Requires-Dist: pytest==8.4.2; python_version < "3.11"
116
+ Requires-Dist: pytest==9.0.2; python_version >= "3.11"
122
117
  Requires-Dist: pytest-html==4.0.2
123
118
  Requires-Dist: pytest-metadata==3.1.1
124
119
  Requires-Dist: pytest-ordering==0.6
125
- Requires-Dist: pytest-rerunfailures==14.0; python_version < "3.9"
126
- Requires-Dist: pytest-rerunfailures==15.1; python_version >= "3.9"
127
- Requires-Dist: pytest-xdist==3.6.1; python_version < "3.9"
128
- Requires-Dist: pytest-xdist==3.8.0; python_version >= "3.9"
120
+ Requires-Dist: pytest-rerunfailures==16.0.1; python_version < "3.10"
121
+ Requires-Dist: pytest-rerunfailures==16.1; python_version >= "3.10"
122
+ Requires-Dist: pytest-xdist==3.8.0
129
123
  Requires-Dist: parameterized==0.9.0
130
124
  Requires-Dist: behave==1.2.6
131
- Requires-Dist: soupsieve==2.7; python_version < "3.9"
132
- Requires-Dist: soupsieve~=2.8; python_version >= "3.9"
133
- Requires-Dist: beautifulsoup4~=4.13.5
125
+ Requires-Dist: soupsieve~=2.8.1
126
+ Requires-Dist: beautifulsoup4~=4.14.3
134
127
  Requires-Dist: pyotp==2.9.0
135
128
  Requires-Dist: python-xlib==0.33; platform_system == "Linux"
129
+ Requires-Dist: PyAutoGUI>=0.9.54; platform_system == "Linux"
136
130
  Requires-Dist: markdown-it-py==3.0.0; python_version < "3.10"
137
131
  Requires-Dist: markdown-it-py==4.0.0; python_version >= "3.10"
138
132
  Requires-Dist: mdurl==0.1.2
139
- Requires-Dist: rich<15,>=14.1.0
133
+ Requires-Dist: rich<15,>=14.2.0
140
134
  Provides-Extra: allure
141
135
  Requires-Dist: allure-pytest>=2.13.5; extra == "allure"
142
136
  Requires-Dist: allure-python-commons>=2.13.5; extra == "allure"
143
137
  Requires-Dist: allure-behave>=2.13.5; extra == "allure"
144
138
  Provides-Extra: coverage
145
- Requires-Dist: coverage>=7.6.1; python_version < "3.9" and extra == "coverage"
146
- Requires-Dist: coverage>=7.10.5; python_version >= "3.9" and extra == "coverage"
147
- Requires-Dist: pytest-cov>=5.0.0; python_version < "3.9" and extra == "coverage"
148
- Requires-Dist: pytest-cov>=6.2.1; python_version >= "3.9" and extra == "coverage"
139
+ Requires-Dist: coverage>=7.10.7; python_version < "3.10" and extra == "coverage"
140
+ Requires-Dist: coverage>=7.13.1; python_version >= "3.10" and extra == "coverage"
141
+ Requires-Dist: pytest-cov>=7.0.0; extra == "coverage"
149
142
  Provides-Extra: flake8
150
- Requires-Dist: flake8==5.0.4; python_version < "3.9" and extra == "flake8"
151
- Requires-Dist: flake8==7.3.0; python_version >= "3.9" and extra == "flake8"
143
+ Requires-Dist: flake8==7.3.0; extra == "flake8"
152
144
  Requires-Dist: mccabe==0.7.0; extra == "flake8"
153
- Requires-Dist: pyflakes==2.5.0; python_version < "3.9" and extra == "flake8"
154
- Requires-Dist: pyflakes==3.4.0; python_version >= "3.9" and extra == "flake8"
155
- Requires-Dist: pycodestyle==2.9.1; python_version < "3.9" and extra == "flake8"
156
- Requires-Dist: pycodestyle==2.14.0; python_version >= "3.9" and extra == "flake8"
145
+ Requires-Dist: pyflakes==3.4.0; extra == "flake8"
146
+ Requires-Dist: pycodestyle==2.14.0; extra == "flake8"
157
147
  Provides-Extra: ipdb
158
148
  Requires-Dist: ipdb==0.13.13; extra == "ipdb"
159
149
  Requires-Dist: ipython==7.34.0; extra == "ipdb"
160
150
  Provides-Extra: mss
161
- Requires-Dist: mss==9.0.2; python_version < "3.9" and extra == "mss"
162
- Requires-Dist: mss==10.0.0; python_version >= "3.9" and extra == "mss"
151
+ Requires-Dist: mss==10.1.0; extra == "mss"
163
152
  Provides-Extra: pdfminer
164
- Requires-Dist: pdfminer.six==20250324; python_version < "3.9" and extra == "pdfminer"
165
- Requires-Dist: pdfminer.six==20250506; python_version >= "3.9" and extra == "pdfminer"
166
- Requires-Dist: cryptography==39.0.2; python_version < "3.9" and extra == "pdfminer"
167
- Requires-Dist: cryptography==45.0.6; python_version >= "3.9" and extra == "pdfminer"
168
- Requires-Dist: cffi==1.17.1; extra == "pdfminer"
169
- Requires-Dist: pycparser==2.22; extra == "pdfminer"
153
+ Requires-Dist: pdfminer.six==20251107; python_version < "3.10" and extra == "pdfminer"
154
+ Requires-Dist: pdfminer.six==20260107; python_version >= "3.10" and extra == "pdfminer"
155
+ Requires-Dist: cryptography==46.0.3; extra == "pdfminer"
156
+ Requires-Dist: cffi==2.0.0; extra == "pdfminer"
157
+ Requires-Dist: pycparser==2.23; extra == "pdfminer"
170
158
  Provides-Extra: pillow
171
- Requires-Dist: Pillow>=10.4.0; python_version < "3.9" and extra == "pillow"
172
- Requires-Dist: Pillow>=11.3.0; python_version >= "3.9" and extra == "pillow"
159
+ Requires-Dist: Pillow>=11.3.0; python_version < "3.10" and extra == "pillow"
160
+ Requires-Dist: Pillow>=12.1.0; python_version >= "3.10" and extra == "pillow"
173
161
  Provides-Extra: pip-system-certs
174
162
  Requires-Dist: pip-system-certs==4.0; platform_system == "Windows" and extra == "pip-system-certs"
175
163
  Provides-Extra: proxy
176
164
  Requires-Dist: proxy.py==2.4.3; extra == "proxy"
165
+ Provides-Extra: playwright
166
+ Requires-Dist: playwright>=1.56.0; extra == "playwright"
177
167
  Provides-Extra: psutil
178
- Requires-Dist: psutil==7.0.0; extra == "psutil"
168
+ Requires-Dist: psutil>=7.1.3; extra == "psutil"
179
169
  Provides-Extra: pyautogui
180
- Requires-Dist: PyAutoGUI==0.9.54; extra == "pyautogui"
170
+ Requires-Dist: PyAutoGUI>=0.9.54; platform_system != "Linux" and extra == "pyautogui"
181
171
  Provides-Extra: selenium-stealth
182
172
  Requires-Dist: selenium-stealth==1.0.6; extra == "selenium-stealth"
183
173
  Provides-Extra: selenium-wire
184
174
  Requires-Dist: selenium-wire==5.1.0; extra == "selenium-wire"
185
- Requires-Dist: pyOpenSSL==24.2.1; extra == "selenium-wire"
175
+ Requires-Dist: pyOpenSSL>=24.2.1; extra == "selenium-wire"
186
176
  Requires-Dist: pyparsing>=3.1.4; extra == "selenium-wire"
187
177
  Requires-Dist: Brotli==1.1.0; extra == "selenium-wire"
188
178
  Requires-Dist: blinker==1.7.0; extra == "selenium-wire"
@@ -191,7 +181,7 @@ Requires-Dist: hpack==4.0.0; extra == "selenium-wire"
191
181
  Requires-Dist: hyperframe==6.0.1; extra == "selenium-wire"
192
182
  Requires-Dist: kaitaistruct==0.10; extra == "selenium-wire"
193
183
  Requires-Dist: pyasn1==0.6.1; extra == "selenium-wire"
194
- Requires-Dist: zstandard==0.23.0; extra == "selenium-wire"
184
+ Requires-Dist: zstandard>=0.23.0; extra == "selenium-wire"
195
185
  Dynamic: author
196
186
  Dynamic: author-email
197
187
  Dynamic: classifier
@@ -219,80 +209,86 @@ Dynamic: summary
219
209
 
220
210
  <p align="center"><a href="https://github.com/seleniumbase/SeleniumBase/"><img src="https://seleniumbase.github.io/cdn/img/super_logo_sb3.png" alt="SeleniumBase" title="SeleniumBase" width="350" /></a></p>
221
211
 
222
- <p align="center" class="hero__title"><b>All-in-one Browser Automation Framework:<br />Web Crawling / Testing / Scraping / Stealth</b></p>
212
+ <p align="center" class="hero__title"><b>Automate, test, and scrape the web on your own terms.<br /></b></p>
223
213
 
224
- <p align="center"><a href="https://pypi.python.org/pypi/seleniumbase" target="_blank"><img src="https://img.shields.io/pypi/v/seleniumbase.svg?color=3399EE" alt="PyPI version" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/releases" target="_blank"><img src="https://img.shields.io/github/v/release/seleniumbase/SeleniumBase.svg?color=22AAEE" alt="GitHub version" /></a> <a href="https://seleniumbase.io"><img src="https://img.shields.io/badge/docs-seleniumbase.io-11BBAA.svg" alt="SeleniumBase Docs" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/actions" target="_blank"><img src="https://github.com/seleniumbase/SeleniumBase/workflows/CI%20build/badge.svg" alt="SeleniumBase GitHub Actions" /></a> <a href="https://discord.gg/EdhQTn3EyE" target="_blank"><img src="https://img.shields.io/discord/727927627830001734?color=7289DA&label=Discord&logo=discord&logoColor=white"/></a></p>
214
+ <p align="center"><a href="https://pypi.python.org/pypi/seleniumbase" target="_blank"><img src="https://img.shields.io/pypi/v/seleniumbase.svg?color=3399EE" alt="PyPI version" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/releases" target="_blank"><img src="https://img.shields.io/github/v/release/seleniumbase/SeleniumBase.svg?color=22AAEE" alt="GitHub version" /></a> <a href="https://seleniumbase.io"><img src="https://img.shields.io/badge/docs-seleniumbase.io-11BBAA.svg" alt="SeleniumBase Docs" /></a></p>
215
+ <p align="center"><a href="https://github.com/seleniumbase/SeleniumBase/actions" target="_blank"><img src="https://github.com/seleniumbase/SeleniumBase/workflows/CI%20build/badge.svg" alt="SeleniumBase GitHub Actions" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/stargazers"><img src="https://img.shields.io/github/stars/seleniumbase/SeleniumBase?style=social"></a> <a href="https://pepy.tech/projects/seleniumbase?timeRange=threeMonths&category=version&includeCIDownloads=true&granularity=daily&viewType=line&versions=*" target="_blank"><img src="https://static.pepy.tech/badge/seleniumbase" alt="SeleniumBase PyPI downloads" /></a> <a href="https://discord.gg/EdhQTn3EyE" target="_blank"><img src="https://img.shields.io/discord/727927627830001734?color=7289DA&label=Discord&logo=discord&logoColor=white"/></a></p>
225
216
 
226
217
  <p align="center">
227
218
  <a href="#python_installation">🚀 Start</a> |
228
219
  <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/features_list.md">🏰 Features</a> |
229
220
  <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/customizing_test_runs.md">🎛️ Options</a> |
230
221
  <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/ReadMe.md">📚 Examples</a> |
231
- <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/console_scripts/ReadMe.md">🌠 Scripts</a> |
222
+ <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/console_scripts/ReadMe.md">🪄 Scripts</a> |
232
223
  <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/mobile_testing.md">📱 Mobile</a>
233
224
  <br />
234
- <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/method_summary.md">📘 APIs</a> |
235
- <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/syntax_formats.md"> 🔠 Formats</a> |
225
+ <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/method_summary.md">📘 The API</a> |
226
+ <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/syntax_formats.md"> 🔠 SyntaxFormats</a> |
236
227
  <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/recorder_mode.md">🔴 Recorder</a> |
237
228
  <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/example_logs/ReadMe.md">📊 Dashboard</a> |
238
- <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/locale_codes.md">🗾 Locales</a> |
239
- <a href="https://seleniumbase.io/devices/?url=seleniumbase.com">💻 Farm</a>
229
+ <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/locale_codes.md">🗾 Locale</a>
240
230
  <br />
241
231
  <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/commander.md">🎖️ GUI</a> |
242
232
  <a href="https://seleniumbase.io/demo_page">📰 TestPage</a> |
243
233
  <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/uc_mode.md">👤 UC Mode</a> |
244
234
  <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/ReadMe.md">🐙 CDP Mode</a> |
245
- <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/chart_maker/ReadMe.md">📶 Charts</a> |
246
- <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/utilities/selenium_grid/ReadMe.md">🌐 Grid</a>
235
+ <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/chart_maker/ReadMe.md">📶 Charts</a> |
236
+ <a href="https://seleniumbase.io/devices/?url=seleniumbase.com">🖥️ Farm</a>
247
237
  <br />
248
238
  <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/how_it_works.md">👁️ How</a> |
249
- <a href="https://github.com/seleniumbase/SeleniumBase/tree/master/examples/migration/raw_selenium">🚝 Migrate</a> |
250
- <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/case_plans.md">🗂️ CasePlans</a> |
251
- <a href="https://github.com/seleniumbase/SeleniumBase/tree/master/examples/boilerplates">♻️ Template</a> |
252
- <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/master_qa/ReadMe.md">🧬 Hybrid</a> |
239
+ <a href="https://github.com/seleniumbase/SeleniumBase/tree/master/examples/migration/raw_selenium">🚝 Migration</a> |
240
+ <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/playwright/ReadMe.md">🎭 Stealthy Playwright</a> |
241
+ <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/master_qa/ReadMe.md">🛂 MasterQA</a> |
253
242
  <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/tour_examples/ReadMe.md">🚎 Tours</a>
254
243
  <br />
255
244
  <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/integrations/github/workflows/ReadMe.md">🤖 CI/CD</a> |
256
- <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/js_package_manager.md">🕹️ JSMgr</a> |
245
+ <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/js_package_manager.md">❇️ JSMgr</a> |
257
246
  <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/translations.md">🌏 Translator</a> |
258
247
  <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/presenter/ReadMe.md">🎞️ Presenter</a> |
259
- <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/dialog_boxes/ReadMe.md">🛂 Dialog</a> |
260
- <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/visual_testing/ReadMe.md">🖼️ Visual</a>
248
+ <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/visual_testing/ReadMe.md">🖼️ Visual</a> |
249
+ <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/case_plans.md">🗂️ CPlans</a>
261
250
  <br />
262
251
  </p>
263
252
 
264
- <p>SeleniumBase is the professional toolkit for web automation activities. Built for testing websites, bypassing CAPTCHAs, enhancing productivity, completing tasks, and scaling your business.</p>
253
+ <p>SeleniumBase is a browser automation framework that empowers software teams to innovate faster and handle modern web challenges with ease. With stealth options like CDP Mode, you'll avoid the usual restrictions imposed by websites deploying bot-detection services.</p>
265
254
 
266
255
  --------
267
256
 
268
257
  📚 Learn from [**over 200 examples** in the **SeleniumBase/examples/** folder](https://github.com/seleniumbase/SeleniumBase/tree/master/examples).
269
258
 
270
- 🐙 Note that <a translate="no" href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/uc_mode.md"><b>UC Mode</b></a> / <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/ReadMe.md"><b>CDP Mode</b></a> (Stealth Mode) have their own ReadMe files.
259
+ 🐙 Stealth modes: <a translate="no" href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/uc_mode.md"><b>UC Mode</b></a> and <a translate="no" href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/ReadMe.md"><b>CDP Mode</b></a> can bypass bot-detection, solve CAPTCHAs, and call advanced methods from the <a href="https://chromedevtools.github.io/devtools-protocol/" translate="no">Chrome Devtools Protocol</a>.
271
260
 
272
- ℹ️ Most scripts run with raw <code translate="no"><b>python</b></code>, although some scripts use <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/syntax_formats.md">Syntax Formats</a> that expect <a href="https://docs.pytest.org/en/latest/how-to/usage.html" translate="no"><b>pytest</b></a> (a Python unit-testing framework included with SeleniumBase that can discover, collect, and run tests automatically).
261
+ ℹ️ Many examples run with raw <code translate="no"><b>python</b></code>, although some use <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/syntax_formats.md">Syntax Formats</a> that expect <a href="https://docs.pytest.org/en/latest/how-to/usage.html" translate="no"><b>pytest</b></a> (a Python unit-testing framework included with SeleniumBase that can discover, collect, and run tests automatically).
273
262
 
274
263
  --------
275
264
 
276
- <p align="left">📗 Here's <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/raw_google.py">raw_google.py</a>, which performs a Google search:</p>
265
+ <p align="left">📗 This script performs a Google Search using SeleniumBase UC Mode + CDP Mode:<br /><a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/raw_google.py">SeleniumBase/examples/raw_google.py</a> (Results are saved as PDF, HTML, and PNG)</p>
277
266
 
278
267
  ```python
279
268
  from seleniumbase import SB
280
269
 
281
- with SB(test=True, uc=True) as sb:
282
- sb.open("https://google.com/ncr")
283
- sb.type('[title="Search"]', "SeleniumBase GitHub page\n")
284
- sb.click('[href*="github.com/seleniumbase/"]')
285
- sb.save_screenshot_to_logs() # ./latest_logs/
270
+ with SB(uc=True, test=True) as sb:
271
+ url = "https://google.com/ncr"
272
+ sb.activate_cdp_mode(url)
273
+ sb.type('[title="Search"]', "SeleniumBase GitHub page")
274
+ sb.click("div:not([jsname]) > * > input")
275
+ sb.sleep(2)
286
276
  print(sb.get_page_title())
277
+ sb.sleep(1) # Wait for the "AI Overview" result
278
+ if sb.is_text_visible("Generating"):
279
+ sb.wait_for_text("AI Overview")
280
+ sb.save_as_pdf_to_logs() # Saved to ./latest_logs/
281
+ sb.save_page_source_to_logs()
282
+ sb.save_screenshot_to_logs()
287
283
  ```
288
284
 
289
285
  > `python raw_google.py`
290
286
 
291
- <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/raw_google.py"><img src="https://seleniumbase.github.io/cdn/gif/google_search.gif" alt="SeleniumBase Test" title="SeleniumBase Test" width="480" /></a>
287
+ <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/raw_google.py"><img src="https://seleniumbase.github.io/cdn/img/google_sb_result.png" alt="SeleniumBase on Google" title="SeleniumBase on Google" width="480" /></a>
292
288
 
293
289
  --------
294
290
 
295
- <p align="left">📗 Here's an example of bypassing Cloudflare's challenge page: <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/raw_gitlab.py">SeleniumBase/examples/cdp_mode/raw_gitlab.py</a></p>
291
+ <p align="left">📗 Here's a script that bypasses Cloudflare's challenge page with UC Mode + CDP Mode: <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/raw_gitlab.py">SeleniumBase/examples/cdp_mode/raw_gitlab.py</a></p>
296
292
 
297
293
  ```python
298
294
  from seleniumbase import SB
@@ -300,16 +296,35 @@ from seleniumbase import SB
300
296
  with SB(uc=True, test=True, locale="en") as sb:
301
297
  url = "https://gitlab.com/users/sign_in"
302
298
  sb.activate_cdp_mode(url)
303
- sb.sleep(1)
304
- sb.uc_gui_click_captcha()
305
299
  sb.sleep(2)
300
+ sb.solve_captcha()
301
+ # (The rest is for testing and demo purposes)
302
+ sb.assert_text("Username", '[for="user_login"]', timeout=3)
303
+ sb.assert_element('label[for="user_login"]')
304
+ sb.highlight('button:contains("Sign in")')
305
+ sb.highlight('h1:contains("GitLab")')
306
+ sb.post_message("SeleniumBase wasn't detected", duration=4)
306
307
  ```
307
308
 
308
309
  <img src="https://seleniumbase.github.io/other/cf_sec.jpg" title="SeleniumBase" width="332"> <img src="https://seleniumbase.github.io/other/gitlab_bypass.png" title="SeleniumBase" width="288">
309
310
 
311
+ <p align="left">📙 There's also SeleniumBase's "Pure CDP Mode", which doesn't use WebDriver or Selenium at all: <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/raw_cdp_gitlab.py">SeleniumBase/examples/cdp_mode/raw_cdp_gitlab.py</a></p>
312
+
313
+ ```python
314
+ from seleniumbase import sb_cdp
315
+
316
+ url = "https://gitlab.com/users/sign_in"
317
+ sb = sb_cdp.Chrome(url, incognito=True)
318
+ sb.sleep(2)
319
+ sb.solve_captcha()
320
+ sb.highlight('h1:contains("GitLab")')
321
+ sb.highlight('button:contains("Sign in")')
322
+ sb.driver.stop()
323
+ ```
324
+
310
325
  --------
311
326
 
312
- <p align="left">📗 Here's <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/test_get_swag.py">test_get_swag.py</a>, which tests an e-commerce site:</p>
327
+ <p align="left">📗 Here's <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/test_get_swag.py">SeleniumBase/examples/test_get_swag.py</a>, which tests an e-commerce site:</p>
313
328
 
314
329
  ```python
315
330
  from seleniumbase import BaseCase
@@ -337,11 +352,11 @@ class MyTestClass(BaseCase):
337
352
 
338
353
  <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/test_get_swag.py"><img src="https://seleniumbase.github.io/cdn/gif/fast_swag_2.gif" alt="SeleniumBase Test" title="SeleniumBase Test" width="480" /></a>
339
354
 
340
- > (The default browser is ``--chrome`` if not set.)
355
+ > (The default browser is `--chrome` if not set.)
341
356
 
342
357
  --------
343
358
 
344
- <p align="left">📗 Here's <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/test_coffee_cart.py" target="_blank">test_coffee_cart.py</a>, which verifies an e-commerce site:</p>
359
+ <p align="left">📗 Here's <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/test_coffee_cart.py" target="_blank">SeleniumBase/examples/test_coffee_cart.py</a>, which verifies an e-commerce site:</p>
345
360
 
346
361
  ```zsh
347
362
  pytest test_coffee_cart.py --demo
@@ -355,7 +370,7 @@ pytest test_coffee_cart.py --demo
355
370
 
356
371
  <a id="multiple_examples"></a>
357
372
 
358
- <p align="left">📗 Here's <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/test_demo_site.py" target="_blank">test_demo_site.py</a>, which covers several actions:</p>
373
+ <p align="left">📗 Here's <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/test_demo_site.py" target="_blank">SeleniumBase/examples/test_demo_site.py</a>, which covers several actions:</p>
359
374
 
360
375
  ```zsh
361
376
  pytest test_demo_site.py
@@ -501,19 +516,18 @@ finally:
501
516
  <a id="install_seleniumbase"></a>
502
517
  <h2><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Install SeleniumBase:</h2>
503
518
 
504
- **You can install ``seleniumbase`` from [PyPI](https://pypi.org/project/seleniumbase/) or [GitHub](https://github.com/seleniumbase/SeleniumBase):**
519
+ **You can install `seleniumbase` from [PyPI](https://pypi.org/project/seleniumbase/) or [GitHub](https://github.com/seleniumbase/SeleniumBase):**
505
520
 
506
- 🔵 **How to install ``seleniumbase`` from PyPI:**
521
+ 🔵 **How to install `seleniumbase` from PyPI:**
507
522
 
508
523
  ```zsh
509
524
  pip install seleniumbase
510
525
  ```
511
526
 
512
- * (Add ``--upgrade`` OR ``-U`` to upgrade SeleniumBase.)
513
- * (Add ``--force-reinstall`` to upgrade indirect packages.)
514
- * (Use ``pip3`` if multiple versions of Python are present.)
527
+ * (Add `--upgrade` OR `-U` to upgrade SeleniumBase.)
528
+ * (Add `--force-reinstall` to upgrade indirect packages.)
515
529
 
516
- 🔵 **How to install ``seleniumbase`` from a GitHub clone:**
530
+ 🔵 **How to install `seleniumbase` from a GitHub clone:**
517
531
 
518
532
  ```zsh
519
533
  git clone https://github.com/seleniumbase/SeleniumBase.git
@@ -528,7 +542,7 @@ git pull
528
542
  pip install -e .
529
543
  ```
530
544
 
531
- 🔵 **Type ``seleniumbase`` or ``sbase`` to verify that SeleniumBase was installed successfully:**
545
+ 🔵 **Type `seleniumbase` or `sbase` to verify that SeleniumBase was installed successfully:**
532
546
 
533
547
  ```zsh
534
548
  ___ _ _ ___
@@ -578,17 +592,17 @@ pip install -e .
578
592
 
579
593
  <h3>🔵 Downloading webdrivers:</h3>
580
594
 
581
- ✅ SeleniumBase automatically downloads webdrivers as needed, such as ``chromedriver``.
595
+ ✅ SeleniumBase automatically downloads webdrivers as needed, such as `chromedriver`.
582
596
 
583
597
  <div></div>
584
598
  <details>
585
599
  <summary> ▶️ Here's sample output from a chromedriver download. (<b>click to expand</b>)</summary>
586
600
 
587
601
  ```zsh
588
- *** chromedriver to download = 131.0.6778.108 (Latest Stable)
602
+ *** chromedriver to download = 141.0.7390.78 (Latest Stable)
589
603
 
590
604
  Downloading chromedriver-mac-arm64.zip from:
591
- https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.108/mac-arm64/chromedriver-mac-arm64.zip ...
605
+ https://storage.googleapis.com/chrome-for-testing-public/141.0.7390.78/mac-arm64/chromedriver-mac-arm64.zip ...
592
606
  Download Complete!
593
607
 
594
608
  Extracting ['chromedriver'] from chromedriver-mac-arm64.zip ...
@@ -598,8 +612,8 @@ The file [chromedriver] was saved to:
598
612
  ~/github/SeleniumBase/seleniumbase/drivers/
599
613
  chromedriver
600
614
 
601
- Making [chromedriver 131.0.6778.108] executable ...
602
- [chromedriver 131.0.6778.108] is now ready for use!
615
+ Making [chromedriver 141.0.7390.78] executable ...
616
+ [chromedriver 141.0.7390.78] is now ready for use!
603
617
  ```
604
618
 
605
619
  </details>
@@ -711,7 +725,7 @@ self.assert_no_js_errors() # Verify there are no JS errors.
711
725
  self.type("input", "dogs\n") # (The "\n" presses ENTER)
712
726
  ```
713
727
 
714
- Most SeleniumBase scripts can be run with <code translate="no">pytest</code>, <code translate="no">pynose</code>, or pure <code translate="no">python</code>. Not all test runners can run all test formats. For example, tests that use the ``sb`` pytest fixture can only be run with ``pytest``. (See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/syntax_formats.md">Syntax Formats</a>) There's also a <a href="https://behave.readthedocs.io/en/stable/gherkin.html#features" target="_blank">Gherkin</a> test format that runs with <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/behave_bdd/ReadMe.md">behave</a>.
728
+ Most SeleniumBase scripts can be run with <code translate="no">pytest</code>, <code translate="no">pynose</code>, or pure <code translate="no">python</code>. Not all test runners can run all test formats. For example, tests that use the `sb` pytest fixture can only be run with `pytest`. (See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/syntax_formats.md">Syntax Formats</a>) There's also a <a href="https://behave.readthedocs.io/en/stable/gherkin.html#features" target="_blank">Gherkin</a> test format that runs with <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/behave_bdd/ReadMe.md">behave</a>.
715
729
 
716
730
  ```zsh
717
731
  pytest coffee_cart_tests.py --rs
@@ -730,10 +744,10 @@ behave calculator.feature -D rs -D dashboard
730
744
 
731
745
  <p>✅ <code translate="no">pytest</code> includes automatic test discovery. If you don't specify a specific file or folder to run, <code translate="no">pytest</code> will automatically search through all subdirectories for tests to run based on the following criteria:</p>
732
746
 
733
- * Python files that start with ``test_`` or end with ``_test.py``.
734
- * Python methods that start with ``test_``.
747
+ * Python files that start with `test_` or end with `_test.py`.
748
+ * Python methods that start with `test_`.
735
749
 
736
- With a SeleniumBase [pytest.ini](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/pytest.ini) file present, you can modify default discovery settings. The Python class name can be anything because ``seleniumbase.BaseCase`` inherits ``unittest.TestCase`` to trigger autodiscovery.
750
+ With a SeleniumBase [pytest.ini](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/pytest.ini) file present, you can modify default discovery settings. The Python class name can be anything because `seleniumbase.BaseCase` inherits `unittest.TestCase` to trigger autodiscovery.
737
751
 
738
752
  <p>✅ You can do a pre-flight check to see which tests would get discovered by <code translate="no">pytest</code> before the actual run:</p>
739
753
 
@@ -775,7 +789,7 @@ pynose [FILE_NAME.py]:[CLASS_NAME].[METHOD_NAME]
775
789
  pytest my_first_test.py --demo
776
790
  ```
777
791
 
778
- 🔵 ``time.sleep(seconds)`` can be used to make a test wait at a specific spot:
792
+ 🔵 `time.sleep(seconds)` can be used to make a test wait at a specific spot:
779
793
 
780
794
  ```python
781
795
  import time; time.sleep(3) # Do nothing for 3 seconds.
@@ -789,15 +803,15 @@ import pytest; pytest.set_trace()
789
803
  breakpoint() # Shortcut for "import pdb; pdb.set_trace()"
790
804
  ```
791
805
 
792
- > (**``pdb``** commands: ``n``, ``c``, ``s``, ``u``, ``d`` => ``next``, ``continue``, ``step``, ``up``, ``down``)
806
+ > (**`pdb`** commands: `n`, `c`, `s`, `u`, `d` => `next`, `continue`, `step`, `up`, `down`)
793
807
 
794
- 🔵 To pause an active test that throws an exception or error, (*and keep the browser window open while **Debug Mode** begins in the console*), add **``--pdb``** as a ``pytest`` option:
808
+ 🔵 To pause an active test that throws an exception or error, (*and keep the browser window open while **Debug Mode** begins in the console*), add **`--pdb`** as a `pytest` option:
795
809
 
796
810
  ```zsh
797
811
  pytest test_fail.py --pdb
798
812
  ```
799
813
 
800
- 🔵 To start tests in Debug Mode, add **``--trace``** as a ``pytest`` option:
814
+ 🔵 To start tests in Debug Mode, add **`--trace`** as a `pytest` option:
801
815
 
802
816
  ```zsh
803
817
  pytest test_coffee_cart.py --trace
@@ -836,6 +850,10 @@ pytest test_coffee_cart.py --trace
836
850
  --edge # (Shortcut for "--browser=edge".)
837
851
  --firefox # (Shortcut for "--browser=firefox".)
838
852
  --safari # (Shortcut for "--browser=safari".)
853
+ --opera # (Shortcut for "--browser=opera".)
854
+ --brave # (Shortcut for "--browser=brave".)
855
+ --comet # (Shortcut for "--browser=comet".)
856
+ --atlas # (Shortcut for "--browser=atlas".)
839
857
  --settings-file=FILE # (Override default SeleniumBase settings.)
840
858
  --env=ENV # (Set the test env. Access with "self.env" in tests.)
841
859
  --account=STR # (Set account. Access with "self.account" in tests.)
@@ -938,7 +956,7 @@ pytest test_coffee_cart.py --trace
938
956
 
939
957
  --------
940
958
 
941
- 🔵 During test failures, logs and screenshots from the most recent test run will get saved to the ``latest_logs/`` folder. Those logs will get moved to ``archived_logs/`` if you add --archive_logs to command-line options, or have ``ARCHIVE_EXISTING_LOGS`` set to True in [settings.py](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/config/settings.py), otherwise log files with be cleaned up at the start of the next test run. The ``test_suite.py`` collection contains tests that fail on purpose so that you can see how logging works.
959
+ 🔵 During test failures, logs and screenshots from the most recent test run will get saved to the `latest_logs/` folder. Those logs will get moved to `archived_logs/` if you add --archive_logs to command-line options, or have `ARCHIVE_EXISTING_LOGS` set to True in [settings.py](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/config/settings.py), otherwise log files with be cleaned up at the start of the next test run. The `test_suite.py` collection contains tests that fail on purpose so that you can see how logging works.
942
960
 
943
961
  ```zsh
944
962
  cd examples/
@@ -950,18 +968,18 @@ pytest test_suite.py --firefox
950
968
 
951
969
  An easy way to override seleniumbase/config/settings.py is by using a custom settings file.
952
970
  Here's the command-line option to add to tests: (See [examples/custom_settings.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/custom_settings.py))
953
- ``--settings_file=custom_settings.py``
971
+ `--settings_file=custom_settings.py`
954
972
  (Settings include default timeout values, a two-factor auth key, DB credentials, S3 credentials, and other important settings used by tests.)
955
973
 
956
- 🔵 To pass additional data from the command-line to tests, add ``--data="ANY STRING"``.
957
- Inside your tests, you can use ``self.data`` to access that.
974
+ 🔵 To pass additional data from the command-line to tests, add `--data="ANY STRING"`.
975
+ Inside your tests, you can use `self.data` to access that.
958
976
 
959
977
  <a id="directory_configuration"></a>
960
978
  <h2><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Directory Configuration:</h2>
961
979
 
962
- 🔵 When running tests with **``pytest``**, you'll want a copy of **[pytest.ini](https://github.com/seleniumbase/SeleniumBase/blob/master/pytest.ini)** in your root folders. When running tests with **``pynose``**, you'll want a copy of **[setup.cfg](https://github.com/seleniumbase/SeleniumBase/blob/master/setup.cfg)** in your root folders. These files specify default configuration details for tests. Test folders should also include a blank **[__init__.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/offline_examples/__init__.py)** file to allow your test files to import other files from that folder.
980
+ 🔵 When running tests with **`pytest`**, you'll want a copy of **[pytest.ini](https://github.com/seleniumbase/SeleniumBase/blob/master/pytest.ini)** in your root folders. When running tests with **`pynose`**, you'll want a copy of **[setup.cfg](https://github.com/seleniumbase/SeleniumBase/blob/master/setup.cfg)** in your root folders. These files specify default configuration details for tests. Test folders should also include a blank **[__init__.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/offline_examples/__init__.py)** file to allow your test files to import other files from that folder.
963
981
 
964
- 🔵 ``sbase mkdir DIR`` creates a folder with config files and sample tests:
982
+ 🔵 `sbase mkdir DIR` creates a folder with config files and sample tests:
965
983
 
966
984
  ```zsh
967
985
  sbase mkdir ui_tests
@@ -993,7 +1011,7 @@ ui_tests/
993
1011
  └── swag_labs_test.py
994
1012
  ```
995
1013
 
996
- <b>ProTip™:</b> You can also create a boilerplate folder without any sample tests in it by adding ``-b`` or ``--basic`` to the ``sbase mkdir`` command:
1014
+ <b>ProTip™:</b> You can also create a boilerplate folder without any sample tests in it by adding `-b` or `--basic` to the `sbase mkdir` command:
997
1015
 
998
1016
  ```zsh
999
1017
  sbase mkdir ui_tests --basic
@@ -1009,7 +1027,16 @@ ui_tests/
1009
1027
  └── setup.cfg
1010
1028
  ```
1011
1029
 
1012
- Of those files, the ``pytest.ini`` config file is the most important, followed by a blank ``__init__.py`` file. There's also a ``setup.cfg`` file (for pynose). Finally, the ``requirements.txt`` file can be used to help you install seleniumbase into your environments (if it's not already installed).
1030
+ Of those files, the `pytest.ini` config file is the most important, followed by a blank `__init__.py` file. There's also a `setup.cfg` file (for pynose). Finally, the `requirements.txt` file can be used to help you install seleniumbase into your environments (if it's not already installed).
1031
+
1032
+ <b>ProTip™:</b> Add `--gha` to include a GitHub Actions `.yml` file with default settings:
1033
+
1034
+ ```zsh
1035
+ ui_tests/
1036
+ └── .github
1037
+ └── workflows/
1038
+ └── python-package.yml
1039
+ ```
1013
1040
 
1014
1041
  --------
1015
1042
 
@@ -1029,20 +1056,20 @@ class MyTestClass(BaseCase):
1029
1056
  self.assert_element("div#ARMY_OF_ROBOTS", timeout=1) # This should fail
1030
1057
  ```
1031
1058
 
1032
- You can run it from the ``examples/`` folder like this:
1059
+ You can run it from the `examples/` folder like this:
1033
1060
 
1034
1061
  ```zsh
1035
1062
  pytest test_fail.py
1036
1063
  ```
1037
1064
 
1038
- 🔵 You'll notice that a logs folder, ``./latest_logs/``, was created to hold information (and screenshots) about the failing test. During test runs, past results get moved to the archived_logs folder if you have ARCHIVE_EXISTING_LOGS set to True in [settings.py](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/config/settings.py), or if your run tests with ``--archive-logs``. If you choose not to archive existing logs, they will be deleted and replaced by the logs of the latest test run.
1065
+ 🔵 You'll notice that a logs folder, `./latest_logs/`, was created to hold information (and screenshots) about the failing test. During test runs, past results get moved to the archived_logs folder if you have ARCHIVE_EXISTING_LOGS set to True in [settings.py](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/config/settings.py), or if your run tests with `--archive-logs`. If you choose not to archive existing logs, they will be deleted and replaced by the logs of the latest test run.
1039
1066
 
1040
1067
  --------
1041
1068
 
1042
1069
  <a id="seleniumbase_dashboard"></a>
1043
1070
  <h2><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> SeleniumBase Dashboard:</h2>
1044
1071
 
1045
- 🔵 The ``--dashboard`` option for pytest generates a SeleniumBase Dashboard located at ``dashboard.html``, which updates automatically as tests run and produce results. Example:
1072
+ 🔵 The `--dashboard` option for pytest generates a SeleniumBase Dashboard located at `dashboard.html`, which updates automatically as tests run and produce results. Example:
1046
1073
 
1047
1074
  ```zsh
1048
1075
  pytest --dashboard --rs --headless
@@ -1050,13 +1077,13 @@ pytest --dashboard --rs --headless
1050
1077
 
1051
1078
  <img src="https://seleniumbase.github.io/cdn/img/dashboard_1.png" alt="The SeleniumBase Dashboard" title="The SeleniumBase Dashboard" width="380" />
1052
1079
 
1053
- 🔵 Additionally, you can host your own SeleniumBase Dashboard Server on a port of your choice. Here's an example of that using Python's ``http.server``:
1080
+ 🔵 Additionally, you can host your own SeleniumBase Dashboard Server on a port of your choice. Here's an example of that using Python's `http.server`:
1054
1081
 
1055
1082
  ```zsh
1056
1083
  python -m http.server 1948
1057
1084
  ```
1058
1085
 
1059
- 🔵 Now you can navigate to ``http://localhost:1948/dashboard.html`` in order to view the dashboard as a web app. This requires two different terminal windows: one for running the server, and another for running the tests, which should be run from the same directory. (Use <kbd>Ctrl+C</kbd> to stop the http server.)
1086
+ 🔵 Now you can navigate to `http://localhost:1948/dashboard.html` in order to view the dashboard as a web app. This requires two different terminal windows: one for running the server, and another for running the tests, which should be run from the same directory. (Use <kbd>Ctrl+C</kbd> to stop the http server.)
1060
1087
 
1061
1088
  🔵 Here's a full example of what the SeleniumBase Dashboard may look like:
1062
1089
 
@@ -1073,7 +1100,7 @@ pytest test_suite.py test_image_saving.py --dashboard --rs --headless
1073
1100
 
1074
1101
  <h3>🔵 <code>pytest</code> HTML Reports:</h3>
1075
1102
 
1076
- ✅ Using ``--html=report.html`` gives you a fancy report of the name specified after your test suite completes.
1103
+ ✅ Using `--html=report.html` gives you a fancy report of the name specified after your test suite completes.
1077
1104
 
1078
1105
  ```zsh
1079
1106
  pytest test_suite.py --html=report.html
@@ -1081,7 +1108,7 @@ pytest test_suite.py --html=report.html
1081
1108
 
1082
1109
  <img src="https://seleniumbase.github.io/cdn/img/html_report.png" alt="Example Pytest Report" title="Example Pytest Report" width="520" />
1083
1110
 
1084
- ✅ When combining pytest html reports with SeleniumBase Dashboard usage, the pie chart from the Dashboard will get added to the html report. Additionally, if you set the html report URL to be the same as the Dashboard URL when also using the dashboard, (example: ``--dashboard --html=dashboard.html``), then the Dashboard will become an advanced html report when all the tests complete.
1111
+ ✅ When combining pytest html reports with SeleniumBase Dashboard usage, the pie chart from the Dashboard will get added to the html report. Additionally, if you set the html report URL to be the same as the Dashboard URL when also using the dashboard, (example: `--dashboard --html=dashboard.html`), then the Dashboard will become an advanced html report when all the tests complete.
1085
1112
 
1086
1113
  ✅ Here's an example of an upgraded html report:
1087
1114
 
@@ -1093,7 +1120,7 @@ pytest test_suite.py --dashboard --html=report.html
1093
1120
 
1094
1121
  If viewing pytest html reports in [Jenkins](https://www.jenkins.io/), you may need to [configure Jenkins settings](https://stackoverflow.com/a/46197356/7058266) for the html to render correctly. This is due to [Jenkins CSP changes](https://www.jenkins.io/doc/book/system-administration/security/configuring-content-security-policy/).
1095
1122
 
1096
- You can also use ``--junit-xml=report.xml`` to get an xml report instead. Jenkins can use this file to display better reporting for your tests.
1123
+ You can also use `--junit-xml=report.xml` to get an xml report instead. Jenkins can use this file to display better reporting for your tests.
1097
1124
 
1098
1125
  ```zsh
1099
1126
  pytest test_suite.py --junit-xml=report.xml
@@ -1101,7 +1128,7 @@ pytest test_suite.py --junit-xml=report.xml
1101
1128
 
1102
1129
  <h3>🔵 <code>pynose</code> Reports:</h3>
1103
1130
 
1104
- The ``--report`` option gives you a fancy report after your test suite completes.
1131
+ The `--report` option gives you a fancy report after your test suite completes.
1105
1132
 
1106
1133
  ```zsh
1107
1134
  pynose test_suite.py --report
@@ -1109,7 +1136,7 @@ pynose test_suite.py --report
1109
1136
 
1110
1137
  <img src="https://seleniumbase.github.io/cdn/img/nose_report.png" alt="Example pynose Report" title="Example pynose Report" width="320" />
1111
1138
 
1112
- (NOTE: You can add ``--show-report`` to immediately display pynose reports after the test suite completes. Only use ``--show-report`` when running tests locally because it pauses the test run.)
1139
+ (NOTE: You can add `--show-report` to immediately display pynose reports after the test suite completes. Only use `--show-report` when running tests locally because it pauses the test run.)
1113
1140
 
1114
1141
  <h3>🔵 <code>behave</code> Dashboard & Reports:</h3>
1115
1142
 
@@ -1121,7 +1148,7 @@ behave behave_bdd/features/ -D dashboard -D headless
1121
1148
 
1122
1149
  <img src="https://seleniumbase.github.io/cdn/img/sb_behave_dashboard.png" title="SeleniumBase" width="520">
1123
1150
 
1124
- You can also use ``--junit`` to get ``.xml`` reports for each <code translate="no">behave</code> feature. Jenkins can use these files to display better reporting for your tests.
1151
+ You can also use `--junit` to get `.xml` reports for each <code translate="no">behave</code> feature. Jenkins can use these files to display better reporting for your tests.
1125
1152
 
1126
1153
  ```zsh
1127
1154
  behave behave_bdd/features/ --junit -D rs -D headless
@@ -1131,7 +1158,7 @@ behave behave_bdd/features/ --junit -D rs -D headless
1131
1158
 
1132
1159
  See: [https://allurereport.org/docs/pytest/](https://allurereport.org/docs/pytest/)
1133
1160
 
1134
- SeleniumBase no longer includes ``allure-pytest`` as part of installed dependencies. If you want to use it, install it first:
1161
+ SeleniumBase no longer includes `allure-pytest` as part of installed dependencies. If you want to use it, install it first:
1135
1162
 
1136
1163
  ```zsh
1137
1164
  pip install allure-pytest
@@ -1147,7 +1174,7 @@ pytest test_suite.py --alluredir=allure_results
1147
1174
 
1148
1175
  <h3><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Using a Proxy Server:</h3>
1149
1176
 
1150
- If you wish to use a proxy server for your browser tests (Chromium or Firefox), you can add ``--proxy=IP_ADDRESS:PORT`` as an argument on the command line.
1177
+ If you wish to use a proxy server for your browser tests (Chromium or Firefox), you can add `--proxy=IP_ADDRESS:PORT` as an argument on the command line.
1151
1178
 
1152
1179
  ```zsh
1153
1180
  pytest proxy_test.py --proxy=IP_ADDRESS:PORT
@@ -1167,7 +1194,7 @@ pytest proxy_test.py --proxy="socks4://IP_ADDRESS:PORT"
1167
1194
  pytest proxy_test.py --proxy="socks5://IP_ADDRESS:PORT"
1168
1195
  ```
1169
1196
 
1170
- To make things easier, you can add your frequently-used proxies to PROXY_LIST in [proxy_list.py](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/config/proxy_list.py), and then use ``--proxy=KEY_FROM_PROXY_LIST`` to use the IP_ADDRESS:PORT of that key.
1197
+ To make things easier, you can add your frequently-used proxies to PROXY_LIST in [proxy_list.py](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/config/proxy_list.py), and then use `--proxy=KEY_FROM_PROXY_LIST` to use the IP_ADDRESS:PORT of that key.
1171
1198
 
1172
1199
  ```zsh
1173
1200
  pytest proxy_test.py --proxy=proxy1
@@ -1176,7 +1203,7 @@ pytest proxy_test.py --proxy=proxy1
1176
1203
 
1177
1204
  <h3><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Changing the User-Agent:</h3>
1178
1205
 
1179
- 🔵 If you wish to change the User-Agent for your browser tests (Chromium and Firefox only), you can add ``--agent="USER AGENT STRING"`` as an argument on the command-line.
1206
+ 🔵 If you wish to change the User-Agent for your browser tests (Chromium and Firefox only), you can add `--agent="USER AGENT STRING"` as an argument on the command-line.
1180
1207
 
1181
1208
  ```zsh
1182
1209
  pytest user_agent_test.py --agent="Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1.7412.EU"
@@ -1190,7 +1217,7 @@ pytest user_agent_test.py --agent="Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1
1190
1217
 
1191
1218
  <h3><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Building Guided Tours for Websites:</h3>
1192
1219
 
1193
- 🔵 Learn about <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/tour_examples/ReadMe.md">SeleniumBase Interactive Walkthroughs</a> (in the ``examples/tour_examples/`` folder). It's great for prototyping a website onboarding experience.
1220
+ 🔵 Learn about <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/tour_examples/ReadMe.md">SeleniumBase Interactive Walkthroughs</a> (in the `examples/tour_examples/` folder). It's great for prototyping a website onboarding experience.
1194
1221
 
1195
1222
 
1196
1223
  <a id="utilizing_advanced_features"></a>
@@ -1259,7 +1286,7 @@ To click an element on the page:
1259
1286
  self.click("div#my_id")
1260
1287
  ```
1261
1288
 
1262
- **ProTip™:** In most web browsers, you can right-click on a page and select ``Inspect Element`` to see the CSS selector details that you'll need to create your own scripts.
1289
+ **ProTip™:** In most web browsers, you can right-click on a page and select `Inspect Element` to see the CSS selector details that you'll need to create your own scripts.
1263
1290
 
1264
1291
  🔵 **Typing Text:**
1265
1292
 
@@ -1289,7 +1316,7 @@ attribute = self.get_attribute("#comic img", "title")
1289
1316
  self.wait_for_element_present("div.my_class", timeout=10)
1290
1317
  ```
1291
1318
 
1292
- (NOTE: You can also use: ``self.assert_element_present(ELEMENT)``)
1319
+ (NOTE: You can also use: `self.assert_element_present(ELEMENT)`)
1293
1320
 
1294
1321
  🔵 **Asserting visibility of an element on a page within some number of seconds:**
1295
1322
 
@@ -1297,9 +1324,9 @@ self.wait_for_element_present("div.my_class", timeout=10)
1297
1324
  self.wait_for_element_visible("a.my_class", timeout=5)
1298
1325
  ```
1299
1326
 
1300
- (NOTE: The short versions of that are ``self.find_element(ELEMENT)`` and ``self.assert_element(ELEMENT)``. The ``find_element()`` version returns the element.)
1327
+ (NOTE: The short versions of that are `self.find_element(ELEMENT)` and `self.assert_element(ELEMENT)`. The `find_element()` version returns the element.)
1301
1328
 
1302
- Since the line above returns the element, you can combine that with ``.click()`` as shown below:
1329
+ Since the line above returns the element, you can combine that with `.click()` as shown below:
1303
1330
 
1304
1331
  ```python
1305
1332
  self.find_element("a.my_class", timeout=5).click()
@@ -1309,9 +1336,9 @@ self.find_element("a.my_class", timeout=5).click()
1309
1336
  self.click("a.my_class") # DO IT THIS WAY!
1310
1337
  ```
1311
1338
 
1312
- **ProTip™:** You can use dots to signify class names (Ex: ``div.class_name``) as a simplified version of ``div[class="class_name"]`` within a CSS selector.
1339
+ **ProTip™:** You can use dots to signify class names (Ex: `div.class_name`) as a simplified version of `div[class="class_name"]` within a CSS selector.
1313
1340
 
1314
- You can also use ``*=`` to search for any partial value in a CSS selector as shown below:
1341
+ You can also use `*=` to search for any partial value in a CSS selector as shown below:
1315
1342
 
1316
1343
  ```python
1317
1344
  self.click('a[name*="partial_name"]')
@@ -1324,7 +1351,7 @@ self.assert_text("Make it so!", "div#trek div.picard div.quotes")
1324
1351
  self.assert_text("Tea. Earl Grey. Hot.", "div#trek div.picard div.quotes", timeout=3)
1325
1352
  ```
1326
1353
 
1327
- (NOTE: ``self.find_text(TEXT, ELEMENT)`` and ``self.wait_for_text(TEXT, ELEMENT)`` also do this. For backwards compatibility, older method names were kept, but the default timeout may be different.)
1354
+ (NOTE: `self.find_text(TEXT, ELEMENT)` and `self.wait_for_text(TEXT, ELEMENT)` also do this. For backwards compatibility, older method names were kept, but the default timeout may be different.)
1328
1355
 
1329
1356
  🔵 **Asserting Anything:**
1330
1357
 
@@ -1338,14 +1365,14 @@ self.assert_equal(var1, var2)
1338
1365
 
1339
1366
  🔵 **Useful Conditional Statements: (with creative examples)**
1340
1367
 
1341
- ``is_element_visible(selector):`` (visible on the page)
1368
+ `is_element_visible(selector):` (visible on the page)
1342
1369
 
1343
1370
  ```python
1344
1371
  if self.is_element_visible('div#warning'):
1345
1372
  print("Red Alert: Something bad might be happening!")
1346
1373
  ```
1347
1374
 
1348
- ``is_element_present(selector):`` (present in the HTML)
1375
+ `is_element_present(selector):` (present in the HTML)
1349
1376
 
1350
1377
  ```python
1351
1378
  if self.is_element_present('div#top_secret img.tracking_cookie'):
@@ -1362,7 +1389,7 @@ def is_there_a_cloaked_klingon_ship_on_this_page():
1362
1389
  return False
1363
1390
  ```
1364
1391
 
1365
- ``is_text_visible(text, selector):`` (text visible on element)
1392
+ `is_text_visible(text, selector):` (text visible on element)
1366
1393
 
1367
1394
  ```python
1368
1395
  if self.is_text_visible("You Shall Not Pass!", "h1"):
@@ -1402,7 +1429,7 @@ def get_mirror_universe_captain_picard_superbowl_ad(superbowl_year):
1402
1429
 
1403
1430
  </details>
1404
1431
 
1405
- ``is_link_text_visible(link_text):``
1432
+ `is_link_text_visible(link_text):`
1406
1433
 
1407
1434
  ```python
1408
1435
  if self.is_link_text_visible("Stop! Hammer time!"):
@@ -1427,7 +1454,7 @@ self.switch_to_frame("iframe")
1427
1454
  self.switch_to_parent_frame() # Exit the current iframe
1428
1455
  ```
1429
1456
 
1430
- To exit from multiple iframes, use ``self.switch_to_default_content()``. (If inside a single iframe, this has the same effect as ``self.switch_to_parent_frame()``.)
1457
+ To exit from multiple iframes, use `self.switch_to_default_content()`. (If inside a single iframe, this has the same effect as `self.switch_to_parent_frame()`.)
1431
1458
 
1432
1459
  ```python
1433
1460
  self.switch_to_frame('iframe[name="frame1"]')
@@ -1500,7 +1527,7 @@ self.execute_script("return jQuery('textarea')[2].value") # Returns the css "va
1500
1527
 
1501
1528
  <h3>🔵 How to handle a restrictive CSP:</h3>
1502
1529
 
1503
- ❗ Some websites have a restrictive [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) to prevent users from loading jQuery and other external libraries onto their websites. If you need to use jQuery or another JS library on those websites, add ``--disable-csp`` as a ``pytest`` command-line option to load a Chromium extension that bypasses the CSP.
1530
+ ❗ Some websites have a restrictive [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) to prevent users from loading jQuery and other external libraries onto their websites. If you need to use jQuery or another JS library on those websites, add `--disable-csp` as a `pytest` command-line option to load a Chromium extension that bypasses the CSP.
1504
1531
 
1505
1532
  <h3>🔵 More JavaScript fun:</h3>
1506
1533