Web 自動化測試中,彈出窗口(新標籤頁、alert、iframe、模態框)是常見難點。Selenium 通過 WindowHandle 機制管理多窗口上下文。本文系統講解彈出窗口處理核心原理、API 用法、實戰代碼與常見坑點。
每個瀏覽器窗口/標籤頁對應唯一 String 句柄:
driver.getWindowHandle():獲取當前窗口句柄driver.getWindowHandles():獲取所有窗口句柄集合(Set<String>)driver.switchTo().window(handle):切換上下文到指定窗口| 類型 | 特徵 | 處理方式 | API |
|---|---|---|---|
| 新標籤頁/窗口 | 獨立 Window Handle | 遍歷 Handles 切換 | switchTo().window() |
| JavaScript Alert | 原生彈框,無 DOM | 直接切換 Alert 上下文 | switchTo().alert() |
| HTML 模態框 | 同窗口 DOM 元素 | 定位元素直接操作 | 常規 findElement |
<html>
<head><title>主頁面</title>
<script>
function openWin() { window.open("https://www.cnblogs.com"); }
</script></head>
<body>
<input type="button" value="打開窗口" onclick="openWin()">
</body></html>
public class WindowHandlingTest {
private static final String TEST_URL = "file:///E:/test/main.html";
@Test
public void testMultipleWindows() {
WebDriver driver = new ChromeDriver();
try {
driver.get(TEST_URL);
String parentHandle = driver.getWindowHandle();
System.out.println("父窗口標題: " + driver.getTitle());
// 觸發新窗口
driver.findElement(By.xpath("//input[@value='打開窗口']")).click();
// 等待新窗口打開(顯式等待最佳實踐)
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.until(d -> d.getWindowHandles().size() > 1);
// 切換到新窗口
Set<String> allHandles = driver.getWindowHandles();
for (String handle : allHandles) {
if (!handle.equals(parentHandle)) {
driver.switchTo().window(handle);
break;
}
}
System.out.println("子窗口標題: " + driver.getTitle());
Assert.assertTrue(driver.getTitle().contains("博客園"));
// 關閉子窗口,切回父窗口
driver.close();
driver.switchTo().window(parentHandle);
System.out.println("回到父窗口: " + driver.getTitle());
} finally {
driver.quit();
}
}
}
public class WindowUtils {
/** 切換到標題包含關鍵字的窗口 */
public static void switchToWindowByTitle(WebDriver driver, String keyword) {
String original = driver.getWindowHandle();
Set<String> handles = driver.getWindowHandles();
for (String handle : handles) {
driver.switchTo().window(handle);
if (driver.getTitle().contains(keyword)) return;
}
// 未找到則恢復原窗口
driver.switchTo().window(original);
throw new NoSuchWindowException("未找到標題包含 '" + keyword + "' 的窗口");
}
/** 切換到最新打開的窗口 */
public static void switchToNewestWindow(WebDriver driver, String originalHandle) {
Set<String> handles = driver.getWindowHandles();
handles.remove(originalHandle);
if (handles.size() == 1) {
driver.switchTo().window(handles.iterator().next());
} else {
throw new IllegalStateException("無法確定最新窗口,候選數: " + handles.size());
}
}
/** 關閉當前窗口並切回父窗口 */
public static void closeAndSwitchBack(WebDriver driver, String parentHandle) {
driver.close();
driver.switchTo().window(parentHandle);
}
}
// Alert 類型:alert、confirm、prompt
Alert alert = driver.switchTo().alert();
// 獲取文本
String text = alert.getText();
// 確認/取消
alert.accept(); // 點擊確定
alert.dismiss(); // 點擊取消(confirm/prompt)
// 輸入文本(僅 prompt)
alert.sendKeys("測試輸入");
alert.accept();
// 完整範例:處理 confirm
try {
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
wait.until(ExpectedConditions.alertIsPresent());
Alert confirm = driver.switchTo().alert();
System.out.println("彈框內容: " + confirm.getText());
confirm.accept(); // 或 dismiss()
} catch (TimeoutException e) {
// 無 Alert 出現
}
getWindowHandles().size() > n--disable-popup-blockingdriver.close() 關閉當前窗口,必須立即切換到有效句柄,否則拋出 NoSuchWindowExceptionWindowUtils 工具類,業務代碼保持乾淨WebDriverWait 替代 Thread.sleep()finally 確保 driver.quit()Selenium 窗口處理核心在於 句柄獲取 → 狀態等待 → 上下文切換 → 業務操作 → 狀態恢復。掌握三類彈出窗口的差異化處理策略,配合顯式等待與工具類封裝,即可構建健壯的自動化測試體系。建議收藏本文作為測試開發參考手冊。