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

Selenium破解showModalDialog模態對話框測試難題:從原理到Hack方案全解析

     編輯:Java 相關知識

核心衝突:為什麼Selenium無法原生支持showModalDialog

window.showModalDialog()是IE專有API,會阻塞父頁面JavaScript執行緒直到對話框關閉。Selenium底層靠注入JavaScript驅動瀏覽器,一旦主線程被阻塞,Selenium自身也會「凍結」,導致:

  • 無法定位模態對話框內元素
  • 命令超時失敗
  • 無法獲取對話框返回值繼續後續測試步驟

業務場景分類與應對策略

核心Hack方案:雙階段JS攔截注入

階段一:首次點擊 → 將模態框轉為普通窗口操作

public void clickAndSelectModalDialog(String locator) {
    clickForModalDialog(locator);
    selenium.selectWindow("name=modal");
}

private void clickForModalDialog(String locator) {
    // 構造JS:覆蓋父頁面showModalDialog為window.open
    String overrideJs = 
        "if (selenium.browserbot.getCurrentWindow().showModalDialog) {" +
        "  selenium.browserbot.getCurrentWindow().showModalDialog = " +
        "    function(sURL, vArguments, sFeatures) {" +
        "      return selenium.browserbot.getCurrentWindow().open(sURL, 'modal', sFeatures);" +
        "    };" +
        "}";
    selenium.getEval(overrideJs);  // 注入覆蓋
    selenium.click(locator);       // 觸發點擊,實際打開window.open
    selenium.openWindow("", "modal"); // 同步窗口句柄
    selenium.waitForPopUp("modal", "15000"); // 等待彈窗加載
}

階段二:在彈窗操作完成 → 關閉彈窗 → 二次點擊注入返回值

public void acceptModalValue(String locator, String[] values) {
    String overrideJs = 
        "if (selenium.browserbot.getCurrentWindow().showModalDialog) {" +
        "  selenium.browserbot.getCurrentWindow().showModalDialog = " +
        "    function(sURL, vArguments, sFeatures) {" +
        generateModalDialogReturnObject(values) + // 生成返回對象代碼
        "      return temp;" +
        "    };" +
        "}";
    selenium.getEval(overrideJs);
    selenium.click(locator); // 二次點擊,此次直接獲得返回值繼續執行後續JS
}

private String generateModalDialogReturnObject(String[] values) {
    StringBuffer sb = new StringBuffer("var temp=new Array();");
    for (int i = 0; i < values.length; i++) {
        sb.append("temp[").append(i).append("]='").append(values[i]).append("';");
    }
    return sb.toString();
}

完整測試用例:部門選擇模態框端到端驗證

// 1. 點擊部門選擇圖標,進入階段一
String depChooseLocator = ".../img";
clickAndSelectModalDialog(depChooseLocator);

// 2. 在彈窗中操作部門樹(普通Selenium操作)
// ... 選中節點、展開樹等 ...

// 3. 獲取彈窗準備返回的數據
String name = selenium.getEval("window.seltree.GetAllCheckText();");
String id   = selenium.getEval("window.seltree.GetAllNodeId();");

// 4. 關閉彈窗,切回主窗口
selenium.getEval("window.close();"); // 或點擊彈窗關閉按鈕
selenium.selectWindow("name=main95598");

// 5. 組裝返回值,執行階段二
String[] returnValues = {name, id};
acceptModalValue(depChooseLocator, returnValues);

// 6. 驗證父頁面字段已正確回填
Assert.assertEquals(name, selenium.getValue("departmentNameField"));
Assert.assertEquals(id, selenium.getValue("departmentIdField"));

關鍵技術細節與避坑指南

1. 窗口句柄管理

  • 首次openWindow("", "modal")建立Selenium內部窗口映射
  • selectWindow("name=modal")切換上下文至彈窗
  • 操作完成後selectWindow("name=主窗口名")切回,主窗口名需提前獲取(如selenium.getEval("window.name"))

2. 時序控制

  • waitForPopUp超時時間需覆蓋頁面加載最長耗時
  • 兩次click(locator)之間必須完成彈窗操作並關閉,否則第二次點擊可能被瀏覽器攔截或觸發異常邏輯

3. 返回值結構約定

模態框返回值通常為數組[顯示文本, 隱藏ID, ...],父頁面原有JS邏輯按索引解析。測試時必須嚴格保持相同順序與類型,否則後續業務JS會報錯。

4. 瀏覽器兼容性

  • 方案依賴selenium.browserbot,僅適用Selenium 1.x (RC)架構
  • Selenium 2/3/4 (WebDriver)架構下,showModalDialog在現代瀏覽器(Edge/Chrome/Firefox)已棄用/移除,建議業務遷移至window.open+postMessage或模態組件庫(Bootstrap Modal等),測試難度大幅降低

模板化封裝建議

將上述邏輯封裝為ModalDialogHandler工具類,暴露模板方法:

public abstract class ModalDialogTestTemplate {
    protected Selenium selenium;
    
    public void executeModalDialogTest(String locator, ModalDialogAction action) {
        // 階段一
        clickAndSelectModalDialog(locator);
        try {
            // 業務方實現具體彈窗操作與數據提取
            String[] returnValues = action.performInModal(selenium);
            // 階段二
            closeModalAndReturnMain();
            acceptModalValue(locator, returnValues);
        } finally {
            ensureBackToMainWindow();
        }
    }
    // ... 內部實現 clickAndSelectModalDialog / acceptModalValue 等
}

總結

針對showModalDialog這類阻塞式舊API,Selenium無法原生支持。通過JS運行時覆蓋將其轉化為可控的window.open流程,配合雙階段注入(首次轉彈窗操作、二次注入返回值),可實現端到端自動化驗證。但鑑於現代瀏覽器已淘汰該API,**根治之道仍是業務代碼重構**,測試層面的Hack僅作過渡方案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
場景類型典型業務測試策略
純數據回填選人、選部門、選業務類型,僅回填父頁面字段數據預置法:測試代碼直接構造返回數據,通過JS賦值父頁面字段,完全跳過模態框
觸發後續業務邏輯工作流派發、審批流轉,返回值後仍需執行一系列JS操作JS覆蓋法(Hack):攔截showModalDialog,首次改為window.open操作,二次調用時直接返回預置數據