講到網頁自動測試,一哥地位非 Selenium 莫屬(參考)。雖然 Selenium IDE 支援錄製網頁操作產生測試腳本,但錄製產生的指令常依賴元素的位置順序定位,配置稍有更動立刻破功。依實務經驗,開發者依據設計邏輯手工撰寫還是較可靠的作法,測試指令也較簡潔有效率。Selenium 本身提供好幾種定位器,包含:ID、Name、DOM、XPATH、CSS Selector…等。習慣 jQuery 再回頭使用這些彈性受限的定位器,每每遇到複雜情境,都會先想 jQuery 如何操作,再設法對應成 CSS Selector,但三不五時就會超出 CSS 能力範圍(例如::contains()、:has(),或是結合 closest()、parent() ),心中滿是恨鐵不成鋼的怨氣。
既然 jQuery 好用,我測試的網頁也多半已載入 jQuery,為什麼寫測試時必須將就這堆能力受限的內建定位器呢?最後,我找到一個解法,為 Selenium 寫擴充函式直接支援 jQuery!
我寫了一個user-extensions.js,為 Selenium 類別加入幾個新函式:
- locateElementByJq: 所有適用 css=… 選擇器的場合,都可以寫成 jq=… 使用 jQuery 選擇器
- getJqText:支援 verifyJqText/waitForJqText,傳入 jQuery 選擇器取回 .text()
- getJqVal:支援 verifyJqVal/waitForJqVal,傳入 jQuery 選擇器取回 .val()
- getJqHtml:支援 verifyJqHtml/waitForJqHtml,傳入 jQuery 選擇器取回 .val()
- doExecute:Selenium 雖然有 runScript,但執行時 this 指向 Selenium 物件,如要存取 DOM 必須寫 window.document.* 有點囉嗉。改良版的 execute 支援直接輸入 JavaScript,以 window.eval() 執行,就跟在 F12 主控台下指令一樣方便。因此,execute 是為我寫測試最慣用的兵器。
- getExecute:沿用 execute 概念,可執行複雜 JavaScript 指令自網頁取值,可配合 verifyForExecute、waitForExecute 使用,威力強大!(例如:取得元素內容進行 Regular Expression 比對、檢查元素個數介於 2 到 4 之間… 這類內建指令不易實現的運算比對)
user-extensions.js 的內容如下:
//http://docs.seleniumhq.org/docs/08_user_extensions.jsp
Selenium.prototype.doExecute = function(script) {
this.browserbot.getCurrentWindow().eval(script);
};
Selenium.prototype.getExecute = function(script) {
returnthis.browserbot.getCurrentWindow().eval(script);
};
Selenium.prototype.getJqMethod = function(selector, method) {
returnthis.getExecute('$("' + selector + '").' + method + '();');
};
Selenium.prototype.getJqText = function(selector) {
returnthis.getJqMethod(selector, "text");
};
Selenium.prototype.getJqHtml = function(selector) {
returnthis.getJqMethod(selector, "html");
};
Selenium.prototype.getJqVal = function(selector) {
returnthis.getJqMethod(selector, "val");
};
PageBot.prototype.locateElementByJq = function(selector, inDocument) {
// FF/Chrome/IE9+: defaultView, OldIE: parentWindow
return (inDocument.defaultView || inDocument.parentWindow)
.eval("jQuery('" + selector.replace(/'/g, "\\'") + "')[0];");
};
要使用它,只需開啟 Selenium IDE 選項設定,加入 user-extensions.js 路徑。血清注射完成,美國隊長要現身了!
用一個簡單網頁示範:
<!DOCTYPEhtml>
<html>
<body>
<div>
<inputtype="text"value="Darkthread"/>
<spanclass='name'>Jeffrey</span>
</div>
<div>
<inputtype="button"value="Hide"/>
<span>Test</span>
</div>
<divclass="last">
<inputtype="text"value="Selenium"disabled/>
<spanstyle="display:none">Selenium IDE</span>
</div>
<scriptsrc="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.js"></script>
<script>
$(":button").click(function() {
$(".name").hide(3000);
});
</script>
</body>
</html>
如以下圖示,展示使用 jq=div:has(:text) 配合 verifyElementPresent 可以做到 CSS 不支援的 :has() 選擇器;verifyExecute 時應用 JavaScript .match() 做 Regular Expression 比對;另外還展示用 execute 執行 JavaScript 直接對 DOM 動手動腳。
能使用 jQuery 選擇器,又可直接用 JavaScript 操作網頁或進行運算,就能輕鬆在 Selenium 測試案例加入各種自訂邏輯,寫起測試案例再也不會被綁手綁腳囉!