import { getRoles } from './patreonTiers'; // adjust path as needed import { PatreonUserResponse } from '../types'; import { expect, it, describe } from 'vitest' const baseUserData = { id: "user1", type: "user", attributes: { about: null, created: new Date().toISOString(), email: "test@example.com", first_name: "Test", full_name: "Test User", image_url: "https://example.com/image.jpg", last_name: "User", thumb_url: "https://example.com/thumb.jpg", url: "https://patreon.com/test", vanity: "testuser" }, relationships: { memberships: { data: [{ id: "member1", type: "member" }] } } }; const baseLinks = { self: "https://www.patreon.com/api/user" }; describe('getRoles', () => { it('returns roles for entitled tiers plus user', () => { const res: PatreonUserResponse = { data: baseUserData, included: [ { id: "member1", type: "member", attributes: {}, relationships: { currently_entitled_tiers: { data: [ { id: "8154170", type: "tier" }, // ArchiveSupporter { id: "9561793", type: "tier" } // StealthSupporter ] } } } ], links: baseLinks }; const roles = getRoles(res); expect(roles).toContain("user"); expect(roles).toContain("supporterTier1"); expect(roles.length).toBe(2); }); it('returns only user if there are no entitled tiers', () => { const res: PatreonUserResponse = { data: baseUserData, included: [ { id: "member1", type: "member", attributes: {}, relationships: { currently_entitled_tiers: { data: [] } } } ], links: baseLinks }; const roles = getRoles(res); expect(roles).toEqual(["user"]); }); it('returns only user if no included members are found', () => { const res: PatreonUserResponse = { data: { ...baseUserData, relationships: { memberships: { data: [] } } }, included: [], links: baseLinks }; const roles = getRoles(res); expect(roles).toEqual(["user"]); }); it('ignores unknown tier IDs', () => { const res: PatreonUserResponse = { data: baseUserData, included: [ { id: "member1", type: "member", attributes: {}, relationships: { currently_entitled_tiers: { data: [ { id: "9999999", type: "tier" }, // unknown tier { id: "8686022", type: "tier" } // LuberPlusPlus ] } } } ], links: baseLinks }; const roles = getRoles(res); expect(roles).toContain("user"); expect(roles).toContain("supporterTier6"); expect(roles.length).toBe(2); }); it('deduplicates roles from overlapping tiers', () => { const res: PatreonUserResponse = { data: baseUserData, included: [ { id: "member1", type: "member", attributes: {}, relationships: { currently_entitled_tiers: { data: [ { id: "22529959", type: "tier" }, // MaxQ { id: "8154171", type: "tier" } // ArchiveCollector ] } } } ], links: baseLinks }; const roles = getRoles(res); expect(roles).toContain("user"); expect(roles).toContain("supporterTier3"); expect(roles).toContain("supporterTier4"); expect(roles.length).toBe(3); }); it('handles multiple members correctly', () => { const res: PatreonUserResponse = { data: { ...baseUserData, relationships: { memberships: { data: [ { id: "member1", type: "member" }, { id: "member2", type: "member" } ] } } }, included: [ { id: "member1", type: "member", attributes: {}, relationships: { currently_entitled_tiers: { data: [{ id: "8154170", type: "tier" }] // ArchiveSupporter } } }, { id: "member2", type: "member", attributes: {}, relationships: { currently_entitled_tiers: { data: [{ id: "9560538", type: "tier" }] // SneakyQuantumSupporter } } } ], links: baseLinks }; const roles = getRoles(res); expect(roles).toContain("user"); expect(roles).toContain("supporterTier1"); expect(roles).toContain("supporterTier5"); expect(roles.length).toBe(3); }); });