# 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 同一層),並在文件中輸入以下的配置碼 ![](https://hackmd.io/_uploads/SkRB6wHAn.png) ```=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 資料夾根目錄 ![](https://hackmd.io/_uploads/SkP76vr02.png) ``` =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'` 下方 ![](https://hackmd.io/_uploads/Bklc0Pr0n.png) ``` =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