cybertextron
cybertextron

Reputation: 10961

Looking and Performing action through xpath variables in Selenium - Python

I have the following page layout:

<div class="x1">
    <button aria-expanded="false" class="button" data-toggle="dropdown" type="button">Actions<span class="caret"></span></button>
    <ul class="dropdown-menu" role="menu">
        <li>
            <a href="<my_link>/start">Start</a>
        </li>
        <li>
            <a data-target="delete" data-toggle="modal">Delete</a>
        </li>
        <li>
            <a href="<my_link>/auth">Authenticate</a>
        </li>
    </ul>
</div>

Each one of these represent a button ("Action"), which when clicked will present a dropdown menu between Start, Delete, and Authenticate. I'm trying to automate my page test from the backend using Selenium and Python. Here what I have so far:

def scan_page(action):
    scan_url = urlparse.urljoin(self.base_url, "foo")
    self.driver.get(scan_url)
    elements = self.driver.find_elements_by_xpath("//div[@class='x1']")
    # loop over all the elements found by xpath
    for element in elements:
        element.click()
        ul = element.find_element_by_class_name("dropdown-menu")

        if action == "scan":
           if "Start" in ul.text:
              # start the action
              button = element.find_element_by_xpath("//button[@data-toggle='dropdown']")
              button.click()
      elif action == "delete":
           if "Delete" in ul.text:
              self.log.info("Deleting...")
     elif action == "auth":
           if "auth" in ul.text:
              self.log.info("Authenticating...")
     else:
        continue

The function is given an action, which define what is to be done. If "start" then loops over all the elements and click the Start option. However, it doesn't look like it's going over all the buttons defined in the page, and only the first button is being started. So, for some reason, the Delete option is somehow selected.

What am I doing wrong?

Update:

I've added a JS Fiddle so people can play with that: http://jsfiddle.net/58rs3kuk/1/

Upvotes: 1

Views: 154

Answers (1)

JeffC
JeffC

Reputation: 25597

I found and fixed a few issues. I think this should work or at least get you on the right track.

1) You were clicking the container DIV which isn't necessary. It probably doens't hurt, it just doesn't do anything productive.

2) You were clicking BUTTON only if action = "scan". You want to click BUTTON for all actions so those lines need to move up before the IF starts. So... you will 1. click the BUTTON, 2. determine what action was requested, and 3. perform that action.

3) You were grabbing the UL to get the text but the text you want is in the LI (but is not needed after the changes I made).

4) I changed the names of some of the variables to make them more identifiable, elements is now buttonContainers and element is now buttonContainer. I would suggest you follow this practice because it will help you (and others) debug your code more easily.

5) Since we know the order of the actions in each button and they are all the same, we don't have to look for the text in the link... we can just click them by index: 0 for Start, 1 for Delete, 2 for Authenticate.

6) Added a warning in the logs if an invalid action is passed. You should probably change that to an exception or whatever is appropriate in your scripts.

7) Fixed the indent of the code you posted

def scan_page(action):
  scan_url = urlparse.urljoin(self.base_url, "foo")
  self.driver.get(scan_url)
  buttonContainers = self.driver.find_elements_by_xpath("//div[@class='x1']")
  # loop over all the buttonContainers
  for buttonContainer in buttonContainers:
    buttonContainer.find_element_by_tag_name("button").click()
    lis = buttonContainer.find_elements_by_tag_name("li")
    if action == "start":
      lis[0].click() # because we know the order of the actions and they are the same in each button, we can just click on them by index.
      self.log.info("Starting...")
    elif action == "delete":
      lis[1].click()
      self.log.info("Deleting...")
    elif action == "auth":
      lis[2].click()
      self.log.info("Authenticating...")
    else:
      self.log.info("WARNING: " + action + " is not a valid action.")
      continue

Upvotes: 1

Related Questions