Search code examples
pythonseleniumweb-scrapingselenium-chromedriverelement

How to resolve TypeError: element_to_be_clickable() takes 1 positional argument?


I'm getting the error TypeError: element_to_be_clickable() takes 1 positional argument but 2 were given when I run the following code:

from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

url = 'https://www.expedia.co.uk/'

s = Service(ChromeDriverManager().install())
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option("excludeSwitches", ['enable-automation'])
driver = webdriver.Chrome(service=s, options=chrome_options)

driver.get(url)
elem = WebDriverWait(driver, 10).until(EC.element_to_be_clickable(By.CSS_SELECTOR, "#add-flight-switch"))
elem.click()
elem1 = driver.find_element(By.XPATH, "button[aria-label='Leaving from']").text
driver.quit()

I can see that there are indeed two arguments within the elements_to_be_clickable() function, but is the By.CSS_SELECTOR part not necessary to find by a specific selector type (in this case CSS) ??

I'm using selector hub to grab the CSS_SELECTOR info.

Any support on how to resolve will be very much appreciated.


Solution

  • You do need both By and the value, but the function expects both values to be packed to one, in a tuple

    EC.element_to_be_clickable((By.CSS_SELECTOR, "#add-flight-switch"))
    

    If you drill down the source code you will see element_to_be_clickable uses _find_element internally, this function unpack the tuple to be used in driver.find_element()

    class element_to_be_clickable(object):
        def __init__(self, locator):
            self.locator = locator
    
        def __call__(self, driver):
            element = visibility_of_element_located(self.locator)(driver)
        ...
    
    class visibility_of_element_located(object):
        def __init__(self, locator):
            self.locator = locator
    
        def __call__(self, driver):
            return _element_if_visible(_find_element(driver, self.locator))
        ...
    
    def _find_element(driver, by):
        ...
        return driver.find_element(*by)
        ...