153 行
5.0 KiB
JavaScript
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");
|
|
});
|
|
});
|