From 7e47b0000f8c62a695b974f1ba4c9cbd7039fa35 Mon Sep 17 00:00:00 2001 From: Ai-Lin Liou Date: Thu, 18 Mar 2021 15:44:55 +0800 Subject: [PATCH 01/30] fix the typo (#96) --- source/locating-elements.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/locating-elements.rst b/source/locating-elements.rst index 630f864..574001c 100644 --- a/source/locating-elements.rst +++ b/source/locating-elements.rst @@ -73,7 +73,7 @@ For instance, consider this page source:: - + The form element can be located like this:: @@ -99,7 +99,7 @@ For instance, consider this page source:: - + The username & password elements can be located like this:: @@ -144,7 +144,7 @@ For instance, consider this page source:: - + The form elements can be located like this:: @@ -220,7 +220,7 @@ For instance, consider this page source:: Continue Cancel - + The continue.html link can be located like this:: @@ -242,7 +242,7 @@ For instance, consider this page source::

Welcome

Site content goes here.

- + The heading (h1) element can be located like this:: @@ -263,7 +263,7 @@ For instance, consider this page source::

Site content goes here.

- + The "p" element can be located like this:: @@ -284,7 +284,7 @@ For instance, consider this page source::

Site content goes here.

- + The "p" element can be located like this:: From 9e4d949b04dac2ba53d1bac533fdc0292a156fb4 Mon Sep 17 00:00:00 2001 From: Baiju Muthukadan Date: Mon, 19 Apr 2021 06:38:37 +0530 Subject: [PATCH 02/30] simplify sentences --- source/page-objects.rst | 44 ++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/source/page-objects.rst b/source/page-objects.rst index ec81c7a..bd5aafb 100644 --- a/source/page-objects.rst +++ b/source/page-objects.rst @@ -3,13 +3,13 @@ Page Objects ------------ -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 interacting. +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. Benefits of using page object pattern: -* Creating reusable code that can be shared across multiple 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 @@ -17,8 +17,9 @@ Benefits of using page object pattern: 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. :: @@ -34,11 +35,10 @@ some results are found. 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. - """ + """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) @@ -61,9 +61,9 @@ some results are found. Page object classes ~~~~~~~~~~~~~~~~~~~ -The page object pattern intends creating an object for each web page. By -following this technique a layer of separation between the test code and -technical implementation is created. +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:: @@ -78,7 +78,8 @@ The ``page.py`` will look like this:: class BasePage(object): - """Base class to initialize the base page that will be called from all pages""" + """Base class to initialize the base page that will be called from all + pages""" def __init__(self, driver): self.driver = driver @@ -92,10 +93,12 @@ The ``page.py`` will look like this:: 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() @@ -122,6 +125,7 @@ The ``element.py`` will look like this:: 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)) @@ -130,6 +134,7 @@ The ``element.py`` will look like this:: 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)) @@ -141,8 +146,8 @@ Locators ~~~~~~~~ One of the practices is to separate the locator strings from the place where -they are being used. In this example, locators of the same page belong to same -class. +they are getting used. In this example, locators of the same page belong to the +same class. The ``locators.py`` will look like this:: @@ -150,8 +155,11 @@ The ``locators.py`` will look like this:: 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""" + """A class for search results locators. All search results locators should + come here""" + pass From df08cb842307fcfe318ee369506219ad124ff102 Mon Sep 17 00:00:00 2001 From: Baiju Muthukadan Date: Mon, 19 Apr 2021 06:50:56 +0530 Subject: [PATCH 03/30] Add readthedocs configguration --- .readthedocs.yaml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .readthedocs.yaml diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..6cd6e72 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,20 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: source/conf.py + +# Optionally build your docs in additional formats such as PDF +formats: + - pdf + +# Optionally set the version of Python and requirements required to build your docs +python: + version: 3.7 + install: + - requirements: requirements.txt From 2c3b5f39dc4ec982b11c4daf51f7c531ce6135eb Mon Sep 17 00:00:00 2001 From: Baiju Muthukadan Date: Mon, 19 Apr 2021 07:06:32 +0530 Subject: [PATCH 04/30] Add one more benefit --- source/page-objects.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/source/page-objects.rst b/source/page-objects.rst index bd5aafb..03c504d 100644 --- a/source/page-objects.rst +++ b/source/page-objects.rst @@ -9,6 +9,7 @@ application user interface. 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 From 513415fc847ff6decd7ac822419fb2643a16f4fc Mon Sep 17 00:00:00 2001 From: Baiju Muthukadan Date: Mon, 19 Apr 2021 07:17:18 +0530 Subject: [PATCH 05/30] Remove outdated TODO --- TODO.txt | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 TODO.txt 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 From 6a8866a9f9ef3b13d6f4101d35bdd0c85895512b Mon Sep 17 00:00:00 2001 From: Baiju Muthukadan Date: Thu, 27 May 2021 12:09:05 +0530 Subject: [PATCH 06/30] whitespace fixes --- source/getting-started.rst | 11 ++++++----- source/page-objects.rst | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/source/getting-started.rst b/source/getting-started.rst index 3dab345..c304155 100644 --- a/source/getting-started.rst +++ b/source/getting-started.rst @@ -96,8 +96,9 @@ 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 `pytest `_ -and `nose `_. +Python's unittest module. The other options for a tool/framework are `pytest +`_ and `nose +`_. 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` @@ -140,8 +141,8 @@ You can run the above test case from a shell like this:: 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: -:: +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) @@ -190,7 +191,7 @@ to the driver object created in `setUp` method. 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 +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*:: diff --git a/source/page-objects.rst b/source/page-objects.rst index 03c504d..da8167e 100644 --- a/source/page-objects.rst +++ b/source/page-objects.rst @@ -19,7 +19,7 @@ Test case ~~~~~~~~~ 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 +ensures some results. The following section will introduce the `page` module where the page objects will be defined. :: From 396a7bb5a89168585383ceb3b8f36782afdf7dae Mon Sep 17 00:00:00 2001 From: Baiju Muthukadan Date: Fri, 28 May 2021 10:33:37 +0530 Subject: [PATCH 07/30] rearrange sections --- source/installation.rst | 110 +++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 57 deletions(-) diff --git a/source/installation.rst b/source/installation.rst index da5ecdd..5098fb7 100644 --- a/source/installation.rst +++ b/source/installation.rst @@ -18,19 +18,18 @@ 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 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Use `pip `_ to install the selenium -package. Python 3.6 has pip available in the `standard library -`_. Using `pip`, you can +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 has `venv +You may consider using `virtualenv `_ to +create isolated Python environments. Python 3 has `venv `_ which is almost the same as virtualenv. @@ -38,6 +37,52 @@ You can also download Python bindings for Selenium from the `PyPI page for selenium package `_. and install manually. + +Instructions for Windows users +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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`. + + :: + + 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:\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 ~~~~~~~ @@ -68,29 +113,6 @@ For more information about driver installation, please refer the `official documentation `_. -Detailed instructions for Windows users -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. Note:: - - You should have an internet connection to perform this installation. - -1. Install Python 3.6 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`. - - :: - - C:\Python35\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:\Python35\python.exe C:\my_selenium_script.py - Downloading Selenium server ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -130,29 +152,3 @@ 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 - - -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. From 6370b59ad48071c023e51d871b73847845fffc6c Mon Sep 17 00:00:00 2001 From: Tim Gates Date: Fri, 3 Sep 2021 21:04:29 +1000 Subject: [PATCH 08/30] docs: fix simple typo, shat -> that (#98) There is a small typo in source/conf.py. Should read `that` rather than `shat`. --- source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/conf.py b/source/conf.py index 316e761..1829d9f 100644 --- a/source/conf.py +++ b/source/conf.py @@ -257,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 = [] From 36a089b51bee2c36aacda6d914fc957c2c0c7983 Mon Sep 17 00:00:00 2001 From: Baiju Muthukadan Date: Mon, 4 Oct 2021 18:23:44 +0530 Subject: [PATCH 09/30] Update driver website link --- source/installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/installation.rst b/source/installation.rst index 5098fb7..a998151 100644 --- a/source/installation.rst +++ b/source/installation.rst @@ -100,7 +100,7 @@ Other supported browsers will have their own drivers available. Links to some of the more popular browser drivers follow. +--------------+-----------------------------------------------------------------------+ -| **Chrome**: | https://sites.google.com/a/chromium.org/chromedriver/downloads | +| **Chrome**: | https://sites.google.com/chromium.org/driver/ | +--------------+-----------------------------------------------------------------------+ | **Edge**: | https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/ | +--------------+-----------------------------------------------------------------------+ From d1ea80957f3b0c4b58d589f3639946544b0b5082 Mon Sep 17 00:00:00 2001 From: meni181818 Date: Wed, 16 Feb 2022 23:47:38 +0200 Subject: [PATCH 10/30] unittest.TestCase.assertNotIn insted of assert " not in (#100) `self.assertNotIn("No results found.", driver.page_source)` insted of `assert "No results found." not in driver.page_source`. as previous `self.assertIn("Python", driver.title)` https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertNotIn --- source/getting-started.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/getting-started.rst b/source/getting-started.rst index c304155..d5c23d9 100644 --- a/source/getting-started.rst +++ b/source/getting-started.rst @@ -120,7 +120,7 @@ search functionality:: 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): @@ -220,7 +220,7 @@ Special keys can be send using `Keys` class imported from 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. From 469d30da4e46c16681f612e3b50d6a81ec8c1226 Mon Sep 17 00:00:00 2001 From: meni181818 Date: Thu, 17 Feb 2022 10:43:01 +0200 Subject: [PATCH 11/30] unittest.TestCase.assertTrue insted of assert (#101) since we use unittet. --- source/page-objects.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/page-objects.rst b/source/page-objects.rst index da8167e..1a59df7 100644 --- a/source/page-objects.rst +++ b/source/page-objects.rst @@ -44,13 +44,13 @@ where the page objects will be defined. #Load the main page. In this case the home page of Python.org. main_page = page.MainPage(self.driver) #Checks if the word "Python" is in title - assert main_page.is_title_matches(), "python.org title doesn't match." + 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) #Verifies that the results page is not empty - assert search_results_page.is_results_found(), "No results found." + self.assertTrue(search_results_page.is_results_found(), "No results found.") def tearDown(self): self.driver.close() From 7a104ef7f8819959def444f4cb912714340e705b Mon Sep 17 00:00:00 2001 From: LRNKN <78888840+LRNKN@users.noreply.github.com> Date: Thu, 10 Mar 2022 18:29:24 +1030 Subject: [PATCH 12/30] Update README.rst (#102) Small wording and syntax change for project introduction text. --- README.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 1f25ce5..1710b67 100644 --- a/README.rst +++ b/README.rst @@ -3,16 +3,16 @@ Selenium Python Bindings Documentation https://selenium-python.readthedocs.io -NOTE: THIS IS NOT AN OFFICIAL DOCUMENTATION +NOTE: THIS IS NOT OFFICIAL DOCUMENTATION -This is not an official documentation. If you would like to contribute to this +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 50+ 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. +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:** From 3b13c2f8f864c2b4a56fb5dddebab0cd86817ad6 Mon Sep 17 00:00:00 2001 From: dysphere <30881686+dysphere@users.noreply.github.com> Date: Tue, 31 May 2022 04:02:22 -0700 Subject: [PATCH 13/30] Updated find_element method (#99) --- source/getting-started.rst | 31 +++++++++------ source/locating-elements.rst | 77 ++++++++++++++++-------------------- source/navigating.rst | 22 +++++------ 3 files changed, 64 insertions(+), 66 deletions(-) diff --git a/source/getting-started.rst b/source/getting-started.rst index d5c23d9..62a9de2 100644 --- a/source/getting-started.rst +++ b/source/getting-started.rst @@ -13,11 +13,12 @@ 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) @@ -36,12 +37,14 @@ 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. +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. @@ -61,13 +64,13 @@ The next line is an assertion to confirm that title has "Python" word 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. A detailed -explanation of finding elements is available in the :ref:`locating-elements` +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 sent using `Keys` class imported from @@ -107,6 +110,7 @@ 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): @@ -117,7 +121,7 @@ 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) self.assertNotIn("No results found.", driver.page_source) @@ -157,13 +161,14 @@ 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. +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:: @@ -202,13 +207,13 @@ The next line is an assertion to confirm that title has "Python" word 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 +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 diff --git a/source/locating-elements.rst b/source/locating-elements.rst index 574001c..8d0ebb1 100644 --- a/source/locating-elements.rst +++ b/source/locating-elements.rst @@ -4,34 +4,13 @@ Locating Elements ----------------- There are various strategies to locate elements in a page. You can use the most -appropriate one for your case. Selenium provides the following methods to +appropriate one for your case. Selenium provides the following method 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` - +- `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` - - -Apart from the public methods given above, there are two private methods which -might be useful for locating page elements: - -- `find_element` - `find_elements` @@ -42,18 +21,32 @@ 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 ~~~~~~~~~~~~~~ @@ -77,7 +70,7 @@ For instance, consider this page source:: The form element can be located like this:: - login_form = driver.find_element_by_id('loginForm') + login_form = driver.find_element(By.ID, 'loginForm') Locating by Name @@ -103,12 +96,12 @@ For instance, consider 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 occurs before the "Clear" button:: - continue = driver.find_element_by_name('continue') + continue = driver.find_element(By.NAME, 'continue') Locating by XPath @@ -148,9 +141,9 @@ For instance, consider 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) @@ -161,9 +154,9 @@ The form elements can be located like this:: 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 `name` set to `username` @@ -174,8 +167,8 @@ The username element can be located like this:: 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 `name` set to `continue` and attribute `type` set to @@ -224,8 +217,8 @@ For instance, consider this page source:: 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 @@ -246,7 +239,7 @@ For instance, consider this page source:: 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 @@ -267,7 +260,7 @@ For instance, consider this page source:: 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -288,7 +281,7 @@ For instance, consider this page source:: 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 diff --git a/source/navigating.rst b/source/navigating.rst index 2e1c511..559bd99 100644 --- a/source/navigating.rst +++ b/source/navigating.rst @@ -28,10 +28,10 @@ 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_css_selector("input#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 @@ -74,8 +74,8 @@ 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() @@ -88,7 +88,7 @@ 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) @@ -96,7 +96,7 @@ provides useful methods for 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 that particular SELECT on the page. @@ -104,7 +104,7 @@ 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("//select[@name='name']")) + select = Select(driver.find_element(By.XPATH, "//select[@name='name']")) all_selected_options = select.all_selected_options To get all available options:: @@ -131,8 +131,8 @@ Drag and drop 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) From 341ca8c30669af259a394e119d59a78cdbb089a5 Mon Sep 17 00:00:00 2001 From: Ryan Slater Date: Wed, 24 Aug 2022 00:50:33 -0400 Subject: [PATCH 14/30] Corrected typo in docs 3.4 (#105) --- source/navigating.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/navigating.rst b/source/navigating.rst index 559bd99..e744218 100644 --- a/source/navigating.rst +++ b/source/navigating.rst @@ -106,7 +106,7 @@ class provides a property method that returns a list:: 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 @@ -175,7 +175,7 @@ would go to the frame named "child" of the first subframe of the frame called 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 From 54fcbcc8418c9000fcd1d747be82c539c789931d Mon Sep 17 00:00:00 2001 From: Kitty Depa Date: Mon, 12 Sep 2022 04:49:17 +0200 Subject: [PATCH 15/30] Grammar edits in the Getting Started page (#107) * Grammar edits Authored-by: kittydepa --- source/getting-started.rst | 40 +++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/source/getting-started.rst b/source/getting-started.rst index 62a9de2..a9a38b7 100644 --- a/source/getting-started.rst +++ b/source/getting-started.rst @@ -60,7 +60,7 @@ 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 @@ -73,7 +73,7 @@ chapter:: 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 sent using `Keys` class imported from +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:: @@ -87,9 +87,9 @@ 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() @@ -104,7 +104,7 @@ Python's unittest module. The other options for a tool/framework are `pytest `_. 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` +modified example which uses the unittest module. This is a test for the `python.org` search functionality:: import unittest @@ -149,7 +149,7 @@ 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) - + Walkthrough of the example @@ -157,9 +157,9 @@ 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 +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, +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. @@ -171,14 +171,14 @@ RETURN, F1, ALT etc. The `By` class is used to locate elements within a document 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 `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 +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 the instance of Firefox WebDriver. +are creating an instance of a Firefox WebDriver. :: @@ -186,7 +186,7 @@ are creating the instance of Firefox WebDriver. 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 +characters `test`. The first line inside this method creates a local reference to the driver object created in `setUp` method. :: @@ -202,7 +202,7 @@ 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) @@ -216,7 +216,7 @@ chapter:: 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 +Special keys can be sent using the `Keys` class imported from `selenium.webdriver.common.keys`:: elem.send_keys("pycon") @@ -229,9 +229,9 @@ is any. To ensure that some results are found, make an assertion:: 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 +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 browser will exit entirely.:: +opened, by default most browsers will exit entirely.:: def tearDown(self): self.driver.close() @@ -246,7 +246,7 @@ 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 +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 @@ -255,7 +255,7 @@ 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 +The above line says that you can use this URL for connecting to the remote WebDriver. Here are some examples:: from selenium import webdriver @@ -273,7 +273,7 @@ WebDriver. Here are some examples:: 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 +The desired capabilities is a dictionary. So instead of using the default dictionaries, you can specify the values explicitly:: driver = webdriver.Remote( From eda1ecca79be3c1a88138cc7f942a554dcf40093 Mon Sep 17 00:00:00 2001 From: amosctlee <51038877+amosctlee@users.noreply.github.com> Date: Mon, 26 Sep 2022 02:58:40 +0800 Subject: [PATCH 16/30] Update: 2.5 Using Selenium with remote WebDriver (#108) The desired_capabilities has been deprecated. Use Options instead of DesiredCapabilities. --- source/getting-started.rst | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/source/getting-started.rst b/source/getting-started.rst index a9a38b7..0c345f5 100644 --- a/source/getting-started.rst +++ b/source/getting-started.rst @@ -259,25 +259,13 @@ The above line says that you can use this URL for connecting to the remote WebDriver. Here are some examples:: from selenium import webdriver - 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) + options=webdriver.ChromeOptions() + ) driver = webdriver.Remote( command_executor='http://127.0.0.1:4444/wd/hub', - desired_capabilities=DesiredCapabilities.OPERA) - - 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 specify the values explicitly:: - - driver = webdriver.Remote( - command_executor='http://127.0.0.1:4444/wd/hub', - desired_capabilities={'browserName': 'htmlunit', - 'version': '2', - 'javascriptEnabled': True}) + options=webdriver.FirefoxOptions() + ) From 0e64cdf5d3954416247f9b12d9faa8669a8ba812 Mon Sep 17 00:00:00 2001 From: Jatin Nagar Date: Fri, 11 Nov 2022 10:00:09 +0530 Subject: [PATCH 17/30] updated the import statement (#109) --- source/waits.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/waits.rst b/source/waits.rst index fc00b1e..1e0c50f 100644 --- a/source/waits.rst +++ b/source/waits.rst @@ -31,7 +31,7 @@ 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() From 57f644a169891b4c89cc4926e1f34848a64e3c82 Mon Sep 17 00:00:00 2001 From: Pavel Lobashov Date: Wed, 7 Dec 2022 09:07:15 +0200 Subject: [PATCH 18/30] Fix incorrect quotes in cookies example (#110) --- source/navigating.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/navigating.rst b/source/navigating.rst index e744218..2ef2597 100644 --- a/source/navigating.rst +++ b/source/navigating.rst @@ -226,7 +226,7 @@ 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 From 1d97c3efbb1c48965e4851f2eaa1004039da04d1 Mon Sep 17 00:00:00 2001 From: Baiju Muthukadan Date: Wed, 14 Dec 2022 10:26:04 +0530 Subject: [PATCH 19/30] Update link Signed-off-by: Baiju Muthukadan --- source/faq.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/faq.rst b/source/faq.rst index 9de4370..529b1f6 100644 --- a/source/faq.rst +++ b/source/faq.rst @@ -9,10 +9,10 @@ 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:: From 656a8b2432b2ada183c64577c5c0f5a78ee4b0ff Mon Sep 17 00:00:00 2001 From: Baiju Muthukadan Date: Wed, 14 Dec 2022 10:46:49 +0530 Subject: [PATCH 20/30] Use new API Signed-off-by: Baiju Muthukadan --- source/navigating.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/navigating.rst b/source/navigating.rst index 2ef2597..4bf3a0c 100644 --- a/source/navigating.rst +++ b/source/navigating.rst @@ -144,9 +144,9 @@ 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:: +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 @@ -154,20 +154,20 @@ 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()" +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:: - 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*.** From af911bbdffbf9db15f8ae4d6c63d8ea8cead1e7a Mon Sep 17 00:00:00 2001 From: hitrust Date: Sun, 21 May 2023 22:34:52 +0800 Subject: [PATCH 21/30] Update navigating.rst (#111) --- source/navigating.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/navigating.rst b/source/navigating.rst index 4bf3a0c..9da1e0e 100644 --- a/source/navigating.rst +++ b/source/navigating.rst @@ -115,7 +115,7 @@ 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 From c001ee278de0847479ae3e554b29da32bb7715c6 Mon Sep 17 00:00:00 2001 From: Baiju Muthukadan Date: Sun, 21 May 2023 20:07:50 +0530 Subject: [PATCH 22/30] Update the contributor count Signed-off-by: Baiju Muthukadan --- README.rst | 2 +- source/index.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 1710b67..54d9a43 100644 --- a/README.rst +++ b/README.rst @@ -8,7 +8,7 @@ NOTE: THIS IS NOT OFFICIAL 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 50+ community members have +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, diff --git a/source/index.rst b/source/index.rst index 7d51db0..8507a6e 100644 --- a/source/index.rst +++ b/source/index.rst @@ -11,7 +11,7 @@ Selenium with Python 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 50+ + 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 From e6762702f74845a5484b8e21c0c8a3027ce096c7 Mon Sep 17 00:00:00 2001 From: Max Zhenzhera <59729293+maxzhenzhera@users.noreply.github.com> Date: Sat, 30 Sep 2023 05:12:18 +0300 Subject: [PATCH 23/30] Update installation Drivers with Selenium Manager and small fixes in API (#112) * fix: correct link to selemium webdriver docs * feat: add info about selenium manager * fix: remove auto doc for modules that do no longer exist * feat: update selenium.webdriver imports --- source/api.rst | 72 +++++++++++------------------------------ source/installation.rst | 22 ++++++++++++- 2 files changed, 40 insertions(+), 54 deletions(-) diff --git a/source/api.rst b/source/api.rst index 8e91d06..1118aed 100644 --- a/source/api.rst +++ b/source/api.rst @@ -23,16 +23,32 @@ 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:: @@ -139,16 +155,6 @@ See the :ref:`selenium-remote-webdriver` section for example usages of desired c :member-order: groupwise :show-inheritance: -Touch Actions -~~~~~~~~~~~~~ - -.. automodule:: selenium.webdriver.common.touch_actions - :members: - :undoc-members: - :special-members: __init__ - :member-order: groupwise - :show-inheritance: - Proxy ~~~~~ @@ -353,46 +359,6 @@ Internet Explorer WebDriver :member-order: groupwise :show-inheritance: -Android WebDriver -~~~~~~~~~~~~~~~~~ - -.. automodule:: selenium.webdriver.android.webdriver - :members: - :undoc-members: - :special-members: __init__ - :member-order: groupwise - :show-inheritance: - -Opera WebDriver -~~~~~~~~~~~~~~~ - -.. automodule:: selenium.webdriver.opera.webdriver - :members: - :undoc-members: - :special-members: __init__ - :member-order: groupwise - :show-inheritance: - -PhantomJS WebDriver -~~~~~~~~~~~~~~~~~~~ - -.. automodule:: selenium.webdriver.phantomjs.webdriver - :members: - :undoc-members: - :special-members: __init__ - :member-order: groupwise - :show-inheritance: - -PhantomJS WebDriver Service -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. automodule:: selenium.webdriver.phantomjs.service - :members: - :undoc-members: - :special-members: __init__ - :member-order: groupwise - :show-inheritance: - Safari WebDriver ~~~~~~~~~~~~~~~~ diff --git a/source/installation.rst b/source/installation.rst index a998151..343bff3 100644 --- a/source/installation.rst +++ b/source/installation.rst @@ -111,8 +111,28 @@ the more popular browser drivers follow. 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 9a0c8e3254bc9dbe9591d61da763a6c68104acac Mon Sep 17 00:00:00 2001 From: Carmen Alvarez Date: Thu, 16 Nov 2023 13:47:23 +0100 Subject: [PATCH 24/30] Update the page objects documentation to use the newer syntax for finding elements by name. (#113) This follows-up the changes done in https://github.com/baijum/selenium-python/pull/99 (commit 3b13c2f8f864c2b4a56fb5dddebab0cd86817ad6 ) --- source/page-objects.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/source/page-objects.rst b/source/page-objects.rst index 1a59df7..e628ad7 100644 --- a/source/page-objects.rst +++ b/source/page-objects.rst @@ -118,6 +118,7 @@ Page elements The ``element.py`` will look like this:: + from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait @@ -129,17 +130,17 @@ The ``element.py`` will look like this:: driver = obj.driver WebDriverWait(driver, 100).until( - 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) + 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") From 21f2a3a2fd8979296c0b9aee987facc1de4c3793 Mon Sep 17 00:00:00 2001 From: Baiju Muthukadan Date: Thu, 16 Nov 2023 18:24:45 +0530 Subject: [PATCH 25/30] Add build section --- .readthedocs.yaml | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 6cd6e72..ef1e03e 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -5,16 +5,23 @@ # 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: + version: "3.10" + install: + - requirements: requirements.txt + # Build documentation in the docs/ directory with Sphinx sphinx: configuration: source/conf.py + fail_on_warning: true # Optionally build your docs in additional formats such as PDF formats: - pdf - -# Optionally set the version of Python and requirements required to build your docs -python: - version: 3.7 - install: - - requirements: requirements.txt From 7cf91983545f55bfdc45836257bcad56c597527f Mon Sep 17 00:00:00 2001 From: Baiju Muthukadan Date: Thu, 16 Nov 2023 18:26:33 +0530 Subject: [PATCH 26/30] Remove version from python section --- .readthedocs.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index ef1e03e..c7bb87b 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -13,7 +13,6 @@ build: # Optionally set the version of Python and requirements required to build your docs python: - version: "3.10" install: - requirements: requirements.txt From 74454219563f5b6ca6e11da66e4382e0b525eb5b Mon Sep 17 00:00:00 2001 From: Baiju Muthukadan Date: Thu, 16 Nov 2023 18:34:26 +0530 Subject: [PATCH 27/30] Do not fail on warning --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index c7bb87b..f8d496e 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -19,7 +19,7 @@ python: # Build documentation in the docs/ directory with Sphinx sphinx: configuration: source/conf.py - fail_on_warning: true + fail_on_warning: false # Optionally build your docs in additional formats such as PDF formats: From 370686950585ba65898e585064c68e5c00b2c7fd Mon Sep 17 00:00:00 2001 From: devid Date: Tue, 5 Mar 2024 05:05:43 -0300 Subject: [PATCH 28/30] Updated the variable name to a python non-reserved word. (#115) --- source/locating-elements.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/locating-elements.rst b/source/locating-elements.rst index 8d0ebb1..7bc499e 100644 --- a/source/locating-elements.rst +++ b/source/locating-elements.rst @@ -101,7 +101,7 @@ The username & password elements can be located like this:: 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 From 81ca746c74b2eab8e04416b83935e28221cb7805 Mon Sep 17 00:00:00 2001 From: Baiju Muthukadan Date: Fri, 5 Apr 2024 13:08:35 +0530 Subject: [PATCH 29/30] Remove the nose testing tool Signed-off-by: Baiju Muthukadan --- source/getting-started.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/getting-started.rst b/source/getting-started.rst index 0c345f5..8c71e49 100644 --- a/source/getting-started.rst +++ b/source/getting-started.rst @@ -99,9 +99,8 @@ 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 `pytest -`_ and `nose -`_. +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 the unittest module. This is a test for the `python.org` From d1b9190381c789fb9db8842084bf10bc857dd971 Mon Sep 17 00:00:00 2001 From: Baiju Muthukadan Date: Fri, 5 Apr 2024 13:12:47 +0530 Subject: [PATCH 30/30] Update year Signed-off-by: Baiju Muthukadan --- source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/conf.py b/source/conf.py index 1829d9f..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-2018, 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