Files
rootandClaude Opus 5.5 ec8b224482 feat(web): 站点页技术信息里显示最近的失败页面样本
站点概览「站点」一栏的技术信息里列出最近 5 份失败样本(搜索 / 列表 / 详情 · 人机验证 / 页面结构无法识别 ·
HTTP 状态),展开看脱敏地址、错误、命中规则、关键响应头和页面正文,可下载文本;没有样本不显示。

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
2026-10-06 15:43:15 +08:00

57 lines
2.7 KiB
TypeScript

import type { SiteFailureSample } from "@umt/contracts";
import { createElement } from "react";
import { renderToStaticMarkup } from "react-dom/server";
import { describe, expect, it } from "vitest";
import { SiteFailureSamples } from "./site-failure-samples.tsx";
import { failureSampleFileName, failureSampleItems, failureSampleText, failureSampleTitle } from "./site-fields.ts";
// 站点页技术信息里的失败样本:一行说清是搜索 / 列表、人机验证还是页面结构变化;展开看地址、响应头、页面,可下载文本。
const sample: SiteFailureSample = {
id: "0f1e2d3c-4b5a-4987-8a6b-5c4d3e2f1a0b",
siteId: "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
kind: "challenge",
requestKind: "search",
url: "https://audiences.me/torrents.php?search=Dune&passkey=[REDACTED]",
httpStatus: 200,
headers: { server: "cloudflare", "cf-ray": "8c00-HKG" },
message: "搜索:搜索页需要人机验证(Cloudflare 等),需要你在原站视图里过一次验证",
rule: "gate*=cf-turnstile",
body: '<html><div class="cf-turnstile"></div></html>',
truncated: false,
createdAt: "2026-10-06T07:30:05.000Z",
};
const { body: _b, ...summary } = sample;
const row = { ...summary, bodyBytes: 44 };
describe("站点失败样本展示", () => {
it("标题区分请求类型与失败类型", () => {
expect(failureSampleTitle(sample)).toBe("搜索 · 人机验证 · HTTP 200");
expect(failureSampleTitle({ kind: "parse_error", requestKind: "list", httpStatus: null })).toBe(
"列表 · 页面结构无法识别",
);
});
it("技术信息条目:地址、错误、规则、关键响应头、页面大小", () => {
const items = failureSampleItems(row);
expect(items.map((i) => i.label)).toEqual(["地址", "错误", "命中规则", "server", "cf-ray", "页面"]);
expect(items[0]?.value).toContain("passkey=[REDACTED]");
});
it("下载文本带请求信息头;文件名带请求类型、类型与时间", () => {
const text = failureSampleText(sample);
expect(text).toContain("# 地址:https://audiences.me/torrents.php");
expect(text).toContain("# cf-ray: 8c00-HKG");
expect(text.endsWith(sample.body)).toBe(true);
expect(failureSampleFileName(sample)).toBe("site-sample-search-challenge-20261006-073005.html.txt");
});
it("列表渲染:每份一行(收起),没有样本不渲染", () => {
const html = renderToStaticMarkup(createElement(SiteFailureSamples, { siteId: sample.siteId, items: [row] }));
expect(html).toContain("最近的失败页面");
expect(html).toContain("搜索 · 人机验证 · HTTP 200");
expect(html).toContain('aria-expanded="false"');
expect(renderToStaticMarkup(createElement(SiteFailureSamples, { siteId: sample.siteId, items: [] }))).toBe("");
});
});