文件
hyb-oa/server/tests/unit/services/wecomCheckinArchive.test.js
2026-05-20 13:58:40 +08:00

153 行
5.0 KiB
JavaScript

const {
buildDailySummaries,
buildMonthlySummaries,
buildRuleSnapshots,
maskExternalUserId,
sanitizeDailySummary,
summarizeRuleOption,
} = require("../../../src/services/integrations/wecomCheckinArchive");
const SENSITIVE_USER_ID = ["checkin", "archive", "full", "userid", "should", "not", "leak"].join("_");
describe("wecomCheckinArchive", () => {
it("builds daily summaries from normalized records without raw payload fields", () => {
const summaries = buildDailySummaries([
{
employee_id: "employee-1",
external_user_id: SENSITIVE_USER_ID,
checkin_time: new Date("2026-05-20T01:00:00.000Z"),
checkin_date: new Date("2026-05-20T00:00:00.000Z"),
checkin_type: "OnDuty",
exception_type: "",
source_type: "app",
result: "normal",
raw_hash: "a".repeat(64),
},
{
employee_id: "employee-1",
external_user_id: SENSITIVE_USER_ID,
checkin_time: new Date("2026-05-20T10:00:00.000Z"),
checkin_date: new Date("2026-05-20T00:00:00.000Z"),
checkin_type: "OffDuty",
exception_type: "late",
source_type: "app",
result: "exception",
raw_hash: "b".repeat(64),
},
]);
expect(summaries).toHaveLength(1);
expect(summaries[0]).toMatchObject({
employee_id: "employee-1",
external_user_id_prefix: "chec***",
record_count: 2,
exception_count: 1,
abnormal_count: 1,
});
expect(summaries[0].checkin_type_summary).toEqual({ OnDuty: 1, OffDuty: 1 });
expect(JSON.stringify(summaries)).not.toContain(SENSITIVE_USER_ID);
});
it("builds monthly summaries from daily summaries", () => {
const daily = buildDailySummaries([
{
employee_id: "employee-1",
external_user_id: SENSITIVE_USER_ID,
checkin_time: new Date("2026-05-19T01:00:00.000Z"),
checkin_date: new Date("2026-05-19T00:00:00.000Z"),
checkin_type: "OnDuty",
result: "normal",
raw_hash: "a".repeat(64),
},
{
employee_id: "employee-1",
external_user_id: SENSITIVE_USER_ID,
checkin_time: new Date("2026-05-20T01:00:00.000Z"),
checkin_date: new Date("2026-05-20T00:00:00.000Z"),
checkin_type: "OnDuty",
result: "normal",
raw_hash: "b".repeat(64),
},
]);
const monthly = buildMonthlySummaries(daily, { expectedWorkdaysByMonth: { "2026-05": 3 } });
expect(monthly).toHaveLength(1);
expect(monthly[0]).toMatchObject({
employee_id: "employee-1",
month: "2026-05",
summary_day_count: 2,
checkin_day_count: 2,
missing_day_candidate_count: 1,
});
});
it("summarizes rule snapshots without location, face, device or raw payload", () => {
const employeeByExternalUserId = new Map([[SENSITIVE_USER_ID, { id: "employee-1" }]]);
const snapshots = buildRuleSnapshots({
snapshotDate: "2026-05-20",
employeeByExternalUserId,
rules: [
{
userid: SENSITIVE_USER_ID,
groupname: { text: "默认规则" },
checkin_time: [{ work_sec: 32400 }],
loc_infos: [{ lat: 30, lng: 120 }],
deviceid: "sensitive-device",
face: "sensitive-face",
},
],
});
expect(snapshots).toHaveLength(1);
expect(snapshots[0].employee_id).toBe("employee-1");
expect(snapshots[0].external_user_id_prefix).toBe(maskExternalUserId(SENSITIVE_USER_ID));
const text = JSON.stringify(snapshots);
expect(text).not.toContain(SENSITIVE_USER_ID);
expect(text).not.toContain("sensitive-device");
expect(text).not.toContain("sensitive-face");
expect(text).not.toContain("loc_infos");
});
it("sanitizes daily rows for reports", () => {
const sanitized = sanitizeDailySummary({
employee_id: "employee-1",
external_user_id_prefix: "chec***",
checkin_date: new Date("2026-05-20T00:00:00.000Z"),
record_count: 1,
first_checkin_at: new Date("2026-05-20T01:00:00.000Z"),
last_checkin_at: new Date("2026-05-20T01:00:00.000Z"),
exception_count: 0,
abnormal_count: 0,
result_summary: { normal: 1 },
raw_hash_digest: "a".repeat(64),
});
expect(sanitized).toMatchObject({
employeeId: "employee-1",
userIdPrefix: "chec***",
checkinDate: "2026-05-20",
rawHashDigestPrefix: "aaaaaaaaaaaa...",
});
});
it("masks short external user ids without exposing the full value", () => {
expect(maskExternalUserId("ABCD")).toBe("A***");
expect(maskExternalUserId("SMOKE002")).toBe("SM***");
expect(maskExternalUserId("SMOKE002X")).toBe("SMOK***");
});
it("filters sensitive rule keys from summaries", () => {
const summary = summarizeRuleOption({
userid: SENSITIVE_USER_ID,
loc_info: "must-not-appear",
device: "must-not-appear",
face: "must-not-appear",
groupname: "默认规则",
});
const text = JSON.stringify(summary);
expect(text).not.toContain("loc_info");
expect(text).not.toContain("device");
expect(text).not.toContain("face");
});
});