# Cypress - test coverage with angular
## 使用 angular 創建 cypress 的 e2e 測試案例
再撰寫完測試案例後,可能會使用 CI 來進行自動化的測試,後續也會需要分析 test 的 coverage
當您編寫越來越多的 E2E 測試時,你會開始思考,我需要編寫更多測試嗎?有沒有哪些部分是尚未測試的?還是有哪些部分的測試過多?
## 創建流程與步驟:
1. 在 angualr 中創建 cypress 資料夾
```
ng add @cypress/schematic
```
2. 下載 cypress/code-coverage 套件
```
npm i -D @cypress/code-coverage
```
3. 下載相關的編譯套件
在 cypress 的官網中告訴我們,cypress 不會檢查我們的程式碼,我們需要另外使用 `istanbuljs` 來進行測試覆蓋的檢查,你無法只有下載 code-coverage 就直接執行測試案例。
```
npm i -D @types/cypress__code-coverage
// 最初沒加入這個套件,導致 ts 一直出現錯誤
npm i -D @jsdevtools/coverage-istanbul-loader
npm i -D istanbul-instrumenter-loader
npm i -D @istanbuljs/nyc-config-typescript
npm i -D istanbul-lib-coverage
npm i -D nyc
npm i -D webpack
```
==各套件使用註解==
**@types/cypress__code-coverage**
這提供了 TypeScript 的類型聲明,以便你可以在 TypeScript 專案中使用 Cypress-code-coverage 的相關功能並獲得類型檢查的支持。
**@jsdevtools/coverage-istanbul-loader:**
這是一個 webpack 加載器,主要是將 istanbul 覆蓋率數據嵌入源代碼中,以便在運行測試時收集覆蓋率的相關資訊
**istanbul-instrumenter-loader:**
這是一個 webpack 加載器,與 @jsdevtools/coverage-istanbul-loader 一起使用,確保建構时在代碼中插入覆盖率儀器
**@istanbuljs/nyc-config-typescript:**
這是一個 istanbul.js 的配置 module,專門用於 TS 的專案,它包含了一組針對 TS 的默認配置選項
**istanbul-lib-coverage:**
istanbul.js 的核心庫,用於處理和操作覆蓋率數據,生成自定義的覆蓋率報告
**nyc:**
測試覆蓋率工具,用於運行測試套件,並生成覆蓋率報告,通常與 istanbul.js 結合使用,以生成詳細的覆蓋率報告。
4. 新增一個文件名稱: `.nycrc` 的 nyc 配置文件於你的專案根目錄(與 package.json 同一層),並在文件中輸入以下的配置碼

```=json
{
"extends": "@istanbuljs/nyc-config-typescript",
"all": true,
"exclude": [
"./coverage/**",
"cypress/**",
"./dist/**",
"**/*.spec.ts",
"./src/main.ts",
"./src/test.ts",
"**/*.conf.js"
]
}
```
5. 將 "node" 的文字加入位於 cypress 資料夾的 `tsconfig.json` 文件中,如果沒有添加的話,TypeScript 會產生錯誤
```=json
{
"extends": "../tsconfig.json",
"include": ["**/*.ts"],
"compilerOptions": {
"sourceMap": false,
"types": ["cypress","node"] // 在這裡加入 'node'
}
}
```
6. 新增一個文件名稱為 `coverage.webpack.ts` 的 webpack 配置文件於你的 cypress 資料夾根目錄

``` =js
import * as path from 'path';
export default {
module: {
rules: [
{
test: /\.(js|ts)$/,
loader: '@jsdevtools/coverage-istanbul-loader',
options: { esModules: true },
enforce: 'post',
include: path.join(__dirname, '..', 'src'),
exclude: [
/\.(e2e|spec)\.ts$/,
/node_modules/,
/(ngfactory|ngstyle)\.js/,
],
},
],
},
}
```
7. 於 `cypress/support/e2e.js` 文件中添加 `@cypress/code-coverage/support` 於 `import './commands'` 下方

``` =js
import '@cypress/code-coverage/support';
```
8. 配置你的 `cypress.config.ts` 文件
```=js
e2e: {
'baseUrl': 'http://localhost:4200',
// 在這裡加入 coverage 的配置
setupNodeEvents(on: any, config: any) {
require("@cypress/code-coverage/task")(on, config);
return config;
}
},
```
9. 修改 `angular.json` 的配置,首先添加 `@angular-builders/custom-webpack`
```
npm i -D @angular-builders/custom-webpack
```
10. 將 `angular.json` 中的 `“builder”: “@angular-devkit/build-angular:browser”` 替換為 **`"builder": "@angular-builders/custom-webpack:browser"`**
```=json
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
}
}
```
11. 在`angular.json` 中的 `configurations` 區塊中的 `development` 下方,配置 e2e 的 config
```=json
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
},
// 添加這一段 e2e 區塊代碼於 development 下方
"e2e": {
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true,
"vendorChunk": true,
"customWebpackConfig": {
"path": "./cypress/coverage.webpack.ts"
}
}
```
12. 於 `angular.json` 文件中的 `serve` 底下,添加 `serve-coverage` 的配置代碼
**將 ${your-project} 替換成你的專案名稱** (你可以在 package.json 中找到你的專案名稱)
```=json
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "${your-project}:build"
},
"configurations": {
"production": {
"browserTarget": "${your-project}:build:production"
},
"local": {
"browserTarget": "${your-project}:build:local"
},
"development": {
"browserTarget": "${your-project}:build:development"
}
},
"defaultConfiguration": "development"
},
// 添加這一段代碼於你的 serve 區塊底下
"serve-coverage": {
"builder": "@angular-builders/custom-webpack:dev-server",
"options": {
"browserTarget": "${your-project}:build:e2e"
}
},
```
13. 於 `angular.json` 文件中的 serve 區塊中,找到 e2e 的區塊,將原有的 e2e 區塊做抽換,並且新增 `e2e-ci` 設定
**將 ${your-project} 替換成你的專案名稱**
```=json
"e2e": {
"builder": "@cypress/schematic:cypress",
"options": {
"devServerTarget": "${your-projetc}:serve-coverage",
"watch": true,
"headless": false
},
"configurations": {
"production": {
"devServerTarget": "${your-projetc}:serve-coverage:production"
}
}
},
"e2e-ci": {
"builder": "@cypress/schematic:cypress",
"options": {
"browser": "chrome",
"devServerTarget": "${your-projetc}:serve-coverage",
"headless": true,
"watch": false
},
"configurations": {
"production": {
"devServerTarget": "${your-projetc}:serve-coverage:production"
}
}
},
```
14. 於`package.json`中,添加快速執行語法,位於 e2e 後方
**將 ${your-project} 替換成你的專案名稱**
```=json
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
// 添加以下兩行語法
"e2e:ci": "ng run novax-kumay-punch-admin:e2e-ci",
"e2e:coverage": "npx nyc report --reporter=lcov --reporter=text-summary",
```
15. 執行測試覆蓋率測試
```
npm run e2e:ci && npm run e2e:coverage
```
參考資料:
- https://lukas-klement.medium.com/implementing-code-coverage-with-angular-and-cypress-6ed08ed7e617
- https://docs.cypress.io/guides/tooling/code-coverage#Instrumenting-code
- https://github.com/webpack-contrib/istanbul-instrumenter-loader/issues/44
- https://stackoverflow.com/questions/40192521/istanbul-instrumenter-loader-can-not-find-source-map-for-angular2-component