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; } });