WebDriverIO – 一個凌駕於 Selenium 之上的 Node.js 前端測試框架
Selenium 為人詬病的就是它的 API 非常不友好,縱使之後出了 Selenium WebDriver 還是有上手困難的窘境,所以我們需要一個框架來協助我們這些弱弱前端測試工程師來協助我們撰寫 End-to-End 測試碼,譬如現在較為火紅的 NightWatch、WebDriverIO or Protractor (以 JavaScript 語言為例)。選哪個都好,重點是上手容易、充裕的官方文件、廣大社群支持以及擴充程度高,以這些挑選準則去決定你想採用的前端測試框架,並且有效解決你的網頁自動化測試即可。我這邊選擇了 WebDriverIO,主要它能夠同步撰寫測試碼與易於除錯的優於 NightWatch 特性外,在台灣也深受 alincode 的資深全端大大講師推薦影響,讓我決定選擇它。
這篇文章主要是帶大家認識並且透過簡單的操作步驟與範例來了解 WebDriverIO,這裏不是全貌,而是一個淺嚐。
WebDriverIO 的特點:
- 基於 Node.js 的網頁自動化測試框架
- 封裝 Selenium WebDriver API,讓操縱瀏覽器行為更為便利
- 你的測試碼將會非常簡單、清晰、易懂,而且兼容大多數的 TDD 與 BDD 測試框架
- 可擴展程度高,你可以輕鬆自製自己的函數與複雜的集合
- 輕鬆跟大量第三方工具整合,也能與雲端測試服務如 Sauce Labs 或 BrowserStack 供應商達到多裝置測試的需求
有沒有覺得異常興奮想要一親芳澤 WebDriverIO?相信我,它能輕快的帶給你網頁測試自動化的成效與標的。
How to Start?
我們必須先設定環境,再來則是專案的建立、測試資料的準備與測試程式碼的撰寫,讓我們現在開始!
設定 Selenium Server 環境?
首先你要先設定 Selenium Server 環境,接著你才可以透過 WebDriverIO 去呼叫 Selenium 讓瀏覽器幫你做事情。
傳統方法是透過下載並安裝瀏覽器驅動程式 (driver) 與 Selenium Server (selenium-server-standalone-3.4.0.jar) ,並透過 java 指令來啟動 selenium,過程繁瑣,且會有 driver 與 standalone 更新落差的問題,這裡建議透過 webdriver-manager 來設定,更新 driver 也只要一個指令即可。
安裝 Selenium Server:
npm install webdriver-manager -g webdriver-manager update
執行 Selenium Server:
webdriver-manager start
其實 Selenium Server 環境可透過 Docker 容器虛擬化工具建置,這部分我之後會另闢文章來為各位解說,這裡我們先以 Local 方式來練習,較為簡單。
WebDriverIO 初始化專案
透過 webdriverio 自帶的 CLI 指令初始化專案非常簡單,它透過問答式方式讓你快速生成專案與設定。
mkdir wdio-demo cd wdio-demo npm init -y npm install webdriverio --save-dev
產生 WebDriverIO 設定檔:
node_modules/.bin/wdio ? Where do you want to execute your tests? On my local machine ? Which framework do you want to use? mocha ? Shall I install the framework adapter for you? Y ? Where are your test specs located? ./test/specs/**/*.js ? Which reporter do you want to use? spec - https://github.com/webdriverio/wdio-spec-reporter ? Shall I install the reporter library for you? Y ? Do you want to add a service to your test setup? testingbot - https://github.com/testingbot/wdio-testingbot-service ? Shall I install the services for you? Y ? Level of logging verbosity silent error ? In which directory should screenshots gets saved if a command fails? ./errorShots/ ? What is the base url? http://localhost
執行:
- 將 package.json 的 script test 指令調整成:wdio wdio.config.js
- command line 執行:npm test
wdio.conf.js 設定檔
你會看到專案產生一個 wdio.confi.js 檔案,這邊我們做一些調整,讓測試的瀏覽器一次測試 firefox 與 chrome,以及我們增加報表格式讓結果更為完整:
exports.config = { // ... capabilities: [ { // maxInstances can get overwritten per capability. So if you have an in-house Selenium // grid with only 5 firefox instances available you can make sure that not more than // 5 instances get started at a time. maxInstances: 5, // browserName: 'chrome' }, { // maxInstances can get overwritten per capability. So if you have an in-house Selenium // grid with only 5 firefox instances available you can make sure that not more than // 5 instances get started at a time. maxInstances: 5, // browserName: 'firefox' } ], // ... reporters: ['dot', 'spec'], // ... }
再來是安裝一下 spec 的 reporters library:
npm install wdio-spec-reporter --save-dev
現在我們完成了環境與專案設定了,再來終於可以開始寫測試代碼囉!
實戰 – 登入與登出
這是我們的測試標的:
- 登入錯誤的正確提示
- 登入成功導到首頁
- 登出成功的正確提示
測試案例
url:http://demo.keystonejs.com/keystone/signin 帳號:demo@keystonejs.com 密碼:demo
撰寫測試程式碼
在 wdio-demo 開一個 js 檔案 (test/specs/sign.test.js):
// test/specs/sign.test.js var assert = require('assert'); describe('第一個前端測試程式', function () { beforeEach(function() { browser.pause(5000); }); it('登入失敗', function () { browser.url('https://demo.keystonejs.com/keystone/signin'); // 輸入帳號 browser.setValue('input[name=email]', 'demo@keystonejs.com'); // 輸入錯誤密碼 browser.setValue('input[name=password]', '1234'); // 按送出按鈕 browser.click('button[type=submit]'); // 檢查是否出現警告訊息 browser.waitForExist('[data-alert-type=danger]'); let alertText = browser.getText('[data-alert-type=danger]'); // 警告訊息的文字內容,是否如預期 assert.equal('The email and password you entered are not valid.', alertText); }); it('登入成功', function() { // 輸入帳號 browser.setValue('input[name=email]', 'demo@keystonejs.com'); // 輸入正確密碼 browser.setValue('input[name=password]', 'demo'); // 按送出按鈕 browser.click('button[type=submit]'); // 檢查是否存在登出連結 browser.waitForExist('[title="Sign Out"]', 7000); }); it('登出', function() { // 點選登出 browser.click('[title="Sign Out"]'); // 檢查是否出現登出成功的訊息 browser.waitForExist('[data-alert-type=info]'); let infoText = browser.getText('[data-alert-type=info]'); assert.equal('You have been signed out.', infoText); }); });
執行
npm test </pre> > demo@1.0.0 test /Users/eden.liu/Desktop/myProjects/wdio-demo > wdio wdio.conf.js ․․․․․------------------------------------------------------------------ [chrome #0-0] Session ID: 296060c4d8786c1aa571193a44caf68f [chrome #0-0] Spec: /Users/eden.liu/Desktop/myProjects/demo/test/specs/sign.test.js [chrome #0-0] Running: chrome [chrome #0-0] [chrome #0-0] 第一個前端測試程式 [chrome #0-0] ✓ 登入失敗 [chrome #0-0] ✓ 登入成功 [chrome #0-0] ✓ 登出 [chrome #0-0] [chrome #0-0] [chrome #0-0] 3 passing (28s) [chrome #0-0] ․------------------------------------------------------------------ [firefox #1-0] Session ID: 6c479228-b18f-a648-86e3-6a66b6f60e58 [firefox #1-0] Spec: /Users/eden.liu/Desktop/myProjects/demo/test/specs/sign.test.js [firefox #1-0] Running: firefox [firefox #1-0] [firefox #1-0] 第一個前端測試程式 [firefox #1-0] ✓ 登入失敗 [firefox #1-0] ✓ 登入成功 [firefox #1-0] ✓ 登出 [firefox #1-0] [firefox #1-0] [firefox #1-0] 3 passing (32s) [firefox #1-0] 6 passing (32.70s) ================================================================== Number of specs: 2 <pre>
嗯!感覺還不錯,我們的第一個 End-To-End 網頁瀏覽器自動化測試看起來運作得非常好,你會看到你的電腦真的啟動 firefox 與 chrome 瀏覽器,並且快速的執行你的測試任務,完成後將會關閉並顯示 spec 的 report 結果!
這裡稍微講解一下上述的程式碼。
常用指令
官網指令種類,分成:
- Protocol
- Action
- Utility
- Property
- State
- Mobile
像我們的 前往某網址 以及 選取元素,就是屬於 Protocol:
browser.url('https://demo.keystonejs.com/keystone/signin');
Action 的部分就是針對設定欄位值跟點選欄位值:
browser.setValue('input[name=email]', 'demo@keystonejs.com'); // 這裡結合 選取元素 與 設定欄位 browser.setValue('input[name=password]', '1234'); browser.click('button[type=submit]');
這邊會看到檢查某個元素是否存在,以及暫停、除錯等程式碼,則屬於 Utility:
browser.waitForExist('[data-alert-type=danger]');
取得某元素文字與值,屬於 Property:
let alertText = browser.getText('[data-alert-type=danger]');
我這邊有將每次瀏覽器執行一個 test case 後會等待個 3 秒鐘,否則有時候會因為銜接的速度太快導致會出現一點畫面衝突小問題:
beforeEach(function() { browser.pause(5000); });
如何?很簡單吧!
你會看到同步化的寫法,非常的直觀易懂,也能輕易的透過 browser.debug() 指令做到逐行測試,WebDriverIO API 就是這麼單純可靠,更多的 API 就詳閱官網吧:http://webdriver.io/api.html
接下來我會在其他文章深入探討 WebDriverIO 的部分,包括比較進階的議題、如何組織你的測試程式碼、雲端瀏覽器測試與 Docker,就請各位看官們期待囉!