import assert from "node:assert/strict"; import test from "node:test"; import { readFileSync } from "node:fs"; const routeSource = readFileSync( new URL("../app/api/partner/route.ts", import.meta.url), "utf8", ); const portalSource = readFileSync( new URL("../koc-portal/app/page.tsx", import.meta.url), "utf8", ); test("partner route accepts identityTicket for wecom-backed claim", () => { assert.match(routeSource, /identityTicket\?: string/); assert.match(routeSource, /verifyWecomIdentityTicket/); assert.match(routeSource, /resolveWecomClaimant/); }); test("claim keeps manual wechat/phone path untouched when no ticket", () => { assert.match( routeSource, /请输入正确的微信号或手机号/, "manual validation message preserved", ); assert.match( routeSource, /VALUES \(\?, \?, \?, '外部KOC', 0, 0\)\s*\n\s*ON CONFLICT\(id\) DO UPDATE SET\s*\n\s*name = excluded\.name,\s*\n\s*wecom_name = excluded\.wecom_name`/, "manual partner upsert statement preserved", ); }); test("claim with ticket upserts wecom_external_user_id for reminders", () => { assert.match( routeSource, /wecom_external_user_id = excluded\.wecom_external_user_id/, ); }); test("internal identity claim resolves the group_owner partner by wecom_userid", () => { assert.match( routeSource, /WHERE wecom_userid = \? AND partner_type = 'group_owner'/, ); assert.match(routeSource, /未找到你的群主身份/); assert.match( routeSource, /claimantName = ownerPartner\.name \|\| internalUserid/, ); }); test("external wecom claim upserts partner_type group_owner", () => { assert.match( routeSource, /wecom_external_user_id, partner_type\)\s*\n\s*VALUES \(\?, \?, \?, '外部KOC', 0, 0, \?, 'group_owner'\)/, ); assert.match( routeSource, /partner_type = 'group_owner'`/, ); }); test("claim records owner_partner_id after validating a group_owner partner", () => { assert.match(routeSource, /owner\?: string/); assert.match( routeSource, /SELECT id FROM partners WHERE id = \? AND partner_type = 'group_owner'/, ); assert.match( routeSource, /INSERT INTO claims\s*\n\s*\(\s*id, task_id, partner_id, owner_partner_id, claimant_name, claim_token, quantity\)/, ); }); test("claim schedules task group creation and broadcast in background", () => { assert.match(routeSource, /ensureTaskChatForMembers/); assert.match(routeSource, /taskClaimBroadcastText/); assert.match(routeSource, /taskChatIntroText/); assert.match(routeSource, /runInBackground\(/); assert.match( routeSource, /internalUserid \? \{ addUserids: \[internalUserid\] \} : \{\}/, ); }); test("recover resolves internal identity via wecom_userid as well", () => { assert.match( routeSource, /wecomIdentity\?\.userId[\s\S]{0,200}WHERE wecom_userid = \? AND partner_type = 'group_owner'/, ); }); test("portal preserves owner param through the oauth round trip and sends it with claim", () => { assert.match(portalSource, /owner: string;/); assert.match(portalSource, /compact\.set\("o", params\.owner\)/); assert.match(portalSource, /fallback\.set\("o", params\.owner\)/); assert.match(portalSource, /parsed\.get\("o"\) \?\? ""/); assert.match(portalSource, /params\.get\("owner"\) \?\? ""/); assert.match( portalSource, /ownerPartnerId \? \{ owner: ownerPartnerId \} : \{\}/, ); assert.match(portalSource, /userType === "internal"/); }); test("recover builds dynamic partner candidates including wecom identity", () => { assert.match( routeSource, /wecomPartnerId \? \[wecomPartnerId\] : \[partnerId, legacyPartnerId\]/, ); assert.match(routeSource, /\.bind\(task\.task_type, task\.task_type, task\.id, \.\.\.partnerCandidates\)/); });