搞定用TypeScript寫Protractor測試,陸續參考一些範例,發現蠻多人偏好使用Chai程式庫。原本Protractor預設的寫法expect(foo).toEqual(5),改用Chai之後變成:
- expect(foo).to.be.a('string');
- expect(foo).to.equal('bar');
- expect(foo).to.have.length(3);
- expect(tea).to.have.property('flavors') .with.length(3);
寫程式像在講話,幾乎就等同BDD Feature裡Then的口語描述,我猜想這是Chai受歡迎的原因。例如以下的BDD Feature範例:
Scenario:Add two numbers
Given I have entered 50 into the calculator
Then I have entered 70 into the calculator
When I press add
Then the result should be 120 on the screen
言歸正傳,要在Protractor改用Chai語法,可在conf.js的onPrepare()用require動態載入chai及chai-as-promised模組,將global.expect換掉(細節可參考Paul Li的介紹):
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['lab1.spec.js'],
onPrepare: () => {
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
global["expect"] = chai.expect;
}
};
回到TypeScript,要讓Visual Studio認得Chai的to.equal()這種語法,就必須載入cha.d.ts及cha-as-promised.d.ts兩個定義檔。老樣子,用Manage NuGet Packages或Package Manager Console安裝chai-as-promised.TypeScript.DefinitelyTyped,它會一併安裝chai.TypeScript.DefinitelyTyped,定義檔就備齊了。
由於chai及chai-as-promised為node.js的外部模組(External Module),應用時跟平常網站TypeScript使用<script src="…">載入的概念有點不同,想深入了解的同學可以參考TypeScript官方文件,這裡只會提到滿足測試撰寫的必要做法。
node.js透過require("…")方式動態載入元件,對應到TypeScript要寫成import chai=require("chai"),由於chai.d.ts只有定義檔不包含實作,故這個import指令目的在匯入chai.d.ts的型別宣告,作用類似宣告/// <reference path="…" />,不會產生實際的JavaScript指令(測試腳本實際上也不需要載入chai,真正的載入及設定動作是在conf.js onPrepare()完成)。
要使用import,專案的TypeScript編譯選項要做些調整,Module System需選擇CommonJS:
接著,我們要宣告declare var expect: Chai.ExpectStatic,將全域變數expect函式定義成Chai版的expect,以便使用Chai的is.equal()串接語法。跟import指令一樣,declare指令不產生JavaScript,只決定TypeScript撰寫階段的變數型別。
還有一個小問題,在Protractor裡,expect()應傳回Promise形式的Assert函式,故得寫成is.eventually.equal()。故一開始的import指令要改成import chaiAsPromised = require("chai-as-promise"),Visual Studio才認得expect().is.eventually.equal()。
完整測試程式碼如下:
import chaiAsPromised = require("chai-as-promised");
declare var expect: Chai.ExpectStatic;
describe('Protractor Demo App', function () {
var firstNumber = element(by.model('first'));
var secondNumber = element(by.model('second'));
var goButton = element(by.id('gobutton'));
var latestResult = element(by.binding('latest'));
beforeEach(function () {
browser.get('http://juliemr.github.io/protractor-demo/');
});
it('should have a title', function () {
expect(browser.getTitle()).is.eventually.equal("Super Calculator");
});
it('should add one and two', function () {
firstNumber.sendKeys("1");
secondNumber.sendKeys("2");
goButton.click();
expect(latestResult.getText()).is.eventually.equal("3");
});
});
總算Visual Studio也認得to.eventual.equal()的chai-as-promise語法,編譯成功,收工!