General.utils.test.ts198 lines · main
| 1 | import { describe, expect, it } from 'vitest' |
| 2 | |
| 3 | import { summarizeProjectAccess } from './General.utils' |
| 4 | |
| 5 | const roles = { |
| 6 | org_scoped_roles: [ |
| 7 | { |
| 8 | id: 1, |
| 9 | name: 'Owner', |
| 10 | description: null, |
| 11 | base_role_id: 1, |
| 12 | projects: [], |
| 13 | }, |
| 14 | ], |
| 15 | project_scoped_roles: [ |
| 16 | { |
| 17 | id: 2, |
| 18 | name: 'Developer', |
| 19 | description: null, |
| 20 | base_role_id: 3, |
| 21 | projects: [{ name: 'Project A', ref: 'ref-a' }], |
| 22 | }, |
| 23 | ], |
| 24 | } as any |
| 25 | |
| 26 | describe('summarizeProjectAccess', () => { |
| 27 | it('includes org-scoped members for every project', () => { |
| 28 | const summary = summarizeProjectAccess({ |
| 29 | organizationMembers: [ |
| 30 | { |
| 31 | gotrue_id: 'owner-id', |
| 32 | username: 'Owner User', |
| 33 | primary_email: 'owner@example.com', |
| 34 | role_ids: [1], |
| 35 | } as any, |
| 36 | ], |
| 37 | roles, |
| 38 | projectRef: 'ref-a', |
| 39 | hasLimitedVisibility: false, |
| 40 | }) |
| 41 | |
| 42 | expect(summary.projectMemberCount).toBe(1) |
| 43 | expect(summary.projectMembers[0].email).toBe('owner@example.com') |
| 44 | expect(summary.projectMembers[0].role).toBe('Owner') |
| 45 | expect(summary.hasOrganizationWideAccess).toBe(true) |
| 46 | }) |
| 47 | |
| 48 | it('filters project-scoped members to the selected project', () => { |
| 49 | const summary = summarizeProjectAccess({ |
| 50 | organizationMembers: [ |
| 51 | { |
| 52 | gotrue_id: 'dev-visible', |
| 53 | username: 'Dev Visible', |
| 54 | primary_email: 'visible@example.com', |
| 55 | role_ids: [2], |
| 56 | } as any, |
| 57 | { |
| 58 | gotrue_id: 'dev-hidden', |
| 59 | username: 'Dev Hidden', |
| 60 | primary_email: 'hidden@example.com', |
| 61 | role_ids: [3], |
| 62 | } as any, |
| 63 | ], |
| 64 | roles: { |
| 65 | ...roles, |
| 66 | project_scoped_roles: [ |
| 67 | { |
| 68 | ...roles.project_scoped_roles[0], |
| 69 | projects: [{ name: 'Project A', ref: 'ref-a' }], |
| 70 | }, |
| 71 | { |
| 72 | ...roles.project_scoped_roles[0], |
| 73 | id: 3, |
| 74 | projects: [{ name: 'Project B', ref: 'ref-b' }], |
| 75 | }, |
| 76 | ], |
| 77 | } as any, |
| 78 | projectRef: 'ref-a', |
| 79 | hasLimitedVisibility: false, |
| 80 | }) |
| 81 | |
| 82 | expect(summary.projectMemberCount).toBe(1) |
| 83 | expect(summary.projectMembers[0].email).toBe('visible@example.com') |
| 84 | }) |
| 85 | |
| 86 | it('excludes invited members', () => { |
| 87 | const summary = summarizeProjectAccess({ |
| 88 | organizationMembers: [ |
| 89 | { |
| 90 | gotrue_id: 'member-id', |
| 91 | username: 'Member', |
| 92 | primary_email: 'member@example.com', |
| 93 | role_ids: [1], |
| 94 | } as any, |
| 95 | { |
| 96 | gotrue_id: 'invite-id', |
| 97 | username: 'invite', |
| 98 | primary_email: 'invite@example.com', |
| 99 | role_ids: [1], |
| 100 | invited_id: 123, |
| 101 | } as any, |
| 102 | ], |
| 103 | roles, |
| 104 | projectRef: 'ref-a', |
| 105 | hasLimitedVisibility: false, |
| 106 | }) |
| 107 | |
| 108 | expect(summary.organizationMemberCount).toBe(1) |
| 109 | expect(summary.projectMemberCount).toBe(1) |
| 110 | }) |
| 111 | |
| 112 | it('does not show org comparison in limited-visibility mode', () => { |
| 113 | const summary = summarizeProjectAccess({ |
| 114 | organizationMembers: [ |
| 115 | { |
| 116 | gotrue_id: 'member-id', |
| 117 | username: 'Member', |
| 118 | primary_email: 'member@example.com', |
| 119 | role_ids: [1], |
| 120 | } as any, |
| 121 | ], |
| 122 | roles, |
| 123 | projectRef: 'ref-a', |
| 124 | hasLimitedVisibility: true, |
| 125 | }) |
| 126 | |
| 127 | expect(summary.shouldShowOrgComparison).toBe(false) |
| 128 | expect(summary.hasOrganizationWideAccess).toBe(false) |
| 129 | }) |
| 130 | |
| 131 | it('caps visible members and tracks hidden count', () => { |
| 132 | const summary = summarizeProjectAccess({ |
| 133 | organizationMembers: [ |
| 134 | { |
| 135 | gotrue_id: '1', |
| 136 | username: 'A', |
| 137 | primary_email: 'a@example.com', |
| 138 | role_ids: [1], |
| 139 | } as any, |
| 140 | { |
| 141 | gotrue_id: '2', |
| 142 | username: 'B', |
| 143 | primary_email: 'b@example.com', |
| 144 | role_ids: [1], |
| 145 | } as any, |
| 146 | ], |
| 147 | roles, |
| 148 | projectRef: 'ref-a', |
| 149 | hasLimitedVisibility: false, |
| 150 | maxVisibleMembers: 1, |
| 151 | }) |
| 152 | |
| 153 | expect(summary.projectMemberCount).toBe(2) |
| 154 | expect(summary.visibleMembers).toHaveLength(1) |
| 155 | expect(summary.hiddenMembersCount).toBe(1) |
| 156 | }) |
| 157 | |
| 158 | it('places current user at the top of project members', () => { |
| 159 | const summary = summarizeProjectAccess({ |
| 160 | organizationMembers: [ |
| 161 | { |
| 162 | gotrue_id: 'alpha-id', |
| 163 | username: 'Alpha', |
| 164 | primary_email: 'alpha@example.com', |
| 165 | role_ids: [1], |
| 166 | } as any, |
| 167 | { |
| 168 | gotrue_id: 'current-user-id', |
| 169 | username: 'Current User', |
| 170 | primary_email: 'zeta@example.com', |
| 171 | role_ids: [1], |
| 172 | } as any, |
| 173 | { |
| 174 | gotrue_id: 'beta-id', |
| 175 | username: 'Beta', |
| 176 | primary_email: 'beta@example.com', |
| 177 | role_ids: [1], |
| 178 | } as any, |
| 179 | ], |
| 180 | roles, |
| 181 | projectRef: 'ref-a', |
| 182 | hasLimitedVisibility: false, |
| 183 | currentUserId: 'current-user-id', |
| 184 | maxVisibleMembers: 2, |
| 185 | }) |
| 186 | |
| 187 | expect(summary.projectMembers.map((member) => member.id)).toEqual([ |
| 188 | 'current-user-id', |
| 189 | 'alpha-id', |
| 190 | 'beta-id', |
| 191 | ]) |
| 192 | expect(summary.visibleMembers.map((member) => member.id)).toEqual([ |
| 193 | 'current-user-id', |
| 194 | 'alpha-id', |
| 195 | ]) |
| 196 | expect(summary.hiddenMembersCount).toBe(1) |
| 197 | }) |
| 198 | }) |