Create custom wait until condition in Python

后端 未结 4 1826
失恋的感觉
失恋的感觉 2021-01-04 09:39

I tried to create a function with custom wait condition in Python. However, I get an error:

TypeError: \'bool\' object is not callable

相关标签:
4条回答
  • 2021-01-04 10:13

    The wait.until(..) function from selenium expects a function that it can call. However, you are, effectively, giving it a boolean.

    element = wait.until(waittest(driver, '//div[@id="text"]', "myCSSClass", "false"))
    

    Can be rewritten as:

    value = waittest(driver, '//div[@id="text"]', "myCSSClass", "false")
    element = wait.until(value)
    

    Which makes this more clear - waittest returns a boolean, and wait.until(..) tries to call it as a function - hence 'bool' object is not callable.

    You need to have your custom condition return a function that selenium can call to check if it's true yet. You can do this by defining a function inside your function:

    def waittest(locator, attr, value):
        def check_condition(driver):
            element = driver.find_element_by_xpath(locator)
            if element.get_attribute(attr) == value:
                return element
            else:
                return False
        return check_condition
    
    0 讨论(0)
  • It may not really answer question, I just want to save my custom wait function here :D

    I don't like WebDriverWait() it need another import that not really easy to remember or type and it also used another function to select element.

    Example:

    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait 
    from selenium.webdriver.support import expected_conditions as EC
    
    WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.CLASS_NAME , 'myClass')))
    

    here custom wait to use with default function

    import time
    
    def waitFor(maxSecond, runFunction, param):
        while maxSecond:
            try:
                return runFunction(param)
            except:
                time.sleep(0.5)
                maxSecond -= 0.5
    

    Usage:

    # wait 5 second
    waitFor(5, driver.find_element_by_class_name, 'myClass')
    # Or
    link = waitFor(5, driver.find_element_by_class_name, 'myClass')
    link.click()
    # Or
    link = waitFor(5,....)
    if not link:
        print('Timeout, link not found')
    

    and for reference

    To find single elements

    • find_element_by_id
    • find_element_by_name
    • find_element_by_xpath
    • find_element_by_link_text
    • find_element_by_partial_link_text
    • find_element_by_tag_name
    • find_element_by_class_name
    • find_element_by_css_selector

    To find multiple elements (these methods will return a list):

    • find_elements_by_name
    • find_elements_by_xpath
    • find_elements_by_link_text
    • find_elements_by_partial_link_text
    • find_elements_by_tag_name
    • find_elements_by_class_name
    • find_elements_by_css_selector
    0 讨论(0)
  • 2021-01-04 10:19

    WebDriverWait(driver, 10).until() accepts a callable object which will accept an instance of a webdriver (driver is our example) as an argument. The simplest custom wait, which expects to see 2 elements, will look like

    WebDriverWait(driver, 10).until(
        lambda wd: len(wd.find_elements(By.XPATH, 'an xpath')) == 2
    )
    

    The waittest function has to be rewritten as:

    class waittest:
        def __init__(self, locator, attr, value):
            self._locator = locator
            self._attribute = attr
            self._attribute_value = value
    
        def __call__(self, driver):
            element = driver.find_element_by_xpath(self._locator)
            if element.get_attribute(self._attribute) == self._attribute_value:
                return element
            else:
                return False
    

    And then it can be used as

    element = WebDriverWait(driver, 10).until(
        waittest('//div[@id="text"]', "myCSSClass", "false")
    )
    
    0 讨论(0)
  • 2021-01-04 10:23

    what I really end up to do is using lambda

    self.wait.until(lambda x: waittest(driver, "//div[@id="text"]", "myCSSClass", "false"))
    
    0 讨论(0)
提交回复
热议问题