forked from baron/baron-sso
591 lines
17 KiB
TypeScript
591 lines
17 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
buildWorksmobilePasswordManageUrl,
|
|
canCreateWorksmobileRow,
|
|
canOpenWorksmobilePasswordManage,
|
|
canSelectWorksmobileRow,
|
|
comparisonFilterOptions,
|
|
filterVisibleWorksmobileComparisonRows,
|
|
filterWorksmobileComparisonRows,
|
|
filterWorksmobileComparisonRowsBySearch,
|
|
formatWorksmobileOrgDetails,
|
|
formatWorksmobilePersonName,
|
|
formatWorksmobileUpdateDetails,
|
|
getDefaultGroupComparisonFilters,
|
|
getDefaultUserComparisonFilters,
|
|
getDefaultWorksmobileComparisonColumns,
|
|
getWorksmobileComparisonStatusLabel,
|
|
getWorksmobileRowSelectionKey,
|
|
getWorksmobileSelectedActionIds,
|
|
getWorksmobileSelectedMissingExternalKeyOrgUnitIds,
|
|
getWorksmobileSelectedWorksOnlyOrgUnitIds,
|
|
isImmutableWorksmobileAccount,
|
|
summarizeWorksmobileComparison,
|
|
userFilterOptions,
|
|
} from "./worksmobileComparison";
|
|
|
|
describe("TenantWorksmobilePage comparison helpers", () => {
|
|
it("summarizes comparison rows by status", () => {
|
|
const summary = summarizeWorksmobileComparison([
|
|
{ resourceType: "USER", status: "matched" },
|
|
{ resourceType: "GROUP", status: "needs_update" },
|
|
{ resourceType: "USER", status: "missing_in_worksmobile" },
|
|
{ resourceType: "USER", status: "missing_in_baron" },
|
|
{ resourceType: "USER", status: "missing_external_key" },
|
|
{ resourceType: "USER", status: "missing_in_baron" },
|
|
]);
|
|
|
|
expect(summary).toEqual({
|
|
total: 6,
|
|
matched: 1,
|
|
needsUpdate: 1,
|
|
missingInWorksmobile: 1,
|
|
missingInBaron: 2,
|
|
missingExternalKey: 1,
|
|
});
|
|
});
|
|
|
|
it("returns Korean labels for known comparison statuses", () => {
|
|
expect(getWorksmobileComparisonStatusLabel("matched")).toBe("일치");
|
|
expect(getWorksmobileComparisonStatusLabel("missing_in_worksmobile")).toBe(
|
|
"WORKS 없음",
|
|
);
|
|
expect(getWorksmobileComparisonStatusLabel("missing_in_baron")).toBe(
|
|
"Baron 없음",
|
|
);
|
|
expect(getWorksmobileComparisonStatusLabel("missing_external_key")).toBe(
|
|
"ex_key 없음",
|
|
);
|
|
expect(getWorksmobileComparisonStatusLabel("needs_update")).toBe(
|
|
"업데이트 필요",
|
|
);
|
|
expect(getWorksmobileComparisonStatusLabel("unknown_status")).toBe(
|
|
"unknown_status",
|
|
);
|
|
});
|
|
|
|
it("allows WORKS creation only for Baron rows missing in WORKS", () => {
|
|
expect(
|
|
canCreateWorksmobileRow({
|
|
resourceType: "USER",
|
|
status: "missing_in_worksmobile",
|
|
baronId: "user-1",
|
|
}),
|
|
).toBe(true);
|
|
|
|
expect(
|
|
canCreateWorksmobileRow({
|
|
resourceType: "USER",
|
|
status: "missing_in_worksmobile",
|
|
}),
|
|
).toBe(false);
|
|
|
|
expect(
|
|
canCreateWorksmobileRow({
|
|
resourceType: "USER",
|
|
status: "missing_in_baron",
|
|
worksmobileId: "works-user-1",
|
|
}),
|
|
).toBe(false);
|
|
});
|
|
|
|
it("allows selection for Baron-only, WORKS-only, and matched rows", () => {
|
|
expect(
|
|
canSelectWorksmobileRow({
|
|
resourceType: "USER",
|
|
status: "missing_in_worksmobile",
|
|
baronId: "user-1",
|
|
}),
|
|
).toBe(true);
|
|
expect(
|
|
canSelectWorksmobileRow({
|
|
resourceType: "USER",
|
|
status: "missing_in_baron",
|
|
worksmobileId: "works-user-1",
|
|
}),
|
|
).toBe(true);
|
|
expect(
|
|
canSelectWorksmobileRow({
|
|
resourceType: "USER",
|
|
status: "matched",
|
|
baronId: "user-2",
|
|
worksmobileId: "works-user-2",
|
|
}),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("does not allow selection for immutable WORKS accounts", () => {
|
|
expect(
|
|
isImmutableWorksmobileAccount({
|
|
resourceType: "USER",
|
|
status: "missing_in_baron",
|
|
worksmobileEmail: "cyhan@samaneng.com",
|
|
worksmobileId: "works-cyhan",
|
|
}),
|
|
).toBe(true);
|
|
expect(
|
|
canSelectWorksmobileRow({
|
|
resourceType: "USER",
|
|
status: "missing_in_baron",
|
|
worksmobileEmail: "CYHAN1@HANMACENG.CO.KR",
|
|
worksmobileId: "works-cyhan1",
|
|
}),
|
|
).toBe(false);
|
|
expect(
|
|
canSelectWorksmobileRow({
|
|
resourceType: "USER",
|
|
status: "missing_in_baron",
|
|
worksmobileEmail: "normal@samaneng.com",
|
|
worksmobileId: "works-normal",
|
|
}),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("does not allow password management for immutable WORKS accounts", () => {
|
|
expect(
|
|
canOpenWorksmobilePasswordManage(
|
|
{
|
|
resourceType: "USER",
|
|
status: "missing_in_baron",
|
|
worksmobileEmail: "su-@samaneng.com",
|
|
worksmobileDomainId: 300285955,
|
|
worksmobileId: "works-su",
|
|
},
|
|
"works-tenant-1",
|
|
),
|
|
).toBe(false);
|
|
});
|
|
|
|
it("hides protected WORKS member accounts from comparison lists", () => {
|
|
const rows = [
|
|
{
|
|
resourceType: "USER",
|
|
status: "missing_in_baron",
|
|
worksmobileEmail: "su-@samaneng.com",
|
|
worksmobileId: "works-su",
|
|
},
|
|
{
|
|
resourceType: "USER",
|
|
status: "matched",
|
|
baronEmail: "CYHAN1@HANMACENG.CO.KR",
|
|
baronId: "baron-cyhan1",
|
|
worksmobileEmail: "cyhan1@hanmaceng.co.kr",
|
|
worksmobileId: "works-cyhan1",
|
|
},
|
|
{
|
|
resourceType: "USER",
|
|
status: "missing_in_baron",
|
|
worksmobileEmail: "normal@samaneng.com",
|
|
worksmobileId: "works-normal",
|
|
},
|
|
{
|
|
resourceType: "GROUP",
|
|
status: "missing_in_baron",
|
|
worksmobileEmail: "su-@samaneng.com",
|
|
worksmobileId: "works-group",
|
|
},
|
|
];
|
|
|
|
expect(filterVisibleWorksmobileComparisonRows(rows)).toEqual([
|
|
rows[2],
|
|
rows[3],
|
|
]);
|
|
});
|
|
|
|
it("keeps row selection keys separate from Baron action ids", () => {
|
|
const rows = [
|
|
{
|
|
resourceType: "USER",
|
|
status: "missing_in_worksmobile",
|
|
baronId: "baron-only",
|
|
},
|
|
{
|
|
resourceType: "USER",
|
|
status: "missing_in_baron",
|
|
worksmobileId: "works-only",
|
|
},
|
|
{
|
|
resourceType: "USER",
|
|
status: "matched",
|
|
baronId: "matched-baron",
|
|
worksmobileId: "matched-works",
|
|
},
|
|
];
|
|
|
|
const selectedKeys = rows.map(getWorksmobileRowSelectionKey);
|
|
|
|
expect(selectedKeys).toEqual([
|
|
"USER:baron:baron-only",
|
|
"USER:works:works-only",
|
|
"USER:baron:matched-baron",
|
|
]);
|
|
expect(getWorksmobileSelectedActionIds(rows, selectedKeys)).toEqual([
|
|
"baron-only",
|
|
"matched-baron",
|
|
]);
|
|
});
|
|
|
|
it("uses compact comparison columns by default", () => {
|
|
expect(getDefaultWorksmobileComparisonColumns()).toEqual({
|
|
status: true,
|
|
baronId: false,
|
|
baron: true,
|
|
baronOrg: true,
|
|
worksmobileId: false,
|
|
externalKey: false,
|
|
worksmobileDomain: true,
|
|
worksmobile: true,
|
|
worksmobileOrg: true,
|
|
manage: true,
|
|
});
|
|
});
|
|
|
|
it("filters user comparison rows by selected relationship", () => {
|
|
const rows = [
|
|
{
|
|
resourceType: "USER",
|
|
status: "missing_in_worksmobile",
|
|
baronId: "baron-only",
|
|
baronName: "Baron only",
|
|
},
|
|
{
|
|
resourceType: "USER",
|
|
status: "missing_in_baron",
|
|
worksmobileId: "works-only",
|
|
worksmobileName: "WORKS only",
|
|
},
|
|
{
|
|
resourceType: "USER",
|
|
status: "matched",
|
|
baronId: "matched",
|
|
worksmobileId: "works-matched",
|
|
},
|
|
{
|
|
resourceType: "USER",
|
|
status: "missing_external_key",
|
|
worksmobileId: "missing-external-key",
|
|
},
|
|
];
|
|
|
|
expect(filterWorksmobileComparisonRows(rows, ["baron_only"])).toEqual([
|
|
rows[0],
|
|
]);
|
|
expect(filterWorksmobileComparisonRows(rows, ["works_only"])).toEqual([
|
|
rows[1],
|
|
rows[3],
|
|
]);
|
|
expect(filterWorksmobileComparisonRows(rows, ["matched"])).toEqual([
|
|
rows[2],
|
|
]);
|
|
expect(
|
|
filterWorksmobileComparisonRows(rows, ["baron_only", "works_only"]),
|
|
).toEqual([rows[0], rows[1], rows[3]]);
|
|
expect(filterWorksmobileComparisonRows(rows, [], true)).toEqual([]);
|
|
expect(filterWorksmobileComparisonRows(rows, [])).toEqual([]);
|
|
expect(
|
|
filterWorksmobileComparisonRows(rows, [
|
|
"baron_only",
|
|
"works_only",
|
|
"matched",
|
|
]),
|
|
).toEqual(rows);
|
|
expect(
|
|
filterWorksmobileComparisonRows(
|
|
rows,
|
|
["baron_only", "works_only", "matched"],
|
|
true,
|
|
),
|
|
).toEqual([rows[0], rows[2], rows[3]]);
|
|
});
|
|
|
|
it("narrows works-only rows to missing external key rows from the detail filter", () => {
|
|
const rows = [
|
|
{
|
|
resourceType: "GROUP",
|
|
status: "missing_in_worksmobile",
|
|
baronId: "baron-only",
|
|
baronName: "Baron only",
|
|
},
|
|
{
|
|
resourceType: "GROUP",
|
|
status: "missing_in_baron",
|
|
worksmobileId: "works-only",
|
|
worksmobileName: "WORKS only",
|
|
},
|
|
{
|
|
resourceType: "GROUP",
|
|
status: "missing_external_key",
|
|
worksmobileId: "missing-external-key",
|
|
},
|
|
{
|
|
resourceType: "GROUP",
|
|
status: "matched",
|
|
baronId: "matched",
|
|
worksmobileId: "works-matched",
|
|
},
|
|
];
|
|
|
|
expect(
|
|
filterWorksmobileComparisonRows(rows, ["works_only"], false),
|
|
).toEqual([rows[1], rows[2]]);
|
|
expect(filterWorksmobileComparisonRows(rows, ["works_only"], true)).toEqual(
|
|
[rows[2]],
|
|
);
|
|
expect(filterWorksmobileComparisonRows(rows, [], true)).toEqual([]);
|
|
expect(filterWorksmobileComparisonRows(rows, ["baron_only"], true)).toEqual(
|
|
[rows[0]],
|
|
);
|
|
});
|
|
|
|
it("filters comparison rows by names and identifiers in real time", () => {
|
|
const rows = [
|
|
{
|
|
resourceType: "USER",
|
|
status: "matched",
|
|
baronId: "baron-user-uuid",
|
|
baronName: "홍길동",
|
|
worksmobileName: "Hong Gildong",
|
|
},
|
|
{
|
|
resourceType: "GROUP",
|
|
status: "missing_external_key",
|
|
worksmobileId: "works-org-uuid",
|
|
worksmobileName: "기술연구소",
|
|
worksmobileParentName: "한맥가족",
|
|
},
|
|
{
|
|
resourceType: "GROUP",
|
|
status: "missing_in_worksmobile",
|
|
baronId: "baron-org-uuid",
|
|
baronSlug: "baron-group-design",
|
|
baronName: "디자인팀",
|
|
},
|
|
];
|
|
|
|
expect(filterWorksmobileComparisonRowsBySearch(rows, "")).toEqual(rows);
|
|
expect(filterWorksmobileComparisonRowsBySearch(rows, "홍길동")).toEqual([
|
|
rows[0],
|
|
]);
|
|
expect(filterWorksmobileComparisonRowsBySearch(rows, "WORKS-ORG")).toEqual([
|
|
rows[1],
|
|
]);
|
|
expect(filterWorksmobileComparisonRowsBySearch(rows, "design")).toEqual([
|
|
rows[2],
|
|
]);
|
|
expect(filterWorksmobileComparisonRowsBySearch(rows, "없음")).toEqual([]);
|
|
});
|
|
|
|
it("returns only selected missing-external-key WORKS orgunit ids for delete", () => {
|
|
const rows = [
|
|
{
|
|
resourceType: "GROUP",
|
|
status: "missing_external_key",
|
|
worksmobileId: "works-missing-key",
|
|
},
|
|
{
|
|
resourceType: "GROUP",
|
|
status: "missing_in_baron",
|
|
worksmobileId: "works-only",
|
|
},
|
|
{
|
|
resourceType: "USER",
|
|
status: "missing_external_key",
|
|
worksmobileId: "works-user-missing-key",
|
|
},
|
|
];
|
|
|
|
expect(
|
|
getWorksmobileSelectedMissingExternalKeyOrgUnitIds(rows, [
|
|
getWorksmobileRowSelectionKey(rows[0]),
|
|
getWorksmobileRowSelectionKey(rows[1]),
|
|
getWorksmobileRowSelectionKey(rows[2]),
|
|
]),
|
|
).toEqual(["works-missing-key"]);
|
|
});
|
|
|
|
it("returns selected WORKS-only orgunit ids for Baron SSOT cleanup", () => {
|
|
const rows = [
|
|
{
|
|
resourceType: "GROUP",
|
|
status: "missing_external_key",
|
|
worksmobileId: "works-missing-key",
|
|
},
|
|
{
|
|
resourceType: "GROUP",
|
|
status: "missing_in_baron",
|
|
worksmobileId: "works-only",
|
|
externalKey: "legacy-external-key",
|
|
},
|
|
{
|
|
resourceType: "GROUP",
|
|
status: "matched",
|
|
baronId: "baron-matched",
|
|
worksmobileId: "works-matched",
|
|
},
|
|
];
|
|
|
|
expect(
|
|
getWorksmobileSelectedWorksOnlyOrgUnitIds(
|
|
rows,
|
|
rows.map(getWorksmobileRowSelectionKey),
|
|
),
|
|
).toEqual(["works-missing-key", "works-only"]);
|
|
});
|
|
|
|
it("orders user comparison filter options from Baron-only first", () => {
|
|
expect(userFilterOptions.map((option) => option.value)).toEqual([
|
|
"baron_only",
|
|
"needs_update",
|
|
"works_only",
|
|
"matched",
|
|
]);
|
|
});
|
|
|
|
it("keeps all organization/group comparison filter labels available", () => {
|
|
expect(comparisonFilterOptions).toEqual([
|
|
{ value: "baron_only", label: "바론에만 있음" },
|
|
{ value: "needs_update", label: "업데이트 필요" },
|
|
{ value: "works_only", label: "웍스에만 있음" },
|
|
{ value: "matched", label: "양쪽 다 있음" },
|
|
]);
|
|
});
|
|
|
|
it("shows update-needed group rows by default", () => {
|
|
const rows = [
|
|
{ resourceType: "GROUP", status: "needs_update", baronId: "org-1" },
|
|
{ resourceType: "GROUP", status: "matched", baronId: "org-2" },
|
|
];
|
|
|
|
expect(
|
|
filterWorksmobileComparisonRows(rows, getDefaultGroupComparisonFilters()),
|
|
).toEqual([rows[0]]);
|
|
});
|
|
|
|
it("shows update-needed user rows by default", () => {
|
|
const rows = [
|
|
{ resourceType: "USER", status: "needs_update", baronId: "user-1" },
|
|
{ resourceType: "USER", status: "matched", baronId: "user-2" },
|
|
];
|
|
|
|
expect(
|
|
filterWorksmobileComparisonRows(rows, getDefaultUserComparisonFilters()),
|
|
).toEqual([rows[0]]);
|
|
});
|
|
|
|
it("formats update details for changed organization rows", () => {
|
|
expect(
|
|
formatWorksmobileUpdateDetails({
|
|
resourceType: "GROUP",
|
|
status: "needs_update",
|
|
baronId: "818c856b-9545-442f-b827-d1c569f200b0",
|
|
baronName: "삼안기술개발센터(조직도용)",
|
|
worksmobileName: "기술개발센터(조직도용)",
|
|
baronParentId: "9caf62e1-297d-4e8f-870b-61780998bbeb",
|
|
baronParentWorksmobileId: "works-saman",
|
|
baronParentWorksmobileName: "삼안",
|
|
worksmobileParentId: "works-other",
|
|
worksmobileParentName: "다른 상위",
|
|
}),
|
|
).toEqual([
|
|
"이름: 기술개발센터(조직도용) -> 삼안기술개발센터(조직도용)",
|
|
"상위: 다른 상위 -> 삼안",
|
|
]);
|
|
});
|
|
|
|
it("formats WORKS account name with level on one line", () => {
|
|
expect(
|
|
formatWorksmobilePersonName({
|
|
resourceType: "USER",
|
|
status: "matched",
|
|
worksmobileName: "홍길동",
|
|
worksmobileLevelName: "책임",
|
|
}),
|
|
).toBe("홍길동 책임");
|
|
});
|
|
|
|
it("formats WORKS organization details with task and manager status", () => {
|
|
expect(
|
|
formatWorksmobileOrgDetails({
|
|
resourceType: "USER",
|
|
status: "matched",
|
|
worksmobileTask: "기술검토",
|
|
worksmobilePrimaryOrgPositionName: "팀장",
|
|
worksmobilePrimaryOrgIsManager: true,
|
|
}),
|
|
).toEqual(["직책 팀장", "직무 기술검토", "조직장"]);
|
|
});
|
|
|
|
it("builds the WORKS admin password management URL from remote user identifiers", () => {
|
|
const url = buildWorksmobilePasswordManageUrl({
|
|
tenantId: " works-tenant-1 ",
|
|
domainId: 300285955,
|
|
userIdNo: " works-user-1 ",
|
|
});
|
|
|
|
const parsed = new URL(url);
|
|
expect(parsed.origin + parsed.pathname).toBe(
|
|
"https://auth.worksmobile.com/integrate/password/manage",
|
|
);
|
|
expect(parsed.searchParams.get("usage")).toBe("admin");
|
|
expect(parsed.searchParams.get("targetUserTenantId")).toBe(
|
|
"works-tenant-1",
|
|
);
|
|
expect(parsed.searchParams.get("targetUserDomainId")).toBe("300285955");
|
|
expect(parsed.searchParams.get("targetUserIdNo")).toBe("works-user-1");
|
|
expect(parsed.searchParams.get("accessUrl")).toBe(
|
|
"https://admin.worksmobile.com/assets/self-close.html",
|
|
);
|
|
});
|
|
|
|
it("does not open WORKS password management without required identifiers", () => {
|
|
const row = {
|
|
resourceType: "USER",
|
|
status: "matched",
|
|
worksmobileDomainId: 300285955,
|
|
worksmobileId: "works-user-1",
|
|
};
|
|
|
|
expect(canOpenWorksmobilePasswordManage(row, "works-tenant-1")).toBe(true);
|
|
expect(canOpenWorksmobilePasswordManage(row, undefined)).toBe(false);
|
|
expect(
|
|
canOpenWorksmobilePasswordManage(
|
|
{ ...row, worksmobileDomainId: undefined },
|
|
"works-tenant-1",
|
|
),
|
|
).toBe(false);
|
|
expect(
|
|
canOpenWorksmobilePasswordManage(
|
|
{ ...row, worksmobileId: undefined },
|
|
"works-tenant-1",
|
|
),
|
|
).toBe(false);
|
|
expect(
|
|
canOpenWorksmobilePasswordManage(
|
|
{ ...row, resourceType: "GROUP" },
|
|
"works-tenant-1",
|
|
),
|
|
).toBe(false);
|
|
expect(
|
|
buildWorksmobilePasswordManageUrl({
|
|
tenantId: "works-tenant-1",
|
|
domainId: 0,
|
|
userIdNo: "works-user-1",
|
|
}),
|
|
).toBe("");
|
|
});
|
|
|
|
it("allows WORKS password management for WORKS-only user rows", () => {
|
|
expect(
|
|
canOpenWorksmobilePasswordManage(
|
|
{
|
|
resourceType: "USER",
|
|
status: "missing_in_baron",
|
|
worksmobileDomainId: 300285955,
|
|
worksmobileId: "works-user-1",
|
|
},
|
|
"works-tenant-1",
|
|
),
|
|
).toBe(true);
|
|
});
|
|
});
|