【问题标题】:Selenium WebDriver - Unable to handle alerts that appear on page loadSelenium WebDriver - 无法处理页面加载时出现的警报
【发布时间】:2021-05-11 07:04:03
【问题描述】:

我有以下场景要自动化:

  1. 导航到应用程序 URL
  2. 单击一个名为打开新窗口的按钮
  3. 该应用会打开一个新窗口,其中包含在页面加载时显示的警报。
  4. 切换到新窗口并接受/关闭警报
  5. 继续其余的自动化操作

我们在第 4 步中遇到了问题。当我们切换到新窗口并尝试执行driver.switchTo().alert().accept() 时,我们得到NoAlertPresentException,即使我们可以看到警报。

下面是我们的代码(为简单起见,提取到一个类中)。

已编辑:根据 Mithilesh Indurkar 的建议(添加了隐式等待新窗口和警报),还添加了检查以验证父窗口句柄

@Slf4j
public class AlertTest {
    
    private static final String GECKO_DRIVER_PATH = "path\to\geckodriver.exe";

    public static void main(String[] args) {
        
        // Launch browser
        log.info("Launching Browser");
        WebDriver driver = launchBrowser();
        String strParentWindowHandle = driver.getWindowHandle();
        // Navigate to the App
        log.info("Navigating to app");
        driver.get("http://localhost:5500");
        
        //Here's where the browser opens a new window
        driver.findElement(By.id("btnNewWindow")).click();
        
        
        // Switch to new window
        log.info("Switching to new window");
        boolean windowSwitched = switchToNewWindow(driver, strParentWindowHandle);
        if(!windowSwitched) {
            log.error("Error --> Switch to new window failed. Script is aborting...");
            close(driver);
            return;
        }
        
       try {
           // Wait for alert
           WebDriverWait wait = new WebDriverWait(driver, 30);
           wait.until(ExpectedConditions.alertIsPresent());
           
           log.info("Alert is present");
       } catch(TimeoutException e) {
           log.error("Timed out (30 seconds) waiting for alert to be present");
           log.error("Script is aborting...");
           close(driver);
           return;
       }
        
        // Handle alert
        boolean alertHandledSuccessfully = false;
        try {
            Alert alert = driver.switchTo().alert();
            String alertText = alert.getText();
            log.info("Alert handled --> {}", alertText);
            alertHandledSuccessfully = true;
        } catch (Exception e) {
            log.error("Error handling alert", e);
        }
        
        if(alertHandledSuccessfully) {
            // Click the button
            log.info("Clicking button");
            driver.findElement(By.id("btn")).click();
        }else {
            log.error("Error --> Could not handle alert on load");
        }
        
        
        // Close the browser
        log.info("Closing...");
        close(driver);
    }

    private static WebDriver launchBrowser() {
        System.setProperty("webdriver.gecko.driver", GECKO_DRIVER_PATH);

        WebDriver driver = new FirefoxDriver();
        driver.manage().window().maximize();
        
        return driver;
    }

    private static boolean switchToNewWindow(WebDriver driver, String strParentWindowHandle) {
        
        try {
            WebDriverWait wait = new WebDriverWait(driver, 10);
            wait.until(ExpectedConditions.numberOfWindowsToBe(2));
            log.info("No. Of windows is now 2");
        } catch(TimeoutException e) {
            log.error("Error --> Timed out (10 seconds) while waiting for second window to be present");
            return false;
        }
        
        //Added/modified by Mithilesh
        String[] windowHandlesArray = driver.getWindowHandles().toArray(new String[] {});
        String strNewWindowHandle = "";
        for(int intHandleLoopCounter = 0; intHandleLoopCounter <windowHandlesArray.length; intHandleLoopCounter++)
        {
            strNewWindowHandle = windowHandlesArray[intHandleLoopCounter];
            if(strNewWindowHandle.equalsIgnoreCase(strParentWindowHandle) == false)
            {
                driver.switchTo().window(strNewWindowHandle);
                log.info("Switched to window with handle {}", strNewWindowHandle);
                return true;

            }
            else if(intHandleLoopCounter==windowHandlesArray.length)
            {
                return false;
            }
        }
        
        return false;
    }
    
    private static void close(WebDriver driver) {
        if(driver == null) return;
        driver.close();
        driver.quit();
    }
}

现在,当我们尝试处理加载新窗口时出现的警报时,我们得到以下异常:

org.openqa.selenium.NoAlertPresentException: 
Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-14T08:17:03'
System info: host: 'YCSLAP0010', ip: '172.22.0.1', os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '1.8.0_231'
Driver info: org.openqa.selenium.firefox.FirefoxDriver
Capabilities {acceptInsecureCerts: true, browserName: firefox, browserVersion: 88.0, javascriptEnabled: true, moz:accessibilityChecks: false, moz:buildID: 20210415204500, moz:geckodriverVersion: 0.29.0, moz:headless: false, moz:processID: 17472, moz:profile: C:\Users\s.sriram\AppData\L..., moz:shutdownTimeout: 60000, moz:useNonSpecCompliantPointerOrigin: false, moz:webdriverClick: true, pageLoadStrategy: normal, platform: WINDOWS, platformName: WINDOWS, platformVersion: 10.0, rotatable: false, setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify}
Session ID: 531336cf-f8d3-429a-98d9-555a40c3f7cd
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.createException(W3CHttpResponseCodec.java:187)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:122)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:49)
    at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:158)
    at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:83)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:552)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:609)
    at org.openqa.selenium.remote.RemoteWebDriver$RemoteTargetLocator.alert(RemoteWebDriver.java:932)
    at com.yethi.agent.wsresponse.util.AlertTest.main(AlertTest.java:36)

问题总结如下:

我们在尝试处理页面加载期间出现的警报时遇到 NoAlertPresentException,尤其是在新窗口中加载页面时。

以下 HTML sn-ps 可帮助您模拟应用的屏幕

index.html - 这被假定为应用的登陆页面

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Alert Simulation</title>
    <script>
      function openNewWindow() {
        window.open("page.html", "_blank", "width=300, height=300");
      }
    </script>
  </head>
  <body>
    <form name="loginForm" action="#" method="POST">
      <div>
        <label for="username">User name: </label>
        <input type="text" id="username" name="username" />
      </div>
      <div>
        <label for="password">Password: </label>
        <input id="password" type="password" name="password" />
      </div>
      <div>
        <button type="button" id="btnLogin" onClick="showAlert();">
          Login
        </button>
        <button type="button" id="btnNewWindow" onClick="openNewWindow();">
          Open New Window
        </button>
      </div>
    </form>
  </body>
</html>

page.html - 这会在一个新窗口中打开,并带有警报 onLoad。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script>
      function showAlert(alertText) {
        alert(alertText ? alertText : "Page Loaded!");
      }

      function onButtonClick() {
        showAlert("Button Clicked");
        document.querySelector("#output").innerText = "Button clicked!";
      }
    </script>
  </head>
  <body onload="showAlert();">
    <h1>This page opens in a new window with an alert onload</h1>
    <button type="button" id="btn" onclick="onButtonClick();">Click Me</button>
    <p id="output"></p>
  </body>
</html>

【问题讨论】:

  • 您是否尝试在使用警报的代码之前添加等待,以确保在您尝试与之交互时它已经出现?
  • 是的。我们尝试了 WebDriverWait 和任意的 Thread.sleep,但都是徒劳的。
  • 切换到窗口句柄不起作用。警报不是浏览器选项卡或浏览器窗口。将boolean isDialogPresent(WebDriver driver) { IAlert alert = ExpectedConditions.AlertIsPresent().Invoke(driver); return (alert != null); } 添加到您的代码中并进行调试。
  • 我认为你错过了一点。警报出现在一个页面上,该页面又在新窗口中打开。我们需要先切换到新窗口,然后再处理alert。
  • 嗨,我相信您一定尝试过各种方法,但在完全理解问题之前我需要了解以下内容。 1、你有没有等过第二个窗口的外观? ==> codoid.com/wait-for-webdriver-windows-count/…。 2.你是否给了webdriverwait期望的条件来等待警报? 3. 从您的方法 switchToNewWindow 中,打印了哪些文本?它打印任何东西吗?

标签: java selenium alert


【解决方案1】:

除了上面我的 cmets,我正在输入一个可以进一步适合您的解决方案的解决方案

在浏览器启动后获取父窗口句柄。

// Launch browser
            log.info("Launching Browser");
            WebDriver driver = launchBrowser();
            //Added by Mithilesh
            String strParentWindowHandle = driver.getWindowHandle();

应该这样调用切换

// Switch to new window
            log.info("Switching to new window");
            boolean windowSwitched = switchToNewWindow(driver, strParentWindowHandle); //Modified by Mithilesh
            if(!windowSwitched) {
                log.error("Error --> Switch to new window failed. Script is aborting...");
                close(driver);
                return;
            }

这应该是你的切换方法实现

private static boolean switchToNewWindow(WebDriver driver, String strParentWindowHandle) {
            
            try {
                WebDriverWait wait = new WebDriverWait(driver, 10);
                wait.until(ExpectedConditions.numberOfWindowsToBe(2));
                log.info("No. Of windows is now 2");
            } catch(TimeoutException e) {
                log.error("Error --> Timed out (10 seconds) while waiting for second window to be present");
                return false;
            }
            
            //Added/modified by Mithilesh
            String[] windowHandlesArray = driver.getWindowHandles().toArray(new String[] {});
            String strNewWindowHandle = "";
            for(int intHandleLoopCounter = 0; intHandleLoopCounter <windowHandlesArray.length; intHandleLoopCounter++)
            {
                strNewWindowHandle = windowHandlesArray[intHandleLoopCounter];
                if(strNewWindowHandle.equalsIgnoreCase(strParentWindowHandle) == false)
                {
                    driver.switchTo().window(strNewWindowHandle);
                    return true;

                }
                else if(intHandleLoopCounter==windowHandlesArray.length)
                {
                    return false;
                }
            }
            
            
        }

此循环是必需的,因为 set 不是有序集合,并且不保证第二个窗口句柄将位于数组中的第二个位置。让我知道它是否有效。

另外,您错误地处理了弹出窗口。弹出窗口应按以下方式处理。

  1. 接受()
  2. 解雇()
  3. getText()
  4. sendKeys()

在您的情况下,应该使用driver.switchTo().alert().accept() 而不是在弹出窗口中查找按钮。您不能像任何其他 Web 元素一样单击弹出按钮作为 Web 元素。

【讨论】:

  • 嗨 Mithilesh,尝试过这种方法。能够切换到新窗口,但 WebDriverWait 等待警报出现在 30 秒后仍然超时。但是,我可以在页面上看到警报。
  • 好的。这很奇怪。对我来说,这看起来不像是一个正常的警报。您能否确认您的 HTML sn-p 生成的警报是否与您收到的警报相同。如果可能,您可以发布警报的屏幕截图
  • 我会安排一张快照。同时,我想告诉你,我一直在测试我粘贴在问题中的sn-p,它不起作用。您能否确认您是否可以成功处理我上面的 html sn-p 中的警报?如果是,那么我所做的事情肯定有问题..
  • @Sriram Sridharan 我尝试运行 HTML sn-p,它运行良好 Page Loaded!按钮点击通过:设置 ============================================== == 默认测试测试运行:1,失败:0,跳过:0 ================================= ==============
  • @YaDavMaNish 你能给我你的代码sn-p吗?我可以在本地尝试相同的..
【解决方案2】:

我刚刚用下面的代码行执行了上面的 html sn-p, 希望这会对您有所帮助

public static void acceptAlert() {
new WebDriverWait(driver,10)
.until(ExpectedConditions.alertIsPresent())
.accept();}

public static String getTextFromAlert() {
String str = new WebDriverWait(driver, 10).until(ExpectedConditions.
alertIsPresent()).getText();
return str;}

@Test
public static void setUp() {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
driver.get("https://stackoverflow.com/questions/67481982/selenium- 
      webdriver-unable-to-handle-alerts-that-appear-on-page-load");
new WebDriverWait(driver,10).until(ExpectedConditions.
elementToBeClickable(By.xpath("//button[contains(text(),'Accept all 
cookies')]"))).click();
WebElement element = driver.findElement(By.xpath
("((//button[@class='s-btn s-btn__primary'])[2]/span[2])"));
    
((JavascriptExecutor)driver).executeScript
("arguments[0].scrollIntoView(true);", element);
element.click();
System.out.println(getTextFromAlert());
acceptAlert();}

[https://imgur.com/Xy2jhQr][1]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-05
    相关资源
    最近更新 更多