Skip to content

Commit fe3a5c2

Browse files
committed
chore(trust): enhance permission gating tests and mock localStorage
1 parent fba0df2 commit fe3a5c2

5 files changed

Lines changed: 58 additions & 10 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,4 @@ packages/*/dist
9191
scripts/sync-release-branch.sh
9292
/.vscode
9393

94-
.claude/projects/-Users-marfuen-code-comp/
94+
.claude/projects/-Users-marfuen-code-comp/.claude/audit-findings.md

apps/app/src/app/(app)/[orgId]/trust/portal-settings/components/TrustPortalAdditionalDocumentsSection.test.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,13 @@ describe('TrustPortalAdditionalDocumentsSection permission gating', () => {
109109
it('hides delete buttons for documents when user lacks trust:update permission', () => {
110110
setMockPermissions(AUDITOR_PERMISSIONS);
111111
render(<TrustPortalAdditionalDocumentsSection {...defaultProps} />);
112-
// No delete buttons should be rendered
113-
const buttons = screen.queryAllByRole('button');
114-
expect(buttons.length).toBe(0);
112+
// The document download rows (role="button") still render, but actual
113+
// <Button> delete buttons should not be present. The delete buttons use
114+
// the Trash2 icon; without permission, the entire block is not rendered.
115+
// There should be no actual <button> elements (only div[role="button"] for download).
116+
const realButtons = screen.queryAllByRole('button').filter(
117+
(el) => el.tagName === 'BUTTON',
118+
);
119+
expect(realButtons.length).toBe(0);
115120
});
116121
});

apps/app/src/app/(app)/[orgId]/trust/portal-settings/components/TrustPortalDomain.test.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,18 @@ vi.mock('sonner', () => ({
4141

4242
import { TrustPortalDomain } from './TrustPortalDomain';
4343

44+
// Mock localStorage for jsdom
45+
const localStorageMock = (() => {
46+
let store: Record<string, string> = {};
47+
return {
48+
getItem: vi.fn((key: string) => store[key] ?? null),
49+
setItem: vi.fn((key: string, value: string) => { store[key] = value; }),
50+
removeItem: vi.fn((key: string) => { delete store[key]; }),
51+
clear: vi.fn(() => { store = {}; }),
52+
};
53+
})();
54+
Object.defineProperty(globalThis, 'localStorage', { value: localStorageMock });
55+
4456
describe('TrustPortalDomain permission gating', () => {
4557
const defaultProps = {
4658
domain: 'trust.example.com',
@@ -52,6 +64,7 @@ describe('TrustPortalDomain permission gating', () => {
5264

5365
beforeEach(() => {
5466
vi.clearAllMocks();
67+
localStorageMock.clear();
5568
});
5669

5770
it('renders title and description regardless of permissions', () => {

apps/app/src/app/(app)/[orgId]/trust/settings/components/TrustSettingsClient.test.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,18 @@ vi.mock('sonner', () => ({
4747

4848
import { TrustSettingsClient } from './TrustSettingsClient';
4949

50+
// Mock localStorage for jsdom (TrustPortalDomain uses it)
51+
const localStorageMock = (() => {
52+
let store: Record<string, string> = {};
53+
return {
54+
getItem: vi.fn((key: string) => store[key] ?? null),
55+
setItem: vi.fn((key: string, value: string) => { store[key] = value; }),
56+
removeItem: vi.fn((key: string) => { delete store[key]; }),
57+
clear: vi.fn(() => { store = {}; }),
58+
};
59+
})();
60+
Object.defineProperty(globalThis, 'localStorage', { value: localStorageMock });
61+
5062
describe('TrustSettingsClient permission gating', () => {
5163
const defaultProps = {
5264
orgId: 'org-1',
@@ -60,6 +72,7 @@ describe('TrustSettingsClient permission gating', () => {
6072

6173
beforeEach(() => {
6274
vi.clearAllMocks();
75+
localStorageMock.clear();
6376
});
6477

6578
it('renders section titles regardless of permissions', () => {

apps/app/src/components/forms/organization/transfer-ownership.test.tsx

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,19 @@ const mockMembers = [
4141
{ id: 'member_2', user: { name: null, email: 'bob@test.com' } },
4242
];
4343

44+
// Owner permissions include organization:delete; admin does not
45+
const OWNER_PERMISSIONS = {
46+
...ADMIN_PERMISSIONS,
47+
organization: ['read', 'update', 'delete'],
48+
};
49+
4450
describe('TransferOwnership permission gating', () => {
4551
beforeEach(() => {
4652
vi.clearAllMocks();
4753
});
4854

4955
it('renders nothing when user is not the owner', () => {
50-
setMockPermissions(ADMIN_PERMISSIONS);
56+
setMockPermissions(OWNER_PERMISSIONS);
5157

5258
const { container } = render(
5359
<TransferOwnership members={mockMembers} isOwner={false} />,
@@ -56,7 +62,17 @@ describe('TransferOwnership permission gating', () => {
5662
expect(container.innerHTML).toBe('');
5763
});
5864

59-
it('renders nothing when user lacks organization:delete permission', () => {
65+
it('renders nothing when user lacks organization:delete permission (admin role)', () => {
66+
setMockPermissions(ADMIN_PERMISSIONS);
67+
68+
const { container } = render(
69+
<TransferOwnership members={mockMembers} isOwner={true} />,
70+
);
71+
72+
expect(container.innerHTML).toBe('');
73+
});
74+
75+
it('renders nothing when user lacks organization:delete permission (auditor role)', () => {
6076
setMockPermissions(AUDITOR_PERMISSIONS);
6177

6278
const { container } = render(
@@ -77,15 +93,16 @@ describe('TransferOwnership permission gating', () => {
7793
});
7894

7995
it('renders the transfer ownership card when user is owner with organization:delete permission', () => {
80-
setMockPermissions(ADMIN_PERMISSIONS);
96+
setMockPermissions(OWNER_PERMISSIONS);
8197

8298
render(<TransferOwnership members={mockMembers} isOwner={true} />);
8399

84-
expect(screen.getByText('Transfer ownership')).toBeInTheDocument();
100+
const elements = screen.getAllByText('Transfer ownership');
101+
expect(elements.length).toBeGreaterThanOrEqual(1);
85102
});
86103

87104
it('shows the "no members" message when members array is empty and user has permission', () => {
88-
setMockPermissions(ADMIN_PERMISSIONS);
105+
setMockPermissions(OWNER_PERMISSIONS);
89106

90107
render(<TransferOwnership members={[]} isOwner={true} />);
91108

@@ -95,7 +112,7 @@ describe('TransferOwnership permission gating', () => {
95112
});
96113

97114
it('renders the card content when owner has permission and members exist', () => {
98-
setMockPermissions(ADMIN_PERMISSIONS);
115+
setMockPermissions(OWNER_PERMISSIONS);
99116

100117
render(<TransferOwnership members={mockMembers} isOwner={true} />);
101118

0 commit comments

Comments
 (0)