4

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

3
  • 1
    Can you elaborate on why the answer you linked did not help you? It seems like a dict would do a lot to alleviate the multiple if and elif blocks in your example code. Are you just having difficulty figuring out how to hash a function call? That is, how to store a function in a hash. Commented Mar 18, 2019 at 19:32
  • @MikeHolt i'm not able to understand how hashing a function call could help? Kindly give me some insight on it. Commented Mar 18, 2019 at 19:50
  • Sorry, my wording was a little sloppy. I was referring to storing (references to) functions as values in a hash (a.k.a. a dict in Python), exactly as shown in chepner's answer. Commented Mar 18, 2019 at 20:14

2 Answers 2

11

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)
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you very much for clearing this up, i'll try this and update you.
It's working , but a small question.. the driver object needs to be instantiated before calling the dictionary?
As shown here, yes. I'll add a solution using methodcaller, which I omitted because it looks a bit more complicated, but makes d independent of the driver.
chepner, can you help once more? How do i make method caller for explicit wait function in selenium. Example: """ WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "myDynamicElement"))) """
4

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)))

4 Comments

Hey Danielle, is there any way we can implement this for the following statement? """ WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, "myDynamicElement"))) """. I have tried the following way: driver.get('https://www.google.com/') locator_type= 'NAME' element = 'q' exp_wait_str = "WebDriverWait({}, 10).until(EC.presence_of_element_located((By.{}, {})))".format(driver, locator_type, element) fun = getattr(driver, exp_wait_str) web_element = fun(locator_type, element)
I'm trying to understand the concept but i'm not able use the method you suggested for the above statement. Kindly look into this.
Hi there! What you're trying to do is dynamically pull the locator_type from the By class. I'll update my answer above with how to do that.
Thank you very much Danielle, it worked like a charm and you helped remove more than 30 lines of repetitve code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.