diff --git a/tests/conftest.py b/tests/conftest.py
index a87bd42..c66cd31 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -293,13 +293,22 @@ def _collect_logs(report_dir: Path) -> list:
def _collect_screenshots() -> list:
- """收集测试过程中生成的截图。"""
+ """收集测试过程中生成的截图,转为 base64 内嵌到 HTML 中。"""
+ import base64
shots = []
ss_dir = Path("output/screenshots")
if ss_dir.exists():
- for p in sorted(ss_dir.rglob("*.png"), reverse=True)[:50]:
- # 用相对路径
- shots.append(str(p).replace("\\", "/"))
+ for p in sorted(ss_dir.rglob("*.png"), reverse=True)[:30]:
+ try:
+ data = p.read_bytes()
+ b64 = base64.b64encode(data).decode("ascii")
+ shots.append({
+ "name": p.name,
+ "path": str(p).replace("\\", "/"),
+ "b64": b64,
+ })
+ except Exception:
+ pass
return shots
@@ -383,11 +392,19 @@ def _build_cn_report_html(total, passed, failed, skipped, rate, cases,
# ── 截图面板 ──
screenshot_html = ""
if screenshots:
- shot_items = "".join(f'
📷 {s.split("/")[-1]}
' for s in screenshots[:30])
+ shot_cards = ""
+ for s in screenshots[:20]:
+ shot_cards += f"""
+
+
+
![{s['name']}](data:image/png;base64,{s['b64']})
+
+
{s['name']}
+
"""
screenshot_html = f"""
-
- 📸 截图列表 ({len(screenshots)} 张)
- {shot_items}
+
+ 📸 测试截图 ({len(screenshots)} 张) — 点击可放大
+ {shot_cards}
"""
return f"""
@@ -432,8 +449,16 @@ tr:hover td{{background:#f5f7fa}}
.log-section{{margin:0 32px 12px;background:#fff;border-radius:8px;box-shadow:0 1px 4px rgba(0,0,0,.06);padding:12px 20px}}
.log-section summary{{font-size:14px;font-weight:500;cursor:pointer;padding:4px 0}}
.log-content{{font-size:11px;background:#1e1e1e;color:#d4d4d4;padding:12px;border-radius:4px;white-space:pre-wrap;word-break:break-all;max-height:400px;overflow-y:auto;font-family:'Consolas','Courier New',monospace}}
-.shot-grid{{display:flex;flex-wrap:wrap;gap:8px;padding:8px 0}}
-.shot-item{{font-size:12px;color:#606266;background:#f5f7fa;padding:4px 10px;border-radius:4px}}
+.shot-gallery{{display:flex;flex-wrap:wrap;gap:16px;padding:8px 0}}
+.shot-card{{width:280px;border-radius:8px;overflow:hidden;box-shadow:0 1px 4px rgba(0,0,0,.08);background:#fff;transition:box-shadow .2s}}
+.shot-card:hover{{box-shadow:0 4px 16px rgba(0,0,0,.15)}}
+.shot-thumb{{width:100%;height:200px;overflow:hidden;cursor:pointer;position:relative;background:#f5f7fa}}
+.shot-thumb img{{width:100%;height:100%;object-fit:contain;display:block}}
+.shot-thumb.expanded{{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:90vw;height:90vh;z-index:9999;background:rgba(0,0,0,.85)}}
+.shot-thumb.expanded img{{width:auto;height:auto;max-width:100%;max-height:100%;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}}
+.shot-thumb::after{{content:'🔍 点击放大';position:absolute;bottom:0;left:0;right:0;padding:6px;background:rgba(0,0,0,.5);color:#fff;font-size:11px;text-align:center;opacity:0;transition:opacity .2s}}
+.shot-thumb:hover::after{{opacity:1}}
+.shot-label{{font-size:11px;color:#606266;padding:6px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}}
.ft{{text-align:center;padding:24px;font-size:12px;color:#c0c4cc}}