:mochawesome輸出HTML報告與合并)
Cypress 跑完測試只會看到命令行里一串綠色的通過標(biāo)記如果只把這條輸出給團隊那可太虧了。測試跑完只是第一步真正關(guān)鍵的是把結(jié)果轉(zhuǎn)成一眼能看出問題、能歸檔、能塞進(jìn)CI流水線的報告。這篇是Cypress系列的第三十三篇專門聊生成測試報告的第一部分——先把最常用的HTML報告方案講透后續(xù)再補上其他格式與CI深度集成。先說清楚這篇要解決什么問題你的自動化測試已經(jīng)寫了不少在本地跑能通過但項目成員怎么確認(rèn)當(dāng)前版本的回歸結(jié)果歷史用例失敗趨勢怎么追蹤新同事進(jìn)來如何快速查看最近一次全量測試的失敗用例這些問題的答案都指向同一個東西一份漂亮且信息完整的測試報告。Cypress 本身默認(rèn)基于 Mocha底層渲染出一份簡單的“點線報告”但那種樣式只適合開發(fā)機上看一跑而過。真正的團隊級報告需要更豐滿的數(shù)據(jù)每個用例的執(zhí)行時間、失敗棧、截圖與視頻鏈接、斷言詳情等。這篇文章適合三類人剛能把 Cypress 跑起來、但還沒認(rèn)真研究過報告格式的入門者已經(jīng)在用mochawesome但沒搞定數(shù)據(jù)合并的進(jìn)階選手還有需要在 Jenkins 這類工具里穩(wěn)定產(chǎn)出報告的工程化實踐者。下面直接進(jìn)入正題我盡量用實操時的經(jīng)驗順一遍而不是照著官方文檔念。1. 報告設(shè)計思路先想清楚你要的是一份什么樣的報告很多人一上來就裝mochawesome裝完發(fā)現(xiàn)生成的 JSON 和 HTML 分開又不知道合并最后干脆只保留 HTML。這種用法不能說錯但如果你真想用好測試報告第一步其實是問自己這份報告最終給誰看要承載哪些信息1.1 報告的使用場景與核心需求拆解個人開發(fā)時你需要的可能只是“哪些用例掛了、掛在哪個斷言”這時候 Cypress 自帶的終端輸出配合截圖就能湊合。但團隊協(xié)作時就需要一份包含匯總統(tǒng)計、失敗用例趨勢、歷史對比的報告最好還能按套件或標(biāo)簽篩選。再往上走CI 流水線里要自動歸檔那么報告文件名就不能帶時間戳或隨機值否則每次構(gòu)建都會覆蓋舊記錄問題追溯無從談起。我在項目里見過最典型的翻車場景報告生成出來了很好看但有個同事跑完本地后順手把mochawesome-report目錄提交到代碼倉庫導(dǎo)致合并沖突不斷。這就是典型的沒有設(shè)計好報告存放與命名規(guī)則。我的建議是先把報告的輸出目錄統(tǒng)一固定為test-results并且加入.gitignore任何本地產(chǎn)出的報告都不入庫只在 CI 服務(wù)端備份或者使用插件上傳到公共平臺。1.2 Cypress 報告機制的本質(zhì)Mocha reporter 的擴展邏輯Cypress 的測試執(zhí)行器沿用了 Mocha 的 reporter 機制也就是說你在cypress.config.js里配置的reporter字段直接被 Cypress 讀取并傳給內(nèi)置的 Mocha 實例。這帶來一個很大的好處生態(tài)里絕大多數(shù)為 Mocha 開發(fā)的 reporter 插件都能在 Cypress 中使用哪怕插件從沒說過自己支持 Cypress。理解了這一點你就知道為什么配置報告不需要改動測試代碼只需在配置文件中指定reporter和reporterOptions。Cypress 在運行時會把每個測試文件spec單獨交給 Mocha 跑一遍對應(yīng)的 reporter 也會在每個 spec 結(jié)束時生成輸出。這個“按 spec 單獨生成”的特性直接導(dǎo)致了多 spec 場景下報告文件會被多次覆蓋或各自獨立。這也是后面我會強調(diào)合并數(shù)據(jù)的關(guān)鍵原因。2. 基礎(chǔ)配置reporters 與 reporterOptions 的準(zhǔn)確含義大部分 Cypress 用戶都知道在cypress.config.js里寫reporter: mochawesome但未必理解reporterOptions中每個字段怎么設(shè)。這一節(jié)先把配置項講明白后續(xù)再給完整示例。2.1 Cypress 配置文件中的 reporter 字段與內(nèi)置選項打開cypress.config.js配置片段一般長這樣const { defineConfig } require(cypress); module.exports defineConfig({ e2e: { specPattern: cypress/e2e/**/*.cy.js, reporter: mochawesome, reporterOptions: { reportDir: cypress/results, overwrite: false, html: true, json: true, charts: true, }, }, });reporter指定使用的 reporter 包名。如果不加任何配置默認(rèn)走的是specreporter也就是終端里列出每個用例的√或×的結(jié)果。這個選擇只會影響輸出形式不影響測試執(zhí)行行為。reporterOptions則直接傳給 reporter 插件不同插件的配置項不一樣但幾個常用項在 mochawesome 里很關(guān)鍵reportDir控制輸出目錄overwrite決定是否覆蓋已有文件html和json分別控制是否生成兩種格式的文件charts控制是否在報告中渲染統(tǒng)計圖表。有件事得單獨拎出來說Cypress 的reporterOptions不一定能被所有插件完整讀取。有些 reporter 插件只認(rèn)頂層reporterOptions如果你在某個測試文件的before鉤子里動態(tài)調(diào)整配置會不生效。所以盡量保證配置文件的靜態(tài)設(shè)置不要用代碼動態(tài)改。2.2 為什么默認(rèn)的報告不適合團隊協(xié)作三個致命缺陷先看 Cypress 內(nèi)置specreporter 的幾個問題。第一個缺陷沒有統(tǒng)計匯總。跑完 20 個文件終端底部會給出總量、通過數(shù)、失敗數(shù)但你想看每個文件的“通過率柱狀圖”抱歉沒有。第二個缺陷歷史比對困難。今天的報告和上周對比只能靠肉眼一行一行看如果測試數(shù)量從三百條漲到三百五十條很難直觀看出新增了哪些。第三個缺陷截圖和視頻信息脫離用例。失敗用例在 Cypress 的cypress/screenshots目錄里能翻到 PNG但報告頁面上看不到快捷入口尤其在 CI 機器上你不可能遠(yuǎn)程登錄去看文件系統(tǒng)。mochawesome這類報告器正好補上了這幾個缺口。它生成的 HTML 頁面自帶統(tǒng)計面板、用例列表、失敗信息、截圖嵌入通過相對路徑預(yù)覽還有按套件折疊的視圖。更關(guān)鍵的是它會把每個用例的數(shù)據(jù)完整寫到 JSON 里之后想二次處理或生成自定義報表JSON 就是數(shù)據(jù)源。3. 實操基礎(chǔ)直接用 mochawesome 生成你的第一份 HTML 報告前面理論聊得差不多了下面進(jìn)入動手環(huán)節(jié)。這一步不難但有幾個坑我踩過會在過程中指出來。3.1 依賴安裝與初始配置三步實現(xiàn)從零到報告第一步安裝必須的 npm 包。這里要注意比較穩(wěn)妥的組合是mochawesome和mochawesome-mergenpm install --save-dev mochawesome mochawesome-merge第二步在cypress.config.js中寫入 reporter 配置const { defineConfig } require(cypress); module.exports defineConfig({ reporter: mochawesome, reporterOptions: { reportDir: cypress/results/mochawesome, overwrite: false, html: false, json: true, }, });這里我把html設(shè)為false只先生成 JSON。原因后面會說當(dāng)你有多個 spec 文件時mochawesome 會為每個 spec 生成獨立的報告而這些報告會互相覆蓋。如果在每個獨立報告里都生成 HTML最后你只會得到最后一個 spec 的 HTML意義不大。正確玩法是先讓每個 spec 生成獨立的 JSON再用合并工具把 JSON 合成一份完整數(shù)據(jù)最后基于合并后的數(shù)據(jù)生成總報告。第三步運行測試npx cypress run跑完后進(jìn)入cypress/results/mochawesome目錄應(yīng)該能看到類似.json的文件里面包含每個用例的標(biāo)題、狀態(tài)、耗時、錯誤信息等。如果這一步報錯多半是 reporter 包沒裝上或者目錄不可寫。3.2 用 mochawesome 直接生成 HTML 時的坑多 spec 覆蓋問題有人會想既然mochawesome本身就能生成 HTML那我直接在配置里設(shè)html: true不就行了不行除非你的項目里只有單個 spec 文件。只要 Cypress 執(zhí)行了多個 spec每一個 spec 跑完時 mochawesome 都會嘗試寫一個固定名字的mochawesome.html后寫的會把先寫的覆蓋掉。最終你得到的是最后一個 spec 的報告前面 spec 的結(jié)果全丟。解決思路是設(shè)置overwrite: false讓它為每個 spec 生成帶不同后綴的文件。但overwrite: false生成的文件名仍基于同一個基礎(chǔ)名會變成mochawesome_001.json、mochawesome_002.json這種。如果項目 spec 數(shù)量不固定編號亂掉的可能性很高。所以我的推薦配置還是html: false, json: true把生成最終 HTML 的職責(zé)交給合并腳本。4. 合并與生成mochawesome-merge 的正確打開方式先說明一下為什么需要合并。Cypress 執(zhí)行多個 spec 時測試數(shù)據(jù)其實是分散在多個 JSON 文件里的如果直接打開某個 spec 的 JSON里面只有那個 spec 的用例信息。團隊報告要的是“全量匯總”你需要把多個 JSON 合并成一個“總 JSON”再用 mochawesome 的 HTML 生成能力渲染總報告。4.1 合并命令的三種寫法與適用場景合并命令的核心很簡單npx mochawesome-merge cypress/results/mochawesome/*.json cypress/results/mochawesome/merged.json注意我加了引號因為通配符需要讓 shell 展開某些 Windows 環(huán)境下沒有引號會匹配不到文件。執(zhí)行完這個命令你會得到一個merged.json里面是一個完整的 JSON 數(shù)組包含了所有 spec 的數(shù)據(jù)。如果你不想在命令行里拼字符串也可以寫成 npm scripts{ scripts: { merge-reports: mochawesome-merge \cypress/results/mochawesome/*.json\ cypress/results/mochawesome/merged.json, generate-report: marge cypress/results/mochawesome/merged.json --reportDir cypress/results/mochawesome --reportTitle My Test Report } }這里的marge就是mochawesome-report-generator的命令行工具在安裝 mochawesome 時會作為依賴一起被安裝也可以顯式安裝mochawesome-report-generator。marge接受一個 JSON 文件生成一個完整的 HTML 報告。第三種寫法是直接在 Node 腳本里調(diào)用const merge require(mochawesome-merge).merge; const generate require(mochawesome-report-generator).generate; (async () { const report await merge({ files: [./cypress/results/mochawesome/json/*.json], }); await generate({ report, reportDir: cypress/results/mochawesome/final, reportTitle: 最終測試報告 }); })();這種寫法適合你需要在合并前后做額外處理的場景比如過濾某些 spec或者改報告標(biāo)題。但對于大部分項目命令行方式足夠。4.2 報告文件名管理與防覆蓋策略剛才我提到文件名覆蓋問題這里展開講一下常用策略。當(dāng)overwrite: false時mochawesome 會生成mochawesome_001.json、mochawesome_002.json……這樣的文件。問題是如果你在同一個目錄里第二次跑測試新生成的文件序號可能會接著原來的編號繼續(xù)也可能前綴相同而直接覆蓋這取決于 Cypress 執(zhí)行時的內(nèi)部邏輯。保險做法是每次跑測試前先清空報告輸出目錄rm -rf cypress/results/mochawesome或者在 npm script 里加一句清理命令scripts: { clean:reports: rm -rf cypress/results/mochawesome, test:report: npm run clean:reports cypress run npm run merge-reports npm run generate-report }這樣每次都是一次干凈的執(zhí)行不會出現(xiàn)舊數(shù)據(jù)殘留導(dǎo)致合并結(jié)果翻倍。5. 讓報告真實可用幾項關(guān)鍵配置與踩坑記錄配置對了報告能出來。但離“真實可用”還差幾步這節(jié)把最常見的幾個坑和對應(yīng)的解決思路整理成表格方便你對照排查。5.1 常見問題速查表從無報告到報告信息不全現(xiàn)象可能原因解決方式跑完后results目錄為空reporter 配置沒生效或reporterOptions里的輸出目錄寫錯確認(rèn)cypress.config.js在cypress run時被加載刪掉node_modules/.cache后重試多個 spec 只生成一份 HTMLoverwrite設(shè)為true或沒設(shè)多 spec 互相覆蓋設(shè)overwrite: false并使用mochawesome-merge合并JSON 文件生成但沒有 HTMLhtml設(shè)為false或合并后沒跑marge執(zhí)行npx marge或調(diào)用generate生成最終報告報告里失敗用例沒有截圖Cypress 截圖文件路徑與報告不在同一根目錄將screenshotsFolder與reportDir設(shè)置在同一個父目錄下配置overwrite之外還需要手動處理相對路徑合并后報告數(shù)量翻倍舊 JSON 未被清理與新 JSON 一起合并每次跑測試前清理輸出目錄CI 上報告文件名為空或固定名被覆蓋未使用時間戳或不傳唯一標(biāo)識在 CI 腳本中為報告目錄加入構(gòu)建號如--reportDirtest-results/$BUILD_NUMBER這張表是我在維護多個項目時總結(jié)出來的高頻問題。其中最隱蔽的是截圖路徑問題Cypress 默認(rèn)會把截圖放在cypress/screenshots下而報告的 HTML 在cypress/results/mochawesome下兩者沒有相對關(guān)系導(dǎo)致 HTML 中嵌入的img src../../screenshots/...失效。解決辦法是設(shè)置統(tǒng)一根目錄比如把截圖目錄設(shè)為cypress/results/screenshots這樣報告的 HTML 就能通過相對路徑訪問到截圖。5.2 高級配置技巧標(biāo)題、時間戳、環(huán)境變量與自定義圖表報告生成出來了接下來要讓它更符合項目需要。幾個常用技巧在marge命令中設(shè)置--reportTitle給報告起一個包含日期或版本號的標(biāo)題方便歷史留存。使用--enableChart或配置charts: true讓報告頂部顯示柱狀圖看起來更專業(yè)。如果想在 HTML 中顯示測試環(huán)境信息可以通過--showPassed、--showFailed、--showPending控制展示哪些狀態(tài)的用例默認(rèn)全顯示測試量很大時可以只顯示失敗項。我最常用的 npm script 示例scripts: { start:report: npm run clean:reports cypress run npm run merge:json npm run gen:html, merge:json: mochawesome-merge \cypress/results/mochawesome/*.json\ cypress/results/mochawesome/merged.json, gen:html: marge cypress/results/mochawesome/merged.json --reportDir cypress/results/mochawesome/final --reportTitle \$(date %Y-%m-%d_%H-%M-%S) Report\ --charts true }這段腳本既完成了清理、執(zhí)行、合并、生成四個環(huán)節(jié)還動態(tài)生成了帶時間戳的標(biāo)題用于區(qū)分不同輪次的測試。注意 macOS/Linux 的date命令格式Windows 下要換成 PowerShell 或使用第三方工具來生成時間字符串這塊在 CI 上一般有現(xiàn)成的環(huán)境變量供使用。6. 從本地到CI報告產(chǎn)物交付前的最后幾步本地能出報告只是萬里長征第一步。如果報告不能穩(wěn)定地在 CI 上生成并歸檔團隊的效率還是上不來。最后聊聊 CI 集成時的幾個關(guān)鍵點。6.1 在 CI 流水線中執(zhí)行報告命令的順序與緩存清理以 Jenkins 為例流水線的 shell 步驟可以這樣組織npm ci npm run test:report關(guān)鍵是test:report里的清理步驟不能省。很多情況下 CI 的工作空間是復(fù)用的上一次構(gòu)建留下的test-results會混入本次產(chǎn)物導(dǎo)致報告數(shù)據(jù)重復(fù)。最佳實踐是把報告輸出目錄和node_modules一樣放入緩存清理范圍或者用 CI 自帶的工作空間清理插件。還要注意一個細(xì)節(jié)Cypress 在 CI 上默認(rèn)可能并行執(zhí)行 spec并行模式下各進(jìn)程的輸出目錄是一樣的如果沒有按進(jìn)程號區(qū)分報告文件合并時就會互相覆蓋。建議在并行執(zhí)行時給每個進(jìn)程設(shè)置一個獨立的環(huán)境變量并將reportDir設(shè)置成包含該變量的路徑。例如配置reporterOptions: { reportDir: test-results/${process.env.CYPRESS_PARALLEL_INDEX || default} }然后合并時用mochawesome-merge test-results/*/*.json來匯總。6.2 讓報告成為團隊資產(chǎn)歸檔與可視化頁面CI 上生成的 HTML 報告默認(rèn)沒有地方展示。如果只是放在工作空間里構(gòu)建結(jié)束后通過鏈接下載體驗很差??梢钥紤]兩個方向一是用 CI 自帶的上報插件把報告目錄作為構(gòu)建產(chǎn)物歸檔這樣在構(gòu)建詳情頁能直接打開 HTML。二是對接開源或商業(yè)的報告平臺把 JSON 數(shù)據(jù)上傳生成可長期訪問的在線報告。無論哪種方案都需要在流水線中加入“上傳歸檔”的步驟而不能只生成文件就完事。歸檔時要注意HTML 報告引用的是 JSON 文件如果只把 HTML 上傳而 JSON 文件不在同目錄頁面會加載不全。所以要整個目錄一起歸檔。另外報告里的截圖路徑如果指向 Cypress 的臨時截圖目錄歸檔時也要一并包含否則頁面里圖片區(qū)域會裂開。這個坑我是在一次演示給上司看的時候踩的當(dāng)時報告標(biāo)題、統(tǒng)計都正常唯獨截圖全裂原因就是歸檔時漏了截圖目錄。從本地跑通報告到在 CI 上穩(wěn)定產(chǎn)出并歸檔整個過程貫穿著“數(shù)據(jù)完整性”和“文件命名可預(yù)測性”這兩個原則。只要每次都先想清楚這兩點即使換了不同的 reporter 插件也不會走太多彎路。下一部分我會繼續(xù)寫如何將 mochawesome 的 JSON 數(shù)據(jù)類型轉(zhuǎn)換為 JUnit XML 格式以及如何在 GitLab CI 中與測試趨勢圖結(jié)合讓報告真正變成項目里的“儀表盤”而不是一堆靜態(tài)文件。