Nightwatch.js
28 Oct 2017在做整合測試時,要怎麼確定使用者能順利走完預定的流程呢?例如:從購買商品到進入購物車、結帳完成。或者,要怎麼確定在修改全站共用的 UI 元件後,網站仍能正常運作?這時候我們往往就會找個人來當 QA,假裝他 / 她是一般使用者,把網站主流程都點一點、用一用。由於靠人力完整測試是非常耗時耗力的,因此,若能有系統的靠程式完成,就能快速、全面地檢查,一下子就知道有沒有問題了。
既然能靠寫程式解決人力檢測的問題,就先選個方法-來用 Nightwatch 吧。
什麼是 Nightwatch?
Nightwatch 是專門給網頁使用的自動化測試框架,它使用 W3C WebDriver 所提供的 API(過去稱為 Selenium WebDriver)來自動操作瀏覽器。好處是可簡化設定 CI(Continuous Integration,持續整合)的過程,自動執行 End-to-End 測試與單元測試。在這裡,我們是要來做 End-to-End 測試。
什麼是 WebDriver?
WebDriver 是一個跨瀏覽器的自動化測試工具,它可遠端控制介面,執行各種操作,例如:瀏覽特定網址、輸入文字、點擊按鈕等。Nightwatch 即是透過 WebDriver API 來控制瀏覽器,模擬人類使用瀏覽器的各種動作。
圖片來源:Theory of Operation
如何使用 Nightwatch?
安裝與基本設定可參考這篇和那篇。以下會直接來探討怎麼撰寫測試程式,像是如何找網頁元素、常用指令、斷言、Hooks 等。
如何定位網頁元素?
有兩種方法「CSS selector」和「XPath」,但我多用 CSS selector。
this.demoTestGoogle = function(browser) {
browser
.url('https://member.ruten.com.tw/user/login.htm')
.waitForElementVisible('body', 1000)
.setValue('#userid', 'test_user')
.setValue('#userpass', 'test_password')
.click('#btnLogin')
.pause(1000)
.assert.urlContains('http://www.ruten.com.tw/')
.assert.containsText('title', '露天拍賣-台灣 NO.1 拍賣網站')
.end();
};
以上這個範例在做登入露天網站的動作,細節列舉如下
- 打開網頁
https://member.ruten.com.tw/user/login.htm
- 確認
<body>
這個元素是否在 1 秒內出現 - 在帳號欄位輸入字串 test_user
- 在密碼欄位輸入字串 test_password
- 點擊登入按鈕
- 等待 1 秒
- 確定網址是否包含
http://www.ruten.com.tw/
- 確定網頁
<title>
是否包含「露天拍賣-台灣 NO.1 拍賣網站」 - 結束 session
常用指令
整理上面這個範例所用到的指令,其實也是一開始撰寫測試程式基本、比較常用的指令。
- url:指定打開的網址
- click:點擊網頁元素
- clearValue:清除 input 的值
- setValue:輸入 input 的值
- pause:暫停
- end:結束 session
更多指令,可參考-Commands。
也可撰寫客製化指令-Writing Custom Commands。
BDD Assertions
Chai 提供 BDD 語法測試用的斷言庫(Assertion Library)。斷言庫是一種判斷工具,驗證執行結果是否符合預期,若實際結果和預測不同,就是測到 bug 了。Chai 在這裡提供了 Expect 和 Assert 的 API。若想了解 Chai 的 Expect 和 Assert 的基本語法,可參考這裡。
可撰寫客製化 Assertions-Writing Custom Assertions。
Test Hooks
- before():在所有測試開始前會執行的程式碼區塊。
- after():在所有測試結束後會執行的程式碼區塊。
- beforeEach():在每個 Test Case 開始前執行的程式碼區塊。
- afterEach():在每個 Test Case 結束後執行的程式碼區塊。
範例如下。
module.exports = {
before: function(browser) {
console.log('Setting up...');
},
after: function(browser) {
console.log('Closing down...');
},
beforeEach: function(browser) {
console.log('Before each test case...');
},
afterEach: function() {
console.log('After each test case...');
},
};
Running Tests
執行 npm test
或自定義的指令即可開始跑測試,跑完就會看到結果。也可選擇客製化成美美的報表喔!
QnA
End-to-End 測試與單元測試差別在哪裡?
End-to-End 測試多用於 UI 功能和網站流程的測試,而單元測試主要是對 Service 或 Module 檢視 input 與 output 是否正確。
Phantom.js 去哪裡了?
Chrome 推出 Headless Mode 之後, Phantom.js 作者宣告進入維護,也意味著走入歷史 …
後記
從上次團隊開始使用 Selenium IDE 至今可改用 Nightwatch + Selenium Webdriver 應該過了三個月左右。Selenium IDE 的確對於節省測試時間是很有幫助的,可惜
- 只支援 Firefox,其他瀏覽器的測試還是得靠人工檢測,耗時耗力。
- 選取網頁元素不夠精準,導致工程師不是修改自己的程式碼,就是修改 Selenium IDE 選取 target 的結果。
- 報錯相較 Nightwatch 是比較粗糙的。
因此當機器環境整理好,能夠開始撰寫並執行 E2E 測試時,我真的感受到「又快又好」的那種感動 XDD
附上露天讀書會投影片-Nightwatch。