/** * 错误处理工具类 * 负责错误收集、清理和报告生成 */ import * as fs from 'fs'; import * as path from 'path'; import { Page } from '@playwright/test'; export interface ErrorRecord { step: string; error: string; timestamp: string; pageUrl: string; } export interface LoginInfo { email: string; password: string; } export class ErrorHandler { private errors: ErrorRecord[] = []; private loginInfo: LoginInfo; constructor(loginInfo: LoginInfo) { this.loginInfo = loginInfo; } /** * 清理错误信息,去除技术细节 */ private cleanErrorMessage(error: unknown): string { let errorMessage = error instanceof Error ? error.message : String(error); // 只保留第一行主要错误,去掉 Call log 等技术细节 const firstLine = errorMessage.split('\n')[0]; const cleanError = firstLine.replace(/\s+\(.*?\)/, '').trim(); return cleanError; } /** * 记录错误 */ recordError(stepName: string, error: unknown, page: Page): void { const cleanError = this.cleanErrorMessage(error); const timestamp = new Date().toISOString(); const pageUrl = page.url(); this.errors.push({ step: stepName, error: cleanError, timestamp, pageUrl, }); console.error(`[失败] ${stepName}: ${cleanError}`); console.error(`[页面URL] ${pageUrl}`); } /** * 执行步骤并捕获错误 */ async executeStep( stepName: string, stepFunction: () => Promise, page: Page ): Promise { try { console.log(`\n[执行] ${stepName}`); await stepFunction(); console.log(`[成功] ${stepName}`); } catch (error) { this.recordError(stepName, error, page); // 继续执行下一步,不中断测试流程 } } /** * 获取所有错误 */ getErrors(): ErrorRecord[] { return this.errors; } /** * 检查是否有错误 */ hasErrors(): boolean { return this.errors.length > 0; } /** * 生成错误报告文件 */ generateErrorReport(reportDir: string = '.', filePrefix: string = 'test-error-report'): string { const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const reportPath = path.join(reportDir, `${filePrefix}-${timestamp}.txt`); let report = '========== 测试错误报告 ==========\n\n'; report += `报告生成时间: ${new Date().toLocaleString('zh-CN')}\n\n`; // 登录账号信息(只显示一次) report += '【登录账号信息】\n'; report += `账号: ${this.loginInfo.email}\n`; report += `密码: ${this.loginInfo.password}\n`; report += `测试环境: https://pre.prodream.cn/en\n\n`; report += `${'='.repeat(60)}\n\n`; if (this.errors.length === 0) { report += '✅ 所有功能测试通过,未发现问题!\n'; } else { report += `发现 ${this.errors.length} 个问题,详情如下:\n\n`; // 每个错误按照格式:问题功能 + 页面链接 this.errors.forEach((err, index) => { report += `【问题 ${index + 1}】\n`; report += `问题功能: ${err.step}\n`; report += `页面链接: ${err.pageUrl}\n`; report += `错误详情: ${err.error}\n`; report += `发生时间: ${new Date(err.timestamp).toLocaleString('zh-CN')}\n`; report += '\n'; }); report += `${'='.repeat(60)}\n`; report += `\n说明: 测试过程中遇到错误会自动跳过并继续执行后续步骤。\n`; } fs.writeFileSync(reportPath, report, 'utf-8'); return reportPath; } /** * 打印错误摘要到控制台 */ printSummary(): void { console.log('\n\n========== 测试执行完成 =========='); if (this.errors.length === 0) { console.log('✅ 所有步骤执行成功!'); } else { console.log(`\n⚠️ 发现 ${this.errors.length} 个问题:\n`); this.errors.forEach((err, index) => { console.log(`【问题 ${index + 1}】`); console.log(` 问题功能: ${err.step}`); console.log(` 页面链接: ${err.pageUrl}`); console.log(` 错误详情: ${err.error}`); console.log(''); }); console.log(`\n账号: ${this.loginInfo.email}`); console.log(`密码: ${this.loginInfo.password}\n`); } } }