I'm trying to automate regression testing for basic html websites using selenium-webdriver using python. I wrote a function that will take input from an excel to determine the type of locator of an element on the webpage which goes like this:
if locator_type == "ID":
web_element = self.__driver.find_element_by_id(element)
elif locator_type == "NAME":
web_element = self.__driver.find_element_by_name(element)
elif locator_type == "XPATH":
web_element = self.__driver.find_element_by_xpath(element)
elif locator_type == "TAG_NAME":
web_element = self.__driver.find_element_by_tag_name(element)
elif locator_type == "LINK_TEXT":
web_element = self.__driver.find_element_by_link_text(element)
elif locator_type == "CLASS_NAME":
web_element = self.__driver.find_element_by_class_name(element)
elif locator_type == "PARTIAL_LINK_TEXT":
web_element = self.__driver.find_element_by_partial_link_text(element)
This is so that the we could specify the locator type and give actual locator('element') so that selenium could try to find the web element on the web-page. Is there any way to reduce the elif statements or any other better way to write this part?
Too many if statements
I tried the method in the above link but it didn't help me. Kindly help me resolve this.
EDIT I tried create a dict like this
locator_dict = {
'ID' : driver.find_element_by_id(element),
'NAME' : driver.find_element_by_name(element)}
then i received an error saying that element is not defined
The only difference between the bodies of the various clauses is which method you actually call. You can factor that out into a dict
.
d = {
"ID": self.__driver.find_element_by_id,
"NAME": self.__driver.find_element_by_name,
# etc
}
if locator_type in d:
web_element = d[locator_type](element)
else:
# do something if you haven't defined a method for locator_type
You can also use methodcaller
, although this first attempt makes d
depend on element
:
from operator import methodcaller
methods = [
("ID", "find_element_by_id"),
("NAME", "find_element_by_name"),
# etc
]
d = { tag: methodcaller(method, element) for tag, method in methods }
if locator_type in d:
web_element = d[locator_type](self.__driver)
To be completely independent of the driver or the element, use
d = dict(methods)
if locator_type in d:
web_element = methodcaller(d[locator_type], element)(self.__driver)
You can construct the name of the function to call from the locator_type
, and then call it:
locator_type_lower = locator_type.lower()
find_function_name = 'find_element_by_{}'.format(locator_type_lower)
driver_function_to_call = getattr(self.__driver, find_function_name)
web_element = driver_function_to_call(element)
You should probably wrap this in some error checking - check if the function exists, check if it's callable, etc.
What this does: converts the locator_type to lowercase, then builds what is hopefully the function name of an existing function in self.__driver, then calls it with your element.
This method has the advantage that you don't have to map strings to functions - if self.__driver
has a function called find_element_by_foo_bar_length
, then you can simply add FOO_BAR_LENGTH
into your excel spreadsheet, and it will get called, no need to update your mapping dict.
Edit: updated for comments
To translate locator_type string into an attribute of the By
class:
locator_type = 'ID'
element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((getattr(By, locator_type), element)))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With