# Jest
> 此內容參考自 [Jest | 讓 Jest 為你的 Code 做測試-基礎用法教學](https://medium.com/enjoy-life-enjoy-coding/%E8%AE%93-jest-%E7%82%BA%E4%BD%A0%E7%9A%84-code-%E5%81%9A%E5%96%AE%E5%85%83%E6%B8%AC%E8%A9%A6-%E5%9F%BA%E7%A4%8E%E7%94%A8%E6%B3%95%E6%95%99%E5%AD%B8-d898f11d9a23) 與 [Day17 | 不知道對不對,就把邏輯通通測起來 feat. Jest](https://ithelp.ithome.com.tw/articles/10222357)。
### Jest 安裝懶人包
1. 開啟命令提示字元,cd 到想要安裝 Jest 的資料夾
2. 輸入 `npm init -y`,在 `node.js` 環境下建立一個 `package.json` 檔案
3. 輸入 `npm install --save-dev jest`,透過 npm 套件管理工具下載 Jest 測試框架到專案的執行環境中
4. 打開 `package.json`,並將 `"scripts"` 中的 key `"test"` 的值改為 `"jest"`:
```
//...略
scripts: {
"test": "jest"
}
//...略
```
改好之後,只需在終端機中輸入 `npm run test`,Jest 便會尋找專案中副檔名為 `.test.js` 結尾的檔案進行測試
### 基本語法範例
``` js
test('two plus two is four', () => {
expect(2 + 2).toBe(4);
});
```
+ test 函式用來描寫一個單元測試,它擁有兩個參數:
+ 第一個參數,用來敘述此單元測試的功能或者邏輯
+ 第二個參數是一個 function,function 內的 `expect()` 的參數為要測試的值或函式;`toBe()` 為一個 matcher,參數為 `expect()` 測試的期望值。
+ 以上面基本語法為例:`'two plus two is four'` 用來描述此測試的功能(二加二等於四);`expect(2 + 2)` 的 2 + 2 為要測試的內容;`toBe(4)`的 4 為 2 + 2 的期望值。
### 示範
#### 在專案資料夾底下,有一個 `main.js` 檔案,我在裡面寫了一個簡單的加法函式:
``` js
//in main.js
function add(a, b) {
return a + b
}
```
#### 我想用 Jest 測試 add 函式,先將它 export 出去:
``` js
function add(a, b) {
return a + b
}
module.exports = add
```
#### 在專案資料夾底下建立一個 `main.test.js` 檔案,import add 函式並寫入測試 function:
> Jest 運行時會尋找專案中副檔名為 `.test.js` 結尾的檔案進行測試
``` js
const add = require('./main')
test('a + b = 5', () => {
expect(add(3, 2)).toBe(5);
});
test('a + b = 10', () => {
expect(add(5, 5)).toBe(10);
});
```
#### 在終端機輸入 `npm run test` 方可進行自動化測試,以下為測試結果:
``` js
PASS ./main.test.js
√ a + b = 5 (7 ms)
√ a + b = 10 (1 ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 2.877 s
Ran all test suites.
```
#### 若我們將第一個 test 函式中的 `toBe(5)` 改為 `toBe(6)`並重新執行測試:
``` js
FAIL ./main.test.js
× a + b = 5 (7 ms)
√ a + b = 10
● a + b = 5
expect(received).toBe(expected) // Object.is equality
Expected: 6
Received: 5
2 |
3 | test('a + b = 5', () => {
> 4 | expect(add(3, 2)).toBe(6);
| ^
5 | });
6 |
7 | test('a + b = 10', () => {
at Object.test (main.test.js:4:23)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 passed, 2 total
Snapshots: 0 total
Time: 6.758 s
```
會顯示 fail,並指出測試結果應為 5 而不是 6。
### 更多常用的 matchers
> 此篇內容引用自 [十分鐘上手前端單元測試 - 使用 Jest](https://wcc723.github.io/development/2020/02/02/jest-intro/)。
編寫測試時需要讓值符合期望,Jest 中的 expect 後方可以使用 `matchers`(匹配器)作為條件驗證,如先前的範例 `expect(...).toBe(...)` 中的 `toBe()` 就屬於 matchers,作為各種不同條件的驗證使用。
#### 測試是否為 `null`、`true`、`false`、或者 `undefined`:
+ `toBeNull`:matches only null
+ `toBeUndefined`: matches only undefined
+ `toBeTruthy`:matches anything that an `if` statement treats as true
+ `toBeFalsy`:matches anything that an `if` statement treats as false
#### 物件對比:
``` js
const boy = {
name: 'Leo'
}
console.log(boy === {name: 'Leo'}) // false
```
這邊得到 false 的結果與變數儲存模型有關,詳情可複習 [從 Object 的等號真正的理解變數(變數儲存模型)](https://github.com/TsaiChihWei/learning-blog/issues/4)。
在 Jest 也是相同概念,如若直接使用 `toBe()` 來比對物件一樣會得到 fail 的結果。
若單純想對比物件內的值則可使用 `toEqual()`,範例:
``` js
test('object assignment', () => {
const data = {one: 1}
data['two'] = 2
expect(data).toEqual({one: 1, two: 2})
})
```
#### 數值比對
``` js
test('two plus two', () => {
const value = 2 + 2
expect(value).toBeGreaterThan(3)
expect(value).toBeGreaterThanOrEqual(3.5)
expect(value).toBeLessThan(5)
expect(value).toBeLessThanOrEqual(4.5)
// toBe and toEqual are equivalent for numbers
expect(value).toBe(4)
expect(value).toEqual(4)
});
```
#### `toMactch` 字串包含
使用 `toMatch()` 測試一個字串有無包含特定字串:
``` js
test('there is no I in team', () => {
expect('team').toMatch('I')
})
```
測試會 fail,因為字串 `'team'` 沒有包含 大寫 `I`,或也可使用**正規表達式**:
``` js
test('but there is a "stop" in Christoph', () => {
expect('Christoph').toMatch(/stop/)
})
```
測試會通過,因為字串 `Christoph` 有包含 `stop`。
#### `toContain` 判斷一個陣列是否含有某值
``` js
// pass the test
const arr = ['a', 'b', 'c']
test('if arr includes specific value', () => {
expect(arr).toContain('b')
})
```
### describe
`describe` 的用途是提供一個群組的描述,將多個 test 包在一起,讓程式看起來更有結構性
``` js
//...略
describe('test reverse', () => {
test('123 reverse should be 321', () => {
expect(reverse('123')).toBe('321')
})
test('!!! reverse should be !!!', () => {
expect(reverse('!!!')).toBe('!!!')
})
test('"" reverse should be ""', () => {
expect(reverse('')).toBe('')
})
})
```
> [延伸題:如何產生覆蓋率報告?](https://medium.com/enjoy-life-enjoy-coding/%E8%AE%93-jest-%E7%82%BA%E4%BD%A0%E7%9A%84-code-%E5%81%9A%E5%96%AE%E5%85%83%E6%B8%AC%E8%A9%A6-%E5%9F%BA%E7%A4%8E%E7%94%A8%E6%B3%95%E6%95%99%E5%AD%B8-d898f11d9a23)