import urllib.request, urllib.error, http.cookiejar, json, sys, re BASE = "http://127.0.0.1:3000" cj = http.cookiejar.CookieJar() op = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj)) def call(path, method="GET", data=None, raw=False): body = json.dumps(data).encode() if data is not None else None req = urllib.request.Request(BASE + path, data=body, method=method) if body: req.add_header("Content-Type", "application/json") try: r = op.open(req, timeout=10) return r.status, r.read() except urllib.error.HTTPError as e: return e.code, e.read() results = [] def check(name, cond, extra=""): results.append((name, cond)); print(("PASS" if cond else "FAIL"), name, extra) # 静态资源可达(不需要登录) for path in ["/vendor/bootstrap.min.css", "/vendor/bootstrap-icons.css", "/vendor/Sortable.min.js", "/vendor/bootstrap-icons.woff2", "/css/style.css", "/js/app.js", "/login.html", "/favicon.ico"]: st, _ = call(path) check(f"静态 {path}", st == 200, f"got {st}") # 登录 st, body = call("/api/auth/login", "POST", {"password": "test123"}) check("登录", st == 200 and json.loads(body).get("ok"), f"got {st}") # 首页返回面板(含 vendor 引用) st, body = call("/") html = body.decode("utf-8", "ignore") check("首页返回面板", st == 200 and "pageSearch" in html and "loginForm" not in html, f"got {st}") check("面板引用本地vendor", "vendor/bootstrap.min.css" in html and "cdn.jsdelivr" not in html) # 资源列表 st, body = call("/api/resources") d = json.loads(body) check("资源列表", st == 200 and len(d["list"]) == 5, f"{len(d.get('list',[]))}") # 检查封面字段(可能为空,本地化后是 /covers/ 或空) covers = [x["albumImage"] for x in d["list"]] print(" 封面字段样例:", covers[:2]) # 流列表 st, body = call("/api/streams") d = json.loads(body) check("流列表", st == 200 and len(d["list"]) >= 1, str([s["id"] for s in d["list"]])) # 播放列表 st, body = call("/api/streams/main/playlist") d = json.loads(body) check("主频道播放列表", st == 200 and "list" in d, f"{len(d.get('list',[]))}项") # 检查 index.html 是否有 import/stream 元素 check("HTML含频道选择器", 'id="streamSelect"' in html) check("HTML含导入卡片", 'id="importCard"' in html or 'id="importFile"' in html) check("HTML含登出按钮", 'id="btnLogout"' in html) print("\n=== 汇总:", sum(1 for _,c in results if c), "/", len(results), "通过 ===") sys.exit(0 if all(c for _,c in results) else 1)