From e24cbd0a5519c30ae231bb7db588d81fe281585d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Fri, 6 Mar 2026 12:56:35 +0800 Subject: [PATCH] feat: add comprehensive test report generator --- .../shared/utils/reporting/TestReporter.ts | 215 ++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 test-framework/shared/utils/reporting/TestReporter.ts diff --git a/test-framework/shared/utils/reporting/TestReporter.ts b/test-framework/shared/utils/reporting/TestReporter.ts new file mode 100644 index 0000000..4c36179 --- /dev/null +++ b/test-framework/shared/utils/reporting/TestReporter.ts @@ -0,0 +1,215 @@ +import * as fs from 'fs'; +import * as path from 'path'; + +export class TestReporter { + private results: Map = new Map(); + + addResult(type: string, result: any): void { + this.results.set(type, result); + } + + generateHTMLReport(): string { + const timestamp = new Date().toLocaleString('zh-CN'); + + let html = ` + + + + + + 综合测试报告 - ${timestamp} + + + +
+

综合测试报告

+

生成时间: ${timestamp}

+
+`; + + for (const [type, result] of this.results.entries()) { + html += this.generateSection(type, result); + } + + html += ` + +`; + + return html; + } + + private generateSection(type: string, result: any): string { + switch (type) { + case 'accessibility': + return this.generateAccessibilitySection(result); + case 'seo': + return this.generateSEOSection(result); + case 'performance': + return this.generatePerformanceSection(result); + default: + return `

${type}

${JSON.stringify(result, null, 2)}
`; + } + } + + private generateAccessibilitySection(results: any[]): string { + const totalViolations = results.reduce((sum: number, r: any) => sum + r.violations.length, 0); + const avgScore = results.reduce((sum: number, r: any) => sum + r.score, 0) / results.length; + + return ` +
+

可访问性测试

+
+ 平均分数: ${avgScore.toFixed(1)} + 总违规数: ${totalViolations} +
+ + + + + + + + + + ${results.map((r: any) => ` + + + + + + `).join('')} + +
页面分数违规数
${r.page}${r.score}${r.violations.length}
+
`; + } + + private generateSEOSection(results: any[]): string { + const avgScore = results.reduce((sum: number, r: any) => sum + r.score, 0) / results.length; + + return ` +
+

SEO检查

+
+ 平均分数: ${avgScore.toFixed(1)} +
+ + + + + + + + + + + ${results.map((r: any) => ` + + + + + + + `).join('')} + +
页面分数Meta标签标题
${r.page}${r.score}${r.metaTags.title && r.metaTags.description ? '✅' : '❌'}${r.headings.hasH1 ? '✅' : '❌'}
+
`; + } + + private generatePerformanceSection(results: any[]): string { + const avgLoadTime = results.reduce((sum: number, r: any) => sum + r.loadTime, 0) / results.length; + + return ` +
+

性能测试

+
+ 平均加载时间: ${avgLoadTime.toFixed(0)}ms +
+ + + + + + + + + + ${results.map((r: any) => ` + + + + + + `).join('')} + +
页面加载时间DOM加载
${r.page}${r.loadTime}ms${r.domContentLoaded}ms
+
`; + } + + saveHTMLReport(outputPath: string): void { + const html = this.generateHTMLReport(); + const dir = path.dirname(outputPath); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + fs.writeFileSync(outputPath, html, 'utf-8'); + } + + generateJSONReport(): any { + return { + timestamp: new Date().toISOString(), + results: Object.fromEntries(this.results) + }; + } + + saveJSONReport(outputPath: string): void { + const json = this.generateJSONReport(); + const dir = path.dirname(outputPath); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + fs.writeFileSync(outputPath, JSON.stringify(json, null, 2), 'utf-8'); + } +}