- Hands-On: Basic Browser Handling Using Python Selenium Client Bindings
- Hands-On: Finding Elements using
driver.find_element
method - Hands-On: Dynamic Waiting and State Checking
- Hands-On: Entering Text
- Defining a Class
- Hands-On: Create a Calculator Class
- Python
unittest
: TestCase Class, Test Methods, Fixtures and Assertions - Hands-On: Calculator Test Class
- Long Exercise: Implement Valid and Invalid Login Scenarios.
- Walk-through: A Sample Solution
In continuation to the demo using ChromeDriver, we'll now automate the following steps using Selenium library:
- Launch Chrome.
- Go to https://www.google.com.
- Find all HTML nodes with the tag input and print the source.
- Quit Chrome.
Let's install selenium:
pip install selenium
To launch chrome:
from selenium import webdriver
driver = webdriver.Chrome(executable_path=<path>)
We'll implement and use the function get_driver_path
in project_utils.py
to create driver path.
To go to a url:
driver.get('<url>')
For finding and printing source of all input nodes:
matches = re.findall(r'(<input.*?>)', driver.page_source)
for match in matches:
print(match)
For quitting Chrome:
driver.quit()
Let's implement these steps in ex17.py
file.
This step onwards, we'll use the WordPress application. You should use the ip address as per the lab machine allocated to you or your own installation of WordPress.
URL for admin interface is: http://<ip address/wp-admin
.
For finding an element, you need to express it as a By
strategy. Following are some commonly used strategies:
from selenium.webdriver.common.by import By
By.ID
By.NAME
By.XPATH
By.CSS_SELECTOR
find_element
returns a WebElement
object.
Let's identify the user name field using all these strategies and implement in ex18.py
file.
Many a times, the element is not available or ready to be interacted with. Ignoing this behavior leads to flaky tests.
A highly suggested approach is to use fluent/dynamic waiting for the desired state.
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(<driver_object>, <time>)
element = wait.until(EC.element_to_be_clickable((<by_type>, <by_value>))
Other common conditions of interest are presence_of_element_located
and visibility_of_element_located
.
Notice that you have to pass, the By
strategy and value as a tuple
unlike find_element
call where you passed them as individual arguments.
Let's implement this new style in ex19.py
file.
To enter some text in the text box, we can use send_keys
method of WebElement
. Optionally, you can also clear the text before entering anything.
element.clear()
element.send_keys('<text>')
Let's enter user
text in the user name text box in ex19.py
file.
You can create a class in Python using the class
keyword. It can contain any number of functions, which are mostly bound to a specific object/instance of a class and hence are called bound methods
or simply methods
. (Python also has class methods and static methods. Beyond scope for this workshop).
The class names in Python are the only exception to naming conventions that you've seen. Class names use the CamelCase
style.
class ClassName:
def __init__(self):
pass
def method1(self, some_arg):
pass
def method2(self, some_arg2):
pass
A class acts as a template/blue-print to create any number of objects.
Note that in the definition of a function, you always pass self
as the first argument (unless you are dealing with class/static methods, which are not in scope of this workshop). This is a reference to the current object/instance and unlike most other languages is defined explicitly in Python.
Creating an object of this class is similar to a function call syntax:
cn = ClassName()
Now, you can call the methods, just like you called methods of pre-defined objects so far:
cn.method1(val1)
Note that while calling, the first argument self
is automatically handled by Python's method call mechanism.
Let's create a simple class Calculator
with 3 methods add
and sub
and reset
.
For each calculation that it does, it increments a state attribute calc_count
. Let's implement it as a property
, which is the suggested way in Python instead of getter/setter methods.
Calling the reset
method should reset the value of calc_count
to 0.
Write usage code in ex20.py
.
Selenium library is meant only for automating the UI of a web application. To write tests, you need a test engine. Python has a built-in unit test engine called unittest
.
Steps:
- Create a test class and inherit it from
unittest.TestCase
- Make a
super().__init__()
call to complete any necessary initialization needed by the engine. - Implement any tests as test methods of this class. For this, the names of methods should be prefixed with
test
. - In the test methods, write validations by using
assert*
methods of theTestCase
object. - Optionally, move set-up and clean-up instructions to
Fixture methods
at test-class-level (setUpClass/tearDownClass
) or test-method-level (setUp/tearDown
) (We'll explore test method level fixtures in this workshop).
Let's write some unit tests for the Calculator class created in calc.py
in ex21.py
.
- Write a test method for
add
method. - Write a test method for
sub
method. - Write a test method with multiple calls to
add
andsub
.
Create the calculator instance in setUp
if it does not exist. Reset the caluclator in tearDown
method.
For each test, assert the output of a method call as well expected calc_count
value.
There are multiple ways to run unit tests. One easy way of doing so is running the following command from terminal:
python -m unittest <test_script_path>
Implement the following test scenarios as test methods in a single test class in ex22_login_tests.py
file.
- Valid Login Test
- Invalid Login Test
- User name is
user
, password isbitnami
. - To click an element, you can call
click()
method of element. - To get the value of an attribute of an element, you can use
get_attribute
method call. - The link URL for a hyperlink in HTML is contained in its
href
attribute.
Let's look at the details of a possible solution. Map to the way you approached the problem and take a note of any new learning or a different way of solving the same problem.