1

I am automating a confirmation request, and my code gets me all the way to the end, but when it comes to actually confirming my reservation, there is a popup modal window that appears as a layover on the original webpage. The button that's clickable is called "Confirm Booking", but when I call that, it doesn't click. My code ends up timing out. Why is this happening and what who do I need to do to correct it?

HTML snippet:

<button _ngcontent-ng-c1987900360="" id="confirmBookingModal" type="button" variant="primary" class="btn btn-primary"> Confirm Booking </button>

My code:

    # Wait for the modal to appear and find the confirm button
    confirm_button = WebDriverWait(driver, 5).until(
        EC.element_to_be_clickable((By.XPATH, "//button[contains(@class, 'btn-primary') and text()='Confirm']"))
    )
    confirm_button.click()

except TimeoutException:
    print("Modal or Confirm button not found. Please check the element ID or visibility.")

finally:
    # Close the browser
    time.sleep(2)  # Optional: wait to see the effect
    driver.quit()

I keep receiving a timeout error or my system will print the modal or confirm button not found. Please check the element ID or visibility. How do I fix this?

1
  • Can you share the page? It could be any number of issues. Commented Sep 4 at 14:05

4 Answers 4

0

It's probably in a frame you need to switch to first:

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


WebDriverWait(driver, 10).until(
    EC.frame_to_be_available_and_switch_to_it((By.ID, "frame"))
)
# ... then select the element and click it
Sign up to request clarification or add additional context in comments.

Comments

0

Given the html:

<button _ngcontent-ng-c1987900360="" id="confirmBookingModal" type="button" variant="primary" class="btn btn-primary"> Confirm Booking </button> 

the xpath condition you are using as text()='Confirm' will look for an exact match of Confirm, where as the exact text is Confirm Booking with leading & trailing spaces.


Solution

As a solution you can use the following xpath:

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

confirm_button = WebDriverWait(driver, 5).until(
    EC.element_to_be_clickable((By.XPATH, "//button[contains(@class, 'btn-primary') and normalize-space()='Confirm Booking']"))
confirm_button.click()

Comments

0

So, based on your HTML

<button _ngcontent-ng-c1987900360="" id="confirmBookingModal" type="button" variant="primary" class="btn btn-primary"> Confirm Booking </button>

And your provided code

# Wait for the modal to appear and find the confirm button
    confirm_button = WebDriverWait(driver, 5).until(
        EC.element_to_be_clickable((By.XPATH, "//button[contains(@class, 'btn-primary') and text()='Confirm']"))
    )
    confirm_button.click()

the issue resides within your text()='Confirm' statement. Your button text is "Confirm Booking". So, your text() will never equal "Confirm".

You can solve your issue in a few ways.

SOLUTION #1

# Wait for the modal to appear and find the confirm button
    confirm_button = WebDriverWait(driver, 5).until(
        EC.element_to_be_clickable((By.XPATH, "//button[contains(@class, 'btn-primary') and contains(text(), 'Confirm Booking')]"))
    )
    confirm_button.click()

Explanation: if you replace text()='Confirm' with Contains() , you can get the "Confirm Booking" button / element.

SOLUTION #2 (my recommendation)

# Wait for the modal to appear and find the confirm button
    confirm_button = WebDriverWait(driver, 5).until(
        EC.element_to_be_clickable((By.XPATH, "//button[@id='confirmBookingModal' and @type='button']"))
    )
    confirm_button.click()

Explanation: I would recommend using @id in the XPath because, for most of the time, the @id attribute value will never change. Your "Confirm Booking" could, some day, change to "Confirm". Or, it could change to "Continue". BUT, the @id will (for the most part) never change. So, I always recommend looking for a unique attribute before creating a more complex XPath.

I hope these solutions and explanations help you!

ADDENDUM

Oh! I had a quick realization. You could also replace EC.element_to_be_clickable() to EC.presence_of_element_located() because presence_of_element_located() waits until the element is found in the DOM vs waiting for it to be interactable. One is a little bit quicker than the other; but, that part is up to you. Anyways, I hope these solutions help you.

Comments

0

It probably due to the

Current:

//button[contains(@class, 'btn-primary') and text()='Confirm']

Change it to

//button[contains(@class, 'btn-primary') and text()='Confirm Booking']

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.