Update generate_static_allure.py
Run Pytest and Serve Report via LocalTunnel / tests (push) Failing after 54s

This commit is contained in:
2025-07-08 10:02:47 +02:00
parent dc2090df2a
commit d2d86ed489
+82 -83
View File
@@ -1,101 +1,100 @@
import json, os
import json
import os
from pathlib import Path
from collections import defaultdict
import matplotlib.pyplot as plt
def parse_results(path="allure-results"):
RESULTS_DIR = Path("allure-results")
REPORT_DIR = Path("ci-reports")
REPORT_DIR.mkdir(parents=True, exist_ok=True)
def parse_allure_results():
results = []
stats = {"passed": 0, "failed": 0, "broken": 0, "skipped": 0}
failures = []
for file in RESULTS_DIR.glob("*.json"):
if file.name.startswith("result"):
with open(file) as f:
results.append(json.load(f))
return results
for file in os.listdir(path):
if file.endswith("-result.json"):
with open(os.path.join(path, file)) as f:
d = json.load(f)
name = d.get("fullName", d.get("name", "Unnamed"))
status = d.get("status", "unknown")
duration = (d.get("stop", 0) - d.get("start", 0)) / 1000
stats[status] = stats.get(status, 0) + 1
def summarize_results(results):
summary = {"passed": 0, "failed": 0, "skipped": 0, "total": 0}
durations = []
grouped = defaultdict(list)
parameters = d.get("parameters", [])
details = d.get("statusDetails", {})
for res in results:
status = res.get("status", "unknown")
summary["total"] += 1
summary[status] += 1
time = res.get("stop", 0) - res.get("start", 0)
durations.append((res["name"], time / 1000))
grouped[res["fullName"]].append({
"name": res["name"],
"status": status,
"time": time / 1000,
"parameters": res.get("parameters", []),
})
return summary, durations, grouped
results.append((name, status, duration))
def generate_donut_chart(summary):
labels = ["Passed", "Failed", "Skipped"]
sizes = [summary["passed"], summary["failed"], summary["skipped"]]
colors = ["#8BC34A", "#F44336", "#FFC107"]
total = sum(sizes)
if status in ["failed", "broken"]:
failures.append({
"name": name,
"status": status,
"duration": duration,
"parameters": parameters,
"message": details.get("message", "No message"),
"trace": details.get("trace", "No trace")
})
return results, stats, failures
def donut_plot(stats, output="summary.png"):
total = sum(stats.values())
passed = stats.get("passed", 0)
success_rate = passed / total if total else 0
fig, ax = plt.subplots()
ax.pie([success_rate, 1 - success_rate], startangle=90,
colors=["#96d38c", "#f5543d"], wedgeprops={'width':0.3})
ax.text(0, 0, f"{success_rate*100:.1f}%", ha='center', va='center', fontsize=20)
plt.axis("equal")
plt.savefig(output, bbox_inches='tight')
ax.pie(sizes, labels=None, colors=colors, startangle=90,
wedgeprops=dict(width=0.3))
ax.text(0, 0, f'{summary["passed"]/total*100:.1f}%', ha='center', va='center', fontsize=20)
plt.savefig(REPORT_DIR / "summary.png", bbox_inches='tight')
plt.close()
def timeline_plot(results, output="timeline.png"):
names = [r[0] for r in results]
durations = [r[2] for r in results]
plt.figure(figsize=(8, len(results) * 0.3))
plt.barh(names, durations, color="#76b5c5")
def generate_timeline_chart(durations):
names, times = zip(*sorted(durations, key=lambda x: x[1], reverse=True))
plt.figure(figsize=(10, max(4, len(times) * 0.3)))
plt.barh(names, times, color="#2196F3")
plt.xlabel("Duration (s)")
plt.title("Test Duration Timeline")
plt.title("Test Execution Timeline")
plt.tight_layout()
plt.savefig(output)
plt.savefig(REPORT_DIR / "timeline.png")
plt.close()
def markdown_report(stats, results, failures, md="report.md"):
with open(md, "w") as f:
f.write("# 🧪 Test Report\n\n")
f.write("## ✅ Summary\n\n")
f.write("![Success Rate](summary.png)\n\n")
for k, v in stats.items():
f.write(f"- **{k.capitalize()}**: {v}\n")
def format_parameters(params):
return ", ".join(f"{p['name']}={p['value']}" for p in params)
f.write("\n## ⏱ Timeline\n\n")
f.write("![Timeline](timeline.png)\n\n")
def write_report(summary, grouped):
with open(REPORT_DIR / "report.md", "w") as f:
f.write(f"# 🧪 Test Summary\n\n")
f.write(f"![Summary](summary.png)\n\n")
f.write(f"![Timeline](timeline.png)\n\n")
f.write(f"**Total:** {summary['total']} | ✅ Passed: {summary['passed']} | ❌ Failed: {summary['failed']} | ⚠️ Skipped: {summary['skipped']}\n\n")
f.write("<details>\n<summary><strong>📋 Test Details</strong></summary>\n\n")
for suite, tests in grouped.items():
f.write(f"<details>\n<summary><code>{suite}</code></summary>\n\n")
for test in tests:
emoji = "" if test["status"] == "passed" else "" if test["status"] == "failed" else "⚠️"
params = format_parameters(test["parameters"])
f.write(f"- {emoji} `{test['name']}` ({test['time']}s)")
if params:
f.write(f" \n ↪️ *Params:* {params}")
f.write("\n")
f.write("</details>\n\n")
f.write("</details>\n")
f.write("\n## 📋 Detailed Results\n")
for name, status, duration in results:
emoji = {"passed": "", "failed": "", "broken": "⚠️", "skipped": "⏭️"}.get(status, "")
f.write(f"- {emoji} `{name}` → **{status.upper()}**, {duration:.2f}s\n")
def write_failures(grouped):
with open(REPORT_DIR / "failures.md", "w") as f:
f.write("# ❌ Failed Tests\n\n")
for suite, tests in grouped.items():
for test in tests:
if test["status"] == "failed":
f.write(f"- `{suite}::{test['name']}`\n")
f.write("\n## ❌ Failures / Errors\n")
if failures:
f.write("For details, see [failures.md](failures.md)\n")
else:
f.write("No failures! 🎉\n")
def main():
results = parse_allure_results()
summary, durations, grouped = summarize_results(results)
generate_donut_chart(summary)
generate_timeline_chart(durations)
write_report(summary, grouped)
write_failures(grouped)
def failure_details(failures, output="failures.md"):
with open(output, "w") as f:
f.write("# ❌ Detailed Failures\n\n")
for fail in failures:
f.write(f"## 🔻 {fail['name']}\n")
f.write(f"**Status**: {fail['status'].upper()}\n\n")
f.write(f"**Duration**: {fail['duration']:.2f}s\n\n")
if fail['parameters']:
f.write("**Parameters:**\n")
for p in fail['parameters']:
f.write(f"- `{p.get('name', '?')}`: `{p.get('value', '?')}`\n")
else:
f.write("_No parameters._\n")
f.write("\n**Message:**\n```\n" + fail['message'] + "\n```\n")
f.write("\n**Trace:**\n```\n" + fail['trace'] + "\n```\n\n---\n\n")
# Full pipeline
results, stats, failures = parse_results()
donut_plot(stats)
timeline_plot(results)
markdown_report(stats, results, failures)
failure_details(failures)
if __name__ == "__main__":
main()