- server 的 src/modules/*/__tests__ 挪到 test/<模块>/;e2e 去掉 eN- 前缀, w5a2 / v2 / search2 / *-dh1 / *-md1 / *-md2、web 的 agui3 / search2、domain 的 id2 / id3 改为按行为命名 - vitest 分三组:unit、pg(真实 PG + 假引擎,文件并行,最多 6 个)、serial(真实引擎 / worker / e2e,串行); pg 组用例超时放宽到 60s(迁移类用例并行时排队等 schema 锁)。server 测试 615s → 约 350s - CLAUDE.md 补测试约定;待办补 harness 去重与 continuous-series 偶发超时(疑似 Slot 评估竞争) - ADR-004 补充:维持 Deno,记录实际只用到 --allow-run 白名单 Co-Authored-By: Claude Opus 5.5 <[email protected]>
75 lines
3.6 KiB
TypeScript
75 lines
3.6 KiB
TypeScript
import { getSiteDefinition } from "@umt/adapters";
|
||
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
||
import { resourceIdFromUrl } from "../../src/modules/browser/resource.ts";
|
||
import { type BrowserHarness, createBrowserHarness, ORIGIN, pgAvailable, READ_KEY } from "./harness.ts";
|
||
|
||
const def = getSiteDefinition("audiences")!;
|
||
describe("原站资源详情定位", () => {
|
||
it("仅按本站详情路径定位,不把列表、登录或别站同 id 当作资源", () => {
|
||
expect(resourceIdFromUrl(`${ORIGIN}/details.php?id=73`, `${ORIGIN}/`, def)).toBe("73");
|
||
expect(resourceIdFromUrl(`${ORIGIN}/torrents.php?id=73`, `${ORIGIN}/`, def)).toBeNull();
|
||
expect(resourceIdFromUrl(`${ORIGIN}/login.php?id=73`, `${ORIGIN}/`, def)).toBeNull();
|
||
expect(resourceIdFromUrl("https://else.example/details.php?id=73", `${ORIGIN}/`, def)).toBeNull();
|
||
});
|
||
});
|
||
|
||
const up = await pgAvailable();
|
||
describe.skipIf(!up)("原站详情页交接(隔离 PG 与浏览器 fixture)", () => {
|
||
let h: BrowserHarness;
|
||
let sid: string;
|
||
beforeAll(async () => {
|
||
h = await createBrowserHarness("resource", {
|
||
html: () => `<!doctype html><html><head><title>资源详情</title></head><body>
|
||
<h1 id="top">Example.Movie.2024.2160p.WEB-DL.DV</h1>
|
||
<table><tr><td class="rowhead">副标题</td><td class="rowfollow">测试译名与简介</td></tr>
|
||
<tr><td class="rowhead">基本信息</td><td class="rowfollow">大小: 2 GB 类型: 电影</td></tr></table>
|
||
<div id="kdescr">详情页提供的影片简介 <a href="https://www.imdb.com/title/tt1234567/">IMDb</a></div>
|
||
</body></html>`,
|
||
});
|
||
h.mock.loggedIn.add(`umt-site-${h.siteId}-acct-${h.accountId}`);
|
||
const session = await h.req("/browser/sessions", {
|
||
body: { siteId: h.siteId, url: `${ORIGIN}/details.php?id=73` },
|
||
});
|
||
expect(session.status).toBe(200);
|
||
sid = session.body.data.id;
|
||
}, 120_000);
|
||
afterAll(async () => {
|
||
await h?.close();
|
||
});
|
||
|
||
it("未在快照/搜索中的详情可直接登记,缓存PT内容供元数据兜底,不点击原站下载按钮", async () => {
|
||
const before = h.mock.actions.length;
|
||
const r = await h.req(`/browser/sessions/${sid}/resource`, { body: {} });
|
||
expect(r.status, JSON.stringify(r.body)).toBe(200);
|
||
expect(r.body.data.release).toMatchObject({
|
||
siteId: h.siteId,
|
||
siteReleaseId: "73",
|
||
title: "Example.Movie.2024.2160p.WEB-DL.DV",
|
||
});
|
||
expect(r.body.data.detailUrl).toBe(`${ORIGIN}/details.php?id=73`);
|
||
const row = await h.db
|
||
.selectFrom("source_release")
|
||
.selectAll()
|
||
.where("id", "=", r.body.data.release.id)
|
||
.executeTakeFirstOrThrow();
|
||
expect(row.detail_fetched_at).not.toBeNull();
|
||
expect(row.raw).toMatchObject({ _detail: { imdbId: "tt1234567", sourceUrl: `${ORIGIN}/details.php?id=73` } });
|
||
expect(h.mock.actions.slice(before).some((a) => a.action === "click")).toBe(false);
|
||
const again = await h.req(`/browser/sessions/${sid}/resource`, { body: {} });
|
||
expect(again.body.data.release.id).toBe(row.id);
|
||
});
|
||
|
||
it("使用当前页面而非旧会话地址;列表页明确提示进入详情", async () => {
|
||
const tab = [...h.mock.tabs.values()][0]!;
|
||
tab.url = `${ORIGIN}/torrents.php`;
|
||
const r = await h.req(`/browser/sessions/${sid}/resource`, { body: {} });
|
||
expect(r.status).toBe(400);
|
||
expect(r.body.error.message).toContain("详情页");
|
||
});
|
||
|
||
it("只读账号不能通过该入口登记下载资源", async () => {
|
||
const r = await h.req(`/browser/sessions/${sid}/resource`, { body: {}, key: READ_KEY });
|
||
expect(r.status).toBe(403);
|
||
});
|
||
});
|