""" Enhanced Report Generator Generates comprehensive reports with framework mapping and detailed analysis """ import os import json from datetime import datetime from typing import Dict, List, Any, Optional from pathlib import Path from state_schema import WorkflowState, VisualDifference class EnhancedReportGenerator: """Generate comprehensive regression testing reports""" # Framework categories FRAMEWORK_CATEGORIES = { "Layout & Structure": 8, "Typography": 10, "Colors & Contrast": 10, "Spacing & Sizing": 8, "Borders & Outlines": 6, "Shadows & Effects": 7, "Components & Elements": 10, "Buttons & Interactive": 10, "Forms & Inputs": 10, "Images & Media": 8 } def __init__(self, state: Dict[str, Any], output_dir: str): """Initialize report generator""" self.state = state self.output_dir = output_dir os.makedirs(output_dir, exist_ok=True) def generate_all_reports(self): """Generate all report types""" self.generate_summary_report() self.generate_detailed_report() self.generate_framework_mapping_report() self.generate_json_report() self.generate_html_report() def generate_summary_report(self) -> str: """Generate summary markdown report""" lines = [] lines.append("# 🎨 UI Regression Testing Report - Summary\n") lines.append(f"**Generated**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n") lines.append(f"**Execution ID**: {self.state.get('execution_id', 'unknown')}\n") lines.append(f"**Website**: {self.state.get('website_url', 'unknown')}\n") lines.append(f"**Figma File**: {self.state.get('figma_file_key', 'unknown')}\n\n") # Overall Score lines.append("## 📊 Overall Results\n") lines.append(f"- **Similarity Score**: {self.state.get('similarity_score', 0.0):.1f}/100") # Severity breakdown visual_differences = self.state.get('visual_differences', []) high = len([d for d in visual_differences if (d.get('severity') if isinstance(d, dict) else d.severity) == "High"]) medium = len([d for d in visual_differences if (d.get('severity') if isinstance(d, dict) else d.severity) == "Medium"]) low = len([d for d in visual_differences if (d.get('severity') if isinstance(d, dict) else d.severity) == "Low"]) total = len(visual_differences) lines.append(f"- **Total Differences**: {total}") lines.append(f"- 🔴 **High Severity**: {high}") lines.append(f"- 🟠 **Medium Severity**: {medium}") lines.append(f"- 🟢 **Low Severity**: {low}\n") # Category breakdown categories = self._group_by_category() if categories: lines.append("## 📂 Issues by Category\n") for category in sorted(categories.keys()): count = len(categories[category]) high_count = len([d for d in categories[category] if d.severity == "High"]) lines.append(f"- **{category}**: {count} issues ({high_count} high severity)") lines.append("") # Viewport breakdown lines.append("## 📱 Issues by Viewport\n") visual_differences = self.state.get('visual_differences', []) desktop_diffs = [d for d in visual_differences if (d.get('viewport') if isinstance(d, dict) else d.viewport) == "desktop"] mobile_diffs = [d for d in visual_differences if (d.get('viewport') if isinstance(d, dict) else d.viewport) == "mobile"] lines.append(f"- **Desktop (1440px)**: {len(desktop_diffs)} issues") lines.append(f"- **Mobile (375px)**: {len(mobile_diffs)} issues\n") # Recommendations lines.append("## 💡 Recommendations\n") if high > 0: lines.append(f"- 🔴 **Critical**: Address all {high} high-severity issues immediately") if medium > 0: lines.append(f"- 🟠 **Important**: Schedule fixes for {medium} medium-severity issues") if low > 0: lines.append(f"- 🟢 **Nice to have**: Consider fixing {low} low-severity issues") report_path = os.path.join(self.output_dir, "report_summary.md") with open(report_path, 'w') as f: f.write("\n".join(lines)) return "\n".join(lines) def generate_detailed_report(self) -> str: """Generate detailed markdown report""" lines = [] lines.append("# 🔍 UI Regression Testing Report - Detailed\n") lines.append(f"**Generated**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n") # Executive Summary lines.append("## Executive Summary\n") lines.append(f"This report details all visual differences detected between the Figma design ") lines.append(f"and the live website. The analysis was performed on {len(self.state.get('viewports', []))} viewports ") lines.append(f"using a hybrid approach combining screenshot analysis, CSS extraction, and AI vision models.\n\n") # Test Configuration lines.append("## Test Configuration\n") lines.append(f"- **Website URL**: {self.state.get('website_url', 'unknown')}") lines.append(f"- **Figma File**: {self.state.get('figma_file_key', 'unknown')}") lines.append(f"- **Execution ID**: {self.state.get('execution_id', 'unknown')}") lines.append(f"- **Viewports Tested**: Desktop (1440px), Mobile (375px)\n\n") # Results Overview lines.append("## Results Overview\n") visual_differences = self.state.get('visual_differences', []) lines.append(f"- **Similarity Score**: {self.state.get('similarity_score', 0.0):.1f}/100") lines.append(f"- **Total Differences Found**: {len(visual_differences)}") lines.append(f"- **High Severity**: {len([d for d in visual_differences if (d.get('severity') if isinstance(d, dict) else d.severity) == 'High'])}") lines.append(f"- **Medium Severity**: {len([d for d in visual_differences if (d.get('severity') if isinstance(d, dict) else d.severity) == 'Medium'])}") lines.append(f"- **Low Severity**: {len([d for d in visual_differences if (d.get('severity') if isinstance(d, dict) else d.severity) == 'Low'])}\n\n") # Detailed Findings lines.append("## Detailed Findings\n\n") # Group by severity visual_differences = self.state.get('visual_differences', []) high_diffs = [d for d in visual_differences if (d.get('severity') if isinstance(d, dict) else d.severity) == "High"] medium_diffs = [d for d in visual_differences if (d.get('severity') if isinstance(d, dict) else d.severity) == "Medium"] low_diffs = [d for d in visual_differences if (d.get('severity') if isinstance(d, dict) else d.severity) == "Low"] if high_diffs: lines.append("### 🔴 High Severity Issues\n") for i, diff in enumerate(high_diffs, 1): name = diff.get('title') if isinstance(diff, dict) else getattr(diff, 'title', 'Difference') category = diff.get('category') if isinstance(diff, dict) else getattr(diff, 'category', 'visual') description = diff.get('description') if isinstance(diff, dict) else getattr(diff, 'description', '') viewport = diff.get('viewport') if isinstance(diff, dict) else getattr(diff, 'viewport', 'desktop') detection_method = diff.get('detection_method') if isinstance(diff, dict) else getattr(diff, 'detection_method', 'manual') confidence = diff.get('confidence', 1.0) if isinstance(diff, dict) else getattr(diff, 'confidence', 1.0) lines.append(f"#### {i}. {name}\n") lines.append(f"- **Category**: {category}") lines.append(f"- **Description**: {description}") lines.append(f"- **Viewport**: {viewport}") lines.append(f"- **Detection Method**: {detection_method}") lines.append(f"- **Confidence**: {confidence*100:.0f}%\n") if medium_diffs: lines.append("### 🟠 Medium Severity Issues\n") for i, diff in enumerate(medium_diffs, 1): lines.append(f"#### {i}. {diff.name}\n") lines.append(f"- **Category**: {diff.category}") lines.append(f"- **Description**: {diff.description}") lines.append(f"- **Viewport**: {diff.viewport}") lines.append(f"- **Detection Method**: {diff.detection_method}") lines.append(f"- **Confidence**: {diff.confidence*100:.0f}%\n") if low_diffs: lines.append("### 🟢 Low Severity Issues\n") for i, diff in enumerate(low_diffs, 1): lines.append(f"#### {i}. {diff.name}\n") lines.append(f"- **Category**: {diff.category}") lines.append(f"- **Description**: {diff.description}") lines.append(f"- **Viewport**: {diff.viewport}") lines.append(f"- **Detection Method**: {diff.detection_method}") lines.append(f"- **Confidence**: {diff.confidence*100:.0f}%\n") # Recommendations lines.append("## Recommendations\n\n") lines.append("### Immediate Actions (High Severity)\n") lines.append("1. Review all high-severity issues with the development team") lines.append("2. Create tickets for each issue in your project management system") lines.append("3. Prioritize fixes based on user impact\n\n") lines.append("### Short-term Actions (Medium Severity)\n") lines.append("1. Schedule review of medium-severity issues") lines.append("2. Determine if issues affect user experience") lines.append("3. Plan fixes in upcoming sprints\n\n") lines.append("### Continuous Improvement\n") lines.append("1. Run regression tests regularly (weekly/bi-weekly)") lines.append("2. Update Figma designs to match implementation") lines.append("3. Establish design-to-development handoff process\n") report_path = os.path.join(self.output_dir, "report_detailed.md") with open(report_path, 'w') as f: f.write("\n".join(lines)) return "\n".join(lines) def generate_framework_mapping_report(self) -> str: """Generate framework mapping report""" lines = [] lines.append("# 📊 Framework Mapping Report\n") lines.append("## 114-Point Visual Differences Framework\n\n") lines.append("This report maps detected differences to the comprehensive 114-point framework ") lines.append("across 10 categories of visual properties.\n\n") # Framework summary lines.append("## Framework Coverage\n\n") lines.append("| Category | Total Issues | Detected | Coverage |\n") lines.append("|----------|-------------|----------|----------|\n") total_framework = 0 total_detected = 0 visual_differences = self.state.get('visual_differences', []) for category, total in self.FRAMEWORK_CATEGORIES.items(): detected = len([d for d in visual_differences if (d.get('category') if isinstance(d, dict) else d.category) == category]) coverage = (detected / total * 100) if total > 0 else 0 lines.append(f"| {category} | {total} | {detected} | {coverage:.0f}% |\n") total_framework += total total_detected += detected coverage = (total_detected / total_framework * 100) if total_framework > 0 else 0 lines.append(f"| **TOTAL** | **{total_framework}** | **{total_detected}** | **{coverage:.0f}%** |\n\n") # Detected issues by category lines.append("## Detected Issues by Category\n\n") categories = self._group_by_category() for category in sorted(categories.keys()): diffs = categories[category] lines.append(f"### {category} ({len(diffs)} issues)\n\n") for diff in diffs: lines.append(f"- **{diff.name}** ({diff.severity})") lines.append(f" - {diff.description}\n") report_path = os.path.join(self.output_dir, "report_framework.md") with open(report_path, 'w') as f: f.write("\n".join(lines)) return "\n".join(lines) def generate_json_report(self) -> str: """Generate JSON report for programmatic access""" report = { "metadata": { "generated": datetime.now().isoformat(), "execution_id": self.state.execution_id, "website_url": self.state.website_url, "figma_file": self.state.figma_file_key }, "summary": { "similarity_score": self.state.similarity_score, "total_differences": len(self.state.visual_differences), "high_severity": len([d for d in self.state.visual_differences if d.severity == "High"]), "medium_severity": len([d for d in self.state.visual_differences if d.severity == "Medium"]), "low_severity": len([d for d in self.state.visual_differences if d.severity == "Low"]) }, "differences": [ { "name": d.name, "category": d.category, "severity": d.severity, "description": d.description, "viewport": d.viewport, "detection_method": d.detection_method, "confidence": d.confidence, "location": d.location } for d in self.state.visual_differences ], "framework_coverage": { category: { "total": total, "detected": len([d for d in self.state.visual_differences if d.category == category]) } for category, total in self.FRAMEWORK_CATEGORIES.items() } } report_path = os.path.join(self.output_dir, "report.json") with open(report_path, 'w') as f: json.dump(report, f, indent=2) return json.dumps(report, indent=2) def generate_html_report(self) -> str: """Generate HTML report""" html_lines = [] html_lines.append("") html_lines.append("") html_lines.append("
") html_lines.append("") html_lines.append("") html_lines.append("Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
") html_lines.append("Similarity Score: {self.state.similarity_score:.1f}/100
") html_lines.append(f"Total Differences: {len(self.state.visual_differences)}
") html_lines.append("🔴 High: {high} | 🟠 Medium: {medium} | 🟢 Low: {low}
") html_lines.append("Category: {diff.category}
") html_lines.append(f"Description: {diff.description}
") html_lines.append(f"Viewport: {diff.viewport}
") html_lines.append(f"