import assert from "node:assert/strict"; import test from "node:test"; import { readFileSync } from "node:fs"; const resourceWrite = readFileSync( new URL("../lib/resource-write.ts", import.meta.url), "utf8", ); const bootstrapRoute = readFileSync( new URL("../app/api/bootstrap/route.ts", import.meta.url), "utf8", ); const resourcesImport = readFileSync( new URL("../app/api/resources-import/route.ts", import.meta.url), "utf8", ); const resourcesInsert = readFileSync( new URL("../app/api/resources-insert/route.ts", import.meta.url), "utf8", ); const actionRoute = readFileSync( new URL("../app/api/action/route.ts", import.meta.url), "utf8", ); const migration = readFileSync( new URL("../mysql/0023_partner_released_account.sql", import.meta.url), "utf8", ); function section(source, action) { const start = source.indexOf(`"${action}"`); assert.ok(start >= 0, `action ${action} 不存在于路由源码`); const next = source.indexOf("} else if (body.action ===", start); return source.slice(start, next === -1 ? undefined : next); } test("ensurePartnersForPoolAccounts 为资源池未绑定账号创建默认合作方", () => { assert.match(resourceWrite, /export async function ensurePartnersForPoolAccounts/); assert.match( resourceWrite, /NOT EXISTS \(SELECT 1 FROM partners p WHERE p\.account_id = a\.id\)/, "只为尚未绑定合作方的资源账号建档", ); assert.match( resourceWrite, /INSERT OR IGNORE INTO partners/, "并发同步幂等:主键冲突直接忽略", ); assert.match(resourceWrite, /'external_koc'/, "默认合作方为外部KOC类型"); assert.match( resourceWrite, /partner-koc-\$\{hashText/, "合作方 id 由账号身份派生,与领取流程的前缀约定一致", ); }); test("默认合作方同步尊重运营显式解绑(released_account_id 不回填)", () => { assert.match( resourceWrite, /NOT EXISTS \(\s*SELECT 1 FROM partners r WHERE r\.released_account_id = a\.id\s*\)/, "被显式解绑/顶替过的资源账号不再自动加入合作方", ); assert.match(migration, /ADD COLUMN `released_account_id`/); assert.match(migration, /partners_released_account_idx/); }); test("空壳默认合作方的名称随昵称补全刷新且不碰有业绩合作方", () => { assert.match(resourceWrite, /async function refreshPoolPartnerNames/); assert.match( resourceWrite, /NOT EXISTS \(SELECT 1 FROM claims c WHERE c\.partner_id = p\.id\)/, "有领取记录的合作方不刷新名称", ); assert.match( resourceWrite, /NOT EXISTS \(SELECT 1 FROM distributions d WHERE d\.partner_id = p\.id\)/, "有分发记录的合作方不刷新名称", ); assert.match( resourceWrite, /p\.wecom_external_user_id IS NULL OR p\.wecom_external_user_id = ''/, "已绑企微的合作方不刷新名称", ); }); test("bootstrap 在返回面板数据前同步默认合作方", () => { const syncIndex = bootstrapRoute.indexOf("await ensurePartnersForPoolAccounts"); const dashboardIndex = bootstrapRoute.indexOf("await getDashboardData("); assert.ok(syncIndex >= 0, "bootstrap 需要调用默认合作方同步"); assert.ok( dashboardIndex > syncIndex, "同步必须发生在 getDashboardData 之前,首次加载即可见", ); }); test("资源导入与手动新增后都会触发默认合作方同步", () => { assert.match( resourcesImport, /runInBackground\(\s*ensurePartnersForPoolAccounts\(\)/, "批量导入 commit 后同步", ); assert.match( resourcesInsert, /runInBackground\(\s*ensurePartnersForPoolAccounts\(\)/, "手动新增后同步", ); }); test("partner_bind_account 换绑时可顶替空壳占用方", () => { const body = section(actionRoute, "partner_bind_account"); assert.match(body, /isShellAccountHolder/, "占用方为空壳时判断是否可顶替"); assert.match( body, /UPDATE partners SET account_id = \?, released_account_id = '' WHERE id = \?/, "绑定目标时清掉自身的释放标记", ); const helper = actionRoute.slice( actionRoute.indexOf("async function isShellAccountHolder"), ); assert.match(helper, /SELECT 1 FROM claims WHERE partner_id = \? LIMIT 1/); assert.match( helper, /SELECT 1 FROM distributions WHERE partner_id = \? LIMIT 1/, "有领取或分发记录的占用方不可顶替,仍走人工解绑", ); });