## ESLint
### 實驗目的
1. 學會使用 ESLint 進行代碼檢查。
### 操作步驟
(1)進入`demos/eslint-demo`目錄,安裝 ESLint。
~~~
$ cd demos/eslint-demo
$ npm install eslint --save-dev
~~~
(2)通常,我們會使用別人已經寫好的代碼檢查規則,這里使用的是 Airbnb 公司的規則。所以,還要安裝 ESLint 這個規則模塊。
~~~
$ npm install eslint-plugin-import eslint-config-airbnb-base --save-dev
~~~
上面代碼中,`eslint-plugin-import`是運行這個規則集必須的,所以也要一起安裝。
(3)ESLint 的配置文件是`.eslintrc.json`,放置在項目的根目錄下面。新建這個文件,在里面指定使用 Airbnb 的規則。
~~~
{
"extends": "airbnb-base"
}
~~~
(4)打開項目的`package.json`,在`scripts`字段里面添加三個腳本。
~~~
{
// ...
"scripts" : {
"test": "echo \"Error: no test specified\" && exit 1",
"lint": "eslint **/*.js",
"lint-html": "eslint **/*.js -f html -o ./reports/lint-results.html",
"lint-fix": "eslint --fix **/*.js"
},
// ...
}
~~~
除了原有的`test`腳本,上面代碼新定義了三個腳本,它們的作用如下。
* `lint`:檢查所有`js`文件的代碼
* `lint-html`:將檢查結果寫入一個網頁文件`./reports/lint-results.html`
* `lint-fix`:自動修正某些不規范的代碼
(5)運行靜態檢查命令。
~~~
$ npm run lint
1:5 error Unexpected var, use let or const instead no-var
2:5 warning Unexpected console statement no-console
? 2 problems (1 error, 1 warning)
~~~
正常情況下,該命令會從`index.js`腳本里面,檢查出來兩個錯誤:一個是不應該使用`var`命令,另一個是不應該在生產環境使用`console.log`方法。
(6)修正錯誤。
~~~
$ npm run lint-fix
~~~
運行上面的命令以后,再查看`index.js`,可以看到`var x = 1;`被自動改成了`const x = 1;`。這樣就消除了一個錯誤,但是還留下一個錯誤。
(7)修改規則。
由于我們想要允許使用`console.log`方法,因此可以修改`.eslintrc.json`,改變`no-console`規則。請將`.eslintrc.json`改成下面的樣子。
~~~
{
"extends": "airbnb-base",
"rules": {
"no-console": "off"
}
}
~~~
再運行`npm run lint`,就不會報錯了。
~~~
$ npm run lint
~~~
## Mocha
### 實驗目的
1. 學會使用 Mocha 進行單元測試。
### 操作步驟
(1) 進入`demos/mocha-demo`目錄,安裝 Mocha 和 Chai。
~~~
$ cd demos/mocha-demo
$ npm install -D mocha
$ npm install -D chai
~~~
(2)打開`add.js`文件,查看源碼,我們要測試的就是這個腳本。
~~~
function add(x, y) {
return x + y;
}
module.exports = add;
~~~
(3)編寫一個測試腳本`add.test.js`。
~~~
var add = require('./add.js');
var expect = require('chai').expect;
describe('加法函數的測試', function() {
it('1 加 1 應該等于 2', function() {
expect(add(1, 1)).to.be.equal(2);
});
});
~~~
測試腳本與所要測試的源碼腳本同名,但是后綴名為`.test.js`(表示測試)或者`.spec.js`(表示規格)。比如,`add.js`的測試腳本名字就是`add.test.js`。
測試腳本里面應該包括一個或多個`describe`塊,每個`describe`塊應該包括一個或多個`it`塊。
`describe`塊稱為"測試套件"(test suite),表示一組相關的測試。它是一個函數,第一個參數是測試套件的名稱("加法函數的測試"),第二個參數是一個實際執行的函數。
`it`塊稱為"測試用例"(test case),表示一個單獨的測試,是測試的最小單位。它也是一個函數,第一個參數是測試用例的名稱("1 加 1 應該等于 2"),第二個參數是一個實際執行的函數。
上面的測試腳本里面,有一句斷言。
~~~
expect(add(1, 1)).to.be.equal(2);
~~~
所謂"斷言",就是判斷源碼的實際執行結果與預期結果是否一致,如果不一致就拋出一個錯誤。上面這句斷言的意思是,調用`add(1, 1)`,結果應該等于`2`。
所有的測試用例(`it`塊)都應該含有一句或多句的斷言。它是編寫測試用例的關鍵。斷言功能由斷言庫來實現,Mocha本身不帶斷言庫,所以必須先引入斷言庫。
~~~
var expect = require('chai').expect;
~~~
斷言庫有很多種,Mocha并不限制使用哪一種。上面代碼引入的斷言庫是`chai`,并且指定使用它的`expect`斷言風格。
(4)打開`package.json`文件,改寫`scripts`字段的`test`腳本。
~~~
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
// 改成
"scripts": {
"test": "mocha *.test.js"
},
~~~
(5)命令行下,執行下面的命令,運行測試用例。
~~~
$ npm test
~~~
正常情況下,命令行會有提示,表示測試用例已經通過了。
### 練習
1. 請在`add.test.js`里面添加一個測試用例,測試`3`加上`-3`,`add`函數應該返回`0`。
## Nightmare
### 實驗目的
1. 學會使用 Nightmare 完成功能測試。
### 操作步驟
(1)進入`./demos/nightmare-demo`目錄,安裝依賴。
~~~
$ cd demos/nightmare-demo
# Linux & Mac
$ env ELECTRON_MIRROR=https://npm.taobao.org/mirrors/electron/ npm install
# Windows
$ set ELECTRON_MIRROR=https://npm.taobao.org/mirrors/electron/
$ npm install
~~~
注意,Nightmare 會先安裝 Electron,而 Electron 的安裝需要下載境外的包,有時會連不上,導致安裝失敗。所以,這里先設置了環境變量,指定使用國內的 Electron 源,然后才執行安裝命令。
(2)查看一下瀏覽器自動化腳本`taobao.test.js`。
~~~
var Nightmare = require('nightmare');
var nightmare = Nightmare({ show: true });
~~~
上面代碼表示新建一個 Nightmare 實例,并且運行功能中,自動打開瀏覽器窗口。
~~~
nightmare
.goto('https://www.taobao.com/')
.type('#q', '電視機')
.click('form[action*="/search"] [type=submit]')
.wait('#spulist-grid')
.evaluate(function () {
return document.querySelector('#spulist-grid .grid-item .info-cont')
.textContent.trim();
})
.end()
~~~
上面代碼表示,打開淘寶首頁,在搜索框鍵入`電視機`,點擊”搜索“按鈕,等待`#spulist-grid`元素出現,在頁面內注入(`evaluate`)代碼,將執行結果返回。
~~~
.then(function (result) {
console.log(result);
})
.catch(function (error) {
console.error('Search failed:', error);
});
~~~
Nightmare 會返回一個 Promise 對象,`then`方法指定操作成功的回調函數,`catch`方法指定操作失敗的回調函數。
(3)命令行下運行這個示例腳本。
~~~
$ node taobao.test.js
~~~
正常情況下,運行結束后,命令行會顯示淘寶”電視機“搜索結果的第一項。
(4)瀏覽器打開`index.html`文件,這是 React 練習時做過的一個例子,點擊`Hello World`,標題會變成`Hello Clicked`。我們就要編寫測試腳本,測試這個功能。
(5)打開測試腳本`test.js`。
~~~
var Nightmare = require('nightmare');
var expect = require('chai').expect;
var fork = require('child_process').fork;
describe('test index.html', function() {
var child;
before(function (done) {
child = fork('./server.js');
child.on('message', function (msg) {
if (msg === 'listening') {
done();
}
});
});
after(function () {
child.kill();
});
~~~
上面代碼中,`before`和`after`是 Mocha 提供的兩個鉤子方法,分別在所有測試開始前和結束后運行。這里,我們在`before`方法里面,新建一個子進程,用來啟動 HTTP 服務器;測試結束后,再殺掉這個子進程。
注意,`before`方法的參數是一個函數,它接受`done`作為參數。`done`是 Mocha 提供的一個函數,用來表示異步操作完成。如果不調用`done`,Mocha 就會認為異步操作沒有結束,一直停在這一步,不往下執行,從而導致超時錯誤。
子進程腳本`server.js`的代碼非常簡單,只有四行。
~~~
var httpServer = require('http-server');
var server = httpServer.createServer();
server.listen(8080);
process.send('listening');
~~~
上面代碼中,我們在`8080`端口啟動 HTTP 服務器,然后向父進程發消息,表示啟動完成。
(6)真正的自動化測試腳本如下。
~~~
it('點擊后標題改變', function(done) {
var nightmare = Nightmare({ show: true });
nightmare
.goto('http://127.0.0.1:8080/index.html')
.click('h1')
.wait(1000)
.evaluate(function () {
return document.querySelector('h1').textContent;
})
.end()
.then(function(text) {
expect(text).to.equal('Hello Clicked');
done();
})
});
~~~
上面代碼中,首先打開網頁,點擊`h1`元素,然后等待 1 秒鐘,注入腳本獲取`h1`元素的文本內容。接著,在`then`方法里面,做一個斷言,判斷獲取的文本是否正確。
(7)運行這個測試腳本。
~~~
$ npm test
~~~
如果一切正常,命令行下會顯示測試通過。
### 練習
1. 請寫一個測試用例,驗證`<h1>`的字體顏色是紅色。(提示:可以使用`Window.getComputedStyle()`方法,獲取元素的最終樣式。)
## Travis CI
### 實驗目的
1. 了解持續集成的做法,學會使用 Travis CI。
### 操作步驟
(1)注冊?[Github](https://github.com/)?的賬戶。如果你已經注冊過,跳過這一步。
(2)訪問這個代碼庫[`github.com/ruanyf/travis-ci-demo`](https://github.com/ruanyf/travis-ci-demo),點擊右上角的`Fork`按鈕,將它克隆到你自己的空間里面。
(3)將你`fork`的代碼庫,克隆到本地。注意,要將下面網址之中的`[your_username]`改成你的 Github 用戶名。
~~~
// Linux & Mac
$ git clone git@github.com:[your_username]/travis-ci-demo.git
// Windows
$ git clone https://github.com:[your_username]/travis-ci-demo
~~~
(4)使用你的 Github 賬戶,登錄?[Travis CI](https://travis-ci.org/auth)?的首頁。然后,訪問?[Profile](https://travis-ci.org/profile)?頁面,選定`travis-ci-demo`代碼庫運行自動構建。
(5)回到命令行,進入你本地的`travis-ci-demo`目錄,切換到`demo01`分支。
~~~
$ cd travis-ci-demo
$ git checkout demo01
~~~
項目根目錄下面有一個`.travis.yml`文件,這是 Travis CI 的配置文件。如果沒有這個文件,就不會觸發 Travis CI 的自動構建。打開看一下。
~~~
language: node_js
node_js:
- "node"
~~~
上面代碼指定,使用 Node 完成構建,版本是最新的穩定版。
指定 Node 的版本號也是可以的。
~~~
language: node_js
node_js:
- "4.1"
~~~
上面代碼指定使用 Node 4.1 版。
(6)Travis CI 默認依次執行以下九個腳本。
* `before_install`
* `install`
* `before_script`
* `script`
* `after_success`?或者?`after_failure`
* `after_script`
* `before_deploy`(可選)
* `deploy`(可選)
* `after_deploy`(可選)
用戶需要用到哪個腳本,就需要提供該腳本的內容。
對于 Node 項目,以下兩個腳本有默認值,可以不用自己設定。
~~~
"install": "npm install",
"script": "npm test"
~~~
(7)打開當前分支的`package.json`,可以發現它的`test`腳本是一個`lint`命令。
~~~
"scripts": {
"test": "jshint hello.js"
},
~~~
(8)在項目根目錄下,新建一個新文件`NewUser.txt`,內容是你的用戶名。提交這個文件,就會觸發 Travis CI 的自動構建。
~~~
$ git add -A
$ git commit -m 'Testing Travis CI'
$ git push
~~~
(9)等到 Travis CI 完成自動構建,到頁面上[檢查](https://travis-ci.org/repositories)構建結果。
(10)切換到`demo02`分支,打開`package.json`,可以看到`test`腳本,現在需要完成兩步操作了。
~~~
"scripts": {
"lint": "jshint hello.js hello.test.js",
"test": "npm run lint && mocha hello.test.js"
},
~~~
(11)重復上面第 8 步和第 9 步。
### 練習
1. 修改`hello.js`,讓其輸出`Hello Node`。并修改測試用例`hello.test.js`,使之能夠通過 Travis CI 的自動構建。