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); }); });