diff --git a/.readthedocs.yaml b/.readthedocs.yaml
new file mode 100644
index 0000000..f8d496e
--- /dev/null
+++ b/.readthedocs.yaml
@@ -0,0 +1,26 @@
+# .readthedocs.yaml
+# Read the Docs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+
+# Required
+version: 2
+
+# Set the version of Python
+build:
+ os: ubuntu-20.04
+ tools:
+ python: "3.10"
+
+# Optionally set the version of Python and requirements required to build your docs
+python:
+ install:
+ - requirements: requirements.txt
+
+# Build documentation in the docs/ directory with Sphinx
+sphinx:
+ configuration: source/conf.py
+ fail_on_warning: false
+
+# Optionally build your docs in additional formats such as PDF
+formats:
+ - pdf
diff --git a/README.rst b/README.rst
index 8008196..54d9a43 100644
--- a/README.rst
+++ b/README.rst
@@ -1,13 +1,20 @@
Selenium Python Bindings Documentation
======================================
-https://selenium-python.readthedocs.org
+https://selenium-python.readthedocs.io
-NOTE: THIS IS NOT AN OFFICIAL DOCUMENTATION
+NOTE: THIS IS NOT OFFICIAL DOCUMENTATION
-If you would like to contribute to this documentation, you can fork
-this project in Github and send pull requests. You can also send your
-feedback to my email: baiju.m.mail AT gmail DOT com.
-So far more around 20 community members has contributed to this
-project (See the closed pull requests). I encourage contributors
-to add more sections and make it a good documentation!
+This is not official documentation. If you would like to contribute to this
+documentation, you can `fork this project in GitHub and send pull requests
+`_. You can also send your feedback
+to my email: baiju.m.mail AT gmail DOT com. So far 60+ community members have
+contributed to this project (See the 'Closed' pull requests). I encourage
+contributors to add more sections to make this documentation even more awesome!
+If you know any translations of this document, or would like to create new translations,
+please send a PR to update the below list.
+
+**Translations:**
+
+- `Chinese `_
+- `Japanese `_
diff --git a/TODO.txt b/TODO.txt
deleted file mode 100644
index d571ab2..0000000
--- a/TODO.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-- Cover basics of unittest
-- XPATH (Appendix)
-- Mouse over
-- Complete: Test Design Considerations
diff --git a/source/_static/logo.png b/source/_static/logo.png
new file mode 100644
index 0000000..cd765bd
Binary files /dev/null and b/source/_static/logo.png differ
diff --git a/source/api.rst b/source/api.rst
index 7e80d2a..1118aed 100644
--- a/source/api.rst
+++ b/source/api.rst
@@ -5,17 +5,17 @@ WebDriver API
.. note::
- This is not an official documentation. Official API documentation
- is available `here
- `_.
+ This is not an official documentation. Official API documentation is
+ available `here
+ `_.
-This chapter cover all the interfaces of Selenium WebDriver.
+This chapter covers all the interfaces of Selenium WebDriver.
**Recommended Import Style**
-The API definitions in this chapter shows the absolute location of classes.
-However the recommended import style is as given below::
+The API definitions in this chapter show the absolute location of classes.
+However, the recommended import style is as given below::
from selenium import webdriver
@@ -23,42 +23,58 @@ Then, you can access the classes like this::
webdriver.Firefox
webdriver.FirefoxProfile
+ webdriver.FirefoxOptions
+ webdriver.FirefoxService
webdriver.Chrome
webdriver.ChromeOptions
+ webdriver.ChromeService
webdriver.Ie
- webdriver.Opera
- webdriver.PhantomJS
+ webdriver.IeOptions
+ webdriver.IeService
+ webdriver.Edge
+ webdriver.ChromiumEdge
+ webdriver.EdgeOptions
+ webdriver.EdgeService
+ webdriver.Safari
+ webdriver.SafariOptions
+ webdriver.SafariService
+ webdriver.WebKitGTK
+ webdriver.WebKitGTKOptions
+ webdriver.WebKitGTKService
+ webdriver.WPEWebKit
+ webdriver.WPEWebKitOptions
+ webdriver.WPEWebKitService
webdriver.Remote
webdriver.DesiredCapabilities
webdriver.ActionChains
- webdriver.TouchActions
webdriver.Proxy
+ webdriver.Keys
The special keys class (``Keys``) can be imported like this::
from selenium.webdriver.common.keys import Keys
-The exception classes can be imported like this (Replace the ``TheNameOfTheExceptionClass`` with actual class name given below)::
+The exception classes can be imported like this (Replace the ``TheNameOfTheExceptionClass``
+with the actual class name given below)::
from selenium.common.exceptions import [TheNameOfTheExceptionClass]
**Conventions used in the API**
Some attributes are callable (or methods) and others are non-callable
-(properties). All the callable attributes are ending with round
-brackets.
+(properties). All the callable attributes are ending with round brackets.
Here is an example for property:
- current_url
- URL of the current loaded page.
+ URL of the currently loaded page.
Usage::
driver.current_url
-Here is an example for a method:
+Here is an example of a method:
- close()
@@ -75,6 +91,7 @@ Exceptions
.. automodule:: selenium.common.exceptions
:members:
:undoc-members:
+ :special-members: __init__
:member-order: groupwise
:show-inheritance:
@@ -85,6 +102,7 @@ Action Chains
.. automodule:: selenium.webdriver.common.action_chains
:members:
:undoc-members:
+ :special-members: __init__
:member-order: groupwise
:show-inheritance:
@@ -95,6 +113,7 @@ Alerts
.. automodule:: selenium.webdriver.common.alert
:members:
:undoc-members:
+ :special-members: __init__
:member-order: groupwise
:show-inheritance:
@@ -105,6 +124,7 @@ Special Keys
.. automodule:: selenium.webdriver.common.keys
:members:
:undoc-members:
+ :special-members: __init__
:member-order: groupwise
:show-inheritance:
@@ -118,6 +138,7 @@ the :ref:`locating-elements` chapter for example usages.
.. automodule:: selenium.webdriver.common.by
:members:
:undoc-members:
+ :special-members: __init__
:member-order: groupwise
:show-inheritance:
@@ -130,6 +151,17 @@ See the :ref:`selenium-remote-webdriver` section for example usages of desired c
.. automodule:: selenium.webdriver.common.desired_capabilities
:members:
:undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
+
+Proxy
+~~~~~
+
+.. automodule:: selenium.webdriver.common.proxy
+ :members:
+ :undoc-members:
+ :special-members: __init__
:member-order: groupwise
:show-inheritance:
@@ -140,6 +172,27 @@ Utilities
.. automodule:: selenium.webdriver.common.utils
:members:
:undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
+
+Service
+~~~~~~~
+
+.. automodule:: selenium.webdriver.common.service
+ :members:
+ :undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
+
+Application Cache
+~~~~~~~~~~~~~~~~~
+
+.. automodule:: selenium.webdriver.common.html5.application_cache
+ :members:
+ :undoc-members:
+ :special-members: __init__
:member-order: groupwise
:show-inheritance:
@@ -150,6 +203,47 @@ Firefox WebDriver
.. automodule:: selenium.webdriver.firefox.webdriver
:members:
:undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
+
+Firefox WebDriver Options
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: selenium.webdriver.firefox.options
+ :members:
+ :undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
+
+Firefox WebDriver Profile
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: selenium.webdriver.firefox.firefox_profile
+ :members:
+ :undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
+
+Firefox WebDriver Binary
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: selenium.webdriver.firefox.firefox_binary
+ :members:
+ :undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
+
+Firefox WebDriver Extension Connection
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: selenium.webdriver.firefox.extension_connection
+ :members:
+ :undoc-members:
+ :special-members: __init__
:member-order: groupwise
:show-inheritance:
@@ -159,9 +253,30 @@ Chrome WebDriver
.. automodule:: selenium.webdriver.chrome.webdriver
:members:
:undoc-members:
+ :special-members: __init__
:member-order: groupwise
:show-inheritance:
+Chrome WebDriver Options
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: selenium.webdriver.chrome.options
+ :members:
+ :undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
+
+
+Chrome WebDriver Service
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: selenium.webdriver.chrome.service
+ :members:
+ :undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
Remote WebDriver
~~~~~~~~~~~~~~~~
@@ -169,31 +284,118 @@ Remote WebDriver
.. automodule:: selenium.webdriver.remote.webdriver
:members:
:undoc-members:
+ :special-members: __init__
:member-order: groupwise
:show-inheritance:
-
-WebElement
-~~~~~~~~~~
+Remote WebDriver WebElement
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. automodule:: selenium.webdriver.remote.webelement
:members:
:undoc-members:
+ :special-members: __init__
:member-order: groupwise
:show-inheritance:
-UI Support
-~~~~~~~~~~
+Remote WebDriver Command
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: selenium.webdriver.remote.command
+ :members:
+ :undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
+
+Remote WebDriver Error Handler
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: selenium.webdriver.remote.errorhandler
+ :members:
+ :undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
+
+Remote WebDriver Mobile
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: selenium.webdriver.remote.mobile
+ :members:
+ :undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
+
+Remote WebDriver Remote Connection
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: selenium.webdriver.remote.remote_connection
+ :members:
+ :undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
+
+Remote WebDriver Utils
+~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: selenium.webdriver.remote.utils
+ :members:
+ :undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
+
+
+Internet Explorer WebDriver
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: selenium.webdriver.ie.webdriver
+ :members:
+ :undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
+
+Safari WebDriver
+~~~~~~~~~~~~~~~~
+
+.. automodule:: selenium.webdriver.safari.webdriver
+ :members:
+ :undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
+
+Safari WebDriver Service
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: selenium.webdriver.safari.service
+ :members:
+ :undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
+
+Select Support
+~~~~~~~~~~~~~~
.. automodule:: selenium.webdriver.support.select
:members:
:undoc-members:
+ :special-members: __init__
:member-order: groupwise
:show-inheritance:
+Wait Support
+~~~~~~~~~~~~
+
.. automodule:: selenium.webdriver.support.wait
:members:
:undoc-members:
+ :special-members: __init__
:member-order: groupwise
:show-inheritance:
@@ -203,6 +405,27 @@ Color Support
.. automodule:: selenium.webdriver.support.color
:members:
:undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
+
+Event Firing WebDriver Support
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: selenium.webdriver.support.event_firing_webdriver
+ :members:
+ :undoc-members:
+ :special-members: __init__
+ :member-order: groupwise
+ :show-inheritance:
+
+Abstract Event Listener Support
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: selenium.webdriver.support.abstract_event_listener
+ :members:
+ :undoc-members:
+ :special-members: __init__
:member-order: groupwise
:show-inheritance:
@@ -212,5 +435,6 @@ Expected conditions Support
.. automodule:: selenium.webdriver.support.expected_conditions
:members:
:undoc-members:
+ :special-members: __init__
:member-order: groupwise
:show-inheritance:
diff --git a/source/conf.py b/source/conf.py
index 253f3fd..3af276f 100644
--- a/source/conf.py
+++ b/source/conf.py
@@ -41,7 +41,7 @@
# General information about the project.
project = u'Selenium Python Bindings'
-copyright = u'2011-2014, Baiju Muthukadan'
+copyright = u'2011-2024, Baiju Muthukadan'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -91,13 +91,28 @@
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
-html_theme = 'default'
+html_theme = 'alabaster'
+
+html_sidebars = {
+ '**': [
+ 'about.html',
+ 'navigation.html',
+ 'relations.html',
+ 'searchbox.html',
+ 'donate.html',
+ ]
+}
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
+html_theme_options = {
+ 'logo': 'logo.png',
+ 'show_related': 'true',
+}
+
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
@@ -222,7 +237,7 @@
epub_title = u'Selenium Python Bindings'
epub_author = u'Baiju Muthukadan'
epub_publisher = u'Baiju Muthukadan'
-epub_copyright = u'2011-2014, Baiju Muthukadan'
+epub_copyright = u'2011-2018, Baiju Muthukadan'
# The language of the text. It defaults to the language option
# or en if the language is not set.
@@ -242,7 +257,7 @@
# The format is a list of tuples containing the path and title.
#epub_pre_files = []
-# HTML files shat should be inserted after the pages created by sphinx.
+# HTML files that should be inserted after the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_post_files = []
diff --git a/source/faq.rst b/source/faq.rst
index 4266371..529b1f6 100644
--- a/source/faq.rst
+++ b/source/faq.rst
@@ -3,16 +3,16 @@
Appendix: Frequently Asked Questions
------------------------------------
-Another FAQ: https://code.google.com/p/selenium/wiki/FrequentlyAskedQuestions
+Another FAQ: https://github.com/SeleniumHQ/selenium/wiki/Frequently-Asked-Questions
How to use ChromeDriver ?
~~~~~~~~~~~~~~~~~~~~~~~~~
Download the latest `chromedriver from download page
-`_. Unzip the
+`_. Unzip the
file::
- unzip chromedriver_linux32_x.x.x.x.zip
+ unzip chromedriver_linux64.zip
You should see a ``chromedriver`` executable. Now you can create an instance of
Chrome WebDriver like this::
@@ -26,10 +26,10 @@ Does Selenium 2 support XPath 2.0 ?
Ref: http://seleniumhq.org/docs/03_webdriver.html#how-xpath-works-in-webdriver
-Selenium delegates XPath queries down to the browser's own XPath
-engine, so Selenium support XPath supports whatever the browser
-supports. In browsers which don't have native XPath engines (IE
-6,7,8), Selenium supports XPath 1.0 only.
+Selenium delegates XPath queries down to the browser's own XPath engine, so
+Selenium support XPath supports whatever the browser supports. In browsers
+which don't have native XPath engines (IE 6,7,8), Selenium supports XPath 1.0
+only.
How to scroll down to the bottom of a page ?
@@ -37,21 +37,20 @@ How to scroll down to the bottom of a page ?
Ref: http://blog.varunin.com/2011/08/scrolling-on-pages-using-selenium.html
-You can use the `execute_script` method to execute javascript on the
-loaded page. So, you can call the JavaScript API to scroll to the
-bottom or any other position of a page.
+You can use the `execute_script` method to execute javascript on the loaded
+page. So, you can call the JavaScript API to scroll to the bottom or any other
+position of a page.
Here is an example to scroll to the bottom of a page::
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
-The `window `_ object
-in DOM has a `scrollTo
-`_ method to
+The `window `_ object in DOM has
+a `scrollTo `_ method to
scroll to any position of an opened window. The `scrollHeight
-`_ is a common
-property for all elements. The `document.body.scrollHeight` will give
-the height of the entire body of the page.
+`_ is a common property for all
+elements. The `document.body.scrollHeight` will give the height of the entire
+body of the page.
How to auto save files using custom Firefox profile ?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -74,8 +73,8 @@ Another way to find content type is using the `requests
content_type = requests.head('http://www.python.org').headers['content-type']
print(content_type)
-Once the content type is identified, you can use it to set the firefox
-profile preference: ``browser.helperApps.neverAsk.saveToDisk``
+Once the content type is identified, you can use it to set the firefox profile
+preference: ``browser.helperApps.neverAsk.saveToDisk``
Here is an example::
@@ -94,24 +93,24 @@ Here is an example::
browser.get("http://pypi.python.org/pypi/selenium")
browser.find_element_by_partial_link_text("selenium-2").click()
-In the above example, ``application/octet-stream`` is used as the
-content type.
+In the above example, ``application/octet-stream`` is used as the content type.
-The ``browser.download.dir`` option specify the directory where you
-want to download the files.
+The ``browser.download.dir`` option specify the directory where you want to
+download the files.
How to upload files into file inputs ?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Select the ```` element and call the ``send_keys()`` method passing
-the file path, either the path relative to the test script, or an absolute path.
-Keep in mind the differences in path names between Windows and Unix systems.
+Select the ```` element and call the ``send_keys()`` method
+passing the file path, either the path relative to the test script, or an
+absolute path. Keep in mind the differences in path names between Windows and
+Unix systems.
How to use firebug with Firefox ?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-First download the Firebug XPI file, later you call the
-``add_extension`` method available for the firefox profile::
+First download the Firebug XPI file, later you call the ``add_extension`` method
+available for the firefox profile::
from selenium import webdriver
diff --git a/source/getting-started.rst b/source/getting-started.rst
index 5744d4e..8c71e49 100644
--- a/source/getting-started.rst
+++ b/source/getting-started.rst
@@ -6,43 +6,45 @@ Getting Started
Simple Usage
~~~~~~~~~~~~
-If you have installed Selenium Python bindings, you can start using it
-from Python like this.
+If you have installed Selenium Python bindings, you can start using it from
+Python like this.
::
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
+ from selenium.webdriver.common.by import By
driver = webdriver.Firefox()
driver.get("http://www.python.org")
assert "Python" in driver.title
- elem = driver.find_element_by_name("q")
+ elem = driver.find_element(By.NAME, "q")
+ elem.clear()
elem.send_keys("pycon")
elem.send_keys(Keys.RETURN)
assert "No results found." not in driver.page_source
driver.close()
-The above script can be saved into a file (eg:-
-`python_org_search.py`), then it can be run like this::
+The above script can be saved into a file (eg:- `python_org_search.py`), then it
+can be run like this::
python python_org_search.py
-The `python` which you are running should have the `selenium` module
-installed.
+The `python` which you are running should have the `selenium` module installed.
-Walk through of the example
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Example Explained
+~~~~~~~~~~~~~~~~~
-The `selenium.webdriver` module provides all the WebDriver
-implementations. Currently supported WebDriver implementations are
-Firefox, Chrome, Ie and Remote. The `Keys` class provide keys in the
-keyboard like RETURN, F1, ALT etc.
+The `selenium.webdriver` module provides all the WebDriver implementations.
+Currently supported WebDriver implementations are Firefox, Chrome, IE and
+Remote. The `Keys` class provide keys in the keyboard like RETURN, F1, ALT etc.
+The `By` class is used to locate elements within a document.
::
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
+ from selenium.webdriver.common.by import By
Next, the instance of Firefox WebDriver is created.
@@ -50,43 +52,44 @@ Next, the instance of Firefox WebDriver is created.
driver = webdriver.Firefox()
-The `driver.get` method will navigate to a page given by the URL.
-WebDriver will wait until the page has fully loaded (that is, the
-"onload" event has fired) before returning control to your test or
-script. It's worth noting that if your page uses a lot of AJAX on
-load then WebDriver may not know when it has completely loaded.::
+The `driver.get` method will navigate to a page given by the URL. WebDriver
+will wait until the page has fully loaded (that is, the "onload" event has
+fired) before returning control to your test or script. *Be aware that if your
+page uses a lot of AJAX on load then WebDriver may not know when it has
+completely loaded*::
driver.get("http://www.python.org")
-The next line is an assertion to confirm that title has "Python" word
-in it::
+The next line is an assertion to confirm that title has the word "Python" in it::
assert "Python" in driver.title
-WebDriver offers a number of ways to find elements using one of the
-`find_element_by_*` methods. For example, the input text element can
-be located by its `name` attribute using `find_element_by_name`
-method. Detailed explanation of finding elements is available in the
-:ref:`locating-elements` chapter::
+WebDriver offers a number of ways to find elements using the
+`find_element` method. For example, the input text element can be located
+by its `name` attribute using the `find_element` method and using By.NAME as its first parameter.
+A detailed explanation of finding elements is available in the :ref:`locating-elements`
+chapter::
- elem = driver.find_element_by_name("q")
+ elem = driver.find_element(By.NAME, "q")
-Next we are sending keys, this is similar to entering keys using your
-keyboard. Special keys can be send using `Keys` class imported from
-`selenium.webdriver.common.keys`::
+Next, we are sending keys, this is similar to entering keys using your keyboard.
+Special keys can be sent using the `Keys` class imported from
+`selenium.webdriver.common.keys`. To be safe, we'll first clear any
+pre-populated text in the input field (e.g. "Search") so it doesn't affect our
+search results::
+ elem.clear()
elem.send_keys("pycon")
elem.send_keys(Keys.RETURN)
-After submission of the page, you should get the result if there is any.
-To ensure that some results are found, make an assertion::
+After submission of the page, you should get the result if there is any. To
+ensure that some results are found, make an assertion::
assert "No results found." not in driver.page_source
-Finally, the browser window is closed. You can also call `quit`
-method instead of `close`. The `quit` will exit entire browser whereas
-close` will close one tab, but if just one tab was open, by default most
-browser will exit entirely.::
+Finally, the browser window is closed. You can also call the `quit` method instead
+of `close`. The `quit` method will exit the browser whereas `close` will close one
+tab, but if just one tab was open, by default most browsers will exit entirely.::
driver.close()
@@ -94,18 +97,19 @@ browser will exit entirely.::
Using Selenium to write tests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Selenium is mostly used for writing test cases. The `selenium`
-package itself doesn't provide a testing tool/framework. You can
-write test cases using Python's unittest module. The other options for
-a tool/framework are py.test and nose.
+Selenium is mostly used for writing test cases. The `selenium` package itself
+doesn't provide a testing tool/framework. You can write test cases using
+Python's unittest module. Alternatively, you may consider `pytest
+`_ for writing tests.
-In this chapter, we use `unittest` as the framework of choice. Here
-is the modified example which uses unittest module. This is a test
-for `python.org` search functionality::
+In this chapter, we use `unittest` as the framework of choice. Here is the
+modified example which uses the unittest module. This is a test for the `python.org`
+search functionality::
import unittest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
+ from selenium.webdriver.common.by import By
class PythonOrgSearch(unittest.TestCase):
@@ -116,10 +120,10 @@ for `python.org` search functionality::
driver = self.driver
driver.get("http://www.python.org")
self.assertIn("Python", driver.title)
- elem = driver.find_element_by_name("q")
+ elem = driver.find_element(By.NAME, "q")
elem.send_keys("pycon")
elem.send_keys(Keys.RETURN)
- assert "No results found." not in driver.page_source
+ self.assertNotIn("No results found.", driver.page_source)
def tearDown(self):
@@ -138,93 +142,95 @@ You can run the above test case from a shell like this::
OK
-The above result shows that the test has been successfully
-completed.
+The above result shows that the test has been successfully completed.
+
+Note: To run the above test in IPython or Jupyter, you should pass a couple of
+arguments to the `main` function as shown below::
+
+ unittest.main(argv=['first-arg-is-ignored'], exit=False)
+
-Walk through of the example
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Walkthrough of the example
+~~~~~~~~~~~~~~~~~~~~~~~~~~
Initially, all the basic modules required are imported. The `unittest
-`_ module is a built-in
-Python based on Java's JUnit. This module provides the framework for
-organizing the test cases. The `selenium.webdriver` module provides
-all the WebDriver implementations. Currently supported WebDriver
-implementations are Firefox, Chrome, Ie and Remote. The `Keys` class
-provide keys in the keyboard like RETURN, F1, ALT etc.
+`_ module is a built-in Python
+module based on Java's JUnit. This module provides the framework for organizing the
+test cases. The `selenium.webdriver` module provides all the WebDriver
+implementations. Currently supported WebDriver implementations are: Firefox,
+Chrome, IE and Remote. The `Keys` class provides keys in the keyboard like
+RETURN, F1, ALT etc. The `By` class is used to locate elements within a document.
::
import unittest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
+ from selenium.webdriver.common.by import By
-The test case class is inherited from `unittest.TestCase`.
-Inheriting from `TestCase` class is the way to tell `unittest` module
-that this is a test case::
+The test case class is inherited from `unittest.TestCase`. Inheriting from
+the `TestCase` class is the way to tell `unittest` module that this is a test case::
class PythonOrgSearch(unittest.TestCase):
-The `setUp` is part of initialization, this method will get called
-before every test function which you are going to write in this test
-case class. Here you are creating the instance of Firefox WebDriver.
+The `setUp` method is part of initialization. This method will get called before every
+test function which you are going to write in this test case class. Here you
+are creating an instance of a Firefox WebDriver.
::
def setUp(self):
self.driver = webdriver.Firefox()
-This is the test case method. The test case method should always start
-with characters `test`. The first line inside this method create a
-local reference to the driver object created in `setUp` method.
+This is the test case method. The test case method should always start with
+characters `test`. The first line inside this method creates a local reference
+to the driver object created in `setUp` method.
::
def test_search_in_python_org(self):
driver = self.driver
-The `driver.get` method will navigate to a page given by the URL.
-WebDriver will wait until the page has fully loaded (that is, the
-"onload" event has fired) before returning control to your test or
-script. It's worth noting that if your page uses a lot of AJAX on
-load then WebDriver may not know when it has completely loaded.::
+The `driver.get` method will navigate to a page given by the URL. WebDriver
+will wait until the page has fully loaded (that is, the "onload" event has
+fired) before returning control to your test or script. *Be aware that if your
+page uses a lot of AJAX on load then WebDriver may not know when it has
+completely loaded*::
driver.get("http://www.python.org")
-The next line is an assertion to confirm that title has "Python" word
-in it::
+The next line is an assertion to confirm that title has the word "Python" in it::
self.assertIn("Python", driver.title)
-WebDriver offers a number of ways to find elements using one of the
-`find_element_by_*` methods. For example, the input text element can
-be located by its `name` attribute using `find_element_by_name`
-method. Detailed explanation of finding elements is available in the
-:ref:`locating-elements` chapter::
+WebDriver offers a number of ways to find elements using the
+`find_element` method. For example, the input text element can be located
+by its `name` attribute using the `find_element` method. Detailed
+explanation of finding elements is available in the :ref:`locating-elements`
+chapter::
- elem = driver.find_element_by_name("q")
+ elem = driver.find_element(By.NAME, "q")
-Next we are sending keys, this is similar to entering keys using your
-keyboard. Special keys can be send using `Keys` class imported from
+Next, we are sending keys, this is similar to entering keys using your keyboard.
+Special keys can be sent using the `Keys` class imported from
`selenium.webdriver.common.keys`::
elem.send_keys("pycon")
elem.send_keys(Keys.RETURN)
-After submission of the page, you should get result as per search if
-there is any. To ensure that some results are found, make an
-assertion::
+After submission of the page, you should get the result as per search if there
+is any. To ensure that some results are found, make an assertion::
- assert "No results found." not in driver.page_source
+ self.assertNotIn("No results found.", driver.page_source)
-The `tearDown` method will get called after every test method. This
-is a place to do all cleanup actions. In the current method, the
-browser window is closed. You can also call `quit` method instead of
-`close`. The `quit` will exit the entire browser, whereas `close`
-will close a tab, but if it is the only tab opened, by default most
-browser will exit entirely.::
+The `tearDown` method will get called after every test method. This is a place
+to do all cleanup actions. In the current method, the browser window is closed.
+You can also call the `quit` method instead of `close`. The `quit` method will exit the
+entire browser, whereas `close` will close a tab, but if it is the only tab
+opened, by default most browsers will exit entirely.::
def tearDown(self):
self.driver.close()
@@ -239,39 +245,26 @@ Final lines are some boiler plate code to run the test suite::
Using Selenium with remote WebDriver
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-To use the remote WebDriver, you should have Selenium server running.
-To run the server, use this command::
+To use the remote WebDriver, you should have the Selenium server running. To run
+the server, use this command::
java -jar selenium-server-standalone-2.x.x.jar
-While running the Selenium server, you could see a message looking like
-this::
+While running the Selenium server, you could see a message looking like this::
15:43:07.541 INFO - RemoteWebDriver instances should connect to: http://127.0.0.1:4444/wd/hub
-The above line says that you can use this URL for connecting to
-remote WebDriver. Here are some examples::
-
- from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
-
- driver = webdriver.Remote(
- command_executor='http://127.0.0.1:4444/wd/hub',
- desired_capabilities=DesiredCapabilities.CHROME)
+The above line says that you can use this URL for connecting to the remote
+WebDriver. Here are some examples::
- driver = webdriver.Remote(
- command_executor='http://127.0.0.1:4444/wd/hub',
- desired_capabilities=DesiredCapabilities.OPERA)
+ from selenium import webdriver
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4444/wd/hub',
- desired_capabilities=DesiredCapabilities.HTMLUNITWITHJS)
-
-The desired capabilities is a dictionary, so instead of using the
-default dictionaries, you can specifies the values explicitly::
+ options=webdriver.ChromeOptions()
+ )
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4444/wd/hub',
- desired_capabilities={'browserName': 'htmlunit',
- 'version': '2',
- 'javascriptEnabled': True})
-
+ options=webdriver.FirefoxOptions()
+ )
diff --git a/source/glossary.rst b/source/glossary.rst
deleted file mode 100644
index c5d5290..0000000
--- a/source/glossary.rst
+++ /dev/null
@@ -1,5 +0,0 @@
-.. _glossary:
-
-Glossary
---------
-
diff --git a/source/index.rst b/source/index.rst
index 7bb6733..8507a6e 100644
--- a/source/index.rst
+++ b/source/index.rst
@@ -2,15 +2,26 @@
Selenium with Python
********************
-:Author: `Baiju Muthukadan `_
+:Author: `Baiju Muthukadan `_
:License: This document is licensed under a
`Creative Commons Attribution-ShareAlike 4.0 International License `_.
.. note::
- This is not an official documentation. Official API documentation
- is available `here
- `_.
+ This is not an official documentation. If you would like to contribute to
+ this documentation, you can `fork this project in GitHub and send pull
+ requests `_. You can also send
+ your feedback to my email: baiju.m.mail AT gmail DOT com. So far 60+
+ community members have contributed to this project (See the closed pull
+ requests). I encourage contributors to add more sections and make it an
+ awesome documentation! If you know any translation of this document, please
+ send a PR to update the below list.
+
+ **Translations:**
+
+ - `Chinese `_
+ - `Japanese `_
+
.. toctree::
:numbered:
diff --git a/source/installation.rst b/source/installation.rst
index 586e896..343bff3 100644
--- a/source/installation.rst
+++ b/source/installation.rst
@@ -6,99 +6,169 @@ Installation
Introduction
~~~~~~~~~~~~
-Selenium Python bindings provides a simple API to write
-functional/acceptance tests using Selenium WebDriver. Through
-Selenium Python API you can access all functionalities of Selenium
-WebDriver in an intuitive way.
+Selenium Python bindings provides a simple API to write functional/acceptance
+tests using Selenium WebDriver. Through Selenium Python API you can access all
+functionalities of Selenium WebDriver in an intuitive way.
-Selenium Python bindings provide a convenient API to access Selenium
-WebDrivers like Firefox, Ie, Chrome, Remote etc. The current supported
-Python versions are 2.7, 3.2, 3.3 and 3.4.
+Selenium Python bindings provide a convenient API to access Selenium WebDrivers
+like Firefox, Ie, Chrome, Remote etc. The current supported Python versions are
+3.5 and above.
-This documentation explains Selenium 2 WebDriver API. Selenium
-1 / Selenium RC API is not covered here.
+This documentation explains Selenium 2 WebDriver API. Selenium 1 / Selenium RC
+API is not covered here.
-Downloading Python bindings for Selenium
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Installing Python bindings for Selenium
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-You can download Python bindings for Selenium from the `PyPI page for
-selenium package `_. However,
-a better approach would be to use
-`pip `_ to
-install the selenium package. Python 3.4 has pip available in the
-`standard library `_.
-Using `pip`, you can install selenium like this::
+Use `pip `_ to install the selenium
+package. Python 3 has pip available in the `standard library
+`_. Using `pip`, you can
+install selenium like this::
pip install selenium
-You may consider using `virtualenv `_
-to create isolated Python environments. Python 3.4 has `pyvenv
-`_
-which is almost same as virtualenv.
-
+You may consider using `virtualenv `_ to
+create isolated Python environments. Python 3 has `venv
+`_ which is almost the same as
+virtualenv.
-Detailed instructions for Windows users
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+You can also download Python bindings for Selenium from the `PyPI page for
+selenium package `_. and install
+manually.
-.. Note::
- You should have internet connection to perform this installation.
+Instructions for Windows users
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-1. Install Python 3.4 using the `MSI available in python.org download
- page `_.
+1. Install Python 3 using the `MSI available in python.org download page
+ `_.
-2. Start a command prompt using the ``cmd.exe`` program and run the
- ``pip`` command as given below to install `selenium`.
+2. Start a command prompt using the ``cmd.exe`` program and run the ``pip``
+ command as given below to install `selenium`.
::
-
- C:\Python34\Scripts\pip.exe install selenium
-Now you can run your test scripts using Python. For example,
-if you have created a Selenium based script and saved it inside
+ C:\Python39\Scripts\pip.exe install selenium
+
+Now you can run your test scripts using Python. For example, if you have
+created a Selenium based script and saved it inside
``C:\my_selenium_script.py``, you can run it like this::
- C:\Python34\python.exe C:\my_selenium_script.py
+ C:\Python39\python.exe C:\my_selenium_script.py
+
+
+Installing from Git sources
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To build Selenium Python from the source code, clone `the official repository
+`_. It contains the source code for
+all official Selenium flavors, like Python, Java, Ruby and others. The Python
+code resides in the ``/py`` directory. To build, you will also need the `Bazel
+`_ build system.
+
+.. note::
+
+ Currently, as Selenium gets near to the 4.0.0 release, it requires Bazel 3.2.0
+ (`Install instructions
+ `_), even though 3.3.0
+ is already available.
+
+To build a Wheel from the sources, run the following command from the repository
+root::
+
+ bazel //py:selenium-wheel
+
+This command will prepare the source code with some preprocessed JS files needed
+by some webdriver modules and build the ``.whl`` package inside the
+``./bazel-bin/py/`` directory. Afterwards, you can use ``pip`` to install it.
+
+Drivers
+~~~~~~~
+
+Selenium requires a driver to interface with the chosen browser. Firefox, for
+example, requires `geckodriver
+`_, which needs to be installed
+before the below examples can be run. Make sure it's in your `PATH`, e. g.,
+place it in `/usr/bin` or `/usr/local/bin`.
+
+Failure to observe this step will give you an error
+`selenium.common.exceptions.WebDriverException: Message: 'geckodriver'
+executable needs to be in PATH.`
+
+Other supported browsers will have their own drivers available. Links to some of
+the more popular browser drivers follow.
+
++--------------+-----------------------------------------------------------------------+
+| **Chrome**: | https://sites.google.com/chromium.org/driver/ |
++--------------+-----------------------------------------------------------------------+
+| **Edge**: | https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/ |
++--------------+-----------------------------------------------------------------------+
+| **Firefox**: | https://github.com/mozilla/geckodriver/releases |
++--------------+-----------------------------------------------------------------------+
+| **Safari**: | https://webkit.org/blog/6900/webdriver-support-in-safari-10/ |
++--------------+-----------------------------------------------------------------------+
+
+For more information about driver installation, please refer the `official
+documentation
+`_.
+
+Starting from version ``4.6.0`` (November 4, 2022)
+selenium comes with **Selenium Manager** packed in distribution.
+
+**Selenium Manager** is a new tool that helps to get a working environment
+to run **Selenium** out of the box:
+
+* automatically discovers, downloads, and caches the ``drivers``
+ required by Selenium when these ``drivers`` are unavailable;
+* automatically discovers, downloads, and caches the ``browsers``
+ driven with Selenium (Chrome, Firefox, and Edge)
+ when these ``browsers`` are not installed in the local system.
+
+For example, to see the result of **Selenium Manager** work
+just run any selenium script without previous driver setup
+and explore `~/.cache/selenium`.
+More about **Selenium Manager** you can read in the
+`documentation `_
+and
+`blog `_.
Downloading Selenium server
~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. note::
- The Selenium server is only required, if you want to use the remote
- WebDriver. See the :ref:`selenium-remote-webdriver` section for
- more details. If you are a beginner learning Selenium, you can
- skip this section and proceed with next chapter.
+ **The Selenium server is only required if you want to use the remote
+ WebDriver**. See the :ref:`selenium-remote-webdriver` section for more
+ details. If you are a beginner learning Selenium, you can skip this section
+ and proceed with next chapter.
-Selenium server is a Java program. Java Runtime Environment (JRE) 1.6
-or newer version is recommended to run Selenium server.
+Selenium server is a Java program. Java Runtime Environment (JRE) 1.6 or newer
+version is recommended to run Selenium server.
-You can download Selenium server 2.x from the `download page of
-selenium website `_. The file name
-should be something like this:
-``selenium-server-standalone-2.x.x.jar``. You can always download the
+You can download Selenium server 2.x from the `download page of selenium website
+`_. The file name should be something like
+this: ``selenium-server-standalone-2.x.x.jar``. You can always download the
latest 2.x version of Selenium server.
-If Java Runtime Environment (JRE) is not installed in your system, you
-can download the `JRE from the Oracle website
-`_.
-If you are using a GNU/Linux system and have root access in your system,
-you can also use your operating system instructions to install JRE.
+If Java Runtime Environment (JRE) is not installed in your system, you can
+download the `JRE from the Oracle website
+`_. If you
+are using a GNU/Linux system and have root access in your system, you can also
+use your operating system instructions to install JRE.
-If `java` command is available in the PATH (environment variable),
-you can start the Selenium server using this command::
+If `java` command is available in the PATH (environment variable), you can start
+the Selenium server using this command::
java -jar selenium-server-standalone-2.x.x.jar
-Replace `2.x.x` with actual version of Selenium server you downloaded
-from the site.
+Replace `2.x.x` with the actual version of Selenium server you downloaded from
+the site.
-If JRE is installed as a non-root user and/or if it is
-not available in the PATH (environment variable), you can type the
-relative or absolute path to the `java` command. Similarly, you can
-provide relative or absolute path to Selenium server jar file.
-Then, the command will look something like this::
+If JRE is installed as a non-root user and/or if it is not available in the PATH
+(environment variable), you can type the relative or absolute path to the `java`
+command. Similarly, you can provide a relative or absolute path to Selenium
+server jar file. Then, the command will look something like this::
/path/to/java -jar /path/to/selenium-server-standalone-2.x.x.jar
diff --git a/source/locating-elements.rst b/source/locating-elements.rst
index 6db0186..7bc499e 100644
--- a/source/locating-elements.rst
+++ b/source/locating-elements.rst
@@ -3,34 +3,16 @@
Locating Elements
-----------------
-There are vaious strategies to locate elements in a page. You can use
-the most appropriate one for your case. Selenium provides the following
-methods to locate elements in a page:
-
-- `find_element_by_id`
-- `find_element_by_name`
-- `find_element_by_xpath`
-- `find_element_by_link_text`
-- `find_element_by_partial_link_text`
-- `find_element_by_tag_name`
-- `find_element_by_class_name`
-- `find_element_by_css_selector`
+There are various strategies to locate elements in a page. You can use the most
+appropriate one for your case. Selenium provides the following method to
+locate elements in a page:
+- `find_element`
**To find multiple elements (these methods will return a list):**
-- `find_elements_by_name`
-- `find_elements_by_xpath`
-- `find_elements_by_link_text`
-- `find_elements_by_partial_link_text`
-- `find_elements_by_tag_name`
-- `find_elements_by_class_name`
-- `find_elements_by_css_selector`
-
+- `find_elements`
-Apart from the public methods given above, there are two private
-methods which might be useful with locators in page objects. These
-are the two private methods: `find_element` and `find_elements`.
Example usage::
@@ -39,26 +21,40 @@ Example usage::
driver.find_element(By.XPATH, '//button[text()="Some text"]')
driver.find_elements(By.XPATH, '//button')
-
+The attributes available for the `By` class are used to locate elements on a page.
These are the attributes available for `By` class::
ID = "id"
+ NAME = "name"
XPATH = "xpath"
LINK_TEXT = "link text"
PARTIAL_LINK_TEXT = "partial link text"
- NAME = "name"
TAG_NAME = "tag name"
CLASS_NAME = "class name"
CSS_SELECTOR = "css selector"
+The 'By' class is used to specify which attribute is used to locate elements on a page.
+These are the various ways the attributes are used to locate elements on a page::
+
+ find_element(By.ID, "id")
+ find_element(By.NAME, "name")
+ find_element(By.XPATH, "xpath")
+ find_element(By.LINK_TEXT, "link text")
+ find_element(By.PARTIAL_LINK_TEXT, "partial link text")
+ find_element(By.TAG_NAME, "tag name")
+ find_element(By.CLASS_NAME, "class name")
+ find_element(By.CSS_SELECTOR, "css selector")
+
+If you want to locate several elements with the same attribute replace find_element with find_elements.
+
Locating by Id
~~~~~~~~~~~~~~
-Use this when you know `id` attribute of an element. With this
-strategy, the first element with the `id` attribute value matching the
-location will be returned. If no element has a matching `id`
-attribute, a ``NoSuchElementException`` will be raised.
+Use this when you know the `id` attribute of an element. With this strategy,
+the first element with a matching `id` attribute will be returned. If no
+element has a matching `id` attribute, a ``NoSuchElementException`` will be
+raised.
For instance, consider this page source::
@@ -70,22 +66,22 @@ For instance, consider this page source::
@@ -96,44 +92,41 @@ For instance, conside this page source::
-
+
The username & password elements can be located like this::
- username = driver.find_element_by_name('username')
- password = driver.find_element_by_name('password')
+ username = driver.find_element(By.NAME, 'username')
+ password = driver.find_element(By.NAME, 'password')
-This will give the "Login" button as it occur before the "Clear"
-button::
+This will give the "Login" button as it occurs before the "Clear" button::
- continue = driver.find_element_by_name('continue')
+ continue_button = driver.find_element(By.NAME, 'continue')
Locating by XPath
~~~~~~~~~~~~~~~~~
-XPath is the language used for locating nodes in an XML document. As
-HTML can be an implementation of XML (XHTML), Selenium users can
-leverage this powerful language to target elements in their web
-applications. XPath extends beyond (as well as supporting) the simple
-methods of locating by id or name attributes, and opens up all sorts
-of new possibilities such as locating the third checkbox on the page.
-
-One of the main reasons for using XPath is when you don't have a
-suitable id or name attribute for the element you wish to locate. You
-can use XPath to either locate the element in absolute terms (not
-advised), or relative to an element that does have an id or name
-attribute. XPath locators can also be used to specify elements via
-attributes other than id and name.
-
-Absolute XPaths contain the location of all elements from the root
-(html) and as a result are likely to fail with only the slightest
-adjustment to the application. By finding a nearby element with an id
-or name attribute (ideally a parent element) you can locate your
-target element based on the relationship. This is much less likely to
-change and can make your tests more robust.
-
-For instance, conside this page source::
+XPath is the language used for locating nodes in an XML document. As HTML can
+be an implementation of XML (XHTML), Selenium users can leverage this powerful
+language to target elements in their web applications. XPath supports the
+simple methods of locating by id or name attributes and extends them by opening
+up all sorts of new possibilities such as locating the third checkbox on the
+page.
+
+One of the main reasons for using XPath is when you don't have a suitable id or
+name attribute for the element you wish to locate. You can use XPath to either
+locate the element in absolute terms (not advised), or relative to an element
+that does have an id or name attribute. XPath locators can also be used to
+specify elements via attributes other than id and name.
+
+Absolute XPaths contain the location of all elements from the root (html) and as
+a result are likely to fail with only the slightest adjustment to the
+application. By finding a nearby element with an id or name attribute (ideally
+a parent element) you can locate your target element based on the relationship.
+This is much less likely to change and can make your tests more robust.
+
+For instance, consider this page source::
@@ -144,66 +137,61 @@ For instance, conside this page source::
-
+
The form elements can be located like this::
- login_form = driver.find_element_by_xpath("/html/body/form[1]")
- login_form = driver.find_element_by_xpath("//form[1]")
- login_form = driver.find_element_by_xpath("//form[@id='loginForm']")
+ login_form = driver.find_element(By.XPATH, "/html/body/form[1]")
+ login_form = driver.find_element(By.XPATH, "//form[1]")
+ login_form = driver.find_element(By.XPATH, "//form[@id='loginForm']")
1. Absolute path (would break if the HTML was changed only slightly)
2. First form element in the HTML
-3. The form element with attribute named `id` and the value `loginForm`
+3. The form element with attribute `id` set to `loginForm`
The username element can be located like this::
- username = driver.find_element_by_xpath("//form[input/@name='username']")
- username = driver.find_element_by_xpath("//form[@id='loginForm']/input[1]")
- username = driver.find_element_by_xpath("//input[@name='username']")
+ username = driver.find_element(By.XPATH, "//form[input/@name='username']")
+ username = driver.find_element(By.XPATH, "//form[@id='loginForm']/input[1]")
+ username = driver.find_element(By.XPATH, "//input[@name='username']")
-1. First form element with an input child element with attribute named
- `name` and the value `username`
+1. First form element with an input child element with `name` set to `username`
-2. First input child element of the form element with attribute named
- `id` and the value `loginForm`
+2. First input child element of the form element with attribute `id` set to
+ `loginForm`
-3. First input element with attribute named 'name' and the value
- `username`
+3. First input element with attribute `name` set to `username`
The "Clear" button element can be located like this::
- clear_button = driver.find_element_by_xpath("//input[@name='continue'][@type='button']")
- clear_button = driver.find_element_by_xpath("//form[@id='loginForm']/input[4]")
+ clear_button = driver.find_element(By.XPATH, "//input[@name='continue'][@type='button']")
+ clear_button = driver.find_element(By.XPATH, "//form[@id='loginForm']/input[4]")
-1. Input with attribute named `name` and the value `continue` and
- attribute named `type` and the value `button`
+1. Input with attribute `name` set to `continue` and attribute `type` set to
+ `button`
-2. Fourth input child element of the form element with attribute named
- `id` and value `loginForm`
+2. Fourth input child element of the form element with attribute `id` set to
+ `loginForm`
-These examples cover some basics, but in order to learn more, the
-following references are recommended:
+These examples cover some basics, but in order to learn more, the following
+references are recommended:
-* `W3Schools XPath Tutorial `_
+* `W3Schools XPath Tutorial `_
* `W3C XPath Recommendation `_
* `XPath Tutorial
`_
- with interactive examples.
-There are also a couple of very useful Add-ons that can assist in
-discovering the XPath of an element:
+Here is a couple of very useful Add-ons that can assist in discovering the XPath
+of an element:
-* `XPath Checker
- `_ -
- suggests XPath and can be used to test XPath results.
-* `Firebug `_ -
- XPath suggestions are just one of the many powerful features of this
- very useful add-on.
+* `xPath Finder
+ `_ -
+ Plugin to get the elements xPath.
* `XPath Helper
`_ -
for Google Chrome
@@ -212,10 +200,10 @@ discovering the XPath of an element:
Locating Hyperlinks by Link Text
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Use this when you know link text used within an anchor tag. With this
-strategy, the first element with the link text value matching the
-location will be returned. If no element has a matching link text
-attribute, a ``NoSuchElementException`` will be raised.
+Use this when you know the link text used within an anchor tag. With this
+strategy, the first element with the link text matching the provided value will
+be returned. If no element has a matching link text attribute, a
+``NoSuchElementException`` will be raised.
For instance, consider this page source::
@@ -225,43 +213,42 @@ For instance, consider this page source::
ContinueCancel
-
+
The continue.html link can be located like this::
- continue_link = driver.find_element_by_link_text('Continue')
- continue_link = driver.find_element_by_partial_link_text('Conti')
+ continue_link = driver.find_element(By.LINK_TEXT, 'Continue')
+ continue_link = driver.find_element(By.PARTIAL_LINK_TEXT, 'Conti')
Locating Elements by Tag Name
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Use this when you want to locate an element by tag name. With this
-strategy, the first element with the given tag name will be returned.
-If no element has a matching tag name, a ``NoSuchElementException``
-will be raised.
+Use this when you want to locate an element by tag name. With this strategy,
+the first element with the given tag name will be returned. If no element has a
+matching tag name, a ``NoSuchElementException`` will be raised.
-For instance, conside this page source::
+For instance, consider this page source::
Welcome
Site content goes here.
-
+
The heading (h1) element can be located like this::
- heading1 = driver.find_element_by_tag_name('h1')
+ heading1 = driver.find_element(By.TAG_NAME, 'h1')
Locating Elements by Class Name
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Use this when you want to locate an element by class attribute name.
-With this strategy, the first element with the matching class attribute
-name will be returned. If no element has a matching class attribute name,
-a ``NoSuchElementException`` will be raised.
+Use this when you want to locate an element by class name. With this strategy,
+the first element with the matching class name attribute will be returned. If
+no element has a matching class name attribute, a ``NoSuchElementException``
+will be raised.
For instance, consider this page source::
@@ -269,19 +256,20 @@ For instance, consider this page source::
Site content goes here.
-
+
The "p" element can be located like this::
- content = driver.find_element_by_class_name('content')
+ content = driver.find_element(By.CLASS_NAME, 'content')
Locating Elements by CSS Selectors
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Use this when you want to locate an element by CSS selector syntaxt.
-With this strategy, the first element with the matching CSS selector
-will be returned. If no element has a matching CSS selector,
-a ``NoSuchElementException`` will be raised.
+Use this when you want to locate an element using `CSS selector
+`_
+syntax. With this strategy, the first element matching the given CSS selector
+will be returned. If no element matches the provided CSS selector, a
+``NoSuchElementException`` will be raised.
For instance, consider this page source::
@@ -289,11 +277,12 @@ For instance, consider this page source::
Site content goes here.
-
+
The "p" element can be located like this::
- content = driver.find_element_by_css_selector('p.content')
+ content = driver.find_element(By.CSS_SELECTOR, 'p.content')
-`Sauce Labs has good documentation `_
-on CSS selectors.
+`Sauce Labs has good documentation
+`_ on CSS
+selectors.
diff --git a/source/navigating.rst b/source/navigating.rst
index b3660c0..9da1e0e 100644
--- a/source/navigating.rst
+++ b/source/navigating.rst
@@ -3,55 +3,53 @@
Navigating
----------
-The first thing you'll want to do with WebDriver is navigate to a
-link. The normal way to do this is by calling ``get`` method:
+The first thing you'll want to do with WebDriver is navigate to a link. The
+normal way to do this is by calling ``get`` method:
::
driver.get("http://www.google.com")
-WebDriver will wait until the page has fully loaded (that is, the
-``onload`` event has fired) before returning control to your test or
-script. It's worth noting that if your page uses a lot of AJAX on
-load then WebDriver may not know when it has completely loaded. If
-you need to ensure such pages are fully loaded then you can use
-:ref:`waits `.
+WebDriver will wait until the page has fully loaded (that is, the ``onload``
+event has fired) before returning control to your test or script. *Be aware
+that if your page uses a lot of AJAX on load then WebDriver may not know when it
+has completely loaded*. If you need to ensure such pages are fully loaded then
+you can use :ref:`waits `.
Interacting with the page
~~~~~~~~~~~~~~~~~~~~~~~~~
-Just being able to go to places isn't terribly useful. What we'd
-really like to do is to interact with the pages, or, more
-specifically, the HTML elements within a page. First of all, we need
-to find one. WebDriver offers a number of ways to find elements. For
-example, given an element defined as::
+Just being able to go to places isn't terribly useful. What we'd really like to
+do is to interact with the pages, or, more specifically, the HTML elements
+within a page. First of all, we need to find one. WebDriver offers a number of
+ways to find elements. For example, given an element defined as::
you could find it using any of::
- element = driver.find_element_by_id("passwd-id")
- element = driver.find_element_by_name("passwd")
- element = driver.find_element_by_xpath("//input[@id='passwd-id']")
+ element = driver.find_element(By.ID, "passwd-id")
+ element = driver.find_element(By.NAME, "passwd")
+ element = driver.find_element(By.XPATH, "//input[@id='passwd-id']")
+ element = driver.find_element(By.CSS_SELECTOR, "input#passwd-id")
-You can also look for a link by its text, but be careful! The text
-must be an exact match! You should also be careful when using `XPATH
-in WebDriver`. If there's more than one element that matches the
-query, then only the first will be returned. If nothing can be found,
-a ``NoSuchElementException`` will be raised.
+You can also look for a link by its text, but be careful! The text must be an
+exact match! You should also be careful when using `XPATH in WebDriver`. If
+there's more than one element that matches the query, then only the first will
+be returned. If nothing can be found, a ``NoSuchElementException`` will be
+raised.
.. TODO: Is this following paragraph correct ?
-WebDriver has an "Object-based" API; we represent all types of
-elements using the same interface. This means that although you may
-see a lot of possible methods you could invoke when you hit your IDE's
-auto-complete key combination, not all of them will make sense or be
-valid. Don't worry! WebDriver will attempt to do the Right Thing, and
-if you call a method that makes no sense ("setSelected()" on a "meta"
-tag, for example) an exception will be raised.
+WebDriver has an "Object-based" API; we represent all types of elements using
+the same interface. This means that although you may see a lot of possible
+methods you could invoke when you hit your IDE's auto-complete key combination,
+not all of them will make sense or be valid. Don't worry! WebDriver will
+attempt to do the Right Thing, and if you call a method that makes no sense
+("setSelected()" on a "meta" tag, for example) an exception will be raised.
-So, you've got an element. What can you do with it? First of all, you
-may want to enter some text into a text field::
+So, you've got an element. What can you do with it? First of all, you may want
+to enter some text into a text field::
element.send_keys("some text")
@@ -59,12 +57,11 @@ You can simulate pressing the arrow keys by using the "Keys" class::
element.send_keys(" and some", Keys.ARROW_DOWN)
-It is possible to call `send_keys` on any element, which makes it
-possible to test keyboard shortcuts such as those used on GMail. A
-side-effect of this is that typing something into a text field won't
-automatically clear it. Instead, what you type will be appended to
-what's already there. You can easily clear the contents of a text
-field or textarea with `clear` method::
+It is possible to call `send_keys` on any element, which makes it possible to
+test keyboard shortcuts such as those used on GMail. A side-effect of this is
+that typing something into a text field won't automatically clear it. Instead,
+what you type will be appended to what's already there. You can easily clear
+the contents of a text field or textarea with the `clear` method::
element.clear()
@@ -72,28 +69,26 @@ field or textarea with `clear` method::
Filling in forms
~~~~~~~~~~~~~~~~
-We've already seen how to enter text into a textarea or text field,
-but what about the other elements? You can "toggle" the state of
-drop down, and you can use "setSelected" to set something like an
-`OPTION` tag selected. Dealing with `SELECT` tags isn't too bad::
+We've already seen how to enter text into a textarea or text field, but what
+about the other elements? You can "toggle" the state of the drop down, and you
+can use "setSelected" to set something like an `OPTION` tag selected. Dealing
+with `SELECT` tags isn't too bad::
- element = driver.find_element_by_xpath("//select[@name='name']")
- all_options = element.find_elements_by_tag_name("option")
+ element = driver.find_element(By.XPATH, "//select[@name='name']")
+ all_options = element.find_elements(By.TAG_NAME, "option")
for option in all_options:
print("Value is: %s" % option.get_attribute("value"))
option.click()
-This will find the first "SELECT" element on the page, and cycle
-through each of it's OPTIONs in turn, printing out their values, and
-selecting each in turn.
+This will find the first "SELECT" element on the page, and cycle through each of
+its OPTIONs in turn, printing out their values, and selecting each in turn.
-As you can see, this isn't the most efficient
-way of dealing with SELECT elements . WebDriver's support classes
-include one called "Select", which provides useful methods for
-interacting with these::
+As you can see, this isn't the most efficient way of dealing with SELECT
+elements. WebDriver's support classes include one called a "Select", which
+provides useful methods for interacting with these::
from selenium.webdriver.support.ui import Select
- select = Select(driver.find_element_by_name('name'))
+ select = Select(driver.find_element(By.NAME, 'name'))
select.select_by_index(index)
select.select_by_visible_text("text")
select.select_by_value(value)
@@ -101,33 +96,31 @@ interacting with these::
WebDriver also provides features for deselecting all the selected options::
- select = Select(driver.find_element_by_id('id'))
+ select = Select(driver.find_element(By.ID, 'id'))
select.deselect_all()
-This will deselect all OPTIONs from the first SELECT on the page.
+This will deselect all OPTIONs from that particular SELECT on the page.
Suppose in a test, we need the list of all default selected options, Select
class provides a property method that returns a list::
- select = Select(driver.find_element_by_xpath("xpath"))
+ select = Select(driver.find_element(By.XPATH, "//select[@name='name']"))
all_selected_options = select.all_selected_options
-
+
To get all available options::
options = select.options
-Once you've finished filling out the form, you probably want to submit
-it. One way to do this would be to find the "submit" button and click
-it::
+Once you've finished filling out the form, you probably want to submit it. One
+way to do this would be to find the "submit" button and click it::
# Assume the button has the ID "submit" :)
- driver.find_element_by_id("submit").click()
+ driver.find_element(By.ID, "submit").click()
-Alternatively, WebDriver has the convenience method "submit" on every
-element. If you call this on an element within a form, WebDriver will
-walk up the DOM until it finds the enclosing form and then calls
-submit on that. If the element isn't in a form, then the
-``NoSuchElementException`` will be raised::
+Alternatively, WebDriver has the convenience method "submit" on every element.
+If you call this on an element within a form, WebDriver will walk up the DOM
+until it finds the enclosing form and then calls submit on that. If the element
+isn't in a form, then the ``NoSuchElementException`` will be raised::
element.submit()
@@ -135,98 +128,97 @@ submit on that. If the element isn't in a form, then the
Drag and drop
~~~~~~~~~~~~~
-You can use drag and drop, either moving an element by a certain
-amount, or on to another element::
+You can use drag and drop, either moving an element by a certain amount, or on
+to another element::
- element = driver.find_element_by_name("source")
- target = driver.find_element_by_name("target")
+ element = driver.find_element(By.NAME, "source")
+ target = driver.find_element(By.NAME, "target")
from selenium.webdriver import ActionChains
action_chains = ActionChains(driver)
- action_chains.drag_and_drop(element, target)
+ action_chains.drag_and_drop(element, target).perform()
Moving between windows and frames
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It's rare for a modern web application not to have any frames or to be
-constrained to a single window. WebDriver supports moving between
-named windows using the "switch_to_window" method::
+constrained to a single window. WebDriver supports moving between named windows
+using the "switch_to.window" method::
- driver.switch_to_window("windowName")
+ driver.switch_to.window("windowName")
-All calls to ``driver`` will now be interpreted as being directed to
-the particular window. But how do you know the window's name? Take a
-look at the javascript or link that opened it::
+All calls to ``driver`` will now be interpreted as being directed to the
+particular window. But how do you know the window's name? Take a look at the
+javascript or link that opened it::
Click here to open a new window
-Alternatively, you can pass a "window handle" to the
-"switch_to_window()" method. Knowing this, it's possible to iterate
-over every open window like so::
+Alternatively, you can pass a "window handle" to the "switch_to.window()"
+method. Knowing this, it's possible to iterate over every open window like so::
for handle in driver.window_handles:
- driver.switch_to_window(handle)
+ driver.switch_to.window(handle)
You can also swing from frame to frame (or into iframes)::
- driver.switch_to_frame("frameName")
+ driver.switch_to.frame("frameName")
+
+It's possible to access subframes by separating the path with a dot, and you can
+specify the frame by its index too. That is::
-It's possible to access subframes by separating the path with a dot,
-and you can specify the frame by its index too. That is::
+ driver.switch_to.frame("frameName.0.child")
- driver.switch_to_frame("frameName.0.child")
+would go to the frame named "child" of the first subframe of the frame called
+"frameName". **All frames are evaluated as if from *top*.**
-would go to the frame named "child" of the first subframe of the frame
-called "frameName". **All frames are evaluated as if from *top*.**
+Once we are done with working on frames, we will have to come back to the parent
+frame which can be done using::
-Once we are done with working on frames, we will have to come back
-to the parent frame which can be done using::
+ driver.switch_to.default_content()
- driver.switch_to_default_content()
Popup dialogs
~~~~~~~~~~~~~
-Selenium WebDriver has built-in support for handling popup dialog
-boxes. After you've triggerd and action that would open a popup, you
-can access the alert with the following::
+Selenium WebDriver has built-in support for handling popup dialog boxes. After
+you've triggered action that would open a popup, you can access the alert with
+the following::
- alert = driver.switch_to_alert()
+ alert = driver.switch_to.alert
-This will return the currently open alert object. With this object
-you can now accept, dismiss, read its contents or even type into a
-prompt. This interface works equally well on alerts, confirms,
-prompts. Refer to the API documentation for more information.
+This will return the currently open alert object. With this object, you can now
+accept, dismiss, read its contents or even type into a prompt. This interface
+works equally well on alerts, confirms, prompts. Refer to the API documentation
+for more information.
Navigation: history and location
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Earlier, we covered navigating to a page using the "get" command (
-``driver.get("http://www.example.com")``) As you've seen, WebDriver
-has a number of smaller, task-focused interfaces, and navigation is a
-useful task. To navigate to a page, you can use `get` method::
+``driver.get("http://www.example.com")``). As you've seen, WebDriver has a
+number of smaller, task-focused interfaces, and navigation is a useful task. To
+navigate to a page, you can use `get` method::
driver.get("http://www.example.com")
-To move backwards and forwards in your browser's history::
+To move backward and forward in your browser's history::
driver.forward()
driver.back()
-Please be aware that this functionality depends entirely on the
-underlying driver. It's just possible that something unexpected may
-happen when you call these methods if you're used to the behaviour of
-one browser over another.
+Please be aware that this functionality depends entirely on the underlying
+driver. It's just possible that something unexpected may happen when you call
+these methods if you're used to the behavior of one browser over another.
Cookies
~~~~~~~
-Before we leave these next steps, you may be interested in
-understanding how to use cookies. First of all, you need to be on the
-domain that the cookie will be valid for:
+Before moving to the next section of the tutorial, you may be interested in
+understanding how to use cookies. First of all, you need to be on the domain
+that the cookie will be valid for:
::
@@ -234,9 +226,8 @@ domain that the cookie will be valid for:
driver.get("http://www.example.com")
# Now set the cookie. This one's valid for the entire domain
- cookie = {‘name’ : ‘foo’, ‘value’ : ‘bar’}
+ cookie = {'name' : 'foo', 'value' : 'bar'}
driver.add_cookie(cookie)
# And now output all the available cookies for the current URL
driver.get_cookies()
-
diff --git a/source/page-objects.rst b/source/page-objects.rst
index ba441de..e628ad7 100644
--- a/source/page-objects.rst
+++ b/source/page-objects.rst
@@ -3,26 +3,24 @@
Page Objects
------------
-.. note::
+This chapter is a tutorial introduction to the Page Objects design pattern. A
+page object represents an area where the test interacts within the web
+application user interface.
- Code in this chapter works and is quite self-descriptive, but a
- little description wouldn't hurt. If anyone interested, please
- send pull request in `Github
- `_. Here is an example
- implementation of the page objects pattern:
- https://github.com/baijum/pitracker/tree/master/test/acceptance
+Benefits of using page object pattern:
+
+* Easy to read test cases
+* Creating reusable code that can share across multiple test cases
+* Reducing the amount of duplicated code
+* If the user interface changes, the fix needs changes in only one place
-This chapter is a tutorial introduction to page objects design
-pattern. A page object represents an area in the web application user
-interface that your test is interating. Page objects reduces the
-amount of duplicated code and if the user interface changes, the fix
-need only changes in one place.
Test case
~~~~~~~~~
-Here is a test case which searches for a word in python.org website
-and ensure some results are found.
+Here is a test case that searches for a word on the `python.org` website and
+ensures some results. The following section will introduce the `page` module
+where the page objects will be defined.
::
@@ -31,18 +29,28 @@ and ensure some results are found.
import page
class PythonOrgSearch(unittest.TestCase):
+ """A sample test class to show how page object works"""
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.get("http://www.python.org")
def test_search_in_python_org(self):
+ """Tests python.org search feature. Searches for the word "pycon" then
+ verified that some results show up. Note that it does not look for
+ any particular text in search results page. This test verifies that
+ the results were not empty."""
+
+ #Load the main page. In this case the home page of Python.org.
main_page = page.MainPage(self.driver)
- assert main_page.is_title_matches(), "python.org title doesn't match."
- main_page.search_text_element = "pycon"
- main_page.click_go_button()
+ #Checks if the word "Python" is in title
+ self.assertTrue(main_page.is_title_matches(), "python.org title doesn't match.")
+ #Sets the text of search textbox to "pycon"
+ main_page.search_text_element = "pycon"
+ main_page.click_go_button()
search_results_page = page.SearchResultsPage(self.driver)
- assert search_results_page.is_results_found(), "No results found."
+ #Verifies that the results page is not empty
+ self.assertTrue(search_results_page.is_results_found(), "No results found.")
def tearDown(self):
self.driver.close()
@@ -50,76 +58,110 @@ and ensure some results are found.
if __name__ == "__main__":
unittest.main()
+
Page object classes
~~~~~~~~~~~~~~~~~~~
+The page object pattern intends to create an object for each part of a web page.
+This technique helps build a separation between the test code and the actual
+code that interacts with the web page.
+
The ``page.py`` will look like this::
from element import BasePageElement
from locators import MainPageLocators
class SearchTextElement(BasePageElement):
+ """This class gets the search text from the specified locator"""
+ #The locator for search box where search string is entered
locator = 'q'
class BasePage(object):
+ """Base class to initialize the base page that will be called from all
+ pages"""
def __init__(self, driver):
self.driver = driver
class MainPage(BasePage):
+ """Home page action methods come here. I.e. Python.org"""
+ #Declares a variable that will contain the retrieved text
search_text_element = SearchTextElement()
def is_title_matches(self):
+ """Verifies that the hardcoded text "Python" appears in page title"""
+
return "Python" in self.driver.title
def click_go_button(self):
+ """Triggers the search"""
+
element = self.driver.find_element(*MainPageLocators.GO_BUTTON)
element.click()
class SearchResultsPage(BasePage):
+ """Search results page action methods come here"""
def is_results_found(self):
# Probably should search for this text in the specific page
# element, but as for now it works fine
return "No results found." not in self.driver.page_source
+
Page elements
~~~~~~~~~~~~~
The ``element.py`` will look like this::
+ from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
class BasePageElement(object):
+ """Base page class that is initialized on every page object class."""
def __set__(self, obj, value):
+ """Sets the text to the value supplied"""
+
driver = obj.driver
WebDriverWait(driver, 100).until(
- lambda driver: driver.find_element_by_name(self.locator))
- driver.find_element_by_name(self.locator).send_keys(value)
+ lambda driver: driver.find_element(By.NAME, self.locator))
+ driver.find_element(By.NAME, self.locator).clear()
+ driver.find_element(By.NAME, self.locator).send_keys(value)
def __get__(self, obj, owner):
+ """Gets the text of the specified object"""
+
driver = obj.driver
WebDriverWait(driver, 100).until(
- lambda driver: driver.find_element_by_name(self.locator))
- element = driver.find_element_by_name(self.locator)
+ lambda driver: driver.find_element(By.NAME, self.locator))
+ element = driver.find_element(By.NAME, self.locator)
return element.get_attribute("value")
+
Locators
~~~~~~~~
+One of the practices is to separate the locator strings from the place where
+they are getting used. In this example, locators of the same page belong to the
+same class.
+
The ``locators.py`` will look like this::
from selenium.webdriver.common.by import By
class MainPageLocators(object):
+ """A class for main page locators. All main page locators should come here"""
+
GO_BUTTON = (By.ID, 'submit')
class SearchResultsPageLocators(object):
+ """A class for search results locators. All search results locators should
+ come here"""
+
pass
diff --git a/source/references.rst b/source/references.rst
deleted file mode 100644
index 069ce8e..0000000
--- a/source/references.rst
+++ /dev/null
@@ -1,14 +0,0 @@
-.. _references:
-
-References
-----------
-
-- Official API: http://selenium.googlecode.com/svn/trunk/docs/api/py/index.html
-
-- Blog post explaining how to use headless X for running Selenium
- tests:
- http://coreygoldberg.blogspot.com/2011/06/python-headless-selenium-webdriver.html
-
-- Jenkins plugin for headless Selenium tests:
- https://wiki.jenkins-ci.org/display/JENKINS/Xvnc+Plugin
-
diff --git a/source/test-design.rst b/source/test-design.rst
deleted file mode 100644
index f9083cb..0000000
--- a/source/test-design.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-.. _test-design:
-
-Test Design Considerations
---------------------------
-
-Page Objects
-~~~~~~~~~~~~
-
-Page objects is a design pattern used for web automated testing.
-
-..
- Typical structure recommended.
-
- tests/pageobject/page.py
- tests/pageobject/element.py
- tests/package1/locators.py
- tests/pakage1/page/somepage.py
- tests/pakage1/test_something.py
- tests/package2/locators.py
- tests/pakage2/page/somepage.py
- tests/pakage2/test_something.py
-
-Few links:
-
-1. http://code.google.com/p/selenium/wiki/PageObjects
-2. http://www.theautomatedtester.co.uk/tutorials/selenium/page-object-pattern.htm
-3. http://pragprog.com/magazines/2010-08/page-objects-in-python
-4. http://docs.seleniumhq.org/docs/06_test_design_considerations.jsp
diff --git a/source/waits.rst b/source/waits.rst
index 2031d64..1e0c50f 100644
--- a/source/waits.rst
+++ b/source/waits.rst
@@ -3,38 +3,35 @@
Waits
-----
-These days most of the web apps are using AJAX techniques. When a
-page is loaded to browser, the elements within that page may load at
-different time intervals. This makes locating elements difficult, if
-the element is not present in the DOM, it will raise
-`ElementNotVisibleException` exception. Using waits, we can solve
-this issue. Waiting provides some time interval between actions
-performed - mostly locating element or any other operation with the
-element.
-
-Selenium Webdriver provides two types of waits - implicit & explicit.
-An explicit wait makes WebDriver to wait for a certain condition to
-occur before proceeding further with executions. An implicit wait
-makes WebDriver to poll the DOM for a certain amount of time when
-trying to locate an element.
+These days, most of the web apps are using AJAX techniques. When a page is
+loaded by the browser, the elements within that page may load at different time
+intervals. This makes locating elements difficult: if an element is not yet
+present in the DOM, a locate function will raise an `ElementNotVisibleException`
+exception. Using waits, we can solve this issue. Waiting provides some slack
+between actions performed - mostly locating an element or any other operation
+with the element.
+
+Selenium Webdriver provides two types of waits - implicit & explicit. An
+explicit wait makes WebDriver wait for a certain condition to occur before
+proceeding further with execution. An implicit wait makes WebDriver poll the
+DOM for a certain amount of time when trying to locate an element.
Explicit Waits
~~~~~~~~~~~~~~
-An explicit waits is code you define to wait for a certain condition
-to occur before proceeding further in the code. The worst case of
-this is time.sleep(), which sets the condition to an exact time period
-to wait. There are some convenience methods provided that help you
-write code that will wait only as long as required. WebDriverWait in
-combination with ExpectedCondition is one way this can be
-accomplished.
+An explicit wait is a code you define to wait for a certain condition to occur
+before proceeding further in the code. The extreme case of this is
+time.sleep(), which sets the condition to an exact time period to wait. There
+are some convenience methods provided that help you write code that will wait
+only as long as required. WebDriverWait in combination with ExpectedCondition
+is one way this can be accomplished.
::
from selenium import webdriver
from selenium.webdriver.common.by import By
- from selenium.webdriver.support.ui import WebDriverWait
+ from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Firefox()
@@ -47,19 +44,20 @@ accomplished.
driver.quit()
-This waits up to 10 seconds before throwing a TimeoutException or if
-it finds the element will return it in 0 - 10 seconds. WebDriverWait
-by default calls the ExpectedCondition every 500 milliseconds until it
-returns successfully. A successful return is for ExpectedCondition
-type is Boolean return true or not null return value for all other
-ExpectedCondition types.
+In the code above, Selenium will wait for a maximum of 10 seconds for an element
+matching the given criteria to be found. If no element is found in that time, a
+TimeoutException is thrown. By default, WebDriverWait calls the
+ExpectedCondition every 500 milliseconds until it returns success.
+ExpectedCondition will return `true` (Boolean) in case of success or `not null`
+if it fails to locate an element.
**Expected Conditions**
-There are some common conditions that are frequently come across when
-automating web browsers. Listed below are Implementations of
-each. Selenium Python binding provides some convienence methods so you
-don't have to code an expected_condition class yourself or create your
+There are some common conditions that are frequently of use when automating web
+browsers. Listed below are the names of each. Selenium Python binding provides
+some `convenience methods
+`_
+so you don't have to code an expected_condition class yourself or create your
own utility package for them.
- title_is
@@ -72,7 +70,7 @@ own utility package for them.
- text_to_be_present_in_element_value
- frame_to_be_available_and_switch_to_it
- invisibility_of_element_located
-- element_to_be_clickable - it is Displayed and Enabled.
+- element_to_be_clickable
- staleness_of
- element_to_be_selected
- element_located_to_be_selected
@@ -85,19 +83,56 @@ own utility package for them.
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 10)
- element = wait.until(EC.element_to_be_clickable((By.ID,'someid')))
+ element = wait.until(EC.element_to_be_clickable((By.ID, 'someid')))
+
+The expected_conditions module contains a set of predefined conditions to use
+with WebDriverWait.
+
+**Custom Wait Conditions**
+
+You can also create custom wait conditions when none of the previous convenience
+methods fit your requirements. A custom wait condition can be created using a
+class with `__call__` method which returns `False` when the condition doesn't
+match.
+
+
+::
+
+ class element_has_css_class(object):
+ """An expectation for checking that an element has a particular css class.
+
+ locator - used to find the element
+ returns the WebElement once it has the particular css class
+ """
+ def __init__(self, locator, css_class):
+ self.locator = locator
+ self.css_class = css_class
+
+ def __call__(self, driver):
+ element = driver.find_element(*self.locator) # Finding the referenced element
+ if self.css_class in element.get_attribute("class"):
+ return element
+ else:
+ return False
+
+ # Wait until an element with id='myNewInput' has class 'myCSSClass'
+ wait = WebDriverWait(driver, 10)
+ element = wait.until(element_has_css_class((By.ID, 'myNewInput'), "myCSSClass"))
+
-The expected_conditions module contains a set of predefined conditions
-to use with WebDriverWait.
+.. note:: **polling2 Library**
+ You may also consider using `polling2
+ `_
+ library which you need to install separately.
Implicit Waits
~~~~~~~~~~~~~~
-An implicit wait is to tell WebDriver to poll the DOM for a certain
-amount of time when trying to find an element or elements if they are
-not immediately available. The default setting is 0. Once set, the
-implicit wait is set for the life of the WebDriver object instance.
+An implicit wait tells WebDriver to poll the DOM for a certain amount of time
+when trying to find any element (or elements) not immediately available. The
+default setting is 0 (zero). Once set, the implicit wait is set for the life of
+the WebDriver object.
::