首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Selenium 處理彈出窗口完整指南:句柄切換、多窗口管理與實戰代碼

     編輯:Java 相關知識

前言

Web 自動化測試中,彈出窗口(新標籤頁、alert、iframe、模態框)是常見難點。Selenium 通過 WindowHandle 機制管理多窗口上下文。本文系統講解彈出窗口處理核心原理、API 用法、實戰代碼與常見坑點。

核心原理:Window Handle 機制

每個瀏覽器窗口/標籤頁對應唯一 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>

Java 測試代碼

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 類型: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 出現
}

常見坑點與解決方案

  1. 窗口切換失效:句柄在瀏覽器重啟/會話失效後失效 → 每次操作前重新獲取
  2. 競態條件:點擊後立即獲取 handles,新窗口尚未創建 → 必須顯式等待 getWindowHandles().size() > n
  3. 無頭模式:Headless Chrome 彈窗行為可能不同 → 添加參數 --disable-popup-blocking
  4. 多標籤頁 vs 多窗口:現代瀏覽器多為標籤頁,API 統一處理,無需區分
  5. 關閉後句柄失效:driver.close() 關閉當前窗口,必須立即切換到有效句柄,否則拋出 NoSuchWindowException

最佳實踐清單

  • ✅ 封裝 WindowUtils 工具類,業務代碼保持乾淨
  • ✅ 使用 WebDriverWait 替代 Thread.sleep()
  • ✅ 測試方法結束時 finally 確保 driver.quit()
  • ✅ 並行測試時使用 ThreadLocal 隔離 WebDriver 實例
  • ✅ 頁面對象模式(POM)中封裝窗口切換邏輯

總結

Selenium 窗口處理核心在於 句柄獲取 → 狀態等待 → 上下文切換 → 業務操作 → 狀態恢復。掌握三類彈出窗口的差異化處理策略,配合顯式等待與工具類封裝,即可構建健壯的自動化測試體系。建議收藏本文作為測試開發參考手冊。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved