# Vue單元測試學習筆記
在深入技術前,可以先閱讀Vue官方的[測試建議](https://cn.vuejs.org/guide/scaling-up/testing.html)
以下,會介紹幾個在專案中撰寫測試搭配的套件及其初始範例,詳細寫法還請參考個別的官方文件。
## Unit-jest (Jest & Vue Test Utils)
### About
>[jest](https://jestjs.io/docs/getting-started) 官方文件
Jest 是一個由Facebook 開發的 test runner,它提供許多豐富的功能,例如:斷言、分析測試涵蓋率、 mock 功能與良好的錯誤提示訊息等。
Jest 可以測試的範圍涵蓋了 JavaScript 相關的技術,包含後端的 Node.js 與前端的 Vue 、 Angular 或 React ,是個完善的測試框架。
> Vue Test Utils [英文](https://v1.test-utils.vuejs.org/guides/#getting-started) / [中文](https://v1.test-utils.vuejs.org/zh/guides/#%E8%B5%B7%E6%AD%A5)官方文件
>
Vue Test Utils 是Vue.js 官方所維護的單元測試套件,它提供了一系列的API 使我們很容易去操作存取元件
#### 建立含有單元測試的專案
```
$ vue create vue-test -m npm
Vue CLI v5.0.8
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Unit
? Choose a version of Vue.js that you want to start the project with 2.x
? Pick a unit testing solution: Jest
...
```
它會直接幫你建立測試的範例檔

運行後可以得到
```shell
$ npm run test:unit
```

#### 於現有專案安裝
```shell
$ vue add unit-jest
```
### 簡單範例:Counter
1. 建立一個counter頁面,點擊按鈕後數字會+1
`@/components/Counter.vue`
```javascript=
<template>
<div>
<h1>Count: {{ count }}</h1>
<button id="increment-btn" @click="count++"> +1 </button>
</div>
</template>
<script>
export default {
data() {
return {
count: 0,
}
},
}
</script>
```
會長得像這樣:

2. 寫測試
預期初始值會是0,點擊一下之後會變成1
`tests/unit/counter.spec.js`
```javascript=
import { mount } from '@vue/test-utils'
import Counter from '@/components/Counter.vue'
describe('Counter.vue', () => {
it('click once', async () => {
// 驗證初始值
const wrapper = mount(Counter)
expect(wrapper.vm.count).toBe(0)
// 獲取元件
const button = wrapper.find('button')
const h1 = wrapper.find('h1')
// 測試互動
await button.trigger('click')
expect(h1.text()).toContain('1')
})
})
```
3. 結果

## Vitest
* Vitest 与大多数 Jest API 和生态系统库都有较好的兼容性,可以無痛轉換
* 如果專案本身由 Vite 驅動,推薦以 Vitest 作為測試工具
* 寫測試時也可以搭配 Vue Test Utils 或 testing-library 做組件測試使用
### Install
基本上用 `vue-create` 建專案的話都會內建,沒有的話可以用下列指令安裝
```shell
$ npm install -D vitest
$ npm i @vitejs/plugin-vue
```
建立設定檔 `vitest.config.ts`
```javascript=
import { fileURLToPath, URL } from "node:url"
import { defineConfig } from "vite"
import type { UserConfig as VitestUserConfigInterface } from "vitest/config"
import vue from "@vitejs/plugin-vue"
const vitestConfig: VitestUserConfigInterface = {
test: {
globals: true,
environment: "jsdom", // 也可以用happy-dom之類的
},
}
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
test: vitestConfig.test,
})
```
配置 `package.json`
```javascript
"scripts": {
"test": "vitest",
"coverage": "vitest --coverage" // 稍後覆蓋率會用到
},
```
> 配置方式參考
> [vue 官方建議](https://vuejs.org/guide/scaling-up/testing.html#recipes)
> [一篇來自 stackoverflow 的建議](https://stackoverflow.com/questions/70769062/vue-test-utils-for-vue3-document-is-not-defined)
### 簡單範例(搭配Vue Test Utils)
要先安裝 Vue Test Utils
```
$ npm install @vue/test-utils --save-dev
```
建立基本測試,檔名須遵照 `xxx.test.js` 規則
code和上面jest的寫法一樣
`@/tests/example.test.js`
```javascript=
import { mount } from "@vue/test-utils";
import HelloWorld from "@/components/HelloWorld.vue";
import { describe, expect, test } from "vitest";
describe('HelloWorld.vue', () => {
test('renders props.msg when passed', () => {
const msg = 'new message'
const wrapper = mount(HelloWorld, {
propsData: { msg } // Mocking Props
})
expect(wrapper.text()).toMatch(msg)
})
})
```
運行測試,本指令會自動 watch
```shell
$ npm test
```

### 覆蓋率
> [官方文件](https://vitest.dev/guide/coverage.html)
設定 `vitest.config.ts`
```javascript
const vitestConfig: VitestUserConfigInterface = {
test: {
globals: true,
environment: "jsdom",
/* 新增以下設定 */
coverage:{
all: true,
provider: 'c8', // 也可以用istanbul
reporter: ['text', 'json', 'html'],
},
include: ['**/tests/*.js'], // 測試檔案路徑,也可以不設定預設抓所有
/* ---------- */
},
}
...
```
安裝覆蓋率套件
```shell
$ npm i -D @vitest/coverage-c8@{你的vitest版本號}
```
運行指令
```shell
$ npm run coverage
```
* 從terminal檢視

* 檢視網頁介面報告
運行覆蓋率指令後,會自動生成 `/converage` 資料夾

打開html網頁後,可以查看詳細的報告

## testing-library
>[testing-library](https://testing-library.com/docs/) 官方文件
```shell
$ npm install --save-dev @testing-library/vue
```
## 語法指令
### Vue Test Utils
> [Vue Test Utils APIs](https://v1.test-utils.vuejs.org/zh/api/#api)
### Vitest
> [vitest APIs](https://cn.vitest.dev/api/)
Jest 的指令基本上和 Vitest 是兼容的
### Jest
> [jest APIs](https://jestjs.io/docs/api)
## 其他
### Cypress
## 參考資料
[尋覓網站開發的神兵利器系列 第 38 篇 Extra07 - Jest - 單元測試框架](https://ithelp.ithome.com.tw/articles/10282152)