pytest-seleniumbase 4.13.11__py3-none-any.whl → 4.44.8__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.
Potentially problematic release.
This version of pytest-seleniumbase might be problematic. Click here for more details.
- {pytest_seleniumbase-4.13.11.dist-info → pytest_seleniumbase-4.44.8.dist-info}/METADATA +513 -308
- pytest_seleniumbase-4.44.8.dist-info/RECORD +4 -0
- {pytest_seleniumbase-4.13.11.dist-info → pytest_seleniumbase-4.44.8.dist-info}/WHEEL +1 -1
- pytest_seleniumbase-4.13.11.dist-info/RECORD +0 -4
- {pytest_seleniumbase-4.13.11.dist-info → pytest_seleniumbase-4.44.8.dist-info}/top_level.txt +0 -0
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: pytest-seleniumbase
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.44.8
|
|
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
|
|
7
7
|
Author-email: mdmintz@gmail.com
|
|
8
8
|
Maintainer: Michael Mintz
|
|
9
9
|
License: MIT
|
|
10
|
+
Project-URL: Homepage, https://github.com/seleniumbase/SeleniumBase
|
|
10
11
|
Project-URL: Changelog, https://github.com/seleniumbase/SeleniumBase/releases
|
|
11
12
|
Project-URL: Download, https://pypi.org/project/seleniumbase/#files
|
|
12
|
-
Project-URL: Gitter, https://gitter.im/seleniumbase/SeleniumBase
|
|
13
|
-
Project-URL: Slack, https://app.slack.com/client/T0ABCRTNX/C01SM888REZ
|
|
14
13
|
Project-URL: Blog, https://seleniumbase.com/
|
|
14
|
+
Project-URL: Discord, https://discord.gg/EdhQTn3EyE
|
|
15
15
|
Project-URL: PyPI, https://pypi.org/project/seleniumbase/
|
|
16
16
|
Project-URL: Source, https://github.com/seleniumbase/SeleniumBase
|
|
17
|
+
Project-URL: Repository, https://github.com/seleniumbase/SeleniumBase
|
|
17
18
|
Project-URL: Documentation, https://seleniumbase.io/
|
|
18
19
|
Platform: Windows
|
|
19
20
|
Platform: Linux
|
|
@@ -26,234 +27,334 @@ Classifier: Environment :: Web Environment
|
|
|
26
27
|
Classifier: Framework :: Pytest
|
|
27
28
|
Classifier: Intended Audience :: Developers
|
|
28
29
|
Classifier: Intended Audience :: Information Technology
|
|
29
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
30
30
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
31
31
|
Classifier: Operating System :: Microsoft :: Windows
|
|
32
32
|
Classifier: Operating System :: POSIX :: Linux
|
|
33
33
|
Classifier: Programming Language :: Python
|
|
34
34
|
Classifier: Programming Language :: Python :: 3
|
|
35
|
-
Classifier: Programming Language :: Python :: 2.7
|
|
36
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
37
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
38
35
|
Classifier: Programming Language :: Python :: 3.8
|
|
39
36
|
Classifier: Programming Language :: Python :: 3.9
|
|
40
37
|
Classifier: Programming Language :: Python :: 3.10
|
|
41
38
|
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
42
42
|
Classifier: Topic :: Internet
|
|
43
43
|
Classifier: Topic :: Scientific/Engineering
|
|
44
44
|
Classifier: Topic :: Software Development
|
|
45
45
|
Classifier: Topic :: Software Development :: Quality Assurance
|
|
46
46
|
Classifier: Topic :: Software Development :: Libraries
|
|
47
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
48
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
47
49
|
Classifier: Topic :: Software Development :: Testing
|
|
48
50
|
Classifier: Topic :: Software Development :: Testing :: Acceptance
|
|
49
51
|
Classifier: Topic :: Software Development :: Testing :: Traffic Generation
|
|
50
52
|
Classifier: Topic :: Utilities
|
|
51
|
-
Requires-Python: >=3.
|
|
53
|
+
Requires-Python: >=3.8
|
|
52
54
|
Description-Content-Type: text/markdown
|
|
53
|
-
Requires-Dist: seleniumbase
|
|
55
|
+
Requires-Dist: seleniumbase>=4.44.8
|
|
56
|
+
Dynamic: author
|
|
57
|
+
Dynamic: author-email
|
|
58
|
+
Dynamic: classifier
|
|
59
|
+
Dynamic: home-page
|
|
60
|
+
Dynamic: license
|
|
61
|
+
Dynamic: maintainer
|
|
62
|
+
Dynamic: platform
|
|
63
|
+
Dynamic: requires-dist
|
|
64
|
+
Dynamic: requires-python
|
|
65
|
+
Dynamic: summary
|
|
54
66
|
|
|
55
67
|
**[<img src="https://img.shields.io/badge/pypi-pytest--seleniumbase-22AAEE.svg" alt="pypi" />](https://pypi.python.org/pypi/pytest-seleniumbase) is a proxy for [<img src="https://img.shields.io/badge/pypi-seleniumbase-22AAEE.svg" alt="pypi" />](https://pypi.python.org/pypi/seleniumbase)**
|
|
56
68
|
****
|
|
57
69
|
|
|
58
70
|
<!-- SeleniumBase Docs -->
|
|
59
71
|
|
|
72
|
+
<meta property="og:site_name" content="SeleniumBase">
|
|
73
|
+
<meta property="og:title" content="SeleniumBase: Python Web Automation and E2E Testing" />
|
|
74
|
+
<meta property="og:description" content="Fast, easy, and reliable Web/UI testing with Python." />
|
|
75
|
+
<meta property="og:keywords" content="Python, pytest, selenium, webdriver, testing, automation, seleniumbase, framework, dashboard, recorder, reports, screenshots">
|
|
76
|
+
<meta property="og:image" content="https://seleniumbase.github.io/cdn/img/mac_sb_logo_5b.png" />
|
|
77
|
+
<link rel="icon" href="https://seleniumbase.github.io/img/logo7.png" />
|
|
60
78
|
|
|
61
79
|
<h1>SeleniumBase</h1>
|
|
62
80
|
|
|
63
|
-
<
|
|
81
|
+
<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>
|
|
64
82
|
|
|
65
|
-
<h3 align="center">Create reliable end-to-end browser tests with Python</h3>
|
|
66
83
|
|
|
67
|
-
<p align="center"
|
|
84
|
+
<p align="center" class="hero__title"><b>All-in-one Browser Automation Framework:<br />Web Crawling / Testing / Scraping / Stealth</b></p>
|
|
85
|
+
|
|
86
|
+
<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/badge/join-discord-infomational" alt="Join the SeleniumBase chat on Discord"/></a></p>
|
|
68
87
|
|
|
69
88
|
<p align="center">
|
|
70
89
|
<a href="#python_installation">🚀 Start</a> |
|
|
71
90
|
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/features_list.md">🏰 Features</a> |
|
|
72
|
-
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/ReadMe.md">📚 Examples</a> |
|
|
73
91
|
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/customizing_test_runs.md">🎛️ Options</a> |
|
|
92
|
+
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/ReadMe.md">📚 Examples</a> |
|
|
74
93
|
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/console_scripts/ReadMe.md">🌠 Scripts</a> |
|
|
75
|
-
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/mobile_testing.md">📱
|
|
94
|
+
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/mobile_testing.md">📱 Mobile</a>
|
|
76
95
|
<br />
|
|
77
96
|
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/method_summary.md">📘 APIs</a> |
|
|
78
|
-
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/syntax_formats.md">
|
|
79
|
-
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/example_logs/ReadMe.md">📊 Dashboard</a> |
|
|
97
|
+
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/syntax_formats.md"> 🔠 Formats</a> |
|
|
80
98
|
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/recorder_mode.md">🔴 Recorder</a> |
|
|
99
|
+
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/example_logs/ReadMe.md">📊 Dashboard</a> |
|
|
81
100
|
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/locale_codes.md">🗾 Locales</a> |
|
|
82
|
-
<a href="https://
|
|
101
|
+
<a href="https://seleniumbase.io/devices/?url=seleniumbase.com">💻 Farm</a>
|
|
83
102
|
<br />
|
|
84
103
|
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/commander.md">🎖️ GUI</a> |
|
|
85
104
|
<a href="https://seleniumbase.io/demo_page">📰 TestPage</a> |
|
|
86
|
-
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/
|
|
87
|
-
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/
|
|
88
|
-
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/
|
|
89
|
-
<a href="https://
|
|
105
|
+
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/uc_mode.md">👤 UC Mode</a> |
|
|
106
|
+
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/ReadMe.md">🐙 CDP Mode</a> |
|
|
107
|
+
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/chart_maker/ReadMe.md">📶 Charts</a> |
|
|
108
|
+
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/utilities/selenium_grid/ReadMe.md">🌐 Grid</a>
|
|
90
109
|
<br />
|
|
91
110
|
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/how_it_works.md">👁️ How</a> |
|
|
92
111
|
<a href="https://github.com/seleniumbase/SeleniumBase/tree/master/examples/migration/raw_selenium">🚝 Migrate</a> |
|
|
93
|
-
<a href="https://github.com/seleniumbase/SeleniumBase/
|
|
94
|
-
<a href="https://github.com/seleniumbase/SeleniumBase/tree/master/
|
|
95
|
-
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/
|
|
112
|
+
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/case_plans.md">🗂️ CasePlans</a> |
|
|
113
|
+
<a href="https://github.com/seleniumbase/SeleniumBase/tree/master/examples/boilerplates">♻️ Template</a> |
|
|
114
|
+
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/master_qa/ReadMe.md">🧬 Hybrid</a> |
|
|
96
115
|
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/tour_examples/ReadMe.md">🚎 Tours</a>
|
|
97
116
|
<br />
|
|
98
117
|
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/integrations/github/workflows/ReadMe.md">🤖 CI/CD</a> |
|
|
99
118
|
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/js_package_manager.md">🕹️ JSMgr</a> |
|
|
100
119
|
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/translations.md">🌏 Translator</a> |
|
|
101
120
|
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/presenter/ReadMe.md">🎞️ Presenter</a> |
|
|
102
|
-
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/dialog_boxes/ReadMe.md">🛂
|
|
121
|
+
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/dialog_boxes/ReadMe.md">🛂 Dialog</a> |
|
|
103
122
|
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/visual_testing/ReadMe.md">🖼️ Visual</a>
|
|
104
123
|
<br />
|
|
105
124
|
</p>
|
|
106
125
|
|
|
126
|
+
<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>
|
|
127
|
+
|
|
107
128
|
--------
|
|
108
129
|
|
|
109
|
-
|
|
110
|
-
<p align="left"><b>Example:</b> <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/test_coffee_cart.py" target="_blank">test_coffee_cart.py</a> from <a href="https://github.com/seleniumbase/SeleniumBase/tree/master/examples" target="_blank">./examples/</a></p>
|
|
130
|
+
📚 Learn from [**over 200 examples** in the **SeleniumBase/examples/** folder](https://github.com/seleniumbase/SeleniumBase/tree/master/examples).
|
|
111
131
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
pytest
|
|
132
|
+
🐙 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.
|
|
133
|
+
|
|
134
|
+
ℹ️ 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).
|
|
135
|
+
|
|
136
|
+
--------
|
|
137
|
+
|
|
138
|
+
<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>
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from seleniumbase import SB
|
|
142
|
+
|
|
143
|
+
with SB(test=True, uc=True) as sb:
|
|
144
|
+
sb.open("https://google.com/ncr")
|
|
145
|
+
sb.type('[title="Search"]', "SeleniumBase GitHub page\n")
|
|
146
|
+
sb.click('[href*="github.com/seleniumbase/"]')
|
|
147
|
+
sb.save_screenshot_to_logs() # ./latest_logs/
|
|
148
|
+
print(sb.get_page_title())
|
|
115
149
|
```
|
|
116
150
|
|
|
117
|
-
|
|
151
|
+
> `python raw_google.py`
|
|
118
152
|
|
|
119
|
-
<
|
|
153
|
+
<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="420" /></a>
|
|
154
|
+
|
|
155
|
+
--------
|
|
156
|
+
|
|
157
|
+
<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>
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from seleniumbase import SB
|
|
161
|
+
|
|
162
|
+
with SB(uc=True, test=True, locale="en") as sb:
|
|
163
|
+
url = "https://gitlab.com/users/sign_in"
|
|
164
|
+
sb.activate_cdp_mode(url)
|
|
165
|
+
sb.uc_gui_click_captcha()
|
|
166
|
+
sb.sleep(2)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
<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">
|
|
120
170
|
|
|
121
|
-
|
|
171
|
+
--------
|
|
172
|
+
|
|
173
|
+
<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>
|
|
122
174
|
|
|
123
175
|
```python
|
|
124
176
|
from seleniumbase import BaseCase
|
|
125
|
-
BaseCase.main(__name__, __file__)
|
|
177
|
+
BaseCase.main(__name__, __file__) # Call pytest
|
|
178
|
+
|
|
179
|
+
class MyTestClass(BaseCase):
|
|
180
|
+
def test_swag_labs(self):
|
|
181
|
+
self.open("https://www.saucedemo.com")
|
|
182
|
+
self.type("#user-name", "standard_user")
|
|
183
|
+
self.type("#password", "secret_sauce\n")
|
|
184
|
+
self.assert_element("div.inventory_list")
|
|
185
|
+
self.click('button[name*="backpack"]')
|
|
186
|
+
self.click("#shopping_cart_container a")
|
|
187
|
+
self.assert_text("Backpack", "div.cart_item")
|
|
188
|
+
self.click("button#checkout")
|
|
189
|
+
self.type("input#first-name", "SeleniumBase")
|
|
190
|
+
self.type("input#last-name", "Automation")
|
|
191
|
+
self.type("input#postal-code", "77123")
|
|
192
|
+
self.click("input#continue")
|
|
193
|
+
self.click("button#finish")
|
|
194
|
+
self.assert_text("Thank you for your order!")
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
> `pytest test_get_swag.py`
|
|
198
|
+
|
|
199
|
+
<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>
|
|
200
|
+
|
|
201
|
+
> (The default browser is ``--chrome`` if not set.)
|
|
202
|
+
|
|
203
|
+
--------
|
|
204
|
+
|
|
205
|
+
<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>
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
pytest test_coffee_cart.py --demo
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
<p align="left"><a href="https://seleniumbase.io/coffee/" target="_blank"><img src="https://seleniumbase.github.io/cdn/gif/coffee_cart.gif" width="480" alt="SeleniumBase Coffee Cart Test" title="SeleniumBase Coffee Cart Test" /></a></p>
|
|
212
|
+
|
|
213
|
+
> <p>(<code translate="no">--demo</code> mode slows down tests and highlights actions)</p>
|
|
214
|
+
|
|
215
|
+
--------
|
|
216
|
+
|
|
217
|
+
<a id="multiple_examples"></a>
|
|
126
218
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
self.click('div[data-sb="Cappuccino"]')
|
|
132
|
-
self.click('div[data-sb="Flat-White"]')
|
|
133
|
-
self.click('div[data-sb="Cafe-Latte"]')
|
|
134
|
-
self.click('a[aria-label="Cart page"]')
|
|
135
|
-
self.assert_exact_text("Total: $53.00", "button.pay")
|
|
136
|
-
self.click("button.pay")
|
|
137
|
-
self.type("input#name", "Selenium Coffee")
|
|
138
|
-
self.type("input#email", "test@test.test")
|
|
139
|
-
self.click("button#submit-payment")
|
|
140
|
-
self.assert_text("Thanks for your purchase.", "#app .success")
|
|
219
|
+
<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>
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
pytest test_demo_site.py
|
|
141
223
|
```
|
|
142
224
|
|
|
225
|
+
<p align="left"><a href="https://seleniumbase.io/demo_page" target="_blank"><img src="https://seleniumbase.github.io/cdn/gif/demo_page_5.gif" width="480" alt="SeleniumBase Example" title="SeleniumBase Example" /></a></p>
|
|
226
|
+
|
|
227
|
+
> Easy to type, click, select, toggle, drag & drop, and more.
|
|
228
|
+
|
|
229
|
+
(For more examples, see the <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/ReadMe.md">SeleniumBase/examples/</a> folder.)
|
|
230
|
+
|
|
231
|
+
--------
|
|
232
|
+
|
|
233
|
+
<p align="left"><a href="https://github.com/seleniumbase/SeleniumBase/"><img src="https://seleniumbase.github.io/cdn/img/super_logo_sb3.png" alt="SeleniumBase" title="SeleniumBase" width="232" /></a></p>
|
|
234
|
+
|
|
235
|
+
<blockquote>
|
|
236
|
+
<p dir="auto"><strong>Explore the README:</strong></p>
|
|
237
|
+
<ul dir="auto">
|
|
238
|
+
<li><a href="#install_seleniumbase" ><strong>Get Started / Installation</strong></a></li>
|
|
239
|
+
<li><a href="#basic_example_and_usage"><strong>Basic Example / Usage</strong></a></li>
|
|
240
|
+
<li><a href="#common_methods" ><strong>Common Test Methods</strong></a></li>
|
|
241
|
+
<li><a href="#fun_facts" ><strong>Fun Facts / Learn More</strong></a></li>
|
|
242
|
+
<li><a href="#demo_mode_and_debugging"><strong>Demo Mode / Debugging</strong></a></li>
|
|
243
|
+
<li><a href="#command_line_options" ><strong>Command-line Options</strong></a></li>
|
|
244
|
+
<li><a href="#directory_configuration"><strong>Directory Configuration</strong></a></li>
|
|
245
|
+
<li><a href="#seleniumbase_dashboard" ><strong>SeleniumBase Dashboard</strong></a></li>
|
|
246
|
+
<li><a href="#creating_visual_reports"><strong>Generating Test Reports</strong></a></li>
|
|
247
|
+
</ul>
|
|
248
|
+
</blockquote>
|
|
249
|
+
|
|
143
250
|
--------
|
|
144
251
|
|
|
145
252
|
<details>
|
|
146
253
|
<summary> ▶️ How is <b>SeleniumBase</b> different from raw Selenium? (<b>click to expand</b>)</summary>
|
|
147
254
|
<div>
|
|
148
255
|
|
|
149
|
-
<p>💡 SeleniumBase is a Python framework for browser automation and testing. SeleniumBase uses <a href="https://www.w3.org/TR/webdriver2/#endpoints" target="_blank">Selenium/WebDriver</a> APIs
|
|
256
|
+
<p>💡 SeleniumBase is a Python framework for browser automation and testing. SeleniumBase uses <a href="https://www.w3.org/TR/webdriver2/#endpoints" target="_blank">Selenium/WebDriver</a> APIs and incorporates test-runners such as <code translate="no">pytest</code>, <code translate="no">pynose</code>, and <code translate="no">behave</code> to provide organized structure, test discovery, test execution, test state (<i>eg. passed, failed, or skipped</i>), and command-line options for changing default settings (<i>eg. browser selection</i>). With raw Selenium, you would need to set up your own options-parser for configuring tests from the command-line.</p>
|
|
257
|
+
|
|
258
|
+
<p>💡 SeleniumBase's driver manager gives you more control over automatic driver downloads. (Use <code translate="no">--driver-version=VER</code> with your <code translate="no">pytest</code> run command to specify the version.) By default, SeleniumBase will download a driver version that matches your major browser version if not set.</p>
|
|
150
259
|
|
|
151
|
-
<p>💡
|
|
260
|
+
<p>💡 SeleniumBase automatically detects between CSS Selectors and XPath, which means you don't need to specify the type of selector in your commands (<i>but optionally you could</i>).</p>
|
|
152
261
|
|
|
153
|
-
<p>💡 SeleniumBase methods often perform multiple actions in a single method call. For example, <code>self.type(selector,text)</code> does the following:<br />1. Waits for the element to be visible.<br />2. Waits for the element to be interactive.<br />3. Clears the text field.<br />4. Types in the new text.<br />5. Presses Enter/Submit if the text ends in "\n"
|
|
262
|
+
<p>💡 SeleniumBase methods often perform multiple actions in a single method call. For example, <code translate="no">self.type(selector, text)</code> does the following:<br />1. Waits for the element to be visible.<br />2. Waits for the element to be interactive.<br />3. Clears the text field.<br />4. Types in the new text.<br />5. Presses Enter/Submit if the text ends in <code translate="no">"\n"</code>.<br />With raw Selenium, those actions require multiple method calls.</p>
|
|
154
263
|
|
|
155
264
|
<p>💡 SeleniumBase uses default timeout values when not set:<br />
|
|
156
|
-
|
|
265
|
+
✅ <code translate="no">self.click("button")</code><br />
|
|
157
266
|
With raw Selenium, methods would fail instantly (<i>by default</i>) if an element needed more time to load:<br />
|
|
158
|
-
|
|
267
|
+
❌ <code translate="no">self.driver.find_element(by="css selector", value="button").click()</code><br />
|
|
159
268
|
(Reliable code is better than unreliable code.)</p>
|
|
160
269
|
|
|
161
270
|
<p>💡 SeleniumBase lets you change the explicit timeout values of methods:<br />
|
|
162
|
-
|
|
271
|
+
✅ <code translate="no">self.click("button", timeout=10)</code><br />
|
|
163
272
|
With raw Selenium, that requires more code:<br />
|
|
164
|
-
|
|
273
|
+
❌ <code translate="no">WebDriverWait(driver, 10).until(EC.element_to_be_clickable("css selector", "button")).click()</code><br />
|
|
165
274
|
(Simple code is better than complex code.)</p>
|
|
166
275
|
|
|
167
276
|
<p>💡 SeleniumBase gives you clean error output when a test fails. With raw Selenium, error messages can get very messy.</p>
|
|
168
277
|
|
|
169
|
-
<p>💡 SeleniumBase gives you the option to generate a dashboard and reports for tests. It also saves screenshots from failing tests to the <code>./latest_logs/</code> folder. Raw <a href="https://www.selenium.dev/documentation/webdriver/" target="_blank">Selenium</a> does not have these options out-of-the-box.</p>
|
|
278
|
+
<p>💡 SeleniumBase gives you the option to generate a dashboard and reports for tests. It also saves screenshots from failing tests to the <code translate="no">./latest_logs/</code> folder. Raw <a href="https://www.selenium.dev/documentation/webdriver/" translate="no" target="_blank">Selenium</a> does not have these options out-of-the-box.</p>
|
|
279
|
+
|
|
280
|
+
<p>💡 SeleniumBase includes desktop GUI apps for running tests, such as <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/commander.md" translate="no">SeleniumBase Commander</a> for <code translate="no">pytest</code> and <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/behave_bdd/ReadMe.md" translate="no">SeleniumBase Behave GUI</a> for <code translate="no">behave</code>.</p>
|
|
170
281
|
|
|
171
|
-
<p>💡 SeleniumBase
|
|
282
|
+
<p>💡 SeleniumBase has its own <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/recorder_mode.md">Recorder / Test Generator</a> for creating tests from manual browser actions.</p>
|
|
172
283
|
|
|
173
|
-
<p>💡 SeleniumBase
|
|
284
|
+
<p>💡 SeleniumBase comes with <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/case_plans.md">test case management software, ("CasePlans")</a>, for organizing tests and step descriptions.</p>
|
|
285
|
+
|
|
286
|
+
<p>💡 SeleniumBase includes tools for <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/chart_maker/ReadMe.md">building data apps, ("ChartMaker")</a>, which can generate JavaScript from Python.</p>
|
|
174
287
|
|
|
175
288
|
</div>
|
|
176
289
|
</details>
|
|
177
290
|
|
|
178
291
|
--------
|
|
179
292
|
|
|
180
|
-
<
|
|
181
|
-
<summary> ▶️ Learn about different ways of writing tests (<b>click to expand</b>)</summary>
|
|
182
|
-
<div>
|
|
293
|
+
<p>📚 <b>Learn about different ways of writing tests:</b></p>
|
|
183
294
|
|
|
184
|
-
<p align="left"
|
|
295
|
+
<p align="left">📗📝 Here's <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/test_simple_login.py">test_simple_login.py</a>, which uses <code translate="no"><a href="https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/fixtures/base_case.py">BaseCase</a></code> class inheritance, and runs with <a href="https://docs.pytest.org/en/latest/how-to/usage.html">pytest</a> or <a href="https://github.com/mdmintz/pynose">pynose</a>. (Use <code translate="no">self.driver</code> to access Selenium's raw <code translate="no">driver</code>.)</p>
|
|
185
296
|
|
|
186
297
|
```python
|
|
187
298
|
from seleniumbase import BaseCase
|
|
299
|
+
BaseCase.main(__name__, __file__)
|
|
188
300
|
|
|
189
|
-
class
|
|
190
|
-
def
|
|
191
|
-
self.open("
|
|
301
|
+
class TestSimpleLogin(BaseCase):
|
|
302
|
+
def test_simple_login(self):
|
|
303
|
+
self.open("seleniumbase.io/simple/login")
|
|
192
304
|
self.type("#username", "demo_user")
|
|
193
305
|
self.type("#password", "secret_pass")
|
|
194
|
-
self.
|
|
306
|
+
self.click('a:contains("Sign in")')
|
|
195
307
|
self.assert_exact_text("Welcome!", "h1")
|
|
196
308
|
self.assert_element("img#image1")
|
|
197
|
-
self.
|
|
198
|
-
self.
|
|
309
|
+
self.highlight("#image1")
|
|
310
|
+
self.click_link("Sign out")
|
|
311
|
+
self.assert_text("signed out", "#top_message")
|
|
199
312
|
```
|
|
200
313
|
|
|
201
|
-
<p align="left"
|
|
314
|
+
<p align="left">📘📝 Here's <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/raw_login_sb.py">raw_login_sb.py</a>, which uses the <b><code translate="no">SB</code></b> Context Manager. Runs with pure <code translate="no">python</code>. (Use <code translate="no">sb.driver</code> to access Selenium's raw <code translate="no">driver</code>.)</p>
|
|
202
315
|
|
|
203
316
|
```python
|
|
204
|
-
|
|
205
|
-
|
|
317
|
+
from seleniumbase import SB
|
|
318
|
+
|
|
319
|
+
with SB() as sb:
|
|
320
|
+
sb.open("seleniumbase.io/simple/login")
|
|
206
321
|
sb.type("#username", "demo_user")
|
|
207
322
|
sb.type("#password", "secret_pass")
|
|
208
|
-
sb.
|
|
323
|
+
sb.click('a:contains("Sign in")')
|
|
209
324
|
sb.assert_exact_text("Welcome!", "h1")
|
|
210
325
|
sb.assert_element("img#image1")
|
|
211
|
-
sb.
|
|
212
|
-
sb.
|
|
326
|
+
sb.highlight("#image1")
|
|
327
|
+
sb.click_link("Sign out")
|
|
328
|
+
sb.assert_text("signed out", "#top_message")
|
|
213
329
|
```
|
|
214
330
|
|
|
215
|
-
<p align="left">📙📝
|
|
331
|
+
<p align="left">📙📝 Here's <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/raw_login_driver.py">raw_login_driver.py</a>, which uses the <b><code translate="no">Driver</code></b> Manager. Runs with pure <code translate="no">python</code>. (The <code>driver</code> is an improved version of Selenium's raw <code translate="no">driver</code>, with more methods.)</p>
|
|
216
332
|
|
|
217
333
|
```python
|
|
218
|
-
from seleniumbase import
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
334
|
+
from seleniumbase import Driver
|
|
335
|
+
|
|
336
|
+
driver = Driver()
|
|
337
|
+
try:
|
|
338
|
+
driver.open("seleniumbase.io/simple/login")
|
|
339
|
+
driver.type("#username", "demo_user")
|
|
340
|
+
driver.type("#password", "secret_pass")
|
|
341
|
+
driver.click('a:contains("Sign in")')
|
|
342
|
+
driver.assert_exact_text("Welcome!", "h1")
|
|
343
|
+
driver.assert_element("img#image1")
|
|
344
|
+
driver.highlight("#image1")
|
|
345
|
+
driver.click_link("Sign out")
|
|
346
|
+
driver.assert_text("signed out", "#top_message")
|
|
347
|
+
finally:
|
|
348
|
+
driver.quit()
|
|
231
349
|
```
|
|
232
350
|
|
|
233
|
-
<p align="left">📕📝 An example test with <b>behave-BDD</b> <a href="https://behave.readthedocs.io/en/stable/gherkin.html" target="_blank">Gherkin</a> structure. Runs with <b><code>behave</code></b>. (<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/behave_bdd/ReadMe.md">Learn more</a>)</p>
|
|
234
|
-
|
|
235
|
-
```gherkin
|
|
236
|
-
Feature: SeleniumBase scenarios for the RealWorld App
|
|
237
|
-
|
|
238
|
-
Scenario: Verify RealWorld App
|
|
239
|
-
Given Open "seleniumbase.io/realworld/login"
|
|
240
|
-
When Type "demo_user" into "#username"
|
|
241
|
-
And Type "secret_pass" into "#password"
|
|
242
|
-
And Do MFA "GAXG2MTEOR3DMMDG" into "#totpcode"
|
|
243
|
-
Then Assert exact text "Welcome!" in "h1"
|
|
244
|
-
And Assert element "img#image1"
|
|
245
|
-
And Click 'a:contains("This Page")'
|
|
246
|
-
And Save screenshot to logs
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
</div>
|
|
250
|
-
</details>
|
|
251
|
-
|
|
252
351
|
--------
|
|
253
352
|
|
|
254
353
|
<a id="python_installation"></a>
|
|
255
354
|
<h2><img src="https://seleniumbase.github.io/cdn/img/python_logo.png" title="SeleniumBase" width="42" /> Set up Python & Git:</h2>
|
|
256
355
|
|
|
356
|
+
<a href="https://www.python.org/downloads/"><img src="https://img.shields.io/pypi/pyversions/seleniumbase.svg?color=FACE42" title="Supported Python Versions" /></a>
|
|
357
|
+
|
|
257
358
|
🔵 Add <b><a href="https://www.python.org/downloads/">Python</a></b> and <b><a href="https://git-scm.com/">Git</a></b> to your System PATH.
|
|
258
359
|
|
|
259
360
|
🔵 Using a <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/virtualenv_instructions.md">Python virtual env</a> is recommended.
|
|
@@ -261,9 +362,19 @@ Feature: SeleniumBase scenarios for the RealWorld App
|
|
|
261
362
|
<a id="install_seleniumbase"></a>
|
|
262
363
|
<h2><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Install SeleniumBase:</h2>
|
|
263
364
|
|
|
264
|
-
**You can install ``seleniumbase`` from [
|
|
365
|
+
**You can install ``seleniumbase`` from [PyPI](https://pypi.org/project/seleniumbase/) or [GitHub](https://github.com/seleniumbase/SeleniumBase):**
|
|
265
366
|
|
|
266
|
-
🔵 **
|
|
367
|
+
🔵 **How to install ``seleniumbase`` from PyPI:**
|
|
368
|
+
|
|
369
|
+
```bash
|
|
370
|
+
pip install seleniumbase
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
* (Add ``--upgrade`` OR ``-U`` to upgrade SeleniumBase.)
|
|
374
|
+
* (Add ``--force-reinstall`` to upgrade indirect packages.)
|
|
375
|
+
* (Use ``pip3`` if multiple versions of Python are present.)
|
|
376
|
+
|
|
377
|
+
🔵 **How to install ``seleniumbase`` from a GitHub clone:**
|
|
267
378
|
|
|
268
379
|
```bash
|
|
269
380
|
git clone https://github.com/seleniumbase/SeleniumBase.git
|
|
@@ -271,86 +382,92 @@ cd SeleniumBase/
|
|
|
271
382
|
pip install -e .
|
|
272
383
|
```
|
|
273
384
|
|
|
274
|
-
**
|
|
385
|
+
🔵 **How to upgrade an existing install from a GitHub clone:**
|
|
275
386
|
|
|
276
387
|
```bash
|
|
277
388
|
git pull
|
|
278
389
|
pip install -e .
|
|
279
390
|
```
|
|
280
391
|
|
|
281
|
-
🔵 **
|
|
392
|
+
🔵 **Type ``seleniumbase`` or ``sbase`` to verify that SeleniumBase was installed successfully:**
|
|
282
393
|
|
|
283
394
|
```bash
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
395
|
+
___ _ _ ___
|
|
396
|
+
/ __| ___| |___ _ _ (_)_ _ _ __ | _ ) __ _ ______
|
|
397
|
+
\__ \/ -_) / -_) ' \| | \| | ' \ | _ \/ _` (_-< -_)
|
|
398
|
+
|___/\___|_\___|_||_|_|\_,_|_|_|_\|___/\__,_/__|___|
|
|
399
|
+
----------------------------------------------------
|
|
400
|
+
|
|
401
|
+
╭──────────────────────────────────────────────────╮
|
|
402
|
+
│ * USAGE: "seleniumbase [COMMAND] [PARAMETERS]" │
|
|
403
|
+
│ * OR: "sbase [COMMAND] [PARAMETERS]" │
|
|
404
|
+
│ │
|
|
405
|
+
│ COMMANDS: PARAMETERS / DESCRIPTIONS: │
|
|
406
|
+
│ get / install [DRIVER_NAME] [OPTIONS] │
|
|
407
|
+
│ methods (List common Python methods) │
|
|
408
|
+
│ options (List common pytest options) │
|
|
409
|
+
│ behave-options (List common behave options) │
|
|
410
|
+
│ gui / commander [OPTIONAL PATH or TEST FILE] │
|
|
411
|
+
│ behave-gui (SBase Commander for Behave) │
|
|
412
|
+
│ caseplans [OPTIONAL PATH or TEST FILE] │
|
|
413
|
+
│ mkdir [DIRECTORY] [OPTIONS] │
|
|
414
|
+
│ mkfile [FILE.py] [OPTIONS] │
|
|
415
|
+
│ mkrec / codegen [FILE.py] [OPTIONS] │
|
|
416
|
+
│ recorder (Open Recorder Desktop App.) │
|
|
417
|
+
│ record (If args: mkrec. Else: App.) │
|
|
418
|
+
│ mkpres [FILE.py] [LANG] │
|
|
419
|
+
│ mkchart [FILE.py] [LANG] │
|
|
420
|
+
│ print [FILE] [OPTIONS] │
|
|
421
|
+
│ translate [SB_FILE.py] [LANG] [ACTION] │
|
|
422
|
+
│ convert [WEBDRIVER_UNITTEST_FILE.py] │
|
|
423
|
+
│ extract-objects [SB_FILE.py] │
|
|
424
|
+
│ inject-objects [SB_FILE.py] [OPTIONS] │
|
|
425
|
+
│ objectify [SB_FILE.py] [OPTIONS] │
|
|
426
|
+
│ revert-objects [SB_FILE.py] [OPTIONS] │
|
|
427
|
+
│ encrypt / obfuscate │
|
|
428
|
+
│ decrypt / unobfuscate │
|
|
429
|
+
│ proxy (Start a basic proxy server) │
|
|
430
|
+
│ download server (Get Selenium Grid JAR file) │
|
|
431
|
+
│ grid-hub [start|stop] [OPTIONS] │
|
|
432
|
+
│ grid-node [start|stop] --hub=[HOST/IP] │
|
|
433
|
+
│ │
|
|
434
|
+
│ * EXAMPLE => "sbase get chromedriver stable" │
|
|
435
|
+
│ * For command info => "sbase help [COMMAND]" │
|
|
436
|
+
│ * For info on all commands => "sbase --help" │
|
|
437
|
+
╰──────────────────────────────────────────────────╯
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
<h3>🔵 Downloading webdrivers:</h3>
|
|
441
|
+
|
|
442
|
+
✅ SeleniumBase automatically downloads webdrivers as needed, such as ``chromedriver``.
|
|
290
443
|
|
|
291
|
-
|
|
444
|
+
<div></div>
|
|
445
|
+
<details>
|
|
446
|
+
<summary> ▶️ Here's sample output from a chromedriver download. (<b>click to expand</b>)</summary>
|
|
292
447
|
|
|
293
448
|
```bash
|
|
294
|
-
|
|
295
|
-
```
|
|
449
|
+
*** chromedriver to download = 131.0.6778.108 (Latest Stable)
|
|
296
450
|
|
|
297
|
-
|
|
451
|
+
Downloading chromedriver-mac-arm64.zip from:
|
|
452
|
+
https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.108/mac-arm64/chromedriver-mac-arm64.zip ...
|
|
453
|
+
Download Complete!
|
|
298
454
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
get / install [DRIVER] [OPTIONS]
|
|
312
|
-
methods (List common Python methods)
|
|
313
|
-
options (List common pytest options)
|
|
314
|
-
behave-options (List common behave options)
|
|
315
|
-
gui / commander [OPTIONAL PATH or TEST FILE]
|
|
316
|
-
behave-gui (SBase Commander for Behave)
|
|
317
|
-
caseplans [OPTIONAL PATH or TEST FILE]
|
|
318
|
-
mkdir [DIRECTORY] [OPTIONS]
|
|
319
|
-
mkfile [FILE.py] [OPTIONS]
|
|
320
|
-
mkrec / codegen [FILE.py] [OPTIONS]
|
|
321
|
-
recorder (Open Recorder Desktop App.)
|
|
322
|
-
record (If args: mkrec. Else: App.)
|
|
323
|
-
mkpres [FILE.py] [LANG]
|
|
324
|
-
mkchart [FILE.py] [LANG]
|
|
325
|
-
print [FILE] [OPTIONS]
|
|
326
|
-
translate [SB_FILE.py] [LANG] [ACTION]
|
|
327
|
-
convert [WEBDRIVER_UNITTEST_FILE.py]
|
|
328
|
-
extract-objects [SB_FILE.py]
|
|
329
|
-
inject-objects [SB_FILE.py] [OPTIONS]
|
|
330
|
-
objectify [SB_FILE.py] [OPTIONS]
|
|
331
|
-
revert-objects [SB_FILE.py] [OPTIONS]
|
|
332
|
-
encrypt / obfuscate
|
|
333
|
-
decrypt / unobfuscate
|
|
334
|
-
download server (Get Selenium Grid JAR file)
|
|
335
|
-
grid-hub [start|stop] [OPTIONS]
|
|
336
|
-
grid-node [start|stop] --hub=[HOST/IP]
|
|
337
|
-
* (EXAMPLE: "sbase get chromedriver latest") *
|
|
338
|
-
|
|
339
|
-
Type "sbase help [COMMAND]" for specific command info.
|
|
340
|
-
For info on all commands, type: "seleniumbase --help".
|
|
341
|
-
Use "pytest" for running tests.
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
<h3><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Downloading web drivers:</h3>
|
|
346
|
-
|
|
347
|
-
✅ SeleniumBase automatically downloads web drivers as needed, such as ``chromedriver``, ``edgedriver``, and ``geckodriver``.
|
|
348
|
-
|
|
349
|
-
✅ To manually download a webdriver, see [Console Scripts](https://seleniumbase.io/seleniumbase/console_scripts/ReadMe/) OR [Webdriver Installation](https://seleniumbase.io/help_docs/webdriver_installation/).
|
|
455
|
+
Extracting ['chromedriver'] from chromedriver-mac-arm64.zip ...
|
|
456
|
+
Unzip Complete!
|
|
457
|
+
|
|
458
|
+
The file [chromedriver] was saved to:
|
|
459
|
+
~/github/SeleniumBase/seleniumbase/drivers/
|
|
460
|
+
chromedriver
|
|
461
|
+
|
|
462
|
+
Making [chromedriver 131.0.6778.108] executable ...
|
|
463
|
+
[chromedriver 131.0.6778.108] is now ready for use!
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
</details>
|
|
350
467
|
|
|
351
468
|
|
|
352
469
|
<a id="basic_example_and_usage"></a>
|
|
353
|
-
<
|
|
470
|
+
<h2><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Basic Example / Usage:</h2>
|
|
354
471
|
|
|
355
472
|
🔵 If you've cloned SeleniumBase, you can run tests from the [examples/](https://github.com/seleniumbase/SeleniumBase/tree/master/examples) folder.
|
|
356
473
|
|
|
@@ -361,14 +478,13 @@ cd examples/
|
|
|
361
478
|
pytest my_first_test.py
|
|
362
479
|
```
|
|
363
480
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/my_first_test.py"><img src="https://seleniumbase.github.io/cdn/gif/swag_labs_4.gif" alt="SeleniumBase Test" title="SeleniumBase Test" width="480" /></a>
|
|
481
|
+
<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/my_first_test.py"><img src="https://seleniumbase.github.io/cdn/gif/fast_swag_2.gif" alt="SeleniumBase Test" title="SeleniumBase Test" width="480" /></a>
|
|
367
482
|
|
|
368
|
-
<p align="left"><b>Here's the code for <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/my_first_test.py">my_first_test.py</a>:</b></p>
|
|
483
|
+
<p align="left"><b>Here's the full code for <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/my_first_test.py">my_first_test.py</a>:</b></p>
|
|
369
484
|
|
|
370
485
|
```python
|
|
371
486
|
from seleniumbase import BaseCase
|
|
487
|
+
BaseCase.main(__name__, __file__)
|
|
372
488
|
|
|
373
489
|
class MyTestClass(BaseCase):
|
|
374
490
|
def test_swag_labs(self):
|
|
@@ -376,20 +492,21 @@ class MyTestClass(BaseCase):
|
|
|
376
492
|
self.type("#user-name", "standard_user")
|
|
377
493
|
self.type("#password", "secret_sauce\n")
|
|
378
494
|
self.assert_element("div.inventory_list")
|
|
379
|
-
self.
|
|
495
|
+
self.assert_exact_text("Products", "span.title")
|
|
380
496
|
self.click('button[name*="backpack"]')
|
|
381
497
|
self.click("#shopping_cart_container a")
|
|
382
|
-
self.
|
|
498
|
+
self.assert_exact_text("Your Cart", "span.title")
|
|
383
499
|
self.assert_text("Backpack", "div.cart_item")
|
|
384
500
|
self.click("button#checkout")
|
|
385
501
|
self.type("#first-name", "SeleniumBase")
|
|
386
502
|
self.type("#last-name", "Automation")
|
|
387
503
|
self.type("#postal-code", "77123")
|
|
388
504
|
self.click("input#continue")
|
|
389
|
-
self.assert_text("
|
|
505
|
+
self.assert_text("Checkout: Overview")
|
|
390
506
|
self.assert_text("Backpack", "div.cart_item")
|
|
507
|
+
self.assert_text("29.99", "div.inventory_item_price")
|
|
391
508
|
self.click("button#finish")
|
|
392
|
-
self.assert_exact_text("
|
|
509
|
+
self.assert_exact_text("Thank you for your order!", "h2")
|
|
393
510
|
self.assert_element('img[alt="Pony Express"]')
|
|
394
511
|
self.js_click("a#logout_sidebar_link")
|
|
395
512
|
self.assert_element("div#login_button_container")
|
|
@@ -401,7 +518,7 @@ class MyTestClass(BaseCase):
|
|
|
401
518
|
|
|
402
519
|
|
|
403
520
|
<a id="common_methods"></a>
|
|
404
|
-
<h3><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Here are some common SeleniumBase methods
|
|
521
|
+
<h3><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Here are some common SeleniumBase methods:</h3>
|
|
405
522
|
|
|
406
523
|
```python
|
|
407
524
|
self.open(url) # Navigate the browser window to the URL.
|
|
@@ -432,6 +549,7 @@ self.sleep(seconds) # Do nothing for the given amount of time.
|
|
|
432
549
|
self.save_screenshot(name) # Save a screenshot in .png format.
|
|
433
550
|
self.assert_element(selector) # Verify the element is visible.
|
|
434
551
|
self.assert_text(text, selector) # Verify text in the element.
|
|
552
|
+
self.assert_exact_text(text, selector) # Verify text is exact.
|
|
435
553
|
self.assert_title(title) # Verify the title of the web page.
|
|
436
554
|
self.assert_downloaded_file(file) # Verify file was downloaded.
|
|
437
555
|
self.assert_no_404_errors() # Verify there are no broken links.
|
|
@@ -446,93 +564,122 @@ self.assert_no_js_errors() # Verify there are no JS errors.
|
|
|
446
564
|
|
|
447
565
|
<p>✅ SeleniumBase automatically handles common <a href="https://www.selenium.dev/documentation/webdriver/" target="_blank">WebDriver</a> actions such as launching web browsers before tests, saving screenshots during failures, and closing web browsers after tests.</p>
|
|
448
566
|
|
|
449
|
-
<p>✅ SeleniumBase lets you <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/customizing_test_runs.md">
|
|
567
|
+
<p>✅ SeleniumBase lets you customize tests via <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/customizing_test_runs.md">command-line options</a>.</p>
|
|
450
568
|
|
|
451
569
|
<p>✅ SeleniumBase uses simple syntax for commands. Example:</p>
|
|
452
570
|
|
|
453
571
|
```python
|
|
454
|
-
self.type("input", "dogs\n")
|
|
572
|
+
self.type("input", "dogs\n") # (The "\n" presses ENTER)
|
|
455
573
|
```
|
|
456
574
|
|
|
457
|
-
SeleniumBase
|
|
575
|
+
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>.
|
|
458
576
|
|
|
459
577
|
```bash
|
|
460
|
-
pytest
|
|
578
|
+
pytest coffee_cart_tests.py --rs
|
|
579
|
+
pytest test_sb_fixture.py --demo
|
|
580
|
+
pytest test_suite.py --rs --html=report.html --dashboard
|
|
581
|
+
|
|
582
|
+
pynose basic_test.py --mobile
|
|
583
|
+
pynose test_suite.py --headless --report --show-report
|
|
584
|
+
|
|
585
|
+
python raw_sb.py
|
|
586
|
+
python raw_test_scripts.py
|
|
461
587
|
|
|
462
|
-
|
|
588
|
+
behave realworld.feature
|
|
589
|
+
behave calculator.feature -D rs -D dashboard
|
|
463
590
|
```
|
|
464
591
|
|
|
465
|
-
<p>✅ <code>pytest</code> includes automatic test discovery. If you don't specify a specific file or folder to run, <code>pytest</code> will automatically search through all subdirectories for tests to run based on the following criteria:</p>
|
|
592
|
+
<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>
|
|
466
593
|
|
|
467
594
|
* Python files that start with ``test_`` or end with ``_test.py``.
|
|
468
595
|
* Python methods that start with ``test_``.
|
|
469
596
|
|
|
470
|
-
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
|
|
597
|
+
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.
|
|
471
598
|
|
|
472
|
-
<p>✅ You can do a pre-flight check to see which tests would get discovered by <code>pytest</code> before the
|
|
599
|
+
<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>
|
|
473
600
|
|
|
474
601
|
```bash
|
|
475
|
-
pytest --
|
|
602
|
+
pytest --co -q
|
|
476
603
|
```
|
|
477
604
|
|
|
478
|
-
<p>✅ You can be more specific when calling <code>pytest</code> on a file:</p>
|
|
605
|
+
<p>✅ You can be more specific when calling <code translate="no">pytest</code> or <code translate="no">pynose</code> on a file:</p>
|
|
479
606
|
|
|
480
607
|
```bash
|
|
481
608
|
pytest [FILE_NAME.py]::[CLASS_NAME]::[METHOD_NAME]
|
|
482
609
|
|
|
483
|
-
|
|
610
|
+
pynose [FILE_NAME.py]:[CLASS_NAME].[METHOD_NAME]
|
|
484
611
|
```
|
|
485
612
|
|
|
486
|
-
<p>✅ No More Flaky Tests! SeleniumBase methods automatically wait for page elements to finish loading before interacting with them (<i>up to a timeout limit</i>). This means <b>you no longer need random <span><code>time.sleep()</code></span> statements</b> in your scripts.</p>
|
|
613
|
+
<p>✅ No More Flaky Tests! SeleniumBase methods automatically wait for page elements to finish loading before interacting with them (<i>up to a timeout limit</i>). This means <b>you no longer need random <span><code translate="no">time.sleep()</code></span> statements</b> in your scripts.</p>
|
|
487
614
|
<img src="https://img.shields.io/badge/Flaky%20Tests%3F-%20NO%21-11BBDD.svg" alt="NO MORE FLAKY TESTS!" />
|
|
488
615
|
|
|
489
616
|
✅ SeleniumBase supports all major browsers and operating systems:
|
|
490
617
|
<p><b>Browsers:</b> Chrome, Edge, Firefox, and Safari.</p>
|
|
491
|
-
<p><b>Systems
|
|
618
|
+
<p><b>Systems:</b> Linux/Ubuntu, macOS, and Windows.</p>
|
|
492
619
|
|
|
493
620
|
✅ SeleniumBase works on all popular CI/CD platforms:
|
|
494
621
|
<p><a href="https://github.com/seleniumbase/SeleniumBase/blob/master/integrations/github/workflows/ReadMe.md"><img alt="GitHub Actions integration" src="https://img.shields.io/badge/GitHub_Actions-12B2C2.svg?logo=GitHubActions&logoColor=CFFFC2" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/integrations/azure/jenkins/ReadMe.md"><img alt="Jenkins integration" src="https://img.shields.io/badge/Jenkins-32B242.svg?logo=jenkins&logoColor=white" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/integrations/azure/azure_pipelines/ReadMe.md"><img alt="Azure integration" src="https://img.shields.io/badge/Azure-2288EE.svg?logo=AzurePipelines&logoColor=white" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/integrations/google_cloud/ReadMe.md"><img alt="Google Cloud integration" src="https://img.shields.io/badge/Google_Cloud-11CAE8.svg?logo=GoogleCloud&logoColor=EE0066" /></a> <a href="#utilizing_advanced_features"><img alt="AWS integration" src="https://img.shields.io/badge/AWS-4488DD.svg?logo=AmazonAWS&logoColor=FFFF44" /></a> <a href="https://en.wikipedia.org/wiki/Personal_computer" target="_blank"><img alt="Your Computer" src="https://img.shields.io/badge/💻_Your_Computer-44E6E6.svg" /></a></p>
|
|
495
622
|
|
|
496
|
-
<p>✅ SeleniumBase includes an automated/manual hybrid solution called <b><a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/master_qa/ReadMe.md">MasterQA</a></b
|
|
623
|
+
<p>✅ SeleniumBase includes an automated/manual hybrid solution called <b><a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/master_qa/ReadMe.md">MasterQA</a></b> to speed up manual testing with automation while manual testers handle validation.</p>
|
|
624
|
+
|
|
625
|
+
<p>✅ SeleniumBase supports <a href="https://github.com/seleniumbase/SeleniumBase/tree/master/examples/offline_examples">running tests while offline</a> (<i>assuming webdrivers have previously been downloaded when online</i>).</p>
|
|
497
626
|
|
|
498
627
|
<p>✅ For a full list of SeleniumBase features, <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/features_list.md">Click Here</a>.</p>
|
|
499
628
|
|
|
500
629
|
|
|
501
|
-
<a id="
|
|
502
|
-
<h2><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" />
|
|
630
|
+
<a id="demo_mode_and_debugging"></a>
|
|
631
|
+
<h2><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Demo Mode / Debugging:</h2>
|
|
503
632
|
|
|
504
|
-
<a
|
|
505
|
-
🔵 <b>Demo Mode</b> helps you see what a test is doing. If a test is moving too fast for your eyes, run it in <b>Demo Mode</b>, which pauses the browser briefly between actions, highlights page elements being acted on, and displays assertions:
|
|
633
|
+
🔵 <b>Demo Mode</b> helps you see what a test is doing. If a test is moving too fast for your eyes, run it in <b>Demo Mode</b> to pause the browser briefly between actions, highlight page elements being acted on, and display assertions:
|
|
506
634
|
|
|
507
635
|
```bash
|
|
508
636
|
pytest my_first_test.py --demo
|
|
509
637
|
```
|
|
510
638
|
|
|
511
|
-
🔵
|
|
639
|
+
🔵 ``time.sleep(seconds)`` can be used to make a test wait at a specific spot:
|
|
640
|
+
|
|
641
|
+
```python
|
|
642
|
+
import time; time.sleep(3) # Do nothing for 3 seconds.
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
🔵 **Debug Mode** with Python's built-in **[pdb](https://docs.python.org/3/library/pdb.html)** library helps you debug tests:
|
|
512
646
|
|
|
513
647
|
```python
|
|
514
|
-
import
|
|
515
|
-
import
|
|
516
|
-
|
|
648
|
+
import pdb; pdb.set_trace()
|
|
649
|
+
import pytest; pytest.set_trace()
|
|
650
|
+
breakpoint() # Shortcut for "import pdb; pdb.set_trace()"
|
|
517
651
|
```
|
|
518
652
|
|
|
653
|
+
> (**``pdb``** commands: ``n``, ``c``, ``s``, ``u``, ``d`` => ``next``, ``continue``, ``step``, ``up``, ``down``)
|
|
654
|
+
|
|
519
655
|
🔵 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:
|
|
520
656
|
|
|
521
657
|
```bash
|
|
522
|
-
pytest
|
|
658
|
+
pytest test_fail.py --pdb
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
🔵 To start tests in Debug Mode, add **``--trace``** as a ``pytest`` option:
|
|
662
|
+
|
|
663
|
+
```bash
|
|
664
|
+
pytest test_coffee_cart.py --trace
|
|
523
665
|
```
|
|
524
666
|
|
|
525
|
-
(
|
|
667
|
+
<a href="https://github.com/mdmintz/pdbp"><img src="https://seleniumbase.github.io/cdn/gif/coffee_pdbp.gif" alt="SeleniumBase test with the pdbp (Pdb+) debugger" title="SeleniumBase test with the pdbp (Pdb+) debugger" /></a>
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
<a id="command_line_options"></a>
|
|
671
|
+
<h2>🔵 Command-line Options:</h2>
|
|
526
672
|
|
|
527
673
|
<a id="pytest_options"></a>
|
|
528
|
-
|
|
674
|
+
✅ Here are some useful command-line options that come with <code translate="no">pytest</code>:
|
|
529
675
|
|
|
530
676
|
```bash
|
|
531
677
|
-v # Verbose mode. Prints the full name of each test and shows more details.
|
|
532
678
|
-q # Quiet mode. Print fewer details in the console output when running tests.
|
|
533
679
|
-x # Stop running the tests after the first failure is reached.
|
|
534
680
|
--html=report.html # Creates a detailed pytest-html report after tests finish.
|
|
535
|
-
--
|
|
681
|
+
--co | --collect-only # Show what tests would get run. (Without running them)
|
|
682
|
+
--co -q # (Both options together!) - Do a dry run with full test names shown.
|
|
536
683
|
-n=NUM # Multithread the tests using that many threads. (Speed up test runs!)
|
|
537
684
|
-s # See print statements. (Should be on by default with pytest.ini present.)
|
|
538
685
|
--junit-xml=report.xml # Creates a junit-xml report after tests finish.
|
|
@@ -542,7 +689,7 @@ pytest my_first_test.py --pdb
|
|
|
542
689
|
```
|
|
543
690
|
|
|
544
691
|
<a id="new_pytest_options"></a>
|
|
545
|
-
|
|
692
|
+
✅ SeleniumBase provides additional <code translate="no">pytest</code> command-line options for tests:
|
|
546
693
|
|
|
547
694
|
```bash
|
|
548
695
|
--browser=BROWSER # (The web browser to use. Default: "chrome".)
|
|
@@ -550,8 +697,6 @@ pytest my_first_test.py --pdb
|
|
|
550
697
|
--edge # (Shortcut for "--browser=edge".)
|
|
551
698
|
--firefox # (Shortcut for "--browser=firefox".)
|
|
552
699
|
--safari # (Shortcut for "--browser=safari".)
|
|
553
|
-
--cap-file=FILE # (The web browser's desired capabilities to use.)
|
|
554
|
-
--cap-string=STRING # (The web browser's desired capabilities to use.)
|
|
555
700
|
--settings-file=FILE # (Override default SeleniumBase settings.)
|
|
556
701
|
--env=ENV # (Set the test env. Access with "self.env" in tests.)
|
|
557
702
|
--account=STR # (Set account. Access with "self.account" in tests.)
|
|
@@ -564,11 +709,15 @@ pytest my_first_test.py --pdb
|
|
|
564
709
|
--protocol=PROTOCOL # (The Selenium Grid protocol: http|https.)
|
|
565
710
|
--server=SERVER # (The Selenium Grid server/IP used for tests.)
|
|
566
711
|
--port=PORT # (The Selenium Grid port used by the test server.)
|
|
567
|
-
--
|
|
568
|
-
--
|
|
569
|
-
--proxy
|
|
712
|
+
--cap-file=FILE # (The web browser's desired capabilities to use.)
|
|
713
|
+
--cap-string=STRING # (The web browser's desired capabilities to use.)
|
|
714
|
+
--proxy=SERVER:PORT # (Connect to a proxy server:port as tests are running)
|
|
715
|
+
--proxy=USERNAME:PASSWORD@SERVER:PORT # (Use an authenticated proxy server)
|
|
716
|
+
--proxy-bypass-list=STRING # (";"-separated hosts to bypass, Eg "*.foo.com")
|
|
570
717
|
--proxy-pac-url=URL # (Connect to a proxy server using a PAC_URL.pac file.)
|
|
571
718
|
--proxy-pac-url=USERNAME:PASSWORD@URL # (Authenticated proxy with PAC URL.)
|
|
719
|
+
--proxy-driver # (If a driver download is needed, will use: --proxy=PROXY.)
|
|
720
|
+
--multi-proxy # (Allow multiple authenticated proxies when multi-threaded.)
|
|
572
721
|
--agent=STRING # (Modify the web browser's User-Agent string.)
|
|
573
722
|
--mobile # (Use the mobile device emulator while running tests.)
|
|
574
723
|
--metrics=STRING # (Set mobile metrics: "CSSWidth,CSSHeight,PixelRatio".)
|
|
@@ -577,13 +726,18 @@ pytest my_first_test.py --pdb
|
|
|
577
726
|
--firefox-pref=SET # (Set a Firefox preference:value set, comma-separated.)
|
|
578
727
|
--extension-zip=ZIP # (Load a Chrome Extension .zip|.crx, comma-separated.)
|
|
579
728
|
--extension-dir=DIR # (Load a Chrome Extension directory, comma-separated.)
|
|
729
|
+
--disable-features="F1,F2" # (Disable features, comma-separated, no spaces.)
|
|
580
730
|
--binary-location=PATH # (Set path of the Chromium browser binary to use.)
|
|
731
|
+
--driver-version=VER # (Set the chromedriver or uc_driver version to use.)
|
|
581
732
|
--sjw # (Skip JS Waits for readyState to be "complete" or Angular to load.)
|
|
733
|
+
--wfa # (Wait for AngularJS to be done loading after specific web actions.)
|
|
582
734
|
--pls=PLS # (Set pageLoadStrategy on Chrome: "normal", "eager", or "none".)
|
|
583
|
-
--headless # (
|
|
584
|
-
--
|
|
735
|
+
--headless # (The default headless mode. Linux uses this mode by default.)
|
|
736
|
+
--headless1 # (Use Chrome's old headless mode. Fast, but has limitations.)
|
|
737
|
+
--headless2 # (Use Chrome's new headless mode, which supports extensions.)
|
|
585
738
|
--headed # (Run tests in headed/GUI mode on Linux OS, where not default.)
|
|
586
739
|
--xvfb # (Run tests using the Xvfb virtual display server on Linux OS.)
|
|
740
|
+
--xvfb-metrics=STRING # (Set Xvfb display size on Linux: "Width,Height".)
|
|
587
741
|
--locale=LOCALE_CODE # (Set the Language Locale Code for the web browser.)
|
|
588
742
|
--interval=SECONDS # (The autoplay interval for presentations & tour steps)
|
|
589
743
|
--start-page=URL # (The starting URL for the web browser when tests begin.)
|
|
@@ -597,13 +751,16 @@ pytest my_first_test.py --pdb
|
|
|
597
751
|
--message-duration=SECONDS # (The time length for Messenger alerts.)
|
|
598
752
|
--check-js # (Check for JavaScript errors after page loads.)
|
|
599
753
|
--ad-block # (Block some types of display ads from loading.)
|
|
754
|
+
--host-resolver-rules=RULES # (Set host-resolver-rules, comma-separated.)
|
|
600
755
|
--block-images # (Block images from loading during tests.)
|
|
601
756
|
--do-not-track # (Indicate to websites that you don't want to be tracked.)
|
|
602
757
|
--verify-delay=SECONDS # (The delay before MasterQA verification checks.)
|
|
758
|
+
--ee | --esc-end # (Lets the user end the current test via the ESC key.)
|
|
603
759
|
--recorder # (Enables the Recorder for turning browser actions into code.)
|
|
604
760
|
--rec-behave # (Same as Recorder Mode, but also generates behave-gherkin.)
|
|
605
761
|
--rec-sleep # (If the Recorder is enabled, also records self.sleep calls.)
|
|
606
762
|
--rec-print # (If the Recorder is enabled, prints output after tests end.)
|
|
763
|
+
--disable-cookies # (Disable Cookies on websites. Pages might break!)
|
|
607
764
|
--disable-js # (Disable JavaScript on websites. Pages might break!)
|
|
608
765
|
--disable-csp # (Disable the Content Security Policy of websites.)
|
|
609
766
|
--disable-ws # (Disable Web Security on Chromium-based browsers.)
|
|
@@ -611,18 +768,22 @@ pytest my_first_test.py --pdb
|
|
|
611
768
|
--enable-sync # (Enable "Chrome Sync" on websites.)
|
|
612
769
|
--uc | --undetected # (Use undetected-chromedriver to evade bot-detection.)
|
|
613
770
|
--uc-cdp-events # (Capture CDP events when running in "--undetected" mode.)
|
|
771
|
+
--log-cdp # ("goog:loggingPrefs", {"performance": "ALL", "browser": "ALL"})
|
|
614
772
|
--remote-debug # (Sync to Chrome Remote Debugger chrome://inspect/#devices)
|
|
615
|
-
--final-
|
|
773
|
+
--ftrace | --final-trace # (Debug Mode after each test. Don't use with CI!)
|
|
616
774
|
--dashboard # (Enable the SeleniumBase Dashboard. Saved at: dashboard.html)
|
|
617
775
|
--dash-title=STRING # (Set the title shown for the generated dashboard.)
|
|
618
|
-
--
|
|
776
|
+
--enable-3d-apis # (Enables WebGL and 3D APIs.)
|
|
777
|
+
--swiftshader # (Chrome "--use-gl=angle" / "--use-angle=swiftshader-webgl")
|
|
619
778
|
--incognito # (Enable Chrome's Incognito mode.)
|
|
620
779
|
--guest # (Enable Chrome's Guest mode.)
|
|
780
|
+
--dark # (Enable Chrome's Dark mode.)
|
|
621
781
|
--devtools # (Open Chrome's DevTools when the browser opens.)
|
|
622
|
-
--
|
|
623
|
-
--reuse-class-session
|
|
782
|
+
--rs | --reuse-session # (Reuse browser session for all tests.)
|
|
783
|
+
--rcs | --reuse-class-session # (Reuse session for tests in class.)
|
|
624
784
|
--crumbs # (Delete all cookies between tests reusing a session.)
|
|
625
785
|
--disable-beforeunload # (Disable the "beforeunload" event on Chrome.)
|
|
786
|
+
--window-position=X,Y # (Set the browser's starting window position.)
|
|
626
787
|
--window-size=WIDTH,HEIGHT # (Set the browser's starting window size.)
|
|
627
788
|
--maximize # (Start tests with the browser window maximized.)
|
|
628
789
|
--screenshot # (Save a screenshot at the end of each test.)
|
|
@@ -636,14 +797,16 @@ pytest my_first_test.py --pdb
|
|
|
636
797
|
|
|
637
798
|
(See the full list of command-line option definitions **[here](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/plugins/pytest_plugin.py)**. For detailed examples of command-line options, see **[customizing_test_runs.md](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/customizing_test_runs.md)**)
|
|
638
799
|
|
|
639
|
-
|
|
800
|
+
--------
|
|
801
|
+
|
|
802
|
+
🔵 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.
|
|
640
803
|
|
|
641
804
|
```bash
|
|
642
805
|
cd examples/
|
|
643
806
|
|
|
644
|
-
pytest test_suite.py --
|
|
807
|
+
pytest test_suite.py --chrome
|
|
645
808
|
|
|
646
|
-
pytest test_suite.py --
|
|
809
|
+
pytest test_suite.py --firefox
|
|
647
810
|
```
|
|
648
811
|
|
|
649
812
|
An easy way to override seleniumbase/config/settings.py is by using a custom settings file.
|
|
@@ -654,10 +817,10 @@ Here's the command-line option to add to tests: (See [examples/custom_settings.p
|
|
|
654
817
|
🔵 To pass additional data from the command-line to tests, add ``--data="ANY STRING"``.
|
|
655
818
|
Inside your tests, you can use ``self.data`` to access that.
|
|
656
819
|
|
|
820
|
+
<a id="directory_configuration"></a>
|
|
821
|
+
<h2><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Directory Configuration:</h2>
|
|
657
822
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
🔵 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 **nosetests**, 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. Folders should also include a blank ``__init__.py`` file, which allows your tests to import files from that folder.
|
|
823
|
+
🔵 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.
|
|
661
824
|
|
|
662
825
|
🔵 ``sbase mkdir DIR`` creates a folder with config files and sample tests:
|
|
663
826
|
|
|
@@ -707,7 +870,7 @@ ui_tests/
|
|
|
707
870
|
└── setup.cfg
|
|
708
871
|
```
|
|
709
872
|
|
|
710
|
-
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 (
|
|
873
|
+
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).
|
|
711
874
|
|
|
712
875
|
--------
|
|
713
876
|
|
|
@@ -718,6 +881,7 @@ Let's try an example of a test that fails:
|
|
|
718
881
|
```python
|
|
719
882
|
""" test_fail.py """
|
|
720
883
|
from seleniumbase import BaseCase
|
|
884
|
+
BaseCase.main(__name__, __file__)
|
|
721
885
|
|
|
722
886
|
class MyTestClass(BaseCase):
|
|
723
887
|
|
|
@@ -732,11 +896,12 @@ You can run it from the ``examples/`` folder like this:
|
|
|
732
896
|
pytest test_fail.py
|
|
733
897
|
```
|
|
734
898
|
|
|
735
|
-
🔵 You'll notice that a logs folder,
|
|
899
|
+
🔵 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.
|
|
736
900
|
|
|
737
901
|
--------
|
|
738
902
|
|
|
739
|
-
<
|
|
903
|
+
<a id="seleniumbase_dashboard"></a>
|
|
904
|
+
<h2><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> SeleniumBase Dashboard:</h2>
|
|
740
905
|
|
|
741
906
|
🔵 The ``--dashboard`` option for pytest generates a SeleniumBase Dashboard located at ``dashboard.html``, which updates automatically as tests run and produce results. Example:
|
|
742
907
|
|
|
@@ -746,30 +911,30 @@ pytest --dashboard --rs --headless
|
|
|
746
911
|
|
|
747
912
|
<img src="https://seleniumbase.github.io/cdn/img/dashboard_1.png" alt="The SeleniumBase Dashboard" title="The SeleniumBase Dashboard" width="380" />
|
|
748
913
|
|
|
749
|
-
🔵 Additionally, you can host your own SeleniumBase Dashboard Server on a port of your choice. Here's an example of that using Python
|
|
914
|
+
🔵 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``:
|
|
750
915
|
|
|
751
916
|
```bash
|
|
752
917
|
python -m http.server 1948
|
|
753
918
|
```
|
|
754
919
|
|
|
755
|
-
🔵 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
|
|
920
|
+
🔵 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.)
|
|
756
921
|
|
|
757
922
|
🔵 Here's a full example of what the SeleniumBase Dashboard may look like:
|
|
758
923
|
|
|
759
924
|
```bash
|
|
760
|
-
pytest test_suite.py --dashboard --rs --headless
|
|
925
|
+
pytest test_suite.py test_image_saving.py --dashboard --rs --headless
|
|
761
926
|
```
|
|
762
927
|
|
|
763
|
-
<img src="https://seleniumbase.github.io/cdn/img/dashboard_2.png" alt="The SeleniumBase Dashboard" title="The SeleniumBase Dashboard" width="
|
|
928
|
+
<img src="https://seleniumbase.github.io/cdn/img/dashboard_2.png" alt="The SeleniumBase Dashboard" title="The SeleniumBase Dashboard" width="520" />
|
|
764
929
|
|
|
765
930
|
--------
|
|
766
931
|
|
|
767
932
|
<a id="creating_visual_reports"></a>
|
|
768
|
-
<
|
|
933
|
+
<h2><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Generating Test Reports:</h2>
|
|
769
934
|
|
|
770
|
-
<
|
|
935
|
+
<h3>🔵 <code>pytest</code> HTML Reports:</h3>
|
|
771
936
|
|
|
772
|
-
|
|
937
|
+
✅ Using ``--html=report.html`` gives you a fancy report of the name specified after your test suite completes.
|
|
773
938
|
|
|
774
939
|
```bash
|
|
775
940
|
pytest test_suite.py --html=report.html
|
|
@@ -777,9 +942,9 @@ pytest test_suite.py --html=report.html
|
|
|
777
942
|
|
|
778
943
|
<img src="https://seleniumbase.github.io/cdn/img/html_report.png" alt="Example Pytest Report" title="Example Pytest Report" width="520" />
|
|
779
944
|
|
|
780
|
-
|
|
945
|
+
✅ 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.
|
|
781
946
|
|
|
782
|
-
|
|
947
|
+
✅ Here's an example of an upgraded html report:
|
|
783
948
|
|
|
784
949
|
```bash
|
|
785
950
|
pytest test_suite.py --dashboard --html=report.html
|
|
@@ -787,7 +952,7 @@ pytest test_suite.py --dashboard --html=report.html
|
|
|
787
952
|
|
|
788
953
|
<img src="https://seleniumbase.github.io/cdn/img/dash_report.jpg" alt="Dashboard Pytest HTML Report" title="Dashboard Pytest HTML Report" width="520" />
|
|
789
954
|
|
|
790
|
-
If viewing pytest html reports in [Jenkins](https://www.jenkins.io/), you may need to [configure Jenkins settings](https://stackoverflow.com/a/46197356) 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/).
|
|
955
|
+
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/).
|
|
791
956
|
|
|
792
957
|
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.
|
|
793
958
|
|
|
@@ -795,19 +960,19 @@ You can also use ``--junit-xml=report.xml`` to get an xml report instead. Jenkin
|
|
|
795
960
|
pytest test_suite.py --junit-xml=report.xml
|
|
796
961
|
```
|
|
797
962
|
|
|
798
|
-
<
|
|
963
|
+
<h3>🔵 <code>pynose</code> Reports:</h3>
|
|
799
964
|
|
|
800
965
|
The ``--report`` option gives you a fancy report after your test suite completes.
|
|
801
966
|
|
|
802
967
|
```bash
|
|
803
|
-
|
|
968
|
+
pynose test_suite.py --report
|
|
804
969
|
```
|
|
805
970
|
|
|
806
|
-
<img src="https://seleniumbase.github.io/cdn/img/nose_report.png" alt="Example
|
|
971
|
+
<img src="https://seleniumbase.github.io/cdn/img/nose_report.png" alt="Example pynose Report" title="Example pynose Report" width="320" />
|
|
807
972
|
|
|
808
|
-
(NOTE: You can add ``--show-report`` to immediately display
|
|
973
|
+
(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.)
|
|
809
974
|
|
|
810
|
-
<
|
|
975
|
+
<h3>🔵 <code>behave</code> Dashboard & Reports:</h3>
|
|
811
976
|
|
|
812
977
|
(The [behave_bdd/](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/behave_bdd) folder can be found in the [examples/](https://github.com/seleniumbase/SeleniumBase/tree/master/examples) folder.)
|
|
813
978
|
|
|
@@ -815,17 +980,17 @@ nosetests test_suite.py --report
|
|
|
815
980
|
behave behave_bdd/features/ -D dashboard -D headless
|
|
816
981
|
```
|
|
817
982
|
|
|
818
|
-
<img src="https://seleniumbase.github.io/cdn/img/sb_behave_dashboard.png" title="SeleniumBase" width="
|
|
983
|
+
<img src="https://seleniumbase.github.io/cdn/img/sb_behave_dashboard.png" title="SeleniumBase" width="520">
|
|
819
984
|
|
|
820
|
-
You can also use ``--junit`` to get ``.xml`` reports for each
|
|
985
|
+
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.
|
|
821
986
|
|
|
822
987
|
```bash
|
|
823
988
|
behave behave_bdd/features/ --junit -D rs -D headless
|
|
824
989
|
```
|
|
825
990
|
|
|
826
|
-
<
|
|
991
|
+
<h3>🔵 Allure Reports:</h3>
|
|
827
992
|
|
|
828
|
-
See: [https://
|
|
993
|
+
See: [https://allurereport.org/docs/pytest/](https://allurereport.org/docs/pytest/)
|
|
829
994
|
|
|
830
995
|
SeleniumBase no longer includes ``allure-pytest`` as part of installed dependencies. If you want to use it, install it first:
|
|
831
996
|
|
|
@@ -839,6 +1004,7 @@ Now your tests can create Allure results files, which can be processed by Allure
|
|
|
839
1004
|
pytest test_suite.py --alluredir=allure_results
|
|
840
1005
|
```
|
|
841
1006
|
|
|
1007
|
+
--------
|
|
842
1008
|
|
|
843
1009
|
<h3><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Using a Proxy Server:</h3>
|
|
844
1010
|
|
|
@@ -878,9 +1044,9 @@ pytest user_agent_test.py --agent="Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1
|
|
|
878
1044
|
```
|
|
879
1045
|
|
|
880
1046
|
|
|
881
|
-
<h3><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Handling Pop-Up
|
|
1047
|
+
<h3><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Handling Pop-Up Alerts:</h3>
|
|
882
1048
|
|
|
883
|
-
🔵 <code>self.accept_alert()</code> automatically waits for and accepts alert pop-ups. <code>self.dismiss_alert()</code> automatically waits for and dismisses alert pop-ups. On occasion, some methods like <code>self.click(SELECTOR)</code> might dismiss a pop-up on its own because they call JavaScript to make sure that the <code>readyState</code> of the page is <code>complete</code> before advancing. If you're trying to accept a pop-up that got dismissed this way, use this workaround: Call <code>self.find_element(SELECTOR).click()</code> instead, (which will let the pop-up remain on the screen), and then use <code>self.accept_alert()</code> to accept the pop-up (<a href="https://github.com/seleniumbase/SeleniumBase/issues/600#issuecomment-647270426">more on that here</a>). If pop-ups are intermittent, wrap code in a try/except block.
|
|
1049
|
+
🔵 <code translate="no">self.accept_alert()</code> automatically waits for and accepts alert pop-ups. <code translate="no">self.dismiss_alert()</code> automatically waits for and dismisses alert pop-ups. On occasion, some methods like <code translate="no">self.click(SELECTOR)</code> might dismiss a pop-up on its own because they call JavaScript to make sure that the <code translate="no">readyState</code> of the page is <code translate="no">complete</code> before advancing. If you're trying to accept a pop-up that got dismissed this way, use this workaround: Call <code translate="no">self.find_element(SELECTOR).click()</code> instead, (which will let the pop-up remain on the screen), and then use <code translate="no">self.accept_alert()</code> to accept the pop-up (<a href="https://github.com/seleniumbase/SeleniumBase/issues/600#issuecomment-647270426">more on that here</a>). If pop-ups are intermittent, wrap code in a try/except block.
|
|
884
1050
|
|
|
885
1051
|
|
|
886
1052
|
<h3><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Building Guided Tours for Websites:</h3>
|
|
@@ -902,11 +1068,11 @@ pytest user_agent_test.py --agent="Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1
|
|
|
902
1068
|
<ul>
|
|
903
1069
|
<li>You can set up a <a href="https://jenkins.io/" target="_blank">Jenkins</a> build server for running tests at regular intervals. For a real-world Jenkins example of headless browser automation in action, check out the <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/integrations/azure/jenkins/ReadMe.md">SeleniumBase Jenkins example on Azure</a> or the <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/integrations/google_cloud/ReadMe.md">SeleniumBase Jenkins example on Google Cloud</a>.</li>
|
|
904
1070
|
|
|
905
|
-
<li>You can use <a href="https://selenium.dev/documentation/en/grid/" target="_blank">the Selenium Grid</a> to scale your testing by distributing tests on several machines with parallel execution. To do this, check out the <a href="https://github.com/seleniumbase/SeleniumBase/tree/master/seleniumbase/utilities/selenium_grid">SeleniumBase selenium_grid folder</a>, which should have everything you need, including the <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/utilities/selenium_grid/ReadMe.md">Selenium Grid ReadMe</a
|
|
1071
|
+
<li>You can use <a href="https://selenium.dev/documentation/en/grid/" target="_blank">the Selenium Grid</a> to scale your testing by distributing tests on several machines with parallel execution. To do this, check out the <a href="https://github.com/seleniumbase/SeleniumBase/tree/master/seleniumbase/utilities/selenium_grid">SeleniumBase selenium_grid folder</a>, which should have everything you need, including the <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/utilities/selenium_grid/ReadMe.md">Selenium Grid ReadMe</a> to help you get started.</li>
|
|
906
1072
|
|
|
907
1073
|
<li>If you're using the <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/mysql_installation.md">SeleniumBase MySQL feature</a> to save results from tests running on a server machine, you can install <a href="https://dev.mysql.com/downloads/tools/workbench/">MySQL Workbench</a> to help you read & write from your DB more easily.</li>
|
|
908
1074
|
|
|
909
|
-
<li>If you're using AWS, you can set up an <a href="https://aws.amazon.com/s3/" target="_blank">Amazon S3</a> account for saving log files and screenshots from your tests. To activate this feature, modify <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/config/settings.py">settings.py</a> with connection details in the S3 section, and add <code>--with-s3-logging</code> on the command-line when running your tests.</li>
|
|
1075
|
+
<li>If you're using AWS, you can set up an <a href="https://aws.amazon.com/s3/" target="_blank">Amazon S3</a> account for saving log files and screenshots from your tests. To activate this feature, modify <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/config/settings.py">settings.py</a> with connection details in the S3 section, and add <code translate="no">--with-s3-logging</code> on the command-line when running your tests.</li>
|
|
910
1076
|
</ul>
|
|
911
1077
|
|
|
912
1078
|
Here's an example of running tests with some additional features enabled:
|
|
@@ -921,7 +1087,7 @@ pytest [YOUR_TEST_FILE.py] --with-db-reporting --with-s3-logging
|
|
|
921
1087
|
<a id="detailed_method_specifications"></a>
|
|
922
1088
|
<h3><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Detailed Method Specifications and Examples:</h3>
|
|
923
1089
|
|
|
924
|
-
🔵 Navigating to a web page: (and related commands)
|
|
1090
|
+
🔵 **Navigating to a web page: (and related commands)**
|
|
925
1091
|
|
|
926
1092
|
```python
|
|
927
1093
|
self.open("https://xkcd.com/378/") # This method opens the specified page.
|
|
@@ -937,7 +1103,7 @@ self.get_current_url() # This method returns the current page URL.
|
|
|
937
1103
|
self.get_page_source() # This method returns the current page source.
|
|
938
1104
|
```
|
|
939
1105
|
|
|
940
|
-
<b>ProTip™:</b> You can use the <code>self.get_page_source()</code> method with Python's <code>find()</code> command to parse through HTML to find something specific. (For more advanced parsing, see the <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/test_parse_soup.py">BeautifulSoup example</a>.)
|
|
1106
|
+
<b>ProTip™:</b> You can use the <code translate="no">self.get_page_source()</code> method with Python's <code translate="no">find()</code> command to parse through HTML to find something specific. (For more advanced parsing, see the <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/test_parse_soup.py">BeautifulSoup example</a>.)
|
|
941
1107
|
|
|
942
1108
|
```python
|
|
943
1109
|
source = self.get_page_source()
|
|
@@ -946,7 +1112,7 @@ head_close_tag = source.find('</head>', head_open_tag)
|
|
|
946
1112
|
everything_inside_head = source[head_open_tag+len('<head>'):head_close_tag]
|
|
947
1113
|
```
|
|
948
1114
|
|
|
949
|
-
🔵 Clicking
|
|
1115
|
+
🔵 **Clicking:**
|
|
950
1116
|
|
|
951
1117
|
To click an element on the page:
|
|
952
1118
|
|
|
@@ -956,29 +1122,29 @@ self.click("div#my_id")
|
|
|
956
1122
|
|
|
957
1123
|
**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.
|
|
958
1124
|
|
|
959
|
-
🔵 Typing Text
|
|
1125
|
+
🔵 **Typing Text:**
|
|
960
1126
|
|
|
961
|
-
<code>self.type(selector, text)</code> # updates the text from the specified element with the specified value. An exception is raised if the element is missing or if the text field is not editable. Example:
|
|
1127
|
+
<code translate="no">self.type(selector, text)</code> # updates the text from the specified element with the specified value. An exception is raised if the element is missing or if the text field is not editable. Example:
|
|
962
1128
|
|
|
963
1129
|
```python
|
|
964
1130
|
self.type("input#id_value", "2012")
|
|
965
1131
|
```
|
|
966
1132
|
|
|
967
|
-
You can also use <code>self.add_text()</code> or the <a href="https://www.selenium.dev/documentation/webdriver/" target="_blank">WebDriver</a> <code>.send_keys()</code> command, but those won't clear the text box first if there's already text inside.
|
|
1133
|
+
You can also use <code translate="no">self.add_text()</code> or the <a href="https://www.selenium.dev/documentation/webdriver/" target="_blank">WebDriver</a> <code translate="no">.send_keys()</code> command, but those won't clear the text box first if there's already text inside.
|
|
968
1134
|
|
|
969
|
-
🔵 Getting the text from an element on a page
|
|
1135
|
+
🔵 **Getting the text from an element on a page:**
|
|
970
1136
|
|
|
971
1137
|
```python
|
|
972
1138
|
text = self.get_text("header h2")
|
|
973
1139
|
```
|
|
974
1140
|
|
|
975
|
-
🔵 Getting the attribute value from an element on a page
|
|
1141
|
+
🔵 **Getting the attribute value from an element on a page:**
|
|
976
1142
|
|
|
977
1143
|
```python
|
|
978
1144
|
attribute = self.get_attribute("#comic img", "title")
|
|
979
1145
|
```
|
|
980
1146
|
|
|
981
|
-
🔵 Asserting existence of an element on a page within some number of seconds
|
|
1147
|
+
🔵 **Asserting existence of an element on a page within some number of seconds:**
|
|
982
1148
|
|
|
983
1149
|
```python
|
|
984
1150
|
self.wait_for_element_present("div.my_class", timeout=10)
|
|
@@ -986,7 +1152,7 @@ self.wait_for_element_present("div.my_class", timeout=10)
|
|
|
986
1152
|
|
|
987
1153
|
(NOTE: You can also use: ``self.assert_element_present(ELEMENT)``)
|
|
988
1154
|
|
|
989
|
-
🔵 Asserting visibility of an element on a page within some number of seconds
|
|
1155
|
+
🔵 **Asserting visibility of an element on a page within some number of seconds:**
|
|
990
1156
|
|
|
991
1157
|
```python
|
|
992
1158
|
self.wait_for_element_visible("a.my_class", timeout=5)
|
|
@@ -1012,7 +1178,7 @@ You can also use ``*=`` to search for any partial value in a CSS selector as sho
|
|
|
1012
1178
|
self.click('a[name*="partial_name"]')
|
|
1013
1179
|
```
|
|
1014
1180
|
|
|
1015
|
-
🔵 Asserting visibility of text inside an element on a page within some number of seconds
|
|
1181
|
+
🔵 **Asserting visibility of text inside an element on a page within some number of seconds:**
|
|
1016
1182
|
|
|
1017
1183
|
```python
|
|
1018
1184
|
self.assert_text("Make it so!", "div#trek div.picard div.quotes")
|
|
@@ -1021,7 +1187,7 @@ self.assert_text("Tea. Earl Grey. Hot.", "div#trek div.picard div.quotes", timeo
|
|
|
1021
1187
|
|
|
1022
1188
|
(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.)
|
|
1023
1189
|
|
|
1024
|
-
🔵 Asserting Anything
|
|
1190
|
+
🔵 **Asserting Anything:**
|
|
1025
1191
|
|
|
1026
1192
|
```python
|
|
1027
1193
|
self.assert_true(var1 == var2)
|
|
@@ -1031,7 +1197,7 @@ self.assert_false(var1 == var2)
|
|
|
1031
1197
|
self.assert_equal(var1, var2)
|
|
1032
1198
|
```
|
|
1033
1199
|
|
|
1034
|
-
🔵 Useful Conditional Statements: (with creative examples)
|
|
1200
|
+
🔵 **Useful Conditional Statements: (with creative examples)**
|
|
1035
1201
|
|
|
1036
1202
|
❓ ``is_element_visible(selector):`` (visible on the page)
|
|
1037
1203
|
|
|
@@ -1066,7 +1232,7 @@ if self.is_text_visible("You Shall Not Pass!", "h1"):
|
|
|
1066
1232
|
|
|
1067
1233
|
<div></div>
|
|
1068
1234
|
<details>
|
|
1069
|
-
<summary> ▶️ Click for a longer example of <code>is_text_visible():</code></summary>
|
|
1235
|
+
<summary> ▶️ Click for a longer example of <code translate="no">is_text_visible():</code></summary>
|
|
1070
1236
|
|
|
1071
1237
|
```python
|
|
1072
1238
|
def get_mirror_universe_captain_picard_superbowl_ad(superbowl_year):
|
|
@@ -1104,24 +1270,52 @@ if self.is_link_text_visible("Stop! Hammer time!"):
|
|
|
1104
1270
|
self.click_link("Stop! Hammer time!")
|
|
1105
1271
|
```
|
|
1106
1272
|
|
|
1107
|
-
|
|
1273
|
+
<h3>🔵 Switching Tabs:</h3>
|
|
1108
1274
|
|
|
1109
|
-
<p>If your test opens up a new tab/window, you can switch to it. (SeleniumBase automatically switches to new tabs that don't open to <code>about:blank</code> URLs.)</p>
|
|
1275
|
+
<p>If your test opens up a new tab/window, you can switch to it. (SeleniumBase automatically switches to new tabs that don't open to <code translate="no">about:blank</code> URLs.)</p>
|
|
1110
1276
|
|
|
1111
1277
|
```python
|
|
1112
1278
|
self.switch_to_window(1) # This switches to the new tab (0 is the first one)
|
|
1113
1279
|
```
|
|
1114
1280
|
|
|
1115
|
-
|
|
1281
|
+
<h3>🔵 How to handle iframes:</h3>
|
|
1282
|
+
|
|
1283
|
+
🔵 <b>iframes</b> follow the same principle as new windows: You must first switch to the iframe if you want to perform actions in there:
|
|
1116
1284
|
|
|
1117
1285
|
```python
|
|
1118
|
-
self.switch_to_frame(
|
|
1119
|
-
# Now
|
|
1120
|
-
#
|
|
1121
|
-
self.switch_to_default_content() # Exit the iframe when you're done
|
|
1286
|
+
self.switch_to_frame("iframe")
|
|
1287
|
+
# ... Now perform actions inside the iframe
|
|
1288
|
+
self.switch_to_parent_frame() # Exit the current iframe
|
|
1122
1289
|
```
|
|
1123
1290
|
|
|
1124
|
-
|
|
1291
|
+
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()``.)
|
|
1292
|
+
|
|
1293
|
+
```python
|
|
1294
|
+
self.switch_to_frame('iframe[name="frame1"]')
|
|
1295
|
+
self.switch_to_frame('iframe[name="frame2"]')
|
|
1296
|
+
# ... Now perform actions inside the inner iframe
|
|
1297
|
+
self.switch_to_default_content() # Back to the main page
|
|
1298
|
+
```
|
|
1299
|
+
|
|
1300
|
+
🔵 You can also use a context manager to act inside iframes:
|
|
1301
|
+
|
|
1302
|
+
```python
|
|
1303
|
+
with self.frame_switch("iframe"):
|
|
1304
|
+
# ... Now perform actions while inside the code block
|
|
1305
|
+
# You have left the iframe
|
|
1306
|
+
```
|
|
1307
|
+
|
|
1308
|
+
This also works with nested iframes:
|
|
1309
|
+
|
|
1310
|
+
```python
|
|
1311
|
+
with self.frame_switch('iframe[name="frame1"]'):
|
|
1312
|
+
with self.frame_switch('iframe[name="frame2"]'):
|
|
1313
|
+
# ... Now perform actions while inside the code block
|
|
1314
|
+
# You are now back inside the first iframe
|
|
1315
|
+
# You have left all the iframes
|
|
1316
|
+
```
|
|
1317
|
+
|
|
1318
|
+
<h3>🔵 How to execute custom jQuery scripts:</h3>
|
|
1125
1319
|
|
|
1126
1320
|
<p>jQuery is a powerful JavaScript library that allows you to perform advanced actions in a web browser.
|
|
1127
1321
|
If the web page you're on already has jQuery loaded, you can start executing jQuery scripts immediately.
|
|
@@ -1165,7 +1359,11 @@ self.execute_script("return jQuery('textarea')[2].value") # Returns the css "va
|
|
|
1165
1359
|
|
|
1166
1360
|
</details>
|
|
1167
1361
|
|
|
1168
|
-
|
|
1362
|
+
<h3>🔵 How to handle a restrictive CSP:</h3>
|
|
1363
|
+
|
|
1364
|
+
❗ 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.
|
|
1365
|
+
|
|
1366
|
+
<h3>🔵 More JavaScript fun:</h3>
|
|
1169
1367
|
|
|
1170
1368
|
<div></div>
|
|
1171
1369
|
<details>
|
|
@@ -1180,35 +1378,37 @@ self.execute_script('''document.body.innerHTML = \"%s\"''' % referral_link)
|
|
|
1180
1378
|
self.click("a.analytics") # Clicks the generated button
|
|
1181
1379
|
```
|
|
1182
1380
|
|
|
1183
|
-
(Due to popular demand, this traffic generation example has been included in SeleniumBase with the <code>self.generate_referral(start_page, end_page)</code> and the <code>self.generate_traffic(start_page, end_page, loops)</code> methods.)
|
|
1381
|
+
(Due to popular demand, this traffic generation example has been included in SeleniumBase with the <code translate="no">self.generate_referral(start_page, end_page)</code> and the <code translate="no">self.generate_traffic(start_page, end_page, loops)</code> methods.)
|
|
1184
1382
|
|
|
1185
1383
|
</details>
|
|
1186
1384
|
|
|
1187
|
-
|
|
1385
|
+
<h3>🔵 How to use deferred asserts:</h3>
|
|
1188
1386
|
|
|
1189
|
-
<p>Let's say you want to verify multiple different elements on a web page in a single test, but you don't want the test to fail until you verified several elements at once so that you don't have to rerun the test to find more missing elements on the same page. That's where deferred asserts come in. Here's
|
|
1387
|
+
<p>Let's say you want to verify multiple different elements on a web page in a single test, but you don't want the test to fail until you verified several elements at once so that you don't have to rerun the test to find more missing elements on the same page. That's where deferred asserts come in. Here's an example:</p>
|
|
1190
1388
|
|
|
1191
1389
|
```python
|
|
1192
1390
|
from seleniumbase import BaseCase
|
|
1391
|
+
BaseCase.main(__name__, __file__)
|
|
1193
1392
|
|
|
1194
|
-
class
|
|
1195
|
-
|
|
1393
|
+
class DeferredAssertTests(BaseCase):
|
|
1196
1394
|
def test_deferred_asserts(self):
|
|
1197
|
-
self.open(
|
|
1198
|
-
self.wait_for_element(
|
|
1395
|
+
self.open("https://xkcd.com/993/")
|
|
1396
|
+
self.wait_for_element("#comic")
|
|
1199
1397
|
self.deferred_assert_element('img[alt="Brand Identity"]')
|
|
1200
1398
|
self.deferred_assert_element('img[alt="Rocket Ship"]') # Will Fail
|
|
1201
|
-
self.deferred_assert_element(
|
|
1202
|
-
self.deferred_assert_text(
|
|
1203
|
-
self.deferred_assert_text(
|
|
1399
|
+
self.deferred_assert_element("#comicmap")
|
|
1400
|
+
self.deferred_assert_text("Fake Item", "ul.comicNav") # Will Fail
|
|
1401
|
+
self.deferred_assert_text("Random", "ul.comicNav")
|
|
1204
1402
|
self.deferred_assert_element('a[name="Super Fake !!!"]') # Will Fail
|
|
1403
|
+
self.deferred_assert_exact_text("Brand Identity", "#ctitle")
|
|
1404
|
+
self.deferred_assert_exact_text("Fake Food", "#comic") # Will Fail
|
|
1205
1405
|
self.process_deferred_asserts()
|
|
1206
1406
|
```
|
|
1207
1407
|
|
|
1208
|
-
<code>deferred_assert_element()</code> and <code>deferred_assert_text()</code> will save any exceptions that would be raised.
|
|
1209
|
-
To flush out all the failed deferred asserts into a single exception, make sure to call <code>self.process_deferred_asserts()</code> at the end of your test method. If your test hits multiple pages, you can call <code>self.process_deferred_asserts()</code> before navigating to a new page so that the screenshot from your log files matches the URL where the deferred asserts were made.
|
|
1408
|
+
<code translate="no">deferred_assert_element()</code> and <code translate="no">deferred_assert_text()</code> will save any exceptions that would be raised.
|
|
1409
|
+
To flush out all the failed deferred asserts into a single exception, make sure to call <code translate="no">self.process_deferred_asserts()</code> at the end of your test method. If your test hits multiple pages, you can call <code translate="no">self.process_deferred_asserts()</code> before navigating to a new page so that the screenshot from your log files matches the URL where the deferred asserts were made.
|
|
1210
1410
|
|
|
1211
|
-
|
|
1411
|
+
<h3>🔵 How to access raw <a href="https://www.selenium.dev/documentation/webdriver/" target="_blank">WebDriver</a>:</h3>
|
|
1212
1412
|
|
|
1213
1413
|
<p>If you need access to any commands that come with standard <a href="https://www.selenium.dev/documentation/webdriver/" target="_blank">WebDriver</a>, you can call them directly like this:</p>
|
|
1214
1414
|
|
|
@@ -1220,42 +1420,47 @@ self.driver.find_elements("partial link text", "GitHub")
|
|
|
1220
1420
|
|
|
1221
1421
|
(In general, you'll want to use the SeleniumBase versions of methods when available.)
|
|
1222
1422
|
|
|
1223
|
-
|
|
1423
|
+
<h3>🔵 How to retry failing tests automatically:</h3>
|
|
1224
1424
|
|
|
1225
|
-
<p>You can use <code
|
|
1425
|
+
<p>You can use <code translate="no">pytest --reruns=NUM</code> to retry failing tests that many times. Add <code translate="no">--reruns-delay=SECONDS</code> to wait that many seconds between retries. Example:</p>
|
|
1226
1426
|
|
|
1227
1427
|
```bash
|
|
1228
1428
|
pytest --reruns=1 --reruns-delay=1
|
|
1229
1429
|
```
|
|
1230
1430
|
|
|
1231
|
-
<p>You can use the <code>@retry_on_exception()</code> decorator to retry failing methods. (First import: <code>from seleniumbase import decorators</code>). To learn more about SeleniumBase decorators, <a href="https://github.com/seleniumbase/SeleniumBase/tree/master/seleniumbase/common">click here</a>.</p>
|
|
1431
|
+
<p>You can use the <code translate="no">@retry_on_exception()</code> decorator to retry failing methods. (First import: <code translate="no">from seleniumbase import decorators</code>). To learn more about SeleniumBase decorators, <a href="https://github.com/seleniumbase/SeleniumBase/tree/master/seleniumbase/common">click here</a>.</p>
|
|
1232
1432
|
|
|
1433
|
+
--------
|
|
1233
1434
|
|
|
1234
|
-
|
|
1435
|
+
> "Catch bugs in QA before deploying code to Production!"
|
|
1436
|
+
|
|
1437
|
+
<p align="left"><a href="https://seleniumbase.io/error_page" target="_blank"><img src="https://seleniumbase.github.io/cdn/gif/error_page.gif" alt="Catch bugs in QA before deploying code to Production!" title="Catch bugs in QA before deploying code to Production!" /></a></p>
|
|
1438
|
+
|
|
1439
|
+
--------
|
|
1235
1440
|
|
|
1236
|
-
<
|
|
1441
|
+
<h3><img src="https://seleniumbase.github.io/img/logo7.png" title="SeleniumBase" width="32" /> Wrap-Up</h3>
|
|
1237
1442
|
|
|
1238
1443
|
<p>
|
|
1239
1444
|
<div><b>If you see something, say something!</b></div>
|
|
1240
|
-
<div><a href="https://github.com/seleniumbase/SeleniumBase/issues?q=is%3Aissue+is%3Aclosed"><img src="https://img.shields.io/github/issues-closed-raw/seleniumbase/SeleniumBase.svg?color=22BB88" title="Closed Issues" /></a>
|
|
1445
|
+
<div><a href="https://github.com/seleniumbase/SeleniumBase/issues?q=is%3Aissue+is%3Aclosed"><img src="https://img.shields.io/github/issues-closed-raw/seleniumbase/SeleniumBase.svg?color=22BB88" title="Closed Issues" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/pulls?q=is%3Apr+is%3Aclosed"><img src="https://img.shields.io/github/issues-pr-closed/seleniumbase/SeleniumBase.svg?logo=github&logoColor=white&color=22BB99" title="Closed Pull Requests" /></a></div>
|
|
1241
1446
|
</p>
|
|
1242
1447
|
|
|
1243
|
-
<p>
|
|
1244
|
-
<div><b>If you like SeleniumBase, star us! ⭐</b></div>
|
|
1245
|
-
<div><a href="https://github.com/seleniumbase/SeleniumBase/stargazers"><img src="https://img.shields.io/github/stars/seleniumbase/seleniumbase.svg?color=19A57B" title="Stargazers" /></a></div>
|
|
1246
|
-
</p>
|
|
1247
|
-
<p><div><a href="https://github.com/mdmintz">https://github.com/mdmintz</a></div></p>
|
|
1448
|
+
<p align="left"><a href="https://github.com/seleniumbase/SeleniumBase/"><img src="https://seleniumbase.github.io/cdn/img/sb_logo_10t.png" alt="SeleniumBase" title="SeleniumBase" width="274" /></a></p>
|
|
1248
1449
|
|
|
1249
|
-
<
|
|
1450
|
+
<a href="https://pypi.org/project/seleniumbase/" target="_blank"><img src="https://img.shields.io/pypi/pyversions/seleniumbase.svg?color=22AAEE&logo=python&logoColor=FEDC54" title="Supported Python Versions" /></a>
|
|
1250
1451
|
|
|
1251
1452
|
<p><div>
|
|
1252
|
-
<span><a href="https://www.youtube.com/playlist?list=PLp9uKicxkBc5UIlGi2BuE3aWC7JyXpD3m"><img src="https://seleniumbase.github.io/cdn/img/youtube.png" title="SeleniumBase Playlist on YouTube" alt="SeleniumBase Playlist on YouTube" width="
|
|
1253
|
-
<span><a href="https://github.com/seleniumbase/SeleniumBase"><img src="https://seleniumbase.github.io/img/social/share_github.svg" title="SeleniumBase on GitHub" alt="SeleniumBase on GitHub" width="
|
|
1254
|
-
<span><a href="https://
|
|
1453
|
+
<span><a href="https://www.youtube.com/playlist?list=PLp9uKicxkBc5UIlGi2BuE3aWC7JyXpD3m"><img src="https://seleniumbase.github.io/cdn/img/youtube.png" title="SeleniumBase Playlist on YouTube" alt="SeleniumBase Playlist on YouTube" width="70" /></a></span>
|
|
1454
|
+
<span><a href="https://github.com/seleniumbase/SeleniumBase"><img src="https://seleniumbase.github.io/img/social/share_github.svg" title="SeleniumBase on GitHub" alt="SeleniumBase on GitHub" width="64" /></a></span>
|
|
1455
|
+
<span><a href="https://discord.gg/EdhQTn3EyE"><img src="https://seleniumbase.github.io/other/discord_icon.png" title="SeleniumBase on Discord" alt="SeleniumBase on Discord" width="66" /></a></span>
|
|
1456
|
+
<span><a href="https://www.facebook.com/SeleniumBase"><img src="https://seleniumbase.io/img/social/share_facebook.svg" title="SeleniumBase on Facebook" alt="SeleniumBase on Facebook" width="62" /></a></span>
|
|
1255
1457
|
</div></p>
|
|
1256
1458
|
|
|
1257
|
-
|
|
1459
|
+
<p><div><b><a href="https://github.com/mdmintz">https://github.com/mdmintz</a></b></div></p>
|
|
1258
1460
|
|
|
1259
|
-
<
|
|
1260
|
-
<
|
|
1261
|
-
<
|
|
1461
|
+
<div><a href="https://github.com/seleniumbase/SeleniumBase/"><img src="https://seleniumbase.github.io/cdn/img/super_logo_sb3.png" title="SeleniumBase" width="274" /></a></div>
|
|
1462
|
+
<div><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/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-22BBCC.svg" title="SeleniumBase" /></a></div>
|
|
1463
|
+
<div><a href="https://github.com/seleniumbase/SeleniumBase"><img src="https://img.shields.io/badge/tested%20with-SeleniumBase-04C38E.svg" alt="Tested with SeleniumBase" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/stargazers"><img src="https://img.shields.io/github/stars/seleniumbase/seleniumbase.svg?color=19A57B" title="Stargazers" /></a></div>
|
|
1464
|
+
<div><a href="https://hellogithub.com/repository/c6be2d0f1969448697683d11a4ff915e" target="_blank"><img src="https://abroad.hellogithub.com/v1/widgets/recommend.svg?rid=c6be2d0f1969448697683d11a4ff915e&claim_uid=xcrm4p9j3d6JCO5&theme=small" alt="Featured|HelloGitHub" /></a> <a href="https://discord.gg/EdhQTn3EyE" target="_blank"><img src="https://img.shields.io/badge/join-discord-infomational" alt="Join the SeleniumBase chat on Discord"/></a> <a href="https://gitter.im/seleniumbase/SeleniumBase" target="_blank"><img src="https://img.shields.io/gitter/room/seleniumbase/SeleniumBase.svg" alt="Gitter chat"/></a></div>
|
|
1465
|
+
<div><a href="https://pepy.tech/project/seleniumbase" target="_blank"><img src="https://static.pepy.tech/badge/seleniumbase" alt="SeleniumBase PyPI downloads" /></a> <img src="https://views.whatilearened.today/views/github/seleniumbase/SeleniumBase.svg" width="98px" height="20px" alt="Views" /></div>
|
|
1466
|
+
<div align="left"></div>
|