0

I have a dropdown in my frontend looking like this:

    <div class="dropdown-menu dropdown-menu-right text-left" id="dropdown_menu">
          <a class="dropdown-item" data-toggle="modal" data-target="#exampleModalCenter" id="dropdown_change_pwd">Change Password</a>
          <a class="dropdown-item" href="{{ url_for('auth.logout') }}" id="dropdown_logout">Logout</a>
    </div>

I want to access these buttons with selenium in python. I tried to access it like this:

class SearchPage:
_CHANGE_PWD_DROPDOWN = (By.ID, 'dropdown_change_pwd')
_LOGOUT_DROPDOWN = (By.ID, 'dropdown_logout')
_DROPDOWN = (By.ID, 'dropdown_menu')

def __init__(self, browser):
    self.browser = browser

def logout(self):
    time.sleep(5)
    dropdown = self.browser.find_element(*self._DROPDOWN)
    dropdown.click()
    logout = self.browser.find_element(*self._LOGOUT_DROPDOWN)
    logout.click()

However I always end up with:

response = {'status': 400, 'value': '{\n\t"value" : \n\t{\n\t\t"error" : "element not interactable",\n\t\t"message" : "Element is not displayed",\n\t\t"stacktrace" : ""\n\t}\n}\r\n'}

It seems like Selenium can't deal with the bootstrap dropdown. How can I still click any of the elements in this dropdown?

If there is no direct solution for doing this, is there some way for an workaround?

Marc B.
  • 94
  • 2
  • 9

2 Answers2

0

To click on the Logout element you have to induce WebDriverWait for the element_to_be_clickable() and you can use either of the following Locator Strategies:

  • Using CSS_SELECTOR:

    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div.dropdown-menu.dropdown-menu-right.text-left"))).click()
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a.dropdown-item#dropdown_logout"))).click()
    
  • Using XPATH:

    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[@class='dropdown-menu dropdown-menu-right text-left']"))).click()
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[@class='dropdown-item' and @id='dropdown_logout']"))).click()
    
  • Note: You have to add the following imports :

    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
0

My dropdown in total looked like this:

    <li class="nav-item">
       <a class="nav-link dropdown-toggle" id="welcome_user" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">Welcome, {{ session['current_user']['name'] }}</a>
       <div class="dropdown-menu dropdown-menu-right text-left">
          <a class="dropdown-item" data-toggle="modal" data-target="#exampleModalCenter" id="dropdown_change_pwd">Change Password</a>
          <a class="dropdown-item" href="{{ url_for('auth.logout') }}" id="dropdown_logout">Logout</a>
       </div>
    </li>

First I had to access the upper element with:

   dropdown = self.browser.find_elemnt(By.ID, 'welcome_user')
   dropdown.click()

And then I can access the link like this:

    dropdown_logout = self.browser.find_elemnt(By.ID, 'dropdown_logout')
    dropdown_logout.click()
Marc B.
  • 94
  • 2
  • 9