seleniumbase / SeleniumBase

📊 Python's all-in-one framework for web crawling, scraping, testing, and reporting. Supports pytest. UC Mode provides stealth. Includes many tools.
https://seleniumbase.io
MIT License
4.46k stars 910 forks source link

Issue with Handling Popup Alerts in SB() mode #2662

Closed LiPingYen closed 3 months ago

LiPingYen commented 3 months ago

I'm encountering an issue while handling popup alerts (as shown in the attached image) in SB mode. I've attempted using sb.dismiss_alert(), sb.accept_alert(), and sb.switch_to_alert() methods, but none of them seem to click the "OK" button successfully. Additionally, when trying to inspect the HTML and combining it with sb.driver.uc_click() to click, there isn't enough information to identify the button's XPath, resulting in an inability to click.

Interestingly, when the popup alert appears, pressing the "Return" key on the keyboard successfully navigates back to the previous page. However, using sb.send_keys('return') or sb.send_keys('/n') doesn't click the button successfully, and it causes the Chromedriver to hang, with subsequent actions not being executed, although the code doesn't terminate. I've also attempted using pyautogui.press('enter'), which leads to the same scenario.

Although I can successfully click the "OK" button using pyautogui.click(500,500) in driver mode, integrating it into SB mode doesn't work, and it leads to the Chromedriver hanging issue described above. Since the entire process needs to be implemented using SB or BC mode, I'm seeking suggestions for a solution to this problem.

Any insights or suggestions on effectively handling this issue would be greatly appreciated. I appreciate your help!

CleanShot 2024-04-04 at 19 26 18

Screenshot 2024-04-04 at 11 24 02 PM
mdmintz commented 3 months ago

You have invalid syntax in your calls to sb.send_keys() - That takes two required parameters: selector and text. You only passed in one value. I also saw that you used /n instead of \n. (\n is the newline/return character).

Also, if that's an actual alert, then sb.accept_alert() should work. I can't debug things unless you post actual stack traces.

LiPingYen commented 3 months ago

Hi @mdmintz , The following code can reproduce the scenario.


with SB(uc = True, incognito=True, demo=True) as sb:

    sb.driver.uc_open_with_reconnect('https://tixcraft.com/ticket/ticket/24_lss/16628/1/11', reconnect_time = 5)

    sb.driver.uc_click('//button[@id="onetrust-reject-all-handler"]', reconnect_time = 5)
    sb.send_keys('//input[@id="TicketForm_verifyCode"]', 'afnd')
    sb.select_option_by_text("#TicketForm_ticketPrice_01", '1')
    sb.driver.uc_click('//input[@id="TicketForm_agree"]', reconnect_time = None)
    sb.driver.uc_click('//button[@type="submit"]', reconnect_time = None)

    sb.sleep(5)

    sb.send_keys('html', '\n')
    # sb.accept_alert()
    # sb.dismiss_alert()

Also, I tested with driver mode, and driver.send_keys('html', '\n') can work. The driver can go back to the previous page successfully but will show the following error.

WebDriverException: Message: To submit an element, it must be nested inside a form element
mdmintz commented 3 months ago

Use this: (Don't use uc_click() if it takes you to a screen with a pop-up alert.)

from seleniumbase import SB

with SB(uc=True, incognito=True) as sb:
    url = 'https://tixcraft.com/ticket/ticket/24_lss/16628/1/11'
    sb.driver.uc_open_with_reconnect(url, reconnect_time=5)

    sb.send_keys('//input[@id="TicketForm_verifyCode"]', 'afnd')
    sb.select_option_by_text("#TicketForm_ticketPrice_01", '1')
    sb.driver.uc_click('input#TicketForm_agree')
    sb.driver.click('button[type="submit"]')

    sb.sleep(2)

    sb.accept_alert()

    sb.sleep(5)
LiPingYen commented 3 months ago

It works!!! Thank you so much @mdmintz.

I did some further tests and got some new issues.

  1. I replaced sb.driver.click('button[type="submit"]') with sb.click('button[type="submit"]') and the following error was shown.
    
    from seleniumbase import SB

with SB(uc=True, incognito=True) as sb: url = 'https://tixcraft.com/ticket/ticket/24_lss/16628/1/11' sb.driver.uc_open_with_reconnect(url, reconnect_time=5)

sb.send_keys('//input[@id="TicketForm_verifyCode"]', 'afnd')
sb.select_option_by_text("#TicketForm_ticketPrice_01", '1')
sb.driver.uc_click('input#TicketForm_agree')
sb.click('button[type="submit"]')

sb.sleep(2)

sb.accept_alert()

sb.sleep(5)

```python
UnexpectedAlertPresentException: Alert Text: The verification code that you entered is incorrect. Please try again.
Message: unexpected alert open: {Alert text : The verification code that you entered is incorrect. Please try again.}
  (Session info: chrome=123.0.6312.107)

Do you know why? In my mind, sb.click() and sb.driver.click() do the same thing.

  1. Will the driver still be undetectable after using sb.driver.click()? I try to remain undetectable with sb.driver.uc_click()
mdmintz commented 3 months ago

Perhaps the only difference between sb.click(selector) and sb.driver.click(selector) is that the first one waits for the readyState of the web page to be complete before performing the action, whereas the second one doesn't. Note that this readyState check is done using JS with driver.execute_script(), however, that can affect any pop-ups that are already present, in which case you can just use sb.driver.click(selector) instead.

As for "Will the driver still be undetectable after using sb.driver.click()?", that really depends on the website. You'll need to try it out yourself.

LiPingYen commented 3 months ago

Thank you for clarifying the difference between those two codes, and it helps me a lot. The project now is running smoothly.