Jossy
Jossy

Reputation: 1021

Why am I unable to select an item in a dropdown?

I have the following MRE code that is mean to select EU Odds from a dropdown:

from pathlib import Path
from time import sleep

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.ui import WebDriverWait

chrome_driver = str(Path("chromedriver/chromedriver/"))
driver = webdriver.Chrome(chrome_driver)
driver.get("https://www.oddsportal.com/matches/tennis/")
driver.find_element(By.ID, "user-header-oddsformat-expander").click()
sleep(1)
wait = WebDriverWait(driver, 10)
target = "EU Odds"
wait.until(ec.element_to_be_clickable((By.XPATH, "//li[.='" + target + "']"))).click()

Everything works up until the final line which doesn't make the selection. If I try to do this manually on the page that chromedriver opens then I'm also unable to make the selection. However, if I open up a normal browsing window then I am able to make the selection.

Where am I going wrong?

Upvotes: 1

Views: 128

Answers (4)

undetected Selenium
undetected Selenium

Reputation: 193308

From a broader perspective there is nothing wrong in your code.

However to optimize your code you may like to:

  • Induce WebDriverWait for the element_to_be_clickable() for the expander to be clickable.

  • The texts EU Odds, UK Odds, US Odds, etc are not exactly within the <li> but within it's grand parent //li/a/span

  • So to select EU Odds, UK Odds, US Odds one by one your optimized Locator Strategies can be:

    driver.get('https://www.oddsportal.com/matches/tennis/')
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.ID, "user-header-oddsformat-expander"))).click()
    target = "EU Odds"
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//li/a/span[text()='" + target + "']"))).click()
    time.sleep(3) # for visual demonstration
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.ID, "user-header-oddsformat-expander"))).click()
    target = "UK Odds"
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//li/a/span[text()='" + target + "']"))).click()
    time.sleep(3) # for visual demonstration
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.ID, "user-header-oddsformat-expander"))).click()
    target = "US Odds"
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//li/a/span[text()='" + target + "']"))).click()
    

This usecase

However even sucessfully clicking on the options with text as EU Odds, UK Odds, US Odds doesn't changes the DOM Tree. Now if you look into the HTML DOM the expander class itself is having the value as user-header-fakeselect-options. Additionally, the onclick attribute of the //li/a/span items are having return false;.

fakeselect

As per the discussion What's the effect of adding 'return false' to a click event listener? return false; does three separate things when called:

  • Calls event.preventDefault();
  • Calls event.stopPropagation();
  • Stops callback execution and returns immediately when called.

Hence selecting either of the dropdown options doesn't fires the onclick event and the HTML DOM remains unchanged.


Conclusion

Possibly the DOM would change as per the onclick events when a authenticated user performs the selection after loggind in within the website.

Upvotes: 1

Jarvis
Jarvis

Reputation: 8564

The actual issue is with the website itself. Trying to select any other option other than EU Odds doesn’t work even manually. Seems like you need to be logged in to do that.

Upvotes: 2

Guy
Guy

Reputation: 50939

There are two issues with the xpatי: Too many apostrophes around the text Trying to locate the wrong tag, the clickable element is the <a> tag, not the <li> tag.

Use "//a[.=' + target + ']"

Upvotes: 0

cozmoguy
cozmoguy

Reputation: 1

Try this. Selenium has a special way to handle dropdown selection

First import select :

from selenium.webdriver.support.ui import Select

Then assign the dropdown to a variable:

dropdown_element = browser.find_element_by_xpath('//*[@id="exam_id"]')

Then create an object:

dropdown_object = Select(dropdown_element)

Finally select the option:(there will be a value for every options)

dropdown_object.select_by_value('17')

Upvotes: 0

Related Questions