const { maskEmail, maskExternalUserId, maskPhone, fetchWecomHrProfiles, normalizeWecomHrProfile, __testables, } = require("../../src/services/integrations/wecomHrMaster"); describe("wecom HR master sync helpers", () => { function jsonResponse(payload, status = 200) { return { ok: status >= 200 && status < 300, status, json: async () => payload, }; } it("normalizes contact and HR assistant data without leaking full sensitive values in summary", () => { const departmentMap = new Map([ ["1", { externalId: "1", name: "研发部" }], ]); const profile = normalizeWecomHrProfile({ departmentMap, contact: { userid: "oa_smoke002", name: "测试员工", mobile: "19912345678", email: "smoke002@hyinda.com", position: "测试工程师", department: [1], direct_leader: ["manager001"], enable: 1, }, staff: { staff_info: [ { fieldid: "入职日期", value: "2026-05-01" }, { fieldid: "在职状态", value: "在职" }, ], }, }); expect(profile.externalUserId).toBe("oa_smoke002"); expect(profile.departmentName).toBe("研发部"); expect(profile.managerExternalUserId).toBe("manager001"); expect(profile.hireDate).toBe("2026-05-01"); expect(profile.sourceStatus).toBe("active"); expect(profile.missingRequiredFields).toEqual([]); expect(JSON.stringify(profile.sourceSummary)).not.toContain("19912345678"); expect(JSON.stringify(profile.sourceSummary)).not.toContain("smoke002@hyinda.com"); expect(JSON.stringify(profile.sourceSummary)).not.toContain("oa_smoke002"); }); it("skips profiles missing OA-required source fields", () => { const profile = normalizeWecomHrProfile({ contact: { userid: "missing-email", name: "缺邮箱", mobile: "19900000001", department: [1], }, staff: {}, departmentMap: new Map([["1", { externalId: "1", name: "行政部" }]]), }); expect(profile.missingRequiredFields).toContain("email"); }); it("accepts a profile with no phone and does not plan clearing an existing phone", () => { const profile = normalizeWecomHrProfile({ contact: { userid: "missing-phone", name: "缺手机号成员", biz_mail: "missing-phone@hyinda.com", department: [1], enable: 1, }, staff: {}, departmentMap: new Map([["1", { externalId: "1", name: "行政部" }]]), }); expect(profile.phone).toBe(""); expect(profile.missingRequiredFields).toEqual([]); const changes = __testables.buildEmployeeChanges( { id: "employee-1", name: profile.name, phone: "19900000009", email: profile.email, department_id: "department-1", title: "员工", wecom_identity_binding: { external_user_id: profile.externalUserId }, }, profile, { id: "department-1", name: "行政部" }, ); expect(changes).not.toHaveProperty("phone"); }); it("marks inactive WeCom members as confirmation-required instead of active", () => { const profile = normalizeWecomHrProfile({ contact: { userid: "inactive001", name: "离职测试", mobile: "19900000002", email: "inactive001@hyinda.com", department: [1], enable: 0, }, staff: {}, departmentMap: new Map([["1", { externalId: "1", name: "行政部" }]]), }); expect(profile.sourceStatus).toBe("inactive"); }); it("builds masked field changes for contact fields", () => { const changes = __testables.buildEmployeeChanges( { id: "employee-1", name: "旧员工", phone: "19911112222", email: "old@hyinda.com", department_id: "dept-old", title: "旧岗位", wecom_identity_binding: null, }, { externalUserId: "oa_smoke002", name: "新员工", phone: "19933334444", email: "new@hyinda.com", title: "新岗位", }, { id: "dept-new", name: "研发部" }, ); expect(changes.phone.before).toBe(maskPhone("19911112222")); expect(changes.phone.after).toBe(maskPhone("19933334444")); expect(changes.email.before).toBe(maskEmail("old@hyinda.com")); expect(changes.externalUserId.after).toBe(maskExternalUserId("oa_smoke002")); }); it("uses fixed contact and agent secrets with list_id for full contact inventory", async () => { const calls = []; const fetchImpl = async (url, init = {}) => { const parsed = new URL(String(url)); calls.push({ path: parsed.pathname, token: parsed.searchParams.get("access_token"), method: init.method ?? "GET", body: init.body ? JSON.parse(init.body) : null, secret: parsed.searchParams.get("corpsecret"), }); if (parsed.pathname === "/cgi-bin/gettoken") { const secret = parsed.searchParams.get("corpsecret"); if (secret === "contact-secret-wapi") { return jsonResponse({ errcode: 0, access_token: "contact-token", expires_in: 7200 }); } if (secret === "agent-secret-wapi") { return jsonResponse({ errcode: 0, access_token: "agent-token", expires_in: 7200 }); } } if (parsed.pathname === "/cgi-bin/department/list" && parsed.searchParams.get("access_token") === "agent-token") { return jsonResponse({ errcode: 0, department: [{ id: 1, name: "研发部", parentid: 0, order: 1 }], }); } if (parsed.pathname === "/cgi-bin/user/list_id" && parsed.searchParams.get("access_token") === "contact-token") { expect(init.method).toBe("POST"); expect(JSON.parse(init.body)).toEqual({ cursor: "", limit: 2 }); return jsonResponse({ errcode: 0, dept_user: [ { userid: "oa_smoke002", department: 1 }, { userid: "oa_smoke002", department: 2 }, ], next_cursor: "", }); } if (parsed.pathname === "/cgi-bin/user/get" && parsed.searchParams.get("access_token") === "agent-token") { return jsonResponse({ errcode: 0, userid: "oa_smoke002", name: "测试员工", mobile: "19912345678", email: "smoke002@hyinda.com", department: [1], position: "测试工程师", enable: 1, }); } if (parsed.pathname === "/cgi-bin/hr/get_staff_info" && parsed.searchParams.get("access_token") === "agent-token") { expect(init.method).toBe("POST"); return jsonResponse({ errcode: 0, staff_info: [ { fieldid: "name", value: "测试员工" }, { fieldid: "mobile", value: "19912345678" }, { fieldid: "email", value: "smoke002@hyinda.com" }, { fieldid: "department", value: "研发部" }, { fieldid: "在职状态", value: "在职" }, ], }); } return jsonResponse({ errcode: 40001, errmsg: "unexpected mock request" }); }; const result = await fetchWecomHrProfiles({ config: { wecomCorpId: "corp-wapi", wecomAgentId: "1000002", wecomContactSecret: "contact-secret-wapi", wecomAgentSecret: "agent-secret-wapi", wecomHrAssistantSecret: "deprecated-hr-secret-should-not-be-used", wecomContactDefaultDepartmentId: "1", }, userids: [], limit: 2, fetchImpl, }); expect(result.tokenSource.contact).toBe("WECOM_CONTACT_SECRET"); expect(result.tokenSource.hr).toBe("WECOM_AGENT_SECRET"); expect(result.profiles).toHaveLength(1); expect(result.profiles[0].externalUserId).toBe("oa_smoke002"); expect(result.profiles[0].name).toBe("测试员工"); expect(result.profiles[0].missingRequiredFields).toEqual([]); expect(calls.some((call) => call.path === "/cgi-bin/department/list" && call.token === "agent-token")).toBe(true); expect(calls.some((call) => call.path === "/cgi-bin/user/list_id" && call.token === "contact-token")).toBe(true); expect(calls.some((call) => call.path === "/cgi-bin/user/get" && call.token === "agent-token")).toBe(true); expect(calls.some((call) => call.path === "/cgi-bin/hr/get_staff_info" && call.token === "agent-token")).toBe(true); expect(calls.some((call) => call.path === "/cgi-bin/department/list" && call.token === "contact-token")).toBe(false); expect(calls.some((call) => call.path === "/cgi-bin/user/get" && call.token === "contact-token")).toBe(false); expect(calls.some((call) => call.secret === "deprecated-hr-secret-should-not-be-used")).toBe(false); }); });