Skip to content
Advertisement

Selenium Python Searching Element By 2 possible ID

I want to find the element using ID, but it seems that the web is sometimes changing the ID.

There are 2 IDs, the first ID will make me possible to enter the email directly, but if the second ID occurs, I need to click a button first before entering my email. I’ve tried using if and else logic but it shows some errors. Here is my code:

@pytest.mark.parametrize('a,b', key0)
def test_login_successful(self, a,b):
    time.sleep(5)
    if WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.ID, 'login-find-account-form'))) == True:
        pass

    else:
    # WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.ID, 'login-form')))
        WebDriverWait(driver, 20).until(EC.element_to_be_clickable(
            (By.XPATH, '//*[@id="login-form"]/div[1]/div/div/div/a'))).click()

    email_box = '//*[@id="user_name"]'
    email_input = driver.find_element_by_xpath(email_box)
    email_input.send_keys(a)

    submit = driver.find_element_by_xpath('//*[@id="submit_button"]').click()
    

If you have any idea to do this I would appreciate it.

Thanks

Advertisement

Answer

You could use CSS selector instead, something like this:

ID_1 = WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.CSS, '#login-form,#login-find-account-form')))

The comma works as an OR operator for CSS, if it doesn’t find the first one then it will attempt to find the second one. It is important that you know that this selector doesn’t work as an AND meaning that it won’t return two results.

Edit:

There is an easy way to achieve this (not the proper one).

Easy way to achieve what you need:

@pytest.mark.parametrize('a,b', key0)
def test_login_successful(self, a,b):
    time.sleep(5)

    # The element to be found on the second condition
    element_of_interest = driver.find_elements_by_xpath('//*[@id="login-form"]/div[1]/div/div/div/a')

    # element_of_interest is a list, if is empty this condition
    # is not valid and then it won't attempt to click on it
    if element_of_interest:
        element_of_interest[0].click()

    email_box = '//*[@id="user_name"]'
    email_input = driver.find_element_by_xpath(email_box)
    email_input.send_keys(a)

    submit = driver.find_element_by_xpath('//*[@id="submit_button"]').click()

A few comments on here. it looks like you don’t really need the first condition as you are not doing anything there. Therefore I added just the second condition.

If you take a look at the solution you will find that is using find_elements_by_xpath (in plural) instead of find_element_by_xpath the reason of this is because if the element is not found then find_elments_by_xpath will return an empty list.

if you need to wait 10 seconds until one of these element appear, then you could do something like this:

@pytest.mark.parametrize('a,b', key0)
def test_login_successful(self, a,b):
    time.sleep(5)

    # The element to be found on the second condition
    element1 = driver.find_elements_by_id('login-find-account-form')
    element2 = driver.find_elements_by_xpath('//*[@id="login-form"]/div[1]/div/div/div/a')

    # Waits up to 10 seconds to find either element 1 or 2
    retries = 10
    while not element1 or not element2:
         time.sleep(1)
         retries -= 1
         if retries < 0:
            raise Exception("some exception in here")
         element1 = driver.find_elements_by_id('login-find-account-form')
         element2 = driver.find_elements_by_xpath('//*[@id="login-form"]/div[1]/div/div/div/a')
       
    # element2 is a list, if is empty this condition
    # is not valid and then it won't attempt to click on it
    if element2:
        element2[0].click()

    email_box = '//*[@id="user_name"]'
    email_input = driver.find_element_by_xpath(email_box)
    email_input.send_keys(a)

    submit = driver.find_element_by_xpath('//*[@id="submit_button"]').click()

There is a better implementation for this I suggest to take a look to the Page object model documentation for selenium, you could benefit a lot from that design pattern: https://www.selenium.dev/documentation/guidelines/page_object_models/

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement