【发布时间】:2021-05-11 07:04:03
【问题描述】:
我有以下场景要自动化:
- 导航到应用程序 URL
- 单击一个名为打开新窗口的按钮
- 该应用会打开一个新窗口,其中包含在页面加载时显示的警报。
- 切换到新窗口并接受/关闭警报
- 继续其余的自动化操作
我们在第 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 中,打印了哪些文本?它打印任何东西吗?