#!/usr/bin/env python3 """Render a per-spec table from a Playwright JSON report for a Gitea job summary (#136). Reads the JSON report (default: tests/e2e/playwright-report.json) that run-e2e-check.sh copies out of the e2e container, and prints a markdown table (one row per spec) to stdout. The CI step redirects it into $GITHUB_STEP_SUMMARY. Stdlib only. """ import json import os import sys STATUS_ICON = {"expected": "✅", "unexpected": "❌", "skipped": "⏭️", "flaky": "⚠️"} def walk(suite, out): for spec in suite.get("specs", []): # A spec's status is carried on its test(s): expected/unexpected/skipped/flaky. statuses = [t.get("status") for t in spec.get("tests", [])] status = ("unexpected" if "unexpected" in statuses else "flaky" if "flaky" in statuses else "skipped" if statuses and all(s == "skipped" for s in statuses) else "expected" if spec.get("ok", False) else "unexpected") out.append({"file": spec.get("file") or suite.get("file") or suite.get("title", ""), "title": spec.get("title", ""), "status": status}) for child in suite.get("suites", []): walk(child, out) def main(path): if not os.path.exists(path): print("## 🎭 e2e (Playwright)\n\n_No e2e report — the run did not reach the e2e step._") return 0 with open(path) as fh: report = json.load(fh) specs = [] for suite in report.get("suites", []): walk(suite, specs) print("## 🎭 e2e (Playwright)\n") stats = report.get("stats", {}) if stats: print(f"**{stats.get('expected', 0)} passed · {stats.get('unexpected', 0)} failed · " f"{stats.get('flaky', 0)} flaky · {stats.get('skipped', 0)} skipped** " f"({round(stats.get('duration', 0) / 1000)}s)\n") if not specs: print("_No specs ran._") return 0 print("| Spec | Result |") print("| ---- | :----: |") for s in specs: print(f"| {s['file']} › {s['title']} | {STATUS_ICON.get(s['status'], '❔')} |") return 0 if __name__ == "__main__": sys.exit(main(sys.argv[1] if len(sys.argv) > 1 else "tests/e2e/playwright-report.json"))