test(danmaku): assert openCommentXml withRelated contract
This commit is contained in:
parent
5b095d677f
commit
07c7108789
|
|
@ -17,8 +17,8 @@
|
||||||
| `@app/models` | Drizzle 表定义(唯一 schema 源) | drizzle-orm |
|
| `@app/models` | Drizzle 表定义(唯一 schema 源) | drizzle-orm |
|
||||||
| `@app/db` | libSQL/Turso 客户端单例 + drizzle-kit | models |
|
| `@app/db` | libSQL/Turso 客户端单例 + drizzle-kit | models |
|
||||||
| `@app/dao` | 数据访问层(`userDao` / `mountDao` / `mediaItemDao` 等) | db, models |
|
| `@app/dao` | 数据访问层(`userDao` / `mountDao` / `mediaItemDao` 等) | db, models |
|
||||||
| `@app/trpc` | tRPC 路由 + service 业务逻辑(调用 DAO) | types, dao |
|
| `@app/trpc` | tRPC 路由 + service 业务逻辑(调用 DAO) | types, dao, danmaku |
|
||||||
| `@app/web` | Astro 前端 + React islands + 本地 tRPC HTTP 适配 | trpc, types, design-tokens, seo-geo, i18n, ui |
|
| `@app/web` | Astro 前端 + React islands + 本地 tRPC HTTP 适配 | trpc, types, danmaku(`./browser`), design-tokens, seo-geo, i18n, ui |
|
||||||
| `@app/ui` | shadcn 风格基础 UI 组件(源码直出 + Storybook) | design-tokens, react (peer) |
|
| `@app/ui` | shadcn 风格基础 UI 组件(源码直出 + Storybook) | design-tokens, react (peer) |
|
||||||
| `@app/design-tokens` | 共享 CSS 设计令牌(`tokens.css`) | — |
|
| `@app/design-tokens` | 共享 CSS 设计令牌(`tokens.css`) | — |
|
||||||
| `@app/seo-geo` | SEO/GEO 纯函数(meta、sitemap、JSON-D、llms.txt) | zod, schema-dts, escape-html, fast-xml-builder, serialize-javascript, mdast-util-to-markdown |
|
| `@app/seo-geo` | SEO/GEO 纯函数(meta、sitemap、JSON-D、llms.txt) | zod, schema-dts, escape-html, fast-xml-builder, serialize-javascript, mdast-util-to-markdown |
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||||
import { hasOpenCredentials, openApiBase, openHeaders, readOpenCredentials } from "./client.js";
|
import {
|
||||||
|
hasOpenCredentials,
|
||||||
|
openApiBase,
|
||||||
|
openCommentXml,
|
||||||
|
openHeaders,
|
||||||
|
openMatch,
|
||||||
|
readOpenCredentials,
|
||||||
|
} from "./client.js";
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
vi.unstubAllEnvs();
|
vi.unstubAllEnvs();
|
||||||
|
|
@ -50,3 +57,59 @@ describe("openHeaders", () => {
|
||||||
expect(openHeaders("/api/v2/match", null)).toEqual({ "Content-Type": "application/json" });
|
expect(openHeaders("/api/v2/match", null)).toEqual({ "Content-Type": "application/json" });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function stubFetchJson(json: unknown) {
|
||||||
|
const fetchMock = vi.fn().mockResolvedValue({
|
||||||
|
ok: true,
|
||||||
|
status: 200,
|
||||||
|
json: async () => json,
|
||||||
|
});
|
||||||
|
vi.stubGlobal("fetch", fetchMock);
|
||||||
|
return fetchMock;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("openCommentXml 请求契约", () => {
|
||||||
|
it("请求路径含 ?withRelated=true(关联弹幕计入)", async () => {
|
||||||
|
const fetchMock = stubFetchJson({ success: true, comments: [] });
|
||||||
|
await openCommentXml(555);
|
||||||
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||||
|
const url = String(fetchMock.mock.calls[0]?.[0]);
|
||||||
|
expect(url).toBe("https://api.dandanplay.net/api/v2/comment/555?withRelated=true");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("comments 序列化为 xml,HTTP 失败返回 null", async () => {
|
||||||
|
const fetchMock = stubFetchJson({
|
||||||
|
success: true,
|
||||||
|
comments: [{ p: "12.5,1,0,0,0,0,,", m: "hi" }],
|
||||||
|
});
|
||||||
|
await expect(openCommentXml(555)).resolves.toContain("<d ");
|
||||||
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
fetchMock.mockResolvedValue({ ok: false, status: 500, json: async () => ({}) });
|
||||||
|
await expect(openCommentXml(555)).resolves.toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("openMatch 请求契约", () => {
|
||||||
|
it("POST /api/v2/match,matchMode 随 hash 切换", async () => {
|
||||||
|
const fetchMock = stubFetchJson({ success: true, isMatched: true, matches: [] });
|
||||||
|
|
||||||
|
await openMatch("Show - 02", 100, "abc");
|
||||||
|
const [url1, init1] = fetchMock.mock.calls[0] ?? [];
|
||||||
|
expect(String(url1)).toBe("https://api.dandanplay.net/api/v2/match");
|
||||||
|
expect(init1?.method).toBe("POST");
|
||||||
|
expect(JSON.parse(String(init1?.body))).toEqual({
|
||||||
|
fileName: "Show - 02",
|
||||||
|
fileHash: "abc",
|
||||||
|
fileSize: 100,
|
||||||
|
matchMode: "hashAndFileName",
|
||||||
|
});
|
||||||
|
|
||||||
|
await openMatch("Show - 02", 100, null);
|
||||||
|
const init2 = fetchMock.mock.calls[1]?.[1];
|
||||||
|
expect(JSON.parse(String(init2?.body))).toMatchObject({
|
||||||
|
fileHash: "",
|
||||||
|
matchMode: "fileNameOnly",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue