import assert from "node:assert/strict"; import test from "node:test"; import { buildCollectionFinishedMessage, buildPublishSubmittedMessage, notifyCollectionFinished, notifyPartnerSubmitted, } from "../lib/wecom-feedback-service.ts"; import { resolveWecomConfig } from "../lib/wecom-client.ts"; const config = resolveWecomConfig({ WECOM_CORP_ID: "corp-test", WECOM_AGENT_ID: "1000001", WECOM_SECRET: "secret-test", WECOM_ROBOT_WEBHOOK: "https://qyapi.example.com/webhook/send?key=abc", }); const submittedRow = { claimant_name: "小王", partner_name: "合作方甲", task_name: "夏日轻盈计划", content_title: "好物分享笔记", publish_url: "https://www.xiaohongshu.com/explore/abc", }; function robotFetch(calls) { return async (input, init = {}) => { const url = new URL(String(input)); calls.push({ url, init }); return Response.json({ errcode: 0, errmsg: "ok" }); }; } function fakeSubmittedDb(row = submittedRow) { return { prepare(sql) { return { bind() { return { async first() { if (/FROM distributions d/.test(sql)) return row; return null; }, }; }, }; }, }; } test("publish submitted message covers partner, task and link", () => { const message = buildPublishSubmittedMessage(submittedRow, "publish"); assert.match(message, /【KOC 已提交发布】/); assert.match(message, /合作方:合作方甲/); assert.match(message, /夏日轻盈计划/); assert.match(message, /xiaohongshu\.com\/explore\/abc/); const screenshot = buildPublishSubmittedMessage(submittedRow, "screenshot"); assert.match(screenshot, /【KOC 已提交截图】/); assert.doesNotMatch(screenshot, /链接:/); }); test("collection digest includes failure hint only when failed", () => { const ok = buildCollectionFinishedMessage({ currentDate: "2026-09-01", dueTasks: 3, attempted: 10, succeeded: 10, failed: 0, }); assert.match(ok, /成功 10、失败 0/); assert.doesNotMatch(ok, /重试/); const bad = buildCollectionFinishedMessage({ currentDate: "2026-09-01", dueTasks: 3, attempted: 10, succeeded: 7, failed: 3, }); assert.match(bad, /重试/); }); test("notifyPartnerSubmitted posts robot message and skips without webhook", async () => { const calls = []; const sent = await notifyPartnerSubmitted( fakeSubmittedDb(), { distributionId: "d-1", kind: "publish" }, config, robotFetch(calls), ); assert.equal(sent, true); assert.equal(calls.length, 1); const body = JSON.parse(String(calls[0].init.body)); assert.equal(body.msgtype, "text"); assert.match(body.text.content, /【KOC 已提交发布】/); const noWebhook = await notifyPartnerSubmitted( fakeSubmittedDb(), { distributionId: "d-1", kind: "publish" }, resolveWecomConfig({}), robotFetch([]), ); assert.equal(noWebhook, false); }); test("notifyCollectionFinished skips empty batches and posts on activity", async () => { const calls = []; const idle = await notifyCollectionFinished( { currentDate: "2026-09-01", dueTasks: 0, attempted: 0, succeeded: 0, failed: 0 }, config, robotFetch(calls), ); assert.equal(idle, false); assert.equal(calls.length, 0); const active = await notifyCollectionFinished( { currentDate: "2026-09-01", dueTasks: 2, attempted: 5, succeeded: 4, failed: 1 }, config, robotFetch(calls), ); assert.equal(active, true); assert.equal(calls.length, 1); assert.match(JSON.parse(String(calls[0].init.body)).text.content, /成功 4、失败 1/); });