Python selenium : Explicitly wait for one of two elements to be loaded
Asked Answered
D

3

14

Is there a way using which I can wait for one of two elements to get loaded in selenium. I am using explicit waits and so far, haven't been able to figure out the solution.

Simply doing

WebDriverWait(driver,5).until(lambda driver : driver.find_element(By.ID,"a") or driver.find_element(By.ID,"b"))

doesn't seem to work. It just looks for element with id ="a".

Thanks!

Desai answered 22/12, 2014 at 15:54 Comment(2)
Just load the page and put a test for the element you want inside a "while True" loop waiting for half a second each cycle.Arnie
How about generating an XPATH that hits both targets? e.g. #73227176Chung
B
16

find_element raises NoSuchElementException exception if no element is found.

If element with the id a does not exist, driver.find_element(By.ID,"a") will raises the exception and the driver.find_element(By.ID,"b") will not be executed.

A simple way to solve the problem is using find_elements which return empty list instead of raising the exception:

WebDriverWait(driver,5).until(
    lambda driver: driver.find_elements(By.ID,"a") or driver.find_elements(By.ID,"b"))
Bogusz answered 22/12, 2014 at 16:24 Comment(1)
It cleared my concept of lambda- until waits for a true case.Verbenia
F
7

As falsetru explained if your first find_element call fails to find an element, it will raise NoSuchElementException and the 2nd part of your test won't execute.

I would suggest using a CSS selector that matches either IDs you are looking for:

WebDriverWait(driver, 5).until(
    lambda driver : driver.find_element_by_css_selector("#a, #b"))

This has an advantage over performing two find_elements calls becayse this will make only one roundtrip between your Selenium client (your script) and the Selenium server. This should always be faster than performing two find_elements calls. When performing tests locally, the difference won't be much but if you perform tests remotely, for instance using Sauce Labs or Browser Stack, the difference will be significant.

Foah answered 22/12, 2014 at 17:14 Comment(0)
F
-1

Note, find_elements returns a list, so if you wanted to test for the element you will have to iterate through a list So in the below code I needed to test for 2 elements (depending on the scenario) and then test what element was returned so I can do the apropriate action

# If the number is NOT a WhatsApp number then there will be an OK Button, not the Message Textbox
            # Test for both situations -> find_elements returns a List
            ctrl_element = self.wait.until(
                lambda ctrl_self:
                    ctrl_self.find_elements(By.XPATH, nr_not_found_xpath) or
                    ctrl_self.find_elements(By.XPATH, inp_xpath)
            )
            # Iterate through the list of elements to test each if they are a textBox or a Button
            for i in ctrl_element:
                if i.aria_role == 'textbox':
                    # This is a WhatsApp Number -> Send Message
                    i.send_keys(message + Keys.ENTER)
                    msg = f"Message sent successfully to {self.mobile}"

                elif i.aria_role == 'button':
                    # This is NOT a WhatsApp Number -> Press enter and continue
                    i.send_keys(Keys.ENTER)
                    msg = f"Not a WhatsApp Number {self.mobile}"
Fennec answered 21/4, 2022 at 15:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.