├── .gitignore ├── .readthedocs.yaml ├── Makefile ├── README.rst ├── make.bat ├── requirements.txt ├── setup.py └── source ├── _static ├── README.txt └── logo.png ├── api.rst ├── conf.py ├── faq.rst ├── getting-started.rst ├── index.rst ├── installation.rst ├── locating-elements.rst ├── navigating.rst ├── page-objects.rst └── waits.rst /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | build 3 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the version of Python 9 | build: 10 | os: ubuntu-20.04 11 | tools: 12 | python: "3.10" 13 | 14 | # Optionally set the version of Python and requirements required to build your docs 15 | python: 16 | install: 17 | - requirements: requirements.txt 18 | 19 | # Build documentation in the docs/ directory with Sphinx 20 | sphinx: 21 | configuration: source/conf.py 22 | fail_on_warning: false 23 | 24 | # Optionally build your docs in additional formats such as PDF 25 | formats: 26 | - pdf 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 14 | 15 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest 16 | 17 | help: 18 | @echo "Please use \`make ' where is one of" 19 | @echo " html to make standalone HTML files" 20 | @echo " dirhtml to make HTML files named index.html in directories" 21 | @echo " singlehtml to make a single large HTML file" 22 | @echo " pickle to make pickle files" 23 | @echo " json to make JSON files" 24 | @echo " htmlhelp to make HTML files and a HTML help project" 25 | @echo " qthelp to make HTML files and a qthelp project" 26 | @echo " devhelp to make HTML files and a Devhelp project" 27 | @echo " epub to make an epub" 28 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 29 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 30 | @echo " text to make text files" 31 | @echo " man to make manual pages" 32 | @echo " changes to make an overview of all changed/added/deprecated items" 33 | @echo " linkcheck to check all external links for integrity" 34 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 35 | 36 | clean: 37 | -rm -rf $(BUILDDIR)/* 38 | 39 | html: 40 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 41 | @echo 42 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 43 | 44 | dirhtml: 45 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 48 | 49 | singlehtml: 50 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 51 | @echo 52 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 53 | 54 | pickle: 55 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 56 | @echo 57 | @echo "Build finished; now you can process the pickle files." 58 | 59 | json: 60 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 61 | @echo 62 | @echo "Build finished; now you can process the JSON files." 63 | 64 | htmlhelp: 65 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 66 | @echo 67 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 68 | ".hhp project file in $(BUILDDIR)/htmlhelp." 69 | 70 | qthelp: 71 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 72 | @echo 73 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 74 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 75 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/SeleniumPythonBindings.qhcp" 76 | @echo "To view the help file:" 77 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/SeleniumPythonBindings.qhc" 78 | 79 | devhelp: 80 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 81 | @echo 82 | @echo "Build finished." 83 | @echo "To view the help file:" 84 | @echo "# mkdir -p $$HOME/.local/share/devhelp/SeleniumPythonBindings" 85 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/SeleniumPythonBindings" 86 | @echo "# devhelp" 87 | 88 | epub: 89 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 90 | @echo 91 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 92 | 93 | latex: 94 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 95 | @echo 96 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 97 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 98 | "(use \`make latexpdf' here to do that automatically)." 99 | 100 | latexpdf: 101 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 102 | @echo "Running LaTeX files through pdflatex..." 103 | make -C $(BUILDDIR)/latex all-pdf 104 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 105 | 106 | text: 107 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 108 | @echo 109 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 110 | 111 | man: 112 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 113 | @echo 114 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 115 | 116 | changes: 117 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 118 | @echo 119 | @echo "The overview file is in $(BUILDDIR)/changes." 120 | 121 | linkcheck: 122 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 123 | @echo 124 | @echo "Link check complete; look for any errors in the above output " \ 125 | "or in $(BUILDDIR)/linkcheck/output.txt." 126 | 127 | doctest: 128 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 129 | @echo "Testing of doctests in the sources finished, look at the " \ 130 | "results in $(BUILDDIR)/doctest/output.txt." 131 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Selenium Python Bindings Documentation 2 | ====================================== 3 | 4 | https://selenium-python.readthedocs.io 5 | 6 | NOTE: THIS IS NOT OFFICIAL DOCUMENTATION 7 | 8 | This is not official documentation. If you would like to contribute to this 9 | documentation, you can `fork this project in GitHub and send pull requests 10 | `_. You can also send your feedback 11 | to my email: baiju.m.mail AT gmail DOT com. So far 60+ community members have 12 | contributed to this project (See the 'Closed' pull requests). I encourage 13 | contributors to add more sections to make this documentation even more awesome! 14 | If you know any translations of this document, or would like to create new translations, 15 | please send a PR to update the below list. 16 | 17 | **Translations:** 18 | 19 | - `Chinese `_ 20 | - `Japanese `_ 21 | -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source 10 | if NOT "%PAPER%" == "" ( 11 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 12 | ) 13 | 14 | if "%1" == "" goto help 15 | 16 | if "%1" == "help" ( 17 | :help 18 | echo.Please use `make ^` where ^ is one of 19 | echo. html to make standalone HTML files 20 | echo. dirhtml to make HTML files named index.html in directories 21 | echo. singlehtml to make a single large HTML file 22 | echo. pickle to make pickle files 23 | echo. json to make JSON files 24 | echo. htmlhelp to make HTML files and a HTML help project 25 | echo. qthelp to make HTML files and a qthelp project 26 | echo. devhelp to make HTML files and a Devhelp project 27 | echo. epub to make an epub 28 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 29 | echo. text to make text files 30 | echo. man to make manual pages 31 | echo. changes to make an overview over all changed/added/deprecated items 32 | echo. linkcheck to check all external links for integrity 33 | echo. doctest to run all doctests embedded in the documentation if enabled 34 | goto end 35 | ) 36 | 37 | if "%1" == "clean" ( 38 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 39 | del /q /s %BUILDDIR%\* 40 | goto end 41 | ) 42 | 43 | if "%1" == "html" ( 44 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 45 | if errorlevel 1 exit /b 1 46 | echo. 47 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 48 | goto end 49 | ) 50 | 51 | if "%1" == "dirhtml" ( 52 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 53 | if errorlevel 1 exit /b 1 54 | echo. 55 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 56 | goto end 57 | ) 58 | 59 | if "%1" == "singlehtml" ( 60 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 61 | if errorlevel 1 exit /b 1 62 | echo. 63 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 64 | goto end 65 | ) 66 | 67 | if "%1" == "pickle" ( 68 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 69 | if errorlevel 1 exit /b 1 70 | echo. 71 | echo.Build finished; now you can process the pickle files. 72 | goto end 73 | ) 74 | 75 | if "%1" == "json" ( 76 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 77 | if errorlevel 1 exit /b 1 78 | echo. 79 | echo.Build finished; now you can process the JSON files. 80 | goto end 81 | ) 82 | 83 | if "%1" == "htmlhelp" ( 84 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 85 | if errorlevel 1 exit /b 1 86 | echo. 87 | echo.Build finished; now you can run HTML Help Workshop with the ^ 88 | .hhp project file in %BUILDDIR%/htmlhelp. 89 | goto end 90 | ) 91 | 92 | if "%1" == "qthelp" ( 93 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 94 | if errorlevel 1 exit /b 1 95 | echo. 96 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 97 | .qhcp project file in %BUILDDIR%/qthelp, like this: 98 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\SeleniumPythonBindings.qhcp 99 | echo.To view the help file: 100 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\SeleniumPythonBindings.ghc 101 | goto end 102 | ) 103 | 104 | if "%1" == "devhelp" ( 105 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 106 | if errorlevel 1 exit /b 1 107 | echo. 108 | echo.Build finished. 109 | goto end 110 | ) 111 | 112 | if "%1" == "epub" ( 113 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 117 | goto end 118 | ) 119 | 120 | if "%1" == "latex" ( 121 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 122 | if errorlevel 1 exit /b 1 123 | echo. 124 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 125 | goto end 126 | ) 127 | 128 | if "%1" == "text" ( 129 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 130 | if errorlevel 1 exit /b 1 131 | echo. 132 | echo.Build finished. The text files are in %BUILDDIR%/text. 133 | goto end 134 | ) 135 | 136 | if "%1" == "man" ( 137 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 138 | if errorlevel 1 exit /b 1 139 | echo. 140 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 141 | goto end 142 | ) 143 | 144 | if "%1" == "changes" ( 145 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 146 | if errorlevel 1 exit /b 1 147 | echo. 148 | echo.The overview file is in %BUILDDIR%/changes. 149 | goto end 150 | ) 151 | 152 | if "%1" == "linkcheck" ( 153 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 154 | if errorlevel 1 exit /b 1 155 | echo. 156 | echo.Link check complete; look for any errors in the above output ^ 157 | or in %BUILDDIR%/linkcheck/output.txt. 158 | goto end 159 | ) 160 | 161 | if "%1" == "doctest" ( 162 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 163 | if errorlevel 1 exit /b 1 164 | echo. 165 | echo.Testing of doctests in the sources finished, look at the ^ 166 | results in %BUILDDIR%/doctest/output.txt. 167 | goto end 168 | ) 169 | 170 | :end 171 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | selenium 2 | Sphinx 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup(name="selenium-python-docs", 4 | version="0.0.0", 5 | description="", 6 | packages=find_packages(), 7 | include_package_data=True, 8 | zip_safe=False, 9 | author='Baiju Muthukadan', 10 | install_requires=['setuptools', 11 | 'selenium', 12 | 'Sphinx', 13 | ], 14 | ) 15 | -------------------------------------------------------------------------------- /source/_static/README.txt: -------------------------------------------------------------------------------- 1 | Static files 2 | -------------------------------------------------------------------------------- /source/_static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baijum/selenium-python/d1b9190381c789fb9db8842084bf10bc857dd971/source/_static/logo.png -------------------------------------------------------------------------------- /source/api.rst: -------------------------------------------------------------------------------- 1 | .. _api: 2 | 3 | WebDriver API 4 | ------------- 5 | 6 | .. note:: 7 | 8 | This is not an official documentation. Official API documentation is 9 | available `here 10 | `_. 11 | 12 | This chapter covers all the interfaces of Selenium WebDriver. 13 | 14 | 15 | **Recommended Import Style** 16 | 17 | The API definitions in this chapter show the absolute location of classes. 18 | However, the recommended import style is as given below:: 19 | 20 | from selenium import webdriver 21 | 22 | Then, you can access the classes like this:: 23 | 24 | webdriver.Firefox 25 | webdriver.FirefoxProfile 26 | webdriver.FirefoxOptions 27 | webdriver.FirefoxService 28 | webdriver.Chrome 29 | webdriver.ChromeOptions 30 | webdriver.ChromeService 31 | webdriver.Ie 32 | webdriver.IeOptions 33 | webdriver.IeService 34 | webdriver.Edge 35 | webdriver.ChromiumEdge 36 | webdriver.EdgeOptions 37 | webdriver.EdgeService 38 | webdriver.Safari 39 | webdriver.SafariOptions 40 | webdriver.SafariService 41 | webdriver.WebKitGTK 42 | webdriver.WebKitGTKOptions 43 | webdriver.WebKitGTKService 44 | webdriver.WPEWebKit 45 | webdriver.WPEWebKitOptions 46 | webdriver.WPEWebKitService 47 | webdriver.Remote 48 | webdriver.DesiredCapabilities 49 | webdriver.ActionChains 50 | webdriver.Proxy 51 | webdriver.Keys 52 | 53 | The special keys class (``Keys``) can be imported like this:: 54 | 55 | from selenium.webdriver.common.keys import Keys 56 | 57 | The exception classes can be imported like this (Replace the ``TheNameOfTheExceptionClass`` 58 | with the actual class name given below):: 59 | 60 | from selenium.common.exceptions import [TheNameOfTheExceptionClass] 61 | 62 | **Conventions used in the API** 63 | 64 | Some attributes are callable (or methods) and others are non-callable 65 | (properties). All the callable attributes are ending with round brackets. 66 | 67 | Here is an example for property: 68 | 69 | - current_url 70 | 71 | URL of the currently loaded page. 72 | 73 | Usage:: 74 | 75 | driver.current_url 76 | 77 | Here is an example of a method: 78 | 79 | - close() 80 | 81 | Closes the current window. 82 | 83 | Usage:: 84 | 85 | driver.close() 86 | 87 | 88 | Exceptions 89 | ~~~~~~~~~~ 90 | 91 | .. automodule:: selenium.common.exceptions 92 | :members: 93 | :undoc-members: 94 | :special-members: __init__ 95 | :member-order: groupwise 96 | :show-inheritance: 97 | 98 | 99 | Action Chains 100 | ~~~~~~~~~~~~~ 101 | 102 | .. automodule:: selenium.webdriver.common.action_chains 103 | :members: 104 | :undoc-members: 105 | :special-members: __init__ 106 | :member-order: groupwise 107 | :show-inheritance: 108 | 109 | 110 | Alerts 111 | ~~~~~~ 112 | 113 | .. automodule:: selenium.webdriver.common.alert 114 | :members: 115 | :undoc-members: 116 | :special-members: __init__ 117 | :member-order: groupwise 118 | :show-inheritance: 119 | 120 | 121 | Special Keys 122 | ~~~~~~~~~~~~ 123 | 124 | .. automodule:: selenium.webdriver.common.keys 125 | :members: 126 | :undoc-members: 127 | :special-members: __init__ 128 | :member-order: groupwise 129 | :show-inheritance: 130 | 131 | 132 | Locate elements By 133 | ~~~~~~~~~~~~~~~~~~ 134 | 135 | These are the attributes which can be used to locate elements. See 136 | the :ref:`locating-elements` chapter for example usages. 137 | 138 | .. automodule:: selenium.webdriver.common.by 139 | :members: 140 | :undoc-members: 141 | :special-members: __init__ 142 | :member-order: groupwise 143 | :show-inheritance: 144 | 145 | 146 | Desired Capabilities 147 | ~~~~~~~~~~~~~~~~~~~~ 148 | 149 | See the :ref:`selenium-remote-webdriver` section for example usages of desired capabilities. 150 | 151 | .. automodule:: selenium.webdriver.common.desired_capabilities 152 | :members: 153 | :undoc-members: 154 | :special-members: __init__ 155 | :member-order: groupwise 156 | :show-inheritance: 157 | 158 | Proxy 159 | ~~~~~ 160 | 161 | .. automodule:: selenium.webdriver.common.proxy 162 | :members: 163 | :undoc-members: 164 | :special-members: __init__ 165 | :member-order: groupwise 166 | :show-inheritance: 167 | 168 | 169 | Utilities 170 | ~~~~~~~~~ 171 | 172 | .. automodule:: selenium.webdriver.common.utils 173 | :members: 174 | :undoc-members: 175 | :special-members: __init__ 176 | :member-order: groupwise 177 | :show-inheritance: 178 | 179 | Service 180 | ~~~~~~~ 181 | 182 | .. automodule:: selenium.webdriver.common.service 183 | :members: 184 | :undoc-members: 185 | :special-members: __init__ 186 | :member-order: groupwise 187 | :show-inheritance: 188 | 189 | Application Cache 190 | ~~~~~~~~~~~~~~~~~ 191 | 192 | .. automodule:: selenium.webdriver.common.html5.application_cache 193 | :members: 194 | :undoc-members: 195 | :special-members: __init__ 196 | :member-order: groupwise 197 | :show-inheritance: 198 | 199 | 200 | Firefox WebDriver 201 | ~~~~~~~~~~~~~~~~~ 202 | 203 | .. automodule:: selenium.webdriver.firefox.webdriver 204 | :members: 205 | :undoc-members: 206 | :special-members: __init__ 207 | :member-order: groupwise 208 | :show-inheritance: 209 | 210 | Firefox WebDriver Options 211 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 212 | 213 | .. automodule:: selenium.webdriver.firefox.options 214 | :members: 215 | :undoc-members: 216 | :special-members: __init__ 217 | :member-order: groupwise 218 | :show-inheritance: 219 | 220 | Firefox WebDriver Profile 221 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 222 | 223 | .. automodule:: selenium.webdriver.firefox.firefox_profile 224 | :members: 225 | :undoc-members: 226 | :special-members: __init__ 227 | :member-order: groupwise 228 | :show-inheritance: 229 | 230 | Firefox WebDriver Binary 231 | ~~~~~~~~~~~~~~~~~~~~~~~~ 232 | 233 | .. automodule:: selenium.webdriver.firefox.firefox_binary 234 | :members: 235 | :undoc-members: 236 | :special-members: __init__ 237 | :member-order: groupwise 238 | :show-inheritance: 239 | 240 | Firefox WebDriver Extension Connection 241 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 242 | 243 | .. automodule:: selenium.webdriver.firefox.extension_connection 244 | :members: 245 | :undoc-members: 246 | :special-members: __init__ 247 | :member-order: groupwise 248 | :show-inheritance: 249 | 250 | Chrome WebDriver 251 | ~~~~~~~~~~~~~~~~ 252 | 253 | .. automodule:: selenium.webdriver.chrome.webdriver 254 | :members: 255 | :undoc-members: 256 | :special-members: __init__ 257 | :member-order: groupwise 258 | :show-inheritance: 259 | 260 | Chrome WebDriver Options 261 | ~~~~~~~~~~~~~~~~~~~~~~~~ 262 | 263 | .. automodule:: selenium.webdriver.chrome.options 264 | :members: 265 | :undoc-members: 266 | :special-members: __init__ 267 | :member-order: groupwise 268 | :show-inheritance: 269 | 270 | 271 | Chrome WebDriver Service 272 | ~~~~~~~~~~~~~~~~~~~~~~~~ 273 | 274 | .. automodule:: selenium.webdriver.chrome.service 275 | :members: 276 | :undoc-members: 277 | :special-members: __init__ 278 | :member-order: groupwise 279 | :show-inheritance: 280 | 281 | Remote WebDriver 282 | ~~~~~~~~~~~~~~~~ 283 | 284 | .. automodule:: selenium.webdriver.remote.webdriver 285 | :members: 286 | :undoc-members: 287 | :special-members: __init__ 288 | :member-order: groupwise 289 | :show-inheritance: 290 | 291 | Remote WebDriver WebElement 292 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 293 | 294 | .. automodule:: selenium.webdriver.remote.webelement 295 | :members: 296 | :undoc-members: 297 | :special-members: __init__ 298 | :member-order: groupwise 299 | :show-inheritance: 300 | 301 | Remote WebDriver Command 302 | ~~~~~~~~~~~~~~~~~~~~~~~~ 303 | 304 | .. automodule:: selenium.webdriver.remote.command 305 | :members: 306 | :undoc-members: 307 | :special-members: __init__ 308 | :member-order: groupwise 309 | :show-inheritance: 310 | 311 | Remote WebDriver Error Handler 312 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 313 | 314 | .. automodule:: selenium.webdriver.remote.errorhandler 315 | :members: 316 | :undoc-members: 317 | :special-members: __init__ 318 | :member-order: groupwise 319 | :show-inheritance: 320 | 321 | Remote WebDriver Mobile 322 | ~~~~~~~~~~~~~~~~~~~~~~~ 323 | 324 | .. automodule:: selenium.webdriver.remote.mobile 325 | :members: 326 | :undoc-members: 327 | :special-members: __init__ 328 | :member-order: groupwise 329 | :show-inheritance: 330 | 331 | Remote WebDriver Remote Connection 332 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 333 | 334 | .. automodule:: selenium.webdriver.remote.remote_connection 335 | :members: 336 | :undoc-members: 337 | :special-members: __init__ 338 | :member-order: groupwise 339 | :show-inheritance: 340 | 341 | Remote WebDriver Utils 342 | ~~~~~~~~~~~~~~~~~~~~~~ 343 | 344 | .. automodule:: selenium.webdriver.remote.utils 345 | :members: 346 | :undoc-members: 347 | :special-members: __init__ 348 | :member-order: groupwise 349 | :show-inheritance: 350 | 351 | 352 | Internet Explorer WebDriver 353 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 354 | 355 | .. automodule:: selenium.webdriver.ie.webdriver 356 | :members: 357 | :undoc-members: 358 | :special-members: __init__ 359 | :member-order: groupwise 360 | :show-inheritance: 361 | 362 | Safari WebDriver 363 | ~~~~~~~~~~~~~~~~ 364 | 365 | .. automodule:: selenium.webdriver.safari.webdriver 366 | :members: 367 | :undoc-members: 368 | :special-members: __init__ 369 | :member-order: groupwise 370 | :show-inheritance: 371 | 372 | Safari WebDriver Service 373 | ~~~~~~~~~~~~~~~~~~~~~~~~ 374 | 375 | .. automodule:: selenium.webdriver.safari.service 376 | :members: 377 | :undoc-members: 378 | :special-members: __init__ 379 | :member-order: groupwise 380 | :show-inheritance: 381 | 382 | Select Support 383 | ~~~~~~~~~~~~~~ 384 | 385 | .. automodule:: selenium.webdriver.support.select 386 | :members: 387 | :undoc-members: 388 | :special-members: __init__ 389 | :member-order: groupwise 390 | :show-inheritance: 391 | 392 | Wait Support 393 | ~~~~~~~~~~~~ 394 | 395 | .. automodule:: selenium.webdriver.support.wait 396 | :members: 397 | :undoc-members: 398 | :special-members: __init__ 399 | :member-order: groupwise 400 | :show-inheritance: 401 | 402 | Color Support 403 | ~~~~~~~~~~~~~ 404 | 405 | .. automodule:: selenium.webdriver.support.color 406 | :members: 407 | :undoc-members: 408 | :special-members: __init__ 409 | :member-order: groupwise 410 | :show-inheritance: 411 | 412 | Event Firing WebDriver Support 413 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 414 | 415 | .. automodule:: selenium.webdriver.support.event_firing_webdriver 416 | :members: 417 | :undoc-members: 418 | :special-members: __init__ 419 | :member-order: groupwise 420 | :show-inheritance: 421 | 422 | Abstract Event Listener Support 423 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 424 | 425 | .. automodule:: selenium.webdriver.support.abstract_event_listener 426 | :members: 427 | :undoc-members: 428 | :special-members: __init__ 429 | :member-order: groupwise 430 | :show-inheritance: 431 | 432 | Expected conditions Support 433 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 434 | 435 | .. automodule:: selenium.webdriver.support.expected_conditions 436 | :members: 437 | :undoc-members: 438 | :special-members: __init__ 439 | :member-order: groupwise 440 | :show-inheritance: 441 | -------------------------------------------------------------------------------- /source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Selenium Python Bindings documentation build configuration file, created by 4 | # sphinx-quickstart on Thu Aug 11 15:17:34 2011. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | #sys.path.insert(0, os.path.abspath('.')) 20 | 21 | # -- General configuration ----------------------------------------------------- 22 | 23 | # If your documentation needs a minimal Sphinx version, state it here. 24 | #needs_sphinx = '1.0' 25 | 26 | # Add any Sphinx extension module names here, as strings. They can be extensions 27 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 28 | extensions = ['sphinx.ext.todo', 'sphinx.ext.autodoc'] 29 | 30 | # Add any paths that contain templates here, relative to this directory. 31 | templates_path = ['_templates'] 32 | 33 | # The suffix of source filenames. 34 | source_suffix = '.rst' 35 | 36 | # The encoding of source files. 37 | #source_encoding = 'utf-8-sig' 38 | 39 | # The master toctree document. 40 | master_doc = 'index' 41 | 42 | # General information about the project. 43 | project = u'Selenium Python Bindings' 44 | copyright = u'2011-2024, Baiju Muthukadan' 45 | 46 | # The version info for the project you're documenting, acts as replacement for 47 | # |version| and |release|, also used in various other places throughout the 48 | # built documents. 49 | # 50 | # The short X.Y version. 51 | version = '2' 52 | # The full version, including alpha/beta/rc tags. 53 | release = '2' 54 | 55 | # The language for content autogenerated by Sphinx. Refer to documentation 56 | # for a list of supported languages. 57 | #language = None 58 | 59 | # There are two options for replacing |today|: either, you set today to some 60 | # non-false value, then it is used: 61 | #today = '' 62 | # Else, today_fmt is used as the format for a strftime call. 63 | #today_fmt = '%B %d, %Y' 64 | 65 | # List of patterns, relative to source directory, that match files and 66 | # directories to ignore when looking for source files. 67 | exclude_patterns = [] 68 | 69 | # The reST default role (used for this markup: `text`) to use for all documents. 70 | #default_role = None 71 | 72 | # If true, '()' will be appended to :func: etc. cross-reference text. 73 | #add_function_parentheses = True 74 | 75 | # If true, the current module name will be prepended to all description 76 | # unit titles (such as .. function::). 77 | #add_module_names = True 78 | 79 | # If true, sectionauthor and moduleauthor directives will be shown in the 80 | # output. They are ignored by default. 81 | #show_authors = False 82 | 83 | # The name of the Pygments (syntax highlighting) style to use. 84 | pygments_style = 'sphinx' 85 | 86 | # A list of ignored prefixes for module index sorting. 87 | #modindex_common_prefix = [] 88 | 89 | 90 | # -- Options for HTML output --------------------------------------------------- 91 | 92 | # The theme to use for HTML and HTML Help pages. See the documentation for 93 | # a list of builtin themes. 94 | html_theme = 'alabaster' 95 | 96 | html_sidebars = { 97 | '**': [ 98 | 'about.html', 99 | 'navigation.html', 100 | 'relations.html', 101 | 'searchbox.html', 102 | 'donate.html', 103 | ] 104 | } 105 | 106 | # Theme options are theme-specific and customize the look and feel of a theme 107 | # further. For a list of options available for each theme, see the 108 | # documentation. 109 | #html_theme_options = {} 110 | 111 | html_theme_options = { 112 | 'logo': 'logo.png', 113 | 'show_related': 'true', 114 | } 115 | 116 | # Add any paths that contain custom themes here, relative to this directory. 117 | #html_theme_path = [] 118 | 119 | # The name for this set of Sphinx documents. If None, it defaults to 120 | # " v documentation". 121 | #html_title = None 122 | 123 | # A shorter title for the navigation bar. Default is the same as html_title. 124 | #html_short_title = None 125 | 126 | # The name of an image file (relative to this directory) to place at the top 127 | # of the sidebar. 128 | #html_logo = None 129 | 130 | # The name of an image file (within the static path) to use as favicon of the 131 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 132 | # pixels large. 133 | #html_favicon = None 134 | 135 | # Add any paths that contain custom static files (such as style sheets) here, 136 | # relative to this directory. They are copied after the builtin static files, 137 | # so a file named "default.css" will overwrite the builtin "default.css". 138 | html_static_path = ['_static'] 139 | 140 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 141 | # using the given strftime format. 142 | #html_last_updated_fmt = '%b %d, %Y' 143 | 144 | # If true, SmartyPants will be used to convert quotes and dashes to 145 | # typographically correct entities. 146 | #html_use_smartypants = True 147 | 148 | # Custom sidebar templates, maps document names to template names. 149 | #html_sidebars = {} 150 | 151 | # Additional templates that should be rendered to pages, maps page names to 152 | # template names. 153 | #html_additional_pages = {} 154 | 155 | # If false, no module index is generated. 156 | #html_domain_indices = True 157 | 158 | # If false, no index is generated. 159 | #html_use_index = True 160 | 161 | # If true, the index is split into individual pages for each letter. 162 | #html_split_index = False 163 | 164 | # If true, links to the reST sources are added to the pages. 165 | #html_show_sourcelink = True 166 | 167 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 168 | #html_show_sphinx = True 169 | 170 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 171 | #html_show_copyright = True 172 | 173 | # If true, an OpenSearch description file will be output, and all pages will 174 | # contain a tag referring to it. The value of this option must be the 175 | # base URL from which the finished HTML is served. 176 | #html_use_opensearch = '' 177 | 178 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 179 | #html_file_suffix = None 180 | 181 | # Output file base name for HTML help builder. 182 | htmlhelp_basename = 'SeleniumPythonBindings' 183 | 184 | 185 | # -- Options for LaTeX output -------------------------------------------------- 186 | 187 | # The paper size ('letter' or 'a4'). 188 | #latex_paper_size = 'letter' 189 | 190 | # The font size ('10pt', '11pt' or '12pt'). 191 | #latex_font_size = '10pt' 192 | 193 | # Grouping the document tree into LaTeX files. List of tuples 194 | # (source start file, target name, title, author, documentclass [howto/manual]). 195 | latex_documents = [ 196 | ('index', 'SeleniumPythonBindings.tex', u'Selenium Python Bindings', 197 | u'Baiju Muthukadan', 'manual'), 198 | ] 199 | 200 | # The name of an image file (relative to this directory) to place at the top of 201 | # the title page. 202 | #latex_logo = None 203 | 204 | # For "manual" documents, if this is true, then toplevel headings are parts, 205 | # not chapters. 206 | #latex_use_parts = False 207 | 208 | # If true, show page references after internal links. 209 | #latex_show_pagerefs = False 210 | 211 | # If true, show URL addresses after external links. 212 | #latex_show_urls = False 213 | 214 | # Additional stuff for the LaTeX preamble. 215 | #latex_preamble = '' 216 | 217 | # Documents to append as an appendix to all manuals. 218 | #latex_appendices = [] 219 | 220 | # If false, no module index is generated. 221 | #latex_domain_indices = True 222 | 223 | 224 | # -- Options for manual page output -------------------------------------------- 225 | 226 | # One entry per manual page. List of tuples 227 | # (source start file, name, description, authors, manual section). 228 | man_pages = [ 229 | ('index', 'seleniumpythonbindings', u'Selenium Python Bindings Documentation', 230 | [u'Baiju Muthukadan'], 1) 231 | ] 232 | 233 | 234 | # -- Options for Epub output --------------------------------------------------- 235 | 236 | # Bibliographic Dublin Core info. 237 | epub_title = u'Selenium Python Bindings' 238 | epub_author = u'Baiju Muthukadan' 239 | epub_publisher = u'Baiju Muthukadan' 240 | epub_copyright = u'2011-2018, Baiju Muthukadan' 241 | 242 | # The language of the text. It defaults to the language option 243 | # or en if the language is not set. 244 | #epub_language = '' 245 | 246 | # The scheme of the identifier. Typical schemes are ISBN or URL. 247 | #epub_scheme = '' 248 | 249 | # The unique identifier of the text. This can be a ISBN number 250 | # or the project homepage. 251 | #epub_identifier = '' 252 | 253 | # A unique identification for the text. 254 | #epub_uid = '' 255 | 256 | # HTML files that should be inserted before the pages created by sphinx. 257 | # The format is a list of tuples containing the path and title. 258 | #epub_pre_files = [] 259 | 260 | # HTML files that should be inserted after the pages created by sphinx. 261 | # The format is a list of tuples containing the path and title. 262 | #epub_post_files = [] 263 | 264 | # A list of files that should not be packed into the epub file. 265 | #epub_exclude_files = [] 266 | 267 | # The depth of the table of contents in toc.ncx. 268 | #epub_tocdepth = 3 269 | 270 | # Allow duplicate toc entries. 271 | #epub_tocdup = True 272 | 273 | 274 | # Example configuration for intersphinx: refer to the Python standard library. 275 | #intersphinx_mapping = {'http://docs.python.org/': None} 276 | -------------------------------------------------------------------------------- /source/faq.rst: -------------------------------------------------------------------------------- 1 | .. _faq: 2 | 3 | Appendix: Frequently Asked Questions 4 | ------------------------------------ 5 | 6 | Another FAQ: https://github.com/SeleniumHQ/selenium/wiki/Frequently-Asked-Questions 7 | 8 | How to use ChromeDriver ? 9 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 10 | 11 | Download the latest `chromedriver from download page 12 | `_. Unzip the 13 | file:: 14 | 15 | unzip chromedriver_linux64.zip 16 | 17 | You should see a ``chromedriver`` executable. Now you can create an instance of 18 | Chrome WebDriver like this:: 19 | 20 | driver = webdriver.Chrome(executable_path="/path/to/chromedriver") 21 | 22 | The rest of the example should work as given in other documentation. 23 | 24 | Does Selenium 2 support XPath 2.0 ? 25 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 26 | 27 | Ref: http://seleniumhq.org/docs/03_webdriver.html#how-xpath-works-in-webdriver 28 | 29 | Selenium delegates XPath queries down to the browser's own XPath engine, so 30 | Selenium support XPath supports whatever the browser supports. In browsers 31 | which don't have native XPath engines (IE 6,7,8), Selenium supports XPath 1.0 32 | only. 33 | 34 | 35 | How to scroll down to the bottom of a page ? 36 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 37 | 38 | Ref: http://blog.varunin.com/2011/08/scrolling-on-pages-using-selenium.html 39 | 40 | You can use the `execute_script` method to execute javascript on the loaded 41 | page. So, you can call the JavaScript API to scroll to the bottom or any other 42 | position of a page. 43 | 44 | Here is an example to scroll to the bottom of a page:: 45 | 46 | driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") 47 | 48 | The `window `_ object in DOM has 49 | a `scrollTo `_ method to 50 | scroll to any position of an opened window. The `scrollHeight 51 | `_ is a common property for all 52 | elements. The `document.body.scrollHeight` will give the height of the entire 53 | body of the page. 54 | 55 | How to auto save files using custom Firefox profile ? 56 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 57 | 58 | Ref: http://stackoverflow.com/questions/1176348/access-to-file-download-dialog-in-firefox 59 | 60 | Ref: http://blog.codecentric.de/en/2010/07/file-downloads-with-selenium-mission-impossible/ 61 | 62 | The first step is to identify the type of file you want to auto save. 63 | 64 | To identify the content type you want to download automatically, you 65 | can use `curl `_:: 66 | 67 | curl -I URL | grep "Content-Type" 68 | 69 | Another way to find content type is using the `requests 70 | `_ module, you can use it like this:: 71 | 72 | import requests 73 | content_type = requests.head('http://www.python.org').headers['content-type'] 74 | print(content_type) 75 | 76 | Once the content type is identified, you can use it to set the firefox profile 77 | preference: ``browser.helperApps.neverAsk.saveToDisk`` 78 | 79 | Here is an example:: 80 | 81 | import os 82 | 83 | from selenium import webdriver 84 | 85 | fp = webdriver.FirefoxProfile() 86 | 87 | fp.set_preference("browser.download.folderList",2) 88 | fp.set_preference("browser.download.manager.showWhenStarting",False) 89 | fp.set_preference("browser.download.dir", os.getcwd()) 90 | fp.set_preference("browser.helperApps.neverAsk.saveToDisk", "application/octet-stream") 91 | 92 | browser = webdriver.Firefox(firefox_profile=fp) 93 | browser.get("http://pypi.python.org/pypi/selenium") 94 | browser.find_element_by_partial_link_text("selenium-2").click() 95 | 96 | In the above example, ``application/octet-stream`` is used as the content type. 97 | 98 | The ``browser.download.dir`` option specify the directory where you want to 99 | download the files. 100 | 101 | How to upload files into file inputs ? 102 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 103 | 104 | Select the ```` element and call the ``send_keys()`` method 105 | passing the file path, either the path relative to the test script, or an 106 | absolute path. Keep in mind the differences in path names between Windows and 107 | Unix systems. 108 | 109 | How to use firebug with Firefox ? 110 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 111 | 112 | First download the Firebug XPI file, later you call the ``add_extension`` method 113 | available for the firefox profile:: 114 | 115 | from selenium import webdriver 116 | 117 | fp = webdriver.FirefoxProfile() 118 | 119 | fp.add_extension(extension='firebug-1.8.4.xpi') 120 | fp.set_preference("extensions.firebug.currentVersion", "1.8.4") #Avoid startup screen 121 | browser = webdriver.Firefox(firefox_profile=fp) 122 | 123 | How to take screenshot of the current window ? 124 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 125 | 126 | Use the `save_screenshot` method provided by the webdriver:: 127 | 128 | from selenium import webdriver 129 | 130 | driver = webdriver.Firefox() 131 | driver.get('http://www.python.org/') 132 | driver.save_screenshot('screenshot.png') 133 | driver.quit() 134 | 135 | -------------------------------------------------------------------------------- /source/getting-started.rst: -------------------------------------------------------------------------------- 1 | .. _getting-started: 2 | 3 | Getting Started 4 | --------------- 5 | 6 | Simple Usage 7 | ~~~~~~~~~~~~ 8 | 9 | If you have installed Selenium Python bindings, you can start using it from 10 | Python like this. 11 | 12 | :: 13 | 14 | from selenium import webdriver 15 | from selenium.webdriver.common.keys import Keys 16 | from selenium.webdriver.common.by import By 17 | 18 | driver = webdriver.Firefox() 19 | driver.get("http://www.python.org") 20 | assert "Python" in driver.title 21 | elem = driver.find_element(By.NAME, "q") 22 | elem.clear() 23 | elem.send_keys("pycon") 24 | elem.send_keys(Keys.RETURN) 25 | assert "No results found." not in driver.page_source 26 | driver.close() 27 | 28 | The above script can be saved into a file (eg:- `python_org_search.py`), then it 29 | can be run like this:: 30 | 31 | python python_org_search.py 32 | 33 | The `python` which you are running should have the `selenium` module installed. 34 | 35 | Example Explained 36 | ~~~~~~~~~~~~~~~~~ 37 | 38 | The `selenium.webdriver` module provides all the WebDriver implementations. 39 | Currently supported WebDriver implementations are Firefox, Chrome, IE and 40 | Remote. The `Keys` class provide keys in the keyboard like RETURN, F1, ALT etc. 41 | The `By` class is used to locate elements within a document. 42 | 43 | :: 44 | 45 | from selenium import webdriver 46 | from selenium.webdriver.common.keys import Keys 47 | from selenium.webdriver.common.by import By 48 | 49 | Next, the instance of Firefox WebDriver is created. 50 | 51 | :: 52 | 53 | driver = webdriver.Firefox() 54 | 55 | The `driver.get` method will navigate to a page given by the URL. WebDriver 56 | will wait until the page has fully loaded (that is, the "onload" event has 57 | fired) before returning control to your test or script. *Be aware that if your 58 | page uses a lot of AJAX on load then WebDriver may not know when it has 59 | completely loaded*:: 60 | 61 | driver.get("http://www.python.org") 62 | 63 | The next line is an assertion to confirm that title has the word "Python" in it:: 64 | 65 | assert "Python" in driver.title 66 | 67 | WebDriver offers a number of ways to find elements using the 68 | `find_element` method. For example, the input text element can be located 69 | by its `name` attribute using the `find_element` method and using By.NAME as its first parameter. 70 | A detailed explanation of finding elements is available in the :ref:`locating-elements` 71 | chapter:: 72 | 73 | elem = driver.find_element(By.NAME, "q") 74 | 75 | Next, we are sending keys, this is similar to entering keys using your keyboard. 76 | Special keys can be sent using the `Keys` class imported from 77 | `selenium.webdriver.common.keys`. To be safe, we'll first clear any 78 | pre-populated text in the input field (e.g. "Search") so it doesn't affect our 79 | search results:: 80 | 81 | elem.clear() 82 | elem.send_keys("pycon") 83 | elem.send_keys(Keys.RETURN) 84 | 85 | After submission of the page, you should get the result if there is any. To 86 | ensure that some results are found, make an assertion:: 87 | 88 | assert "No results found." not in driver.page_source 89 | 90 | Finally, the browser window is closed. You can also call the `quit` method instead 91 | of `close`. The `quit` method will exit the browser whereas `close` will close one 92 | tab, but if just one tab was open, by default most browsers will exit entirely.:: 93 | 94 | driver.close() 95 | 96 | 97 | Using Selenium to write tests 98 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 99 | 100 | Selenium is mostly used for writing test cases. The `selenium` package itself 101 | doesn't provide a testing tool/framework. You can write test cases using 102 | Python's unittest module. Alternatively, you may consider `pytest 103 | `_ for writing tests. 104 | 105 | In this chapter, we use `unittest` as the framework of choice. Here is the 106 | modified example which uses the unittest module. This is a test for the `python.org` 107 | search functionality:: 108 | 109 | import unittest 110 | from selenium import webdriver 111 | from selenium.webdriver.common.keys import Keys 112 | from selenium.webdriver.common.by import By 113 | 114 | class PythonOrgSearch(unittest.TestCase): 115 | 116 | def setUp(self): 117 | self.driver = webdriver.Firefox() 118 | 119 | def test_search_in_python_org(self): 120 | driver = self.driver 121 | driver.get("http://www.python.org") 122 | self.assertIn("Python", driver.title) 123 | elem = driver.find_element(By.NAME, "q") 124 | elem.send_keys("pycon") 125 | elem.send_keys(Keys.RETURN) 126 | self.assertNotIn("No results found.", driver.page_source) 127 | 128 | 129 | def tearDown(self): 130 | self.driver.close() 131 | 132 | if __name__ == "__main__": 133 | unittest.main() 134 | 135 | 136 | You can run the above test case from a shell like this:: 137 | 138 | python test_python_org_search.py 139 | . 140 | ---------------------------------------------------------------------- 141 | Ran 1 test in 15.566s 142 | 143 | OK 144 | 145 | The above result shows that the test has been successfully completed. 146 | 147 | Note: To run the above test in IPython or Jupyter, you should pass a couple of 148 | arguments to the `main` function as shown below:: 149 | 150 | unittest.main(argv=['first-arg-is-ignored'], exit=False) 151 | 152 | 153 | 154 | Walkthrough of the example 155 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 156 | 157 | Initially, all the basic modules required are imported. The `unittest 158 | `_ module is a built-in Python 159 | module based on Java's JUnit. This module provides the framework for organizing the 160 | test cases. The `selenium.webdriver` module provides all the WebDriver 161 | implementations. Currently supported WebDriver implementations are: Firefox, 162 | Chrome, IE and Remote. The `Keys` class provides keys in the keyboard like 163 | RETURN, F1, ALT etc. The `By` class is used to locate elements within a document. 164 | 165 | :: 166 | 167 | import unittest 168 | from selenium import webdriver 169 | from selenium.webdriver.common.keys import Keys 170 | from selenium.webdriver.common.by import By 171 | 172 | The test case class is inherited from `unittest.TestCase`. Inheriting from 173 | the `TestCase` class is the way to tell `unittest` module that this is a test case:: 174 | 175 | class PythonOrgSearch(unittest.TestCase): 176 | 177 | 178 | The `setUp` method is part of initialization. This method will get called before every 179 | test function which you are going to write in this test case class. Here you 180 | are creating an instance of a Firefox WebDriver. 181 | 182 | :: 183 | 184 | def setUp(self): 185 | self.driver = webdriver.Firefox() 186 | 187 | This is the test case method. The test case method should always start with 188 | characters `test`. The first line inside this method creates a local reference 189 | to the driver object created in `setUp` method. 190 | 191 | :: 192 | 193 | def test_search_in_python_org(self): 194 | driver = self.driver 195 | 196 | The `driver.get` method will navigate to a page given by the URL. WebDriver 197 | will wait until the page has fully loaded (that is, the "onload" event has 198 | fired) before returning control to your test or script. *Be aware that if your 199 | page uses a lot of AJAX on load then WebDriver may not know when it has 200 | completely loaded*:: 201 | 202 | driver.get("http://www.python.org") 203 | 204 | The next line is an assertion to confirm that title has the word "Python" in it:: 205 | 206 | self.assertIn("Python", driver.title) 207 | 208 | 209 | WebDriver offers a number of ways to find elements using the 210 | `find_element` method. For example, the input text element can be located 211 | by its `name` attribute using the `find_element` method. Detailed 212 | explanation of finding elements is available in the :ref:`locating-elements` 213 | chapter:: 214 | 215 | elem = driver.find_element(By.NAME, "q") 216 | 217 | Next, we are sending keys, this is similar to entering keys using your keyboard. 218 | Special keys can be sent using the `Keys` class imported from 219 | `selenium.webdriver.common.keys`:: 220 | 221 | elem.send_keys("pycon") 222 | elem.send_keys(Keys.RETURN) 223 | 224 | After submission of the page, you should get the result as per search if there 225 | is any. To ensure that some results are found, make an assertion:: 226 | 227 | self.assertNotIn("No results found.", driver.page_source) 228 | 229 | The `tearDown` method will get called after every test method. This is a place 230 | to do all cleanup actions. In the current method, the browser window is closed. 231 | You can also call the `quit` method instead of `close`. The `quit` method will exit the 232 | entire browser, whereas `close` will close a tab, but if it is the only tab 233 | opened, by default most browsers will exit entirely.:: 234 | 235 | def tearDown(self): 236 | self.driver.close() 237 | 238 | Final lines are some boiler plate code to run the test suite:: 239 | 240 | if __name__ == "__main__": 241 | unittest.main() 242 | 243 | .. _selenium-remote-webdriver: 244 | 245 | Using Selenium with remote WebDriver 246 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 247 | 248 | To use the remote WebDriver, you should have the Selenium server running. To run 249 | the server, use this command:: 250 | 251 | java -jar selenium-server-standalone-2.x.x.jar 252 | 253 | While running the Selenium server, you could see a message looking like this:: 254 | 255 | 15:43:07.541 INFO - RemoteWebDriver instances should connect to: http://127.0.0.1:4444/wd/hub 256 | 257 | The above line says that you can use this URL for connecting to the remote 258 | WebDriver. Here are some examples:: 259 | 260 | from selenium import webdriver 261 | 262 | driver = webdriver.Remote( 263 | command_executor='http://127.0.0.1:4444/wd/hub', 264 | options=webdriver.ChromeOptions() 265 | ) 266 | 267 | driver = webdriver.Remote( 268 | command_executor='http://127.0.0.1:4444/wd/hub', 269 | options=webdriver.FirefoxOptions() 270 | ) 271 | -------------------------------------------------------------------------------- /source/index.rst: -------------------------------------------------------------------------------- 1 | ******************** 2 | Selenium with Python 3 | ******************** 4 | 5 | :Author: `Baiju Muthukadan `_ 6 | :License: This document is licensed under a 7 | `Creative Commons Attribution-ShareAlike 4.0 International License `_. 8 | 9 | .. note:: 10 | 11 | This is not an official documentation. If you would like to contribute to 12 | this documentation, you can `fork this project in GitHub and send pull 13 | requests `_. You can also send 14 | your feedback to my email: baiju.m.mail AT gmail DOT com. So far 60+ 15 | community members have contributed to this project (See the closed pull 16 | requests). I encourage contributors to add more sections and make it an 17 | awesome documentation! If you know any translation of this document, please 18 | send a PR to update the below list. 19 | 20 | **Translations:** 21 | 22 | - `Chinese `_ 23 | - `Japanese `_ 24 | 25 | 26 | .. toctree:: 27 | :numbered: 28 | 29 | installation 30 | getting-started 31 | navigating 32 | locating-elements 33 | waits 34 | page-objects 35 | api 36 | faq 37 | 38 | 39 | Indices and tables 40 | ================== 41 | 42 | * :ref:`genindex` 43 | * :ref:`modindex` 44 | * :ref:`search` 45 | -------------------------------------------------------------------------------- /source/installation.rst: -------------------------------------------------------------------------------- 1 | .. _installation: 2 | 3 | Installation 4 | ------------ 5 | 6 | Introduction 7 | ~~~~~~~~~~~~ 8 | 9 | Selenium Python bindings provides a simple API to write functional/acceptance 10 | tests using Selenium WebDriver. Through Selenium Python API you can access all 11 | functionalities of Selenium WebDriver in an intuitive way. 12 | 13 | Selenium Python bindings provide a convenient API to access Selenium WebDrivers 14 | like Firefox, Ie, Chrome, Remote etc. The current supported Python versions are 15 | 3.5 and above. 16 | 17 | This documentation explains Selenium 2 WebDriver API. Selenium 1 / Selenium RC 18 | API is not covered here. 19 | 20 | 21 | Installing Python bindings for Selenium 22 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 23 | 24 | Use `pip `_ to install the selenium 25 | package. Python 3 has pip available in the `standard library 26 | `_. Using `pip`, you can 27 | install selenium like this:: 28 | 29 | pip install selenium 30 | 31 | You may consider using `virtualenv `_ to 32 | create isolated Python environments. Python 3 has `venv 33 | `_ which is almost the same as 34 | virtualenv. 35 | 36 | You can also download Python bindings for Selenium from the `PyPI page for 37 | selenium package `_. and install 38 | manually. 39 | 40 | 41 | Instructions for Windows users 42 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 43 | 44 | 1. Install Python 3 using the `MSI available in python.org download page 45 | `_. 46 | 47 | 2. Start a command prompt using the ``cmd.exe`` program and run the ``pip`` 48 | command as given below to install `selenium`. 49 | 50 | :: 51 | 52 | C:\Python39\Scripts\pip.exe install selenium 53 | 54 | Now you can run your test scripts using Python. For example, if you have 55 | created a Selenium based script and saved it inside 56 | ``C:\my_selenium_script.py``, you can run it like this:: 57 | 58 | C:\Python39\python.exe C:\my_selenium_script.py 59 | 60 | 61 | Installing from Git sources 62 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 63 | 64 | To build Selenium Python from the source code, clone `the official repository 65 | `_. It contains the source code for 66 | all official Selenium flavors, like Python, Java, Ruby and others. The Python 67 | code resides in the ``/py`` directory. To build, you will also need the `Bazel 68 | `_ build system. 69 | 70 | .. note:: 71 | 72 | Currently, as Selenium gets near to the 4.0.0 release, it requires Bazel 3.2.0 73 | (`Install instructions 74 | `_), even though 3.3.0 75 | is already available. 76 | 77 | To build a Wheel from the sources, run the following command from the repository 78 | root:: 79 | 80 | bazel //py:selenium-wheel 81 | 82 | This command will prepare the source code with some preprocessed JS files needed 83 | by some webdriver modules and build the ``.whl`` package inside the 84 | ``./bazel-bin/py/`` directory. Afterwards, you can use ``pip`` to install it. 85 | 86 | Drivers 87 | ~~~~~~~ 88 | 89 | Selenium requires a driver to interface with the chosen browser. Firefox, for 90 | example, requires `geckodriver 91 | `_, which needs to be installed 92 | before the below examples can be run. Make sure it's in your `PATH`, e. g., 93 | place it in `/usr/bin` or `/usr/local/bin`. 94 | 95 | Failure to observe this step will give you an error 96 | `selenium.common.exceptions.WebDriverException: Message: 'geckodriver' 97 | executable needs to be in PATH.` 98 | 99 | Other supported browsers will have their own drivers available. Links to some of 100 | the more popular browser drivers follow. 101 | 102 | +--------------+-----------------------------------------------------------------------+ 103 | | **Chrome**: | https://sites.google.com/chromium.org/driver/ | 104 | +--------------+-----------------------------------------------------------------------+ 105 | | **Edge**: | https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/ | 106 | +--------------+-----------------------------------------------------------------------+ 107 | | **Firefox**: | https://github.com/mozilla/geckodriver/releases | 108 | +--------------+-----------------------------------------------------------------------+ 109 | | **Safari**: | https://webkit.org/blog/6900/webdriver-support-in-safari-10/ | 110 | +--------------+-----------------------------------------------------------------------+ 111 | 112 | For more information about driver installation, please refer the `official 113 | documentation 114 | `_. 115 | 116 | Starting from version ``4.6.0`` (November 4, 2022) 117 | selenium comes with **Selenium Manager** packed in distribution. 118 | 119 | **Selenium Manager** is a new tool that helps to get a working environment 120 | to run **Selenium** out of the box: 121 | 122 | * automatically discovers, downloads, and caches the ``drivers`` 123 | required by Selenium when these ``drivers`` are unavailable; 124 | * automatically discovers, downloads, and caches the ``browsers`` 125 | driven with Selenium (Chrome, Firefox, and Edge) 126 | when these ``browsers`` are not installed in the local system. 127 | 128 | For example, to see the result of **Selenium Manager** work 129 | just run any selenium script without previous driver setup 130 | and explore `~/.cache/selenium`. 131 | 132 | More about **Selenium Manager** you can read in the 133 | `documentation `_ 134 | and 135 | `blog `_. 136 | 137 | Downloading Selenium server 138 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 139 | 140 | .. note:: 141 | 142 | **The Selenium server is only required if you want to use the remote 143 | WebDriver**. See the :ref:`selenium-remote-webdriver` section for more 144 | details. If you are a beginner learning Selenium, you can skip this section 145 | and proceed with next chapter. 146 | 147 | Selenium server is a Java program. Java Runtime Environment (JRE) 1.6 or newer 148 | version is recommended to run Selenium server. 149 | 150 | You can download Selenium server 2.x from the `download page of selenium website 151 | `_. The file name should be something like 152 | this: ``selenium-server-standalone-2.x.x.jar``. You can always download the 153 | latest 2.x version of Selenium server. 154 | 155 | If Java Runtime Environment (JRE) is not installed in your system, you can 156 | download the `JRE from the Oracle website 157 | `_. If you 158 | are using a GNU/Linux system and have root access in your system, you can also 159 | use your operating system instructions to install JRE. 160 | 161 | If `java` command is available in the PATH (environment variable), you can start 162 | the Selenium server using this command:: 163 | 164 | java -jar selenium-server-standalone-2.x.x.jar 165 | 166 | Replace `2.x.x` with the actual version of Selenium server you downloaded from 167 | the site. 168 | 169 | If JRE is installed as a non-root user and/or if it is not available in the PATH 170 | (environment variable), you can type the relative or absolute path to the `java` 171 | command. Similarly, you can provide a relative or absolute path to Selenium 172 | server jar file. Then, the command will look something like this:: 173 | 174 | /path/to/java -jar /path/to/selenium-server-standalone-2.x.x.jar 175 | -------------------------------------------------------------------------------- /source/locating-elements.rst: -------------------------------------------------------------------------------- 1 | .. _locating-elements: 2 | 3 | Locating Elements 4 | ----------------- 5 | 6 | There are various strategies to locate elements in a page. You can use the most 7 | appropriate one for your case. Selenium provides the following method to 8 | locate elements in a page: 9 | 10 | - `find_element` 11 | 12 | **To find multiple elements (these methods will return a list):** 13 | 14 | - `find_elements` 15 | 16 | 17 | Example usage:: 18 | 19 | from selenium.webdriver.common.by import By 20 | 21 | driver.find_element(By.XPATH, '//button[text()="Some text"]') 22 | driver.find_elements(By.XPATH, '//button') 23 | 24 | The attributes available for the `By` class are used to locate elements on a page. 25 | These are the attributes available for `By` class:: 26 | 27 | ID = "id" 28 | NAME = "name" 29 | XPATH = "xpath" 30 | LINK_TEXT = "link text" 31 | PARTIAL_LINK_TEXT = "partial link text" 32 | TAG_NAME = "tag name" 33 | CLASS_NAME = "class name" 34 | CSS_SELECTOR = "css selector" 35 | 36 | The 'By' class is used to specify which attribute is used to locate elements on a page. 37 | These are the various ways the attributes are used to locate elements on a page:: 38 | 39 | find_element(By.ID, "id") 40 | find_element(By.NAME, "name") 41 | find_element(By.XPATH, "xpath") 42 | find_element(By.LINK_TEXT, "link text") 43 | find_element(By.PARTIAL_LINK_TEXT, "partial link text") 44 | find_element(By.TAG_NAME, "tag name") 45 | find_element(By.CLASS_NAME, "class name") 46 | find_element(By.CSS_SELECTOR, "css selector") 47 | 48 | If you want to locate several elements with the same attribute replace find_element with find_elements. 49 | 50 | 51 | Locating by Id 52 | ~~~~~~~~~~~~~~ 53 | 54 | Use this when you know the `id` attribute of an element. With this strategy, 55 | the first element with a matching `id` attribute will be returned. If no 56 | element has a matching `id` attribute, a ``NoSuchElementException`` will be 57 | raised. 58 | 59 | For instance, consider this page source:: 60 | 61 | 62 | 63 |
64 | 65 | 66 | 67 |
68 | 69 | 70 | 71 | The form element can be located like this:: 72 | 73 | login_form = driver.find_element(By.ID, 'loginForm') 74 | 75 | 76 | Locating by Name 77 | ~~~~~~~~~~~~~~~~ 78 | 79 | Use this when you know the `name` attribute of an element. With this strategy, 80 | the first element with a matching `name` attribute will be returned. If no 81 | element has a matching `name` attribute, a ``NoSuchElementException`` will be 82 | raised. 83 | 84 | For instance, consider this page source:: 85 | 86 | 87 | 88 |
89 | 90 | 91 | 92 | 93 |
94 | 95 | 96 | 97 | The username & password elements can be located like this:: 98 | 99 | username = driver.find_element(By.NAME, 'username') 100 | password = driver.find_element(By.NAME, 'password') 101 | 102 | This will give the "Login" button as it occurs before the "Clear" button:: 103 | 104 | continue_button = driver.find_element(By.NAME, 'continue') 105 | 106 | 107 | Locating by XPath 108 | ~~~~~~~~~~~~~~~~~ 109 | 110 | XPath is the language used for locating nodes in an XML document. As HTML can 111 | be an implementation of XML (XHTML), Selenium users can leverage this powerful 112 | language to target elements in their web applications. XPath supports the 113 | simple methods of locating by id or name attributes and extends them by opening 114 | up all sorts of new possibilities such as locating the third checkbox on the 115 | page. 116 | 117 | One of the main reasons for using XPath is when you don't have a suitable id or 118 | name attribute for the element you wish to locate. You can use XPath to either 119 | locate the element in absolute terms (not advised), or relative to an element 120 | that does have an id or name attribute. XPath locators can also be used to 121 | specify elements via attributes other than id and name. 122 | 123 | Absolute XPaths contain the location of all elements from the root (html) and as 124 | a result are likely to fail with only the slightest adjustment to the 125 | application. By finding a nearby element with an id or name attribute (ideally 126 | a parent element) you can locate your target element based on the relationship. 127 | This is much less likely to change and can make your tests more robust. 128 | 129 | For instance, consider this page source:: 130 | 131 | 132 | 133 |
134 | 135 | 136 | 137 | 138 |
139 | 140 | 141 | 142 | The form elements can be located like this:: 143 | 144 | login_form = driver.find_element(By.XPATH, "/html/body/form[1]") 145 | login_form = driver.find_element(By.XPATH, "//form[1]") 146 | login_form = driver.find_element(By.XPATH, "//form[@id='loginForm']") 147 | 148 | 149 | 1. Absolute path (would break if the HTML was changed only slightly) 150 | 151 | 2. First form element in the HTML 152 | 153 | 3. The form element with attribute `id` set to `loginForm` 154 | 155 | The username element can be located like this:: 156 | 157 | username = driver.find_element(By.XPATH, "//form[input/@name='username']") 158 | username = driver.find_element(By.XPATH, "//form[@id='loginForm']/input[1]") 159 | username = driver.find_element(By.XPATH, "//input[@name='username']") 160 | 161 | 1. First form element with an input child element with `name` set to `username` 162 | 163 | 2. First input child element of the form element with attribute `id` set to 164 | `loginForm` 165 | 166 | 3. First input element with attribute `name` set to `username` 167 | 168 | The "Clear" button element can be located like this:: 169 | 170 | clear_button = driver.find_element(By.XPATH, "//input[@name='continue'][@type='button']") 171 | clear_button = driver.find_element(By.XPATH, "//form[@id='loginForm']/input[4]") 172 | 173 | 174 | 1. Input with attribute `name` set to `continue` and attribute `type` set to 175 | `button` 176 | 177 | 2. Fourth input child element of the form element with attribute `id` set to 178 | `loginForm` 179 | 180 | These examples cover some basics, but in order to learn more, the following 181 | references are recommended: 182 | 183 | * `W3Schools XPath Tutorial `_ 184 | * `W3C XPath Recommendation `_ 185 | * `XPath Tutorial 186 | `_ 187 | - with interactive examples. 188 | 189 | Here is a couple of very useful Add-ons that can assist in discovering the XPath 190 | of an element: 191 | 192 | * `xPath Finder 193 | `_ - 194 | Plugin to get the elements xPath. 195 | * `XPath Helper 196 | `_ - 197 | for Google Chrome 198 | 199 | 200 | Locating Hyperlinks by Link Text 201 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 202 | 203 | Use this when you know the link text used within an anchor tag. With this 204 | strategy, the first element with the link text matching the provided value will 205 | be returned. If no element has a matching link text attribute, a 206 | ``NoSuchElementException`` will be raised. 207 | 208 | For instance, consider this page source:: 209 | 210 | 211 | 212 |

Are you sure you want to do this?

213 | Continue 214 | Cancel 215 | 216 | 217 | 218 | The continue.html link can be located like this:: 219 | 220 | continue_link = driver.find_element(By.LINK_TEXT, 'Continue') 221 | continue_link = driver.find_element(By.PARTIAL_LINK_TEXT, 'Conti') 222 | 223 | 224 | Locating Elements by Tag Name 225 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 226 | 227 | Use this when you want to locate an element by tag name. With this strategy, 228 | the first element with the given tag name will be returned. If no element has a 229 | matching tag name, a ``NoSuchElementException`` will be raised. 230 | 231 | For instance, consider this page source:: 232 | 233 | 234 | 235 |

Welcome

236 |

Site content goes here.

237 | 238 | 239 | 240 | The heading (h1) element can be located like this:: 241 | 242 | heading1 = driver.find_element(By.TAG_NAME, 'h1') 243 | 244 | 245 | Locating Elements by Class Name 246 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 247 | 248 | Use this when you want to locate an element by class name. With this strategy, 249 | the first element with the matching class name attribute will be returned. If 250 | no element has a matching class name attribute, a ``NoSuchElementException`` 251 | will be raised. 252 | 253 | For instance, consider this page source:: 254 | 255 | 256 | 257 |

Site content goes here.

258 | 259 | 260 | 261 | The "p" element can be located like this:: 262 | 263 | content = driver.find_element(By.CLASS_NAME, 'content') 264 | 265 | Locating Elements by CSS Selectors 266 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 267 | 268 | Use this when you want to locate an element using `CSS selector 269 | `_ 270 | syntax. With this strategy, the first element matching the given CSS selector 271 | will be returned. If no element matches the provided CSS selector, a 272 | ``NoSuchElementException`` will be raised. 273 | 274 | For instance, consider this page source:: 275 | 276 | 277 | 278 |

Site content goes here.

279 | 280 | 281 | 282 | The "p" element can be located like this:: 283 | 284 | content = driver.find_element(By.CSS_SELECTOR, 'p.content') 285 | 286 | `Sauce Labs has good documentation 287 | `_ on CSS 288 | selectors. 289 | -------------------------------------------------------------------------------- /source/navigating.rst: -------------------------------------------------------------------------------- 1 | .. _navigating: 2 | 3 | Navigating 4 | ---------- 5 | 6 | The first thing you'll want to do with WebDriver is navigate to a link. The 7 | normal way to do this is by calling ``get`` method: 8 | 9 | :: 10 | 11 | driver.get("http://www.google.com") 12 | 13 | WebDriver will wait until the page has fully loaded (that is, the ``onload`` 14 | event has fired) before returning control to your test or script. *Be aware 15 | that if your page uses a lot of AJAX on load then WebDriver may not know when it 16 | has completely loaded*. If you need to ensure such pages are fully loaded then 17 | you can use :ref:`waits `. 18 | 19 | Interacting with the page 20 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 21 | 22 | Just being able to go to places isn't terribly useful. What we'd really like to 23 | do is to interact with the pages, or, more specifically, the HTML elements 24 | within a page. First of all, we need to find one. WebDriver offers a number of 25 | ways to find elements. For example, given an element defined as:: 26 | 27 | 28 | 29 | you could find it using any of:: 30 | 31 | element = driver.find_element(By.ID, "passwd-id") 32 | element = driver.find_element(By.NAME, "passwd") 33 | element = driver.find_element(By.XPATH, "//input[@id='passwd-id']") 34 | element = driver.find_element(By.CSS_SELECTOR, "input#passwd-id") 35 | 36 | You can also look for a link by its text, but be careful! The text must be an 37 | exact match! You should also be careful when using `XPATH in WebDriver`. If 38 | there's more than one element that matches the query, then only the first will 39 | be returned. If nothing can be found, a ``NoSuchElementException`` will be 40 | raised. 41 | 42 | .. TODO: Is this following paragraph correct ? 43 | 44 | WebDriver has an "Object-based" API; we represent all types of elements using 45 | the same interface. This means that although you may see a lot of possible 46 | methods you could invoke when you hit your IDE's auto-complete key combination, 47 | not all of them will make sense or be valid. Don't worry! WebDriver will 48 | attempt to do the Right Thing, and if you call a method that makes no sense 49 | ("setSelected()" on a "meta" tag, for example) an exception will be raised. 50 | 51 | So, you've got an element. What can you do with it? First of all, you may want 52 | to enter some text into a text field:: 53 | 54 | element.send_keys("some text") 55 | 56 | You can simulate pressing the arrow keys by using the "Keys" class:: 57 | 58 | element.send_keys(" and some", Keys.ARROW_DOWN) 59 | 60 | It is possible to call `send_keys` on any element, which makes it possible to 61 | test keyboard shortcuts such as those used on GMail. A side-effect of this is 62 | that typing something into a text field won't automatically clear it. Instead, 63 | what you type will be appended to what's already there. You can easily clear 64 | the contents of a text field or textarea with the `clear` method:: 65 | 66 | element.clear() 67 | 68 | 69 | Filling in forms 70 | ~~~~~~~~~~~~~~~~ 71 | 72 | We've already seen how to enter text into a textarea or text field, but what 73 | about the other elements? You can "toggle" the state of the drop down, and you 74 | can use "setSelected" to set something like an `OPTION` tag selected. Dealing 75 | with `SELECT` tags isn't too bad:: 76 | 77 | element = driver.find_element(By.XPATH, "//select[@name='name']") 78 | all_options = element.find_elements(By.TAG_NAME, "option") 79 | for option in all_options: 80 | print("Value is: %s" % option.get_attribute("value")) 81 | option.click() 82 | 83 | This will find the first "SELECT" element on the page, and cycle through each of 84 | its OPTIONs in turn, printing out their values, and selecting each in turn. 85 | 86 | As you can see, this isn't the most efficient way of dealing with SELECT 87 | elements. WebDriver's support classes include one called a "Select", which 88 | provides useful methods for interacting with these:: 89 | 90 | from selenium.webdriver.support.ui import Select 91 | select = Select(driver.find_element(By.NAME, 'name')) 92 | select.select_by_index(index) 93 | select.select_by_visible_text("text") 94 | select.select_by_value(value) 95 | 96 | 97 | WebDriver also provides features for deselecting all the selected options:: 98 | 99 | select = Select(driver.find_element(By.ID, 'id')) 100 | select.deselect_all() 101 | 102 | This will deselect all OPTIONs from that particular SELECT on the page. 103 | 104 | Suppose in a test, we need the list of all default selected options, Select 105 | class provides a property method that returns a list:: 106 | 107 | select = Select(driver.find_element(By.XPATH, "//select[@name='name']")) 108 | all_selected_options = select.all_selected_options 109 | 110 | To get all available options:: 111 | 112 | options = select.options 113 | 114 | Once you've finished filling out the form, you probably want to submit it. One 115 | way to do this would be to find the "submit" button and click it:: 116 | 117 | # Assume the button has the ID "submit" :) 118 | driver.find_element(By.ID, "submit").click() 119 | 120 | Alternatively, WebDriver has the convenience method "submit" on every element. 121 | If you call this on an element within a form, WebDriver will walk up the DOM 122 | until it finds the enclosing form and then calls submit on that. If the element 123 | isn't in a form, then the ``NoSuchElementException`` will be raised:: 124 | 125 | element.submit() 126 | 127 | 128 | Drag and drop 129 | ~~~~~~~~~~~~~ 130 | 131 | You can use drag and drop, either moving an element by a certain amount, or on 132 | to another element:: 133 | 134 | element = driver.find_element(By.NAME, "source") 135 | target = driver.find_element(By.NAME, "target") 136 | 137 | from selenium.webdriver import ActionChains 138 | action_chains = ActionChains(driver) 139 | action_chains.drag_and_drop(element, target).perform() 140 | 141 | 142 | Moving between windows and frames 143 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 144 | 145 | It's rare for a modern web application not to have any frames or to be 146 | constrained to a single window. WebDriver supports moving between named windows 147 | using the "switch_to.window" method:: 148 | 149 | driver.switch_to.window("windowName") 150 | 151 | All calls to ``driver`` will now be interpreted as being directed to the 152 | particular window. But how do you know the window's name? Take a look at the 153 | javascript or link that opened it:: 154 | 155 | Click here to open a new window 156 | 157 | Alternatively, you can pass a "window handle" to the "switch_to.window()" 158 | method. Knowing this, it's possible to iterate over every open window like so:: 159 | 160 | for handle in driver.window_handles: 161 | driver.switch_to.window(handle) 162 | 163 | You can also swing from frame to frame (or into iframes):: 164 | 165 | driver.switch_to.frame("frameName") 166 | 167 | It's possible to access subframes by separating the path with a dot, and you can 168 | specify the frame by its index too. That is:: 169 | 170 | driver.switch_to.frame("frameName.0.child") 171 | 172 | would go to the frame named "child" of the first subframe of the frame called 173 | "frameName". **All frames are evaluated as if from *top*.** 174 | 175 | Once we are done with working on frames, we will have to come back to the parent 176 | frame which can be done using:: 177 | 178 | driver.switch_to.default_content() 179 | 180 | 181 | Popup dialogs 182 | ~~~~~~~~~~~~~ 183 | 184 | Selenium WebDriver has built-in support for handling popup dialog boxes. After 185 | you've triggered action that would open a popup, you can access the alert with 186 | the following:: 187 | 188 | alert = driver.switch_to.alert 189 | 190 | This will return the currently open alert object. With this object, you can now 191 | accept, dismiss, read its contents or even type into a prompt. This interface 192 | works equally well on alerts, confirms, prompts. Refer to the API documentation 193 | for more information. 194 | 195 | 196 | Navigation: history and location 197 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 198 | 199 | Earlier, we covered navigating to a page using the "get" command ( 200 | ``driver.get("http://www.example.com")``). As you've seen, WebDriver has a 201 | number of smaller, task-focused interfaces, and navigation is a useful task. To 202 | navigate to a page, you can use `get` method:: 203 | 204 | driver.get("http://www.example.com") 205 | 206 | To move backward and forward in your browser's history:: 207 | 208 | driver.forward() 209 | driver.back() 210 | 211 | Please be aware that this functionality depends entirely on the underlying 212 | driver. It's just possible that something unexpected may happen when you call 213 | these methods if you're used to the behavior of one browser over another. 214 | 215 | 216 | Cookies 217 | ~~~~~~~ 218 | 219 | Before moving to the next section of the tutorial, you may be interested in 220 | understanding how to use cookies. First of all, you need to be on the domain 221 | that the cookie will be valid for: 222 | 223 | :: 224 | 225 | # Go to the correct domain 226 | driver.get("http://www.example.com") 227 | 228 | # Now set the cookie. This one's valid for the entire domain 229 | cookie = {'name' : 'foo', 'value' : 'bar'} 230 | driver.add_cookie(cookie) 231 | 232 | # And now output all the available cookies for the current URL 233 | driver.get_cookies() 234 | -------------------------------------------------------------------------------- /source/page-objects.rst: -------------------------------------------------------------------------------- 1 | .. _page-objects: 2 | 3 | Page Objects 4 | ------------ 5 | 6 | This chapter is a tutorial introduction to the Page Objects design pattern. A 7 | page object represents an area where the test interacts within the web 8 | application user interface. 9 | 10 | Benefits of using page object pattern: 11 | 12 | * Easy to read test cases 13 | * Creating reusable code that can share across multiple test cases 14 | * Reducing the amount of duplicated code 15 | * If the user interface changes, the fix needs changes in only one place 16 | 17 | 18 | Test case 19 | ~~~~~~~~~ 20 | 21 | Here is a test case that searches for a word on the `python.org` website and 22 | ensures some results. The following section will introduce the `page` module 23 | where the page objects will be defined. 24 | 25 | :: 26 | 27 | import unittest 28 | from selenium import webdriver 29 | import page 30 | 31 | class PythonOrgSearch(unittest.TestCase): 32 | """A sample test class to show how page object works""" 33 | 34 | def setUp(self): 35 | self.driver = webdriver.Firefox() 36 | self.driver.get("http://www.python.org") 37 | 38 | def test_search_in_python_org(self): 39 | """Tests python.org search feature. Searches for the word "pycon" then 40 | verified that some results show up. Note that it does not look for 41 | any particular text in search results page. This test verifies that 42 | the results were not empty.""" 43 | 44 | #Load the main page. In this case the home page of Python.org. 45 | main_page = page.MainPage(self.driver) 46 | #Checks if the word "Python" is in title 47 | self.assertTrue(main_page.is_title_matches(), "python.org title doesn't match.") 48 | #Sets the text of search textbox to "pycon" 49 | main_page.search_text_element = "pycon" 50 | main_page.click_go_button() 51 | search_results_page = page.SearchResultsPage(self.driver) 52 | #Verifies that the results page is not empty 53 | self.assertTrue(search_results_page.is_results_found(), "No results found.") 54 | 55 | def tearDown(self): 56 | self.driver.close() 57 | 58 | if __name__ == "__main__": 59 | unittest.main() 60 | 61 | 62 | Page object classes 63 | ~~~~~~~~~~~~~~~~~~~ 64 | 65 | The page object pattern intends to create an object for each part of a web page. 66 | This technique helps build a separation between the test code and the actual 67 | code that interacts with the web page. 68 | 69 | The ``page.py`` will look like this:: 70 | 71 | from element import BasePageElement 72 | from locators import MainPageLocators 73 | 74 | class SearchTextElement(BasePageElement): 75 | """This class gets the search text from the specified locator""" 76 | 77 | #The locator for search box where search string is entered 78 | locator = 'q' 79 | 80 | 81 | class BasePage(object): 82 | """Base class to initialize the base page that will be called from all 83 | pages""" 84 | 85 | def __init__(self, driver): 86 | self.driver = driver 87 | 88 | 89 | class MainPage(BasePage): 90 | """Home page action methods come here. I.e. Python.org""" 91 | 92 | #Declares a variable that will contain the retrieved text 93 | search_text_element = SearchTextElement() 94 | 95 | def is_title_matches(self): 96 | """Verifies that the hardcoded text "Python" appears in page title""" 97 | 98 | return "Python" in self.driver.title 99 | 100 | def click_go_button(self): 101 | """Triggers the search""" 102 | 103 | element = self.driver.find_element(*MainPageLocators.GO_BUTTON) 104 | element.click() 105 | 106 | 107 | class SearchResultsPage(BasePage): 108 | """Search results page action methods come here""" 109 | 110 | def is_results_found(self): 111 | # Probably should search for this text in the specific page 112 | # element, but as for now it works fine 113 | return "No results found." not in self.driver.page_source 114 | 115 | 116 | Page elements 117 | ~~~~~~~~~~~~~ 118 | 119 | The ``element.py`` will look like this:: 120 | 121 | from selenium.webdriver.common.by import By 122 | from selenium.webdriver.support.ui import WebDriverWait 123 | 124 | 125 | class BasePageElement(object): 126 | """Base page class that is initialized on every page object class.""" 127 | 128 | def __set__(self, obj, value): 129 | """Sets the text to the value supplied""" 130 | 131 | driver = obj.driver 132 | WebDriverWait(driver, 100).until( 133 | lambda driver: driver.find_element(By.NAME, self.locator)) 134 | driver.find_element(By.NAME, self.locator).clear() 135 | driver.find_element(By.NAME, self.locator).send_keys(value) 136 | 137 | def __get__(self, obj, owner): 138 | """Gets the text of the specified object""" 139 | 140 | driver = obj.driver 141 | WebDriverWait(driver, 100).until( 142 | lambda driver: driver.find_element(By.NAME, self.locator)) 143 | element = driver.find_element(By.NAME, self.locator) 144 | return element.get_attribute("value") 145 | 146 | 147 | Locators 148 | ~~~~~~~~ 149 | 150 | One of the practices is to separate the locator strings from the place where 151 | they are getting used. In this example, locators of the same page belong to the 152 | same class. 153 | 154 | The ``locators.py`` will look like this:: 155 | 156 | from selenium.webdriver.common.by import By 157 | 158 | class MainPageLocators(object): 159 | """A class for main page locators. All main page locators should come here""" 160 | 161 | GO_BUTTON = (By.ID, 'submit') 162 | 163 | class SearchResultsPageLocators(object): 164 | """A class for search results locators. All search results locators should 165 | come here""" 166 | 167 | pass 168 | -------------------------------------------------------------------------------- /source/waits.rst: -------------------------------------------------------------------------------- 1 | .. _waits: 2 | 3 | Waits 4 | ----- 5 | 6 | These days, most of the web apps are using AJAX techniques. When a page is 7 | loaded by the browser, the elements within that page may load at different time 8 | intervals. This makes locating elements difficult: if an element is not yet 9 | present in the DOM, a locate function will raise an `ElementNotVisibleException` 10 | exception. Using waits, we can solve this issue. Waiting provides some slack 11 | between actions performed - mostly locating an element or any other operation 12 | with the element. 13 | 14 | Selenium Webdriver provides two types of waits - implicit & explicit. An 15 | explicit wait makes WebDriver wait for a certain condition to occur before 16 | proceeding further with execution. An implicit wait makes WebDriver poll the 17 | DOM for a certain amount of time when trying to locate an element. 18 | 19 | 20 | Explicit Waits 21 | ~~~~~~~~~~~~~~ 22 | 23 | An explicit wait is a code you define to wait for a certain condition to occur 24 | before proceeding further in the code. The extreme case of this is 25 | time.sleep(), which sets the condition to an exact time period to wait. There 26 | are some convenience methods provided that help you write code that will wait 27 | only as long as required. WebDriverWait in combination with ExpectedCondition 28 | is one way this can be accomplished. 29 | 30 | :: 31 | 32 | from selenium import webdriver 33 | from selenium.webdriver.common.by import By 34 | from selenium.webdriver.support.wait import WebDriverWait 35 | from selenium.webdriver.support import expected_conditions as EC 36 | 37 | driver = webdriver.Firefox() 38 | driver.get("http://somedomain/url_that_delays_loading") 39 | try: 40 | element = WebDriverWait(driver, 10).until( 41 | EC.presence_of_element_located((By.ID, "myDynamicElement")) 42 | ) 43 | finally: 44 | driver.quit() 45 | 46 | 47 | In the code above, Selenium will wait for a maximum of 10 seconds for an element 48 | matching the given criteria to be found. If no element is found in that time, a 49 | TimeoutException is thrown. By default, WebDriverWait calls the 50 | ExpectedCondition every 500 milliseconds until it returns success. 51 | ExpectedCondition will return `true` (Boolean) in case of success or `not null` 52 | if it fails to locate an element. 53 | 54 | **Expected Conditions** 55 | 56 | There are some common conditions that are frequently of use when automating web 57 | browsers. Listed below are the names of each. Selenium Python binding provides 58 | some `convenience methods 59 | `_ 60 | so you don't have to code an expected_condition class yourself or create your 61 | own utility package for them. 62 | 63 | - title_is 64 | - title_contains 65 | - presence_of_element_located 66 | - visibility_of_element_located 67 | - visibility_of 68 | - presence_of_all_elements_located 69 | - text_to_be_present_in_element 70 | - text_to_be_present_in_element_value 71 | - frame_to_be_available_and_switch_to_it 72 | - invisibility_of_element_located 73 | - element_to_be_clickable 74 | - staleness_of 75 | - element_to_be_selected 76 | - element_located_to_be_selected 77 | - element_selection_state_to_be 78 | - element_located_selection_state_to_be 79 | - alert_is_present 80 | 81 | :: 82 | 83 | from selenium.webdriver.support import expected_conditions as EC 84 | 85 | wait = WebDriverWait(driver, 10) 86 | element = wait.until(EC.element_to_be_clickable((By.ID, 'someid'))) 87 | 88 | The expected_conditions module contains a set of predefined conditions to use 89 | with WebDriverWait. 90 | 91 | **Custom Wait Conditions** 92 | 93 | You can also create custom wait conditions when none of the previous convenience 94 | methods fit your requirements. A custom wait condition can be created using a 95 | class with `__call__` method which returns `False` when the condition doesn't 96 | match. 97 | 98 | 99 | :: 100 | 101 | class element_has_css_class(object): 102 | """An expectation for checking that an element has a particular css class. 103 | 104 | locator - used to find the element 105 | returns the WebElement once it has the particular css class 106 | """ 107 | def __init__(self, locator, css_class): 108 | self.locator = locator 109 | self.css_class = css_class 110 | 111 | def __call__(self, driver): 112 | element = driver.find_element(*self.locator) # Finding the referenced element 113 | if self.css_class in element.get_attribute("class"): 114 | return element 115 | else: 116 | return False 117 | 118 | # Wait until an element with id='myNewInput' has class 'myCSSClass' 119 | wait = WebDriverWait(driver, 10) 120 | element = wait.until(element_has_css_class((By.ID, 'myNewInput'), "myCSSClass")) 121 | 122 | 123 | .. note:: **polling2 Library** 124 | 125 | You may also consider using `polling2 126 | `_ 127 | library which you need to install separately. 128 | 129 | Implicit Waits 130 | ~~~~~~~~~~~~~~ 131 | 132 | An implicit wait tells WebDriver to poll the DOM for a certain amount of time 133 | when trying to find any element (or elements) not immediately available. The 134 | default setting is 0 (zero). Once set, the implicit wait is set for the life of 135 | the WebDriver object. 136 | 137 | :: 138 | 139 | from selenium import webdriver 140 | 141 | driver = webdriver.Firefox() 142 | driver.implicitly_wait(10) # seconds 143 | driver.get("http://somedomain/url_that_delays_loading") 144 | myDynamicElement = driver.find_element_by_id("myDynamicElement") 145 | --------------------------------------------------------------------------------