- M1-M2: 数据层与核心API(DuckDB, entries/tags/comments/search服务) - M3: SSR页面(EJS模板,接真实数据) - M4: 管理后台(登录/用户/内容源/AI ingest) - M5: 采集层(scheduler+rss/html/eryajf适配器) - M6: MCP只读接口(Streamable HTTP, 4工具) - M7: Docker部署(Dockerfile+docker-compose) - 测试: 10个用例全部通过 - 修复: DuckDB连接参数绑定、状态机迁移、标签树操作
75 lines
2.2 KiB
JavaScript
75 lines
2.2 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { withApp } from "./helpers.js";
|
|
|
|
test("seeded entries are searchable", async () => {
|
|
await withApp(async ({ api }) => {
|
|
const res = await api("/api/entries?q=ripgrep");
|
|
assert.equal(res.status, 200);
|
|
assert.ok(res.json.data.total >= 1);
|
|
assert.equal(res.json.data.items[0].title, "ripgrep");
|
|
});
|
|
});
|
|
|
|
test("random endpoint returns an active entry", async () => {
|
|
await withApp(async ({ api }) => {
|
|
const res = await api("/api/entries/random");
|
|
assert.equal(res.status, 200);
|
|
assert.equal(res.json.data.status, "active");
|
|
});
|
|
});
|
|
|
|
test("invalid status transition is rejected", async () => {
|
|
await withApp(async ({ api, loginAdmin }) => {
|
|
const cookie = await loginAdmin();
|
|
const found = await api("/api/entries?q=ripgrep");
|
|
const id = found.json.data.items[0].id;
|
|
const res = await api(`/api/entries/${id}/status`, {
|
|
method: "PATCH",
|
|
body: { status: "active" },
|
|
cookie,
|
|
});
|
|
assert.equal(res.status, 400);
|
|
});
|
|
});
|
|
|
|
test("greyed -> active is allowed", async () => {
|
|
await withApp(async ({ api, loginAdmin }) => {
|
|
const cookie = await loginAdmin();
|
|
const found = await api("/api/entries?q=ripgrep");
|
|
const id = found.json.data.items[0].id;
|
|
const grey = await api(`/api/entries/${id}/status`, {
|
|
method: "PATCH",
|
|
body: { status: "greyed" },
|
|
cookie,
|
|
});
|
|
assert.equal(grey.json.data.status, "greyed");
|
|
const back = await api(`/api/entries/${id}/status`, {
|
|
method: "PATCH",
|
|
body: { status: "active" },
|
|
cookie,
|
|
});
|
|
assert.equal(back.json.data.status, "active");
|
|
});
|
|
});
|
|
|
|
test("AI ingest without a valid key is forbidden", async () => {
|
|
await withApp(async ({ api }) => {
|
|
const res = await api("/api/ingest/entry", {
|
|
method: "POST",
|
|
body: { title: "x", url: "https://github.com/a/b", type: "工具" },
|
|
});
|
|
assert.equal(res.status, 403);
|
|
});
|
|
});
|
|
|
|
test("unauthenticated writes to entries are forbidden", async () => {
|
|
await withApp(async ({ api }) => {
|
|
const res = await api("/api/entries", {
|
|
method: "POST",
|
|
body: { title: "x", url: "https://github.com/a/c", type: "工具" },
|
|
});
|
|
assert.equal(res.status, 403);
|
|
});
|
|
});
|