#!/usr/bin/env python3 """Parse E2E test report JSON and output formatted Markdown summary.""" import json import os import sys from datetime import datetime def parse_report(path): with open(path) as f: return json.load(f) def format_report(data): ts = data.get('timestamp', '')[:19] total = data['total'] passed = data['passed'] failed = data['failed'] errors = data['errors'] rate = data['pass_rate'] lines = [] lines.append(f"## NexusCRM E2E Test Report") lines.append(f"**Time:** {ts} | **Pass Rate:** {rate} | **Total:** {total} case(s)") lines.append("") lines.append(f"| Scene | Pass | Fail | Total | Rate |") lines.append(f"|-------|------|------|-------|------|") coverage = data.get('coverage', {}) scene_order = [ 'lead_convert', 'quote', 'order', 'campaign', 'sdr', 'hubspot', 'approval', 'contract', 'validation', 'demo', 'product', 'opportunity_line', 'order_line', 'quote_line', 'campaign_member', 'account', 'contact', 'task' ] ordered_scenes = [scene for scene in scene_order if scene in coverage] ordered_scenes.extend(sorted(scene for scene in coverage if scene not in ordered_scenes)) for scene in ordered_scenes: if scene not in coverage: continue s = coverage[scene] s_total = s['total'] s_pass = s['passed'] s_fail = s['failed'] s_rate = f"{(s_pass/s_total*100):.0f}%" if s_total > 0 else "0%" lines.append(f"| {scene} | {s_pass} | {s_fail} | {s_total} | {s_rate} |") lines.append("") lines.append("### Failed Cases") lines.append("") failed_cases = [r for r in data['results'] if r['status'] == 'FAIL'] error_cases = [r for r in data['results'] if r['status'] == 'ERROR'] by_scene = {} for c in failed_cases + error_cases: scene = c.get('scene', 'unknown') by_scene.setdefault(scene, []).append(c) scene_labels = { 'lead_convert': 'Lead Convert', 'quote': 'Quote', 'order': 'Order', 'campaign': 'Campaign', 'sdr': 'SDR Status Machine', 'hubspot': 'HubSpot Sync', 'approval': 'Approval', 'contract': 'Contract', 'validation': 'Field Validation', 'demo': 'Demo', 'product': 'Product', 'opportunity_line': 'Opportunity Line', 'order_line': 'Order Line', 'quote_line': 'Quote Line', 'campaign_member': 'Campaign Member', 'account': 'Account', 'contact': 'Contact', 'task': 'Task', 'unknown': 'Unknown', } for scene, cases in by_scene.items(): label = scene_labels.get(scene, scene) lines.append(f"#### {label}") for c in cases: case_id = c['id'] name = c.get('name', '') error = c.get('error', '') if len(error) > 120: error = error[:120] + '...' lines.append(f"- **{case_id}** — {name}") if error: lines.append(f" - `{error}`") lines.append("") lines.append(f"_Report generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}_") return '\n'.join(lines) def main(): # Accept report path from CLI arg, else find latest if len(sys.argv) > 1: report_path = sys.argv[1] data = parse_report(report_path) print(format_report(data)) return # Find latest report: current dir first, then fallback candidates = [ '.', os.path.expanduser('~/github/bingwang-MetaDrivenPlatform4AI/tests/e2e-api'), ] reports = [] for d in candidates: if not os.path.isdir(d): continue found = sorted([ f for f in os.listdir(d) if f.startswith('report-') and f.endswith('.json') ]) reports.extend([(d, f) for f in found]) if not reports: print("No reports found!") sys.exit(1) reports.sort(key=lambda x: x[1]) report_dir, report_file = reports[-1] latest = os.path.join(report_dir, report_file) print(f"Reading: {latest}") data = parse_report(latest) print(format_report(data)) if __name__ == '__main__': main()