Michael Francis
Michael Francis

Reputation: 8757

WebDriverWait throws TimeoutException, why?

I'm making a little program which automatically fills out the fast food survey at Del Taco so I can get $1 off my next purchase. I'm using Selenium WebDriver in python for this, and it works beautifully except for one little hiccup where there is one page that sometimes shows up, and sometimes doesn't.

I try to tell whether the extra page shows up with this function here, which is supposed to detect which of the telltale ID's shows up

def whichID(id1, id2):
    def find(driver):
        if driver.find_element_by_id(id1):
            return id1
        if driver.find_element_by_id(id2):
            return id2
        # if neither id is found
        return False

    try:
        print 'waiting'
        id = WebDriverWait(driver, timeout).until(find)
        print 'done waiting'
        return id
    except TimeoutException:
        print 'timeout exception'
        return False

id = whichID("option_745653_340084", "option_522363_247141")

if (id == "option_745653_340084"):
    # final page
    clickBy('id', "option_745653_340084")
else:
    # demographics page
    clickBy('id', "option_522363_247141")
    clickBy('id', "option_522373_247142")
    nextButton.click()
    #final page
    clickBy('id', "option_745653_340084")

This does work, but any time the extra page (I call it the demographics page) shows up, it takes an extra 5 seconds before it moves on to the final page (I have timeout set to 5). I checked it out with some print statements as you can see above, and it looks WebDriverWait is throwing a TimeoutException every time the demographics page comes up. I don't understand why. Clearly the IDs are showing up on the page, why would it time out?

For reference, here is the program in it's current iteration

Upvotes: 2

Views: 2658

Answers (1)

Andersson
Andersson

Reputation: 52685

I think this is the root-cause of your problem:

if driver.find_element_by_id(id1):
    return id1
if driver.find_element_by_id(id2):
    return id2
return False

It doesn't work as you seem to expect... If driver.find_element_by_id(id1) doesn't find the element you will not switch to next if block, but get an exception which will be handled then by except block. return False will NEVER be executed.

I would do something like:

from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

# First option
def whichID(id1, id2):
    id_value = None
    try:
        WebDriverWait(driver, timeout).until(EC.presence_of_element_located((By.ID, id1)))
        id_value = id1
    except TimeoutException:
        try:
            WebDriverWait(driver, timeout).until(EC.presence_of_element_located((By.ID, id2)))
            id_value = id2
        except TimeoutException:
            print("No nodes found")
    return id_value

# Second option
def whichID(id1, id2):
    try:
        id_value = WebDriverWait(driver, timeout).until(EC.presence_of_element_located((By.XPATH, "//*[@id='{0}' or @id='{1}']".format(id1, id2)))).get_attribute("id")
        return id_value
    except TimeoutException:
        return None

id_value = whichID("option_745653_340084", "option_522363_247141")

P.S. Note that id() is a Python built-in function. You shouldn't use "id" as variable name

Upvotes: 4

Related Questions