/** * Tests for claims mapping utilities */ import { mapClaimsToProfile, extractCustomClaims } from "../../src/utils/claims-mapper"; describe("claims-mapper", () => { describe("mapClaimsToProfile", () => { it("should map standard OIDC claims to profile", () => { const claims = { sub: "user-123", email: "test@example.com", email_verified: true, name: "Test User", given_name: "Test", family_name: "User", preferred_username: "testuser", picture: "https://example.com/photo.jpg", phone_number: "+1234567890", }; const profile = mapClaimsToProfile(claims); expect(profile.id).toBe("user-123"); expect(profile.email).toBe("test@example.com"); expect(profile.emailVerified).toBe(true); expect(profile.name).toBe("Test User"); expect(profile.givenName).toBe("Test"); expect(profile.familyName).toBe("User"); expect(profile.username).toBe("testuser"); expect(profile.picture).toBe("https://example.com/photo.jpg"); expect(profile.phoneNumber).toBe("+1234567890"); }); it("should handle minimal claims (only sub and email)", () => { const claims = { sub: "user-456", email: "minimal@example.com", }; const profile = mapClaimsToProfile(claims); expect(profile.id).toBe("user-456"); expect(profile.email).toBe("minimal@example.com"); expect(profile.emailVerified).toBeUndefined(); expect(profile.name).toBeUndefined(); expect(profile.givenName).toBeUndefined(); expect(profile.familyName).toBeUndefined(); }); it("should include all raw claims", () => { const claims = { sub: "user-789", email: "test@example.com", custom_field: "custom_value", another_field: 123, }; const profile = mapClaimsToProfile(claims); expect(profile.raw).toEqual(claims); expect(profile.raw.custom_field).toBe("custom_value"); expect(profile.raw.another_field).toBe(123); }); it("should handle missing email", () => { const claims = { sub: "user-000", }; const profile = mapClaimsToProfile(claims); expect(profile.id).toBe("user-000"); expect(profile.email).toBeUndefined(); }); it("should pass through email_verified as-is", () => { const claims1 = { sub: "user-111", email: "test@example.com", email_verified: "true" as any, }; const profile1 = mapClaimsToProfile(claims1); expect(profile1.emailVerified).toBe("true" as any); const claims2 = { sub: "user-222", email: "test@example.com", email_verified: true, }; const profile2 = mapClaimsToProfile(claims2); expect(profile2.emailVerified).toBe(true); }); it("should use email as fallback for missing preferred_username", () => { const claims = { sub: "user-333", email: "username@example.com", }; const profile = mapClaimsToProfile(claims); // Should not set username if preferred_username is missing expect(profile.username).toBeUndefined(); }); }); describe("extractCustomClaims", () => { it("should extract custom claims using mapping", () => { const claims = { sub: "user-123", email: "test@example.com", organization_id: "org-456", department: "Engineering", employee_id: "EMP-789", }; const claimMapping = { organizationId: "organization_id", department: "department", employeeId: "employee_id", }; const customClaims = extractCustomClaims(claims, claimMapping); expect(customClaims.organizationId).toBe("org-456"); expect(customClaims.department).toBe("Engineering"); expect(customClaims.employeeId).toBe("EMP-789"); }); it("should handle nested claim paths with dot notation", () => { const claims = { sub: "user-123", email: "test@example.com", "custom:org": { id: "org-456", name: "ACME Corp", }, roles: ["admin", "user"], }; const claimMapping = { organizationId: "custom:org.id", organizationName: "custom:org.name", roles: "roles", }; const customClaims = extractCustomClaims(claims, claimMapping); expect(customClaims.organizationId).toBe("org-456"); expect(customClaims.organizationName).toBe("ACME Corp"); expect(customClaims.roles).toEqual(["admin", "user"]); }); it("should return undefined for missing claims", () => { const claims = { sub: "user-123", email: "test@example.com", }; const claimMapping = { organizationId: "organization_id", missingField: "does_not_exist", }; const customClaims = extractCustomClaims(claims, claimMapping); expect(customClaims.organizationId).toBeUndefined(); expect(customClaims.missingField).toBeUndefined(); }); it("should handle empty claim mapping", () => { const claims = { sub: "user-123", email: "test@example.com", }; const customClaims = extractCustomClaims(claims, {}); expect(customClaims).toEqual({}); }); it("should preserve data types", () => { const claims = { sub: "user-123", email: "test@example.com", age: 30, active: true, roles: ["admin", "user"], metadata: { key: "value" }, }; const claimMapping = { age: "age", active: "active", roles: "roles", metadata: "metadata", }; const customClaims = extractCustomClaims(claims, claimMapping); expect(customClaims.age).toBe(30); expect(typeof customClaims.age).toBe("number"); expect(customClaims.active).toBe(true); expect(typeof customClaims.active).toBe("boolean"); expect(Array.isArray(customClaims.roles)).toBe(true); expect(typeof customClaims.metadata).toBe("object"); }); it("should handle array access in paths", () => { const claims = { sub: "user-123", email: "test@example.com", groups: [{ id: "group-1", name: "Admins" }, { id: "group-2", name: "Users" }], }; const claimMapping = { firstGroupId: "groups.0.id", firstGroupName: "groups.0.name", }; const customClaims = extractCustomClaims(claims, claimMapping); expect(customClaims.firstGroupId).toBe("group-1"); expect(customClaims.firstGroupName).toBe("Admins"); }); }); describe("integration: mapClaimsToProfile with extractCustomClaims", () => { it("should work together to create enriched profile", () => { const claims = { sub: "user-123", email: "test@example.com", name: "Test User", organization_id: "org-456", department: "Engineering", }; const claimMapping = { organizationId: "organization_id", department: "department", }; const customClaims = extractCustomClaims(claims, claimMapping); const enrichedClaims = { ...claims, ...customClaims }; const profile = mapClaimsToProfile(enrichedClaims); expect(profile.id).toBe("user-123"); expect(profile.email).toBe("test@example.com"); expect(profile.name).toBe("Test User"); expect(profile.raw.organizationId).toBe("org-456"); expect(profile.raw.department).toBe("Engineering"); }); }); });