Files
boss/tests/telegram-integration-route.test.ts

226 lines
7.5 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import os from "node:os";
import path from "node:path";
import { mkdtemp, rm } from "node:fs/promises";
import { NextRequest } from "next/server";
let runtimeRoot = "";
let getRoute: (typeof import("../src/app/api/v1/integrations/telegram/route"))["GET"];
let postRoute: (typeof import("../src/app/api/v1/integrations/telegram/route"))["POST"];
let createAuthSession: (typeof import("../src/lib/boss-data"))["createAuthSession"];
let AUTH_SESSION_COOKIE = "";
async function setup() {
if (runtimeRoot) return;
runtimeRoot = await mkdtemp(path.join(os.tmpdir(), "boss-telegram-route-"));
process.env.BOSS_RUNTIME_ROOT = runtimeRoot;
process.env.BOSS_STATE_FILE = path.join(runtimeRoot, "boss-state.json");
const [routeModule, data, auth] = await Promise.all([
import("../src/app/api/v1/integrations/telegram/route.ts"),
import("../src/lib/boss-data.ts"),
import("../src/lib/boss-auth.ts"),
]);
getRoute = routeModule.GET;
postRoute = routeModule.POST;
createAuthSession = data.createAuthSession;
AUTH_SESSION_COOKIE = auth.AUTH_SESSION_COOKIE;
}
test.after(async () => {
if (runtimeRoot) {
await rm(runtimeRoot, { recursive: true, force: true });
}
});
async function createAuthedRequest(url: string, method: "GET" | "POST", body?: unknown) {
const session = await createAuthSession({
account: "krisolo",
role: "highest_admin",
displayName: "Boss 超级管理员",
loginMethod: "password",
});
return new NextRequest(url, {
method,
headers: {
cookie: `${AUTH_SESSION_COOKIE}=${session.sessionToken}`,
...(body ? { "content-type": "application/json" } : {}),
},
body: body ? JSON.stringify(body) : undefined,
});
}
test("Telegram 配置接口返回脱敏配置视图", async () => {
await setup();
const saveResponse = await postRoute(
await createAuthedRequest("http://127.0.0.1:3000/api/v1/integrations/telegram", "POST", {
enabled: true,
botToken: "123:abc",
allowFrom: ["123456"],
webhookSecret: "secret-demo",
}),
);
assert.equal(saveResponse.status, 200);
const getResponse = await getRoute(
await createAuthedRequest("http://127.0.0.1:3000/api/v1/integrations/telegram", "GET"),
);
assert.equal(getResponse.status, 200);
const payload = (await getResponse.json()) as {
ok: boolean;
telegram: {
botTokenConfigured: boolean;
webhookSecretConfigured: boolean;
allowFrom: string[];
};
};
assert.equal(payload.ok, true);
assert.equal(payload.telegram.botTokenConfigured, true);
assert.equal(payload.telegram.webhookSecretConfigured, true);
assert.deepEqual(payload.telegram.allowFrom, ["123456"]);
assert.equal("botToken" in payload.telegram, false);
});
test("Telegram 配置保存到 webhook 模式时会自动调用 setWebhook", async () => {
await setup();
const originalFetch = globalThis.fetch;
const calls: Array<{ url: string; body?: unknown }> = [];
globalThis.fetch = (async (input, init) => {
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
calls.push({
url,
body: init?.body ? JSON.parse(String(init.body)) : undefined,
});
if (url === "https://api.telegram.org/bot123:abc/setWebhook") {
return new Response(JSON.stringify({ ok: true, result: true }), {
status: 200,
headers: { "content-type": "application/json" },
});
}
throw new Error(`unexpected fetch: ${url}`);
}) as typeof fetch;
try {
const response = await postRoute(
await createAuthedRequest("http://127.0.0.1:3000/api/v1/integrations/telegram", "POST", {
enabled: true,
mode: "webhook",
botToken: "123:abc",
webhookSecret: "boss-telegram-secret",
webhookUrl: "https://boss.hyzq.net/api/v1/integrations/telegram/webhook",
}),
);
assert.equal(response.status, 200);
const payload = (await response.json()) as {
ok: boolean;
webhookSync?: { ok: boolean; action: string };
};
assert.equal(payload.ok, true);
assert.equal(payload.webhookSync?.ok, true);
assert.equal(payload.webhookSync?.action, "set_webhook");
assert.equal(calls.length, 1);
assert.equal(calls[0]?.url, "https://api.telegram.org/bot123:abc/setWebhook");
assert.deepEqual(calls[0]?.body, {
url: "https://boss.hyzq.net/api/v1/integrations/telegram/webhook",
secret_token: "boss-telegram-secret",
drop_pending_updates: false,
});
} finally {
globalThis.fetch = originalFetch;
}
});
test("Telegram 配置切回 polling 时会自动调用 deleteWebhook", async () => {
await setup();
const originalFetch = globalThis.fetch;
const calls: string[] = [];
globalThis.fetch = (async (input) => {
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
calls.push(url);
if (url === "https://api.telegram.org/bot123:abc/deleteWebhook") {
return new Response(JSON.stringify({ ok: true, result: true }), {
status: 200,
headers: { "content-type": "application/json" },
});
}
throw new Error(`unexpected fetch: ${url}`);
}) as typeof fetch;
try {
const response = await postRoute(
await createAuthedRequest("http://127.0.0.1:3000/api/v1/integrations/telegram", "POST", {
enabled: true,
mode: "polling",
botToken: "123:abc",
}),
);
assert.equal(response.status, 200);
const payload = (await response.json()) as {
ok: boolean;
webhookSync?: { ok: boolean; action: string };
};
assert.equal(payload.ok, true);
assert.equal(payload.webhookSync?.ok, true);
assert.equal(payload.webhookSync?.action, "delete_webhook");
assert.deepEqual(calls, ["https://api.telegram.org/bot123:abc/deleteWebhook"]);
} finally {
globalThis.fetch = originalFetch;
}
});
test("Telegram 配置接口可以保存群聊到项目的路由表", async () => {
await setup();
const originalFetch = globalThis.fetch;
globalThis.fetch = (async (input) => {
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
if (url === "https://api.telegram.org/bot123:abc/deleteWebhook") {
return new Response(JSON.stringify({ ok: true, result: true }), {
status: 200,
headers: { "content-type": "application/json" },
});
}
throw new Error(`unexpected fetch: ${url}`);
}) as typeof fetch;
try {
const response = await postRoute(
await createAuthedRequest("http://127.0.0.1:3000/api/v1/integrations/telegram", "POST", {
enabled: true,
groupProjectRoutes: [
{
chatId: "-100200300",
projectId: "audit-collab",
label: "审计群",
},
{
chatId: "-100200300",
threadId: 12,
projectId: "master-agent",
label: "主控 Topic",
},
],
}),
);
assert.equal(response.status, 200);
const payload = (await response.json()) as {
ok: boolean;
telegram: {
groupProjectRoutes: Array<{ chatId: string; threadId?: number; projectId: string; label?: string }>;
};
};
assert.equal(payload.ok, true);
assert.deepEqual(payload.telegram.groupProjectRoutes, [
{ chatId: "-100200300", projectId: "audit-collab", label: "审计群" },
{ chatId: "-100200300", threadId: 12, projectId: "master-agent", label: "主控 Topic" },
]);
} finally {
globalThis.fetch = originalFetch;
}
});