Files
UHD_Media_Tool/packages/adapters/src/sites/spiders/tnode.test.ts
T

76 lines
3.3 KiB
TypeScript

import { createMockFetch, TNODE_HOME_HTML, TNODE_HOME_NO_TOKEN, TNODE_SEARCH_OK } from "@umt/testkit";
import { describe, expect, it } from "vitest";
import { createSiteRateLimiter } from "../rate-limit.ts";
import { createSpecializedSiteAdapter } from "./adapter.ts";
import { adapterWith, expectSiteError, testDef, withTorrent } from "./testing.ts";
import { parseTnodeToken, tnodeSearchParams, tnodeSpider } from "./tnode.ts";
const def = testDef("TNodeSpider", { domain: "https://tnode.example/" });
describe("TNodeSpider(MP tnode.py)", () => {
it("凭据变更后不复用旧CSRF令牌", async () => {
let cookie = "session=first";
const mock = createMockFetch({
"GET /": { body: TNODE_HOME_HTML },
"POST /api/torrent/advancedSearch": { body: TNODE_SEARCH_OK },
});
const adapter = createSpecializedSiteAdapter(def, tnodeSpider, {
fetch: mock.fetch,
secrets: {
async resolve() {
return cookie;
},
},
limiter: createSiteRateLimiter({ minIntervalMs: 0 }),
});
await adapter.list(1);
await adapter.list(1);
cookie = "session=second";
await adapter.list(1);
expect(mock.requests.filter((request) => request.url.pathname === "/")).toHaveLength(2);
});
it("__get_params / token 解析", () => {
expect(tnodeSearchParams("tt0923811", 1)).toMatchObject({
page: 2,
size: 100,
type: "imdbid",
keyword: "tt0923811",
});
expect(tnodeSearchParams(null)).toMatchObject({ type: "title", keyword: "", category: [501, 502, 503, 504] });
expect(parseTnodeToken(TNODE_HOME_HTML)).toBe("CSRF-TOKEN-XYZ");
});
it("列表解析:CSRF token 缓存、系数直取、时间戳转 UTC", async () => {
const m = createMockFetch({
"GET /": { body: TNODE_HOME_HTML },
"POST /api/torrent/advancedSearch": { body: TNODE_SEARCH_OK },
});
const a = adapterWith(def, tnodeSpider, m.fetch);
const page = await a.search("eva");
await a.list(1);
expect(m.requests.filter((r) => r.url.pathname === "/")).toHaveLength(1);
expect(m.requests[1]!.headers["x-csrf-token"]).toBe("CSRF-TOKEN-XYZ");
const [x, y] = page.items;
expect(x).toMatchObject({
siteReleaseId: "3301",
promotion: { type: "free", downloadFactor: 0, uploadFactor: 1 },
uploadedAt: "2024-09-20T00:00:00.000Z",
imdbId: "tt0923811",
detailUrl: "https://tnode.example/torrent/info/3301",
hr: "unknown",
});
expect(y!.promotion.type).toBe("2x50%");
const t = withTorrent(m.fetch, (u) => u.pathname.startsWith("/api/torrent/download/"));
await adapterWith(def, tnodeSpider, t.fetch).downloadTarget("3301");
expect(t.hits[0]!.headers.get("cookie")).toBe("c=COOKIESECRET");
});
it("取不到 token → auth_expired;缺 Cookie → auth_missing;搜索 HTTP 403 → auth_invalid", async () => {
const m = createMockFetch({ "GET /": { body: TNODE_HOME_NO_TOKEN } });
await expectSiteError(adapterWith(def, tnodeSpider, m.fetch).list(1), "auth_expired");
await expectSiteError(adapterWith(def, tnodeSpider, m.fetch, {}).list(1), "auth_missing");
const f = createMockFetch({ "GET /": { body: TNODE_HOME_HTML }, "/api/torrent/advancedSearch": { status: 403 } });
await expectSiteError(adapterWith(def, tnodeSpider, f.fetch).list(1), "auth_invalid");
});
});