@jmruthers/pace-core 0.5.3 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DataTable-ZQDRE46Q.js → DataTable-3SSI644S.js} +2 -2
- package/dist/{chunk-M4RW7PIP.js → chunk-2BJFM2JC.js} +105 -81
- package/dist/chunk-2BJFM2JC.js.map +1 -0
- package/dist/{chunk-5H3C2SWM.js → chunk-RTCA5ZNK.js} +2 -2
- package/dist/components.js +2 -2
- package/dist/index.js +2 -2
- package/dist/styles/core.css +3 -0
- package/dist/utils.js +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +1 -1
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +1 -1
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +34 -34
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventContextType.md +1 -1
- package/docs/api/interfaces/EventLogoProps.md +1 -1
- package/docs/api/interfaces/EventProviderProps.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACContextType.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RBACProviderProps.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +3 -3
- package/docs/implementation-guides/data-tables.md +20 -0
- package/docs/quick-reference.md +9 -0
- package/docs/rbac/examples.md +4 -0
- package/package.json +1 -1
- package/src/__tests__/helpers/test-utils.tsx +147 -1
- package/src/components/DataTable/DataTable.tsx +20 -0
- package/src/components/DataTable/__tests__/DataTable.hooks.test 2.tsx +191 -0
- package/src/components/DataTable/__tests__/DataTable.hooks.test.tsx +191 -0
- package/src/components/DataTable/components/DataTableCore.tsx +167 -138
- package/src/components/Header/Header.test.tsx +1 -1
- package/src/components/OrganisationSelector/OrganisationSelector.test.tsx +1 -1
- package/src/hooks/__tests__/hooks.integration.test.tsx +575 -0
- package/src/hooks/__tests__/useApiFetch.unit.test.ts +115 -0
- package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +133 -0
- package/src/hooks/__tests__/useDebounce.unit.test.ts +82 -0
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +293 -0
- package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +385 -0
- package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +286 -0
- package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +838 -0
- package/src/hooks/__tests__/usePermissionCache.simple.test.ts +104 -0
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +633 -0
- package/src/hooks/__tests__/useRBAC.unit.test.ts +856 -0
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +537 -0
- package/src/hooks/__tests__/useToast.unit.test.tsx +62 -0
- package/src/hooks/__tests__/useZodForm.unit.test.tsx +37 -0
- package/src/rbac/api.test.ts +511 -0
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +843 -0
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +1007 -0
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +806 -0
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +741 -0
- package/src/rbac/hooks/useCan.test.ts +1 -1
- package/src/rbac/hooks/usePermissions.test.ts +10 -5
- package/src/rbac/hooks/useRBAC.test.ts +141 -93
- package/src/rbac/utils/__tests__/eventContext.test.ts +428 -0
- package/src/rbac/utils/__tests__/eventContext.unit.test.ts +428 -0
- package/src/styles/core.css +3 -0
- package/src/utils/__tests__/appConfig.unit.test.ts +55 -0
- package/src/utils/__tests__/audit.unit.test.ts +69 -0
- package/src/utils/__tests__/auth-utils.unit.test.ts +70 -0
- package/src/utils/__tests__/bundleAnalysis.unit.test.ts +317 -0
- package/src/utils/__tests__/cn.unit.test.ts +34 -0
- package/src/utils/__tests__/deviceFingerprint.unit.test.ts +503 -0
- package/src/utils/__tests__/dynamicUtils.unit.test.ts +322 -0
- package/src/utils/__tests__/formatDate.unit.test.ts +109 -0
- package/src/utils/__tests__/formatting.unit.test.ts +66 -0
- package/src/utils/__tests__/index.unit.test.ts +251 -0
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +309 -0
- package/src/utils/__tests__/organisationContext.unit.test.ts +192 -0
- package/src/utils/__tests__/performanceBudgets.unit.test.ts +259 -0
- package/src/utils/__tests__/permissionTypes.unit.test.ts +250 -0
- package/src/utils/__tests__/permissionUtils.unit.test.ts +362 -0
- package/src/utils/__tests__/sanitization.unit.test.ts +346 -0
- package/src/utils/__tests__/schemaUtils.unit.test.ts +441 -0
- package/src/utils/__tests__/secureDataAccess.unit.test.ts +334 -0
- package/src/utils/__tests__/secureErrors.unit.test.ts +377 -0
- package/src/utils/__tests__/secureStorage.unit.test.ts +293 -0
- package/src/utils/__tests__/security.unit.test.ts +127 -0
- package/src/utils/__tests__/securityMonitor.unit.test.ts +280 -0
- package/src/utils/__tests__/sessionTracking.unit.test.ts +356 -0
- package/src/utils/__tests__/validation.unit.test.ts +84 -0
- package/src/utils/__tests__/validationUtils.unit.test.ts +571 -0
- package/src/validation/__tests__/common.unit.test.ts +101 -0
- package/src/validation/__tests__/csrf.unit.test.ts +302 -0
- package/src/validation/__tests__/passwordSchema.unit.test 2.ts +98 -0
- package/src/validation/__tests__/passwordSchema.unit.test.ts +98 -0
- package/src/validation/__tests__/sqlInjectionProtection.unit.test.ts +466 -0
- package/dist/chunk-M4RW7PIP.js.map +0 -1
- /package/dist/{DataTable-ZQDRE46Q.js.map → DataTable-3SSI644S.js.map} +0 -0
- /package/dist/{chunk-5H3C2SWM.js.map → chunk-RTCA5ZNK.js.map} +0 -0
|
@@ -226,7 +226,9 @@ describe('usePermissions Hook', () => {
|
|
|
226
226
|
mockGetPermissionMap.mockImplementation(() => new Promise(() => {}));
|
|
227
227
|
result.current.refetch();
|
|
228
228
|
|
|
229
|
-
|
|
229
|
+
await waitFor(() => {
|
|
230
|
+
expect(result.current.isLoading).toBe(true);
|
|
231
|
+
}, { timeout: 1000 });
|
|
230
232
|
});
|
|
231
233
|
});
|
|
232
234
|
|
|
@@ -288,12 +290,15 @@ describe('usePermissions Hook', () => {
|
|
|
288
290
|
|
|
289
291
|
const { result } = renderHook(() => usePermissions(mockUserId, {} as any));
|
|
290
292
|
|
|
293
|
+
// Wait for the hook to complete loading
|
|
291
294
|
await waitFor(() => {
|
|
292
295
|
expect(result.current.isLoading).toBe(false);
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
296
|
+
}, { timeout: 20000 });
|
|
297
|
+
|
|
298
|
+
// Then check the API call
|
|
299
|
+
expect(mockGetPermissionMap).toHaveBeenCalledWith({
|
|
300
|
+
userId: mockUserId,
|
|
301
|
+
scope: {}
|
|
297
302
|
});
|
|
298
303
|
});
|
|
299
304
|
|
|
@@ -33,12 +33,22 @@ const mockSupabase = {
|
|
|
33
33
|
select: vi.fn(() => ({
|
|
34
34
|
eq: vi.fn(() => ({
|
|
35
35
|
eq: vi.fn(() => ({
|
|
36
|
-
single: vi.fn()
|
|
36
|
+
single: vi.fn().mockResolvedValue({ data: { global_role: 'user' }, error: null })
|
|
37
37
|
}))
|
|
38
38
|
}))
|
|
39
|
-
}))
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
}))
|
|
40
|
+
})),
|
|
41
|
+
rpc: vi.fn().mockResolvedValue({
|
|
42
|
+
data: [
|
|
43
|
+
{
|
|
44
|
+
permission_type: 'organisation_access',
|
|
45
|
+
role_name: 'user',
|
|
46
|
+
operation: 'read',
|
|
47
|
+
resource: 'users'
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
error: null
|
|
51
|
+
})
|
|
42
52
|
};
|
|
43
53
|
|
|
44
54
|
// Mock data
|
|
@@ -93,14 +103,25 @@ describe('useRBAC Hook', () => {
|
|
|
93
103
|
});
|
|
94
104
|
|
|
95
105
|
describe('Initialization', () => {
|
|
96
|
-
it('initializes with loading state', () => {
|
|
106
|
+
it('initializes with loading state', async () => {
|
|
97
107
|
const { result } = renderHook(() => useRBAC());
|
|
98
108
|
|
|
99
|
-
|
|
109
|
+
// Wait for loading to complete
|
|
110
|
+
await waitFor(() => {
|
|
111
|
+
expect(result.current.isLoading).toBe(false);
|
|
112
|
+
});
|
|
113
|
+
|
|
100
114
|
expect(result.current.globalRole).toBeNull();
|
|
101
|
-
expect(result.current.organisationRole).
|
|
115
|
+
expect(result.current.organisationRole).toBe('user');
|
|
102
116
|
expect(result.current.eventAppRole).toBeNull();
|
|
103
|
-
expect(result.current.permissions).toEqual([
|
|
117
|
+
expect(result.current.permissions).toEqual([
|
|
118
|
+
{
|
|
119
|
+
permission_type: 'organisation_access',
|
|
120
|
+
role_name: 'user',
|
|
121
|
+
operation: 'read',
|
|
122
|
+
resource: 'users'
|
|
123
|
+
}
|
|
124
|
+
]);
|
|
104
125
|
expect(result.current.error).toBeNull();
|
|
105
126
|
});
|
|
106
127
|
|
|
@@ -144,17 +165,17 @@ describe('useRBAC Hook', () => {
|
|
|
144
165
|
|
|
145
166
|
describe('Role Detection', () => {
|
|
146
167
|
it('detects super admin role', async () => {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
168
|
+
// Override the rpc mock for this test
|
|
169
|
+
mockSupabase.rpc.mockResolvedValue({
|
|
170
|
+
data: [
|
|
171
|
+
{
|
|
172
|
+
permission_type: 'all_permissions',
|
|
173
|
+
role_name: 'super_admin',
|
|
174
|
+
operation: 'read',
|
|
175
|
+
resource: 'users'
|
|
176
|
+
}
|
|
177
|
+
],
|
|
178
|
+
error: null
|
|
158
179
|
});
|
|
159
180
|
|
|
160
181
|
const { result } = renderHook(() => useRBAC());
|
|
@@ -166,20 +187,17 @@ describe('useRBAC Hook', () => {
|
|
|
166
187
|
});
|
|
167
188
|
|
|
168
189
|
it('detects organisation roles', async () => {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}))
|
|
181
|
-
}))
|
|
182
|
-
}))
|
|
190
|
+
// Override the rpc mock for this test
|
|
191
|
+
mockSupabase.rpc.mockResolvedValue({
|
|
192
|
+
data: [
|
|
193
|
+
{
|
|
194
|
+
permission_type: 'organisation_access',
|
|
195
|
+
role_name: 'org_admin',
|
|
196
|
+
operation: 'read',
|
|
197
|
+
resource: 'users'
|
|
198
|
+
}
|
|
199
|
+
],
|
|
200
|
+
error: null
|
|
183
201
|
});
|
|
184
202
|
|
|
185
203
|
const { result } = renderHook(() => useRBAC());
|
|
@@ -191,21 +209,17 @@ describe('useRBAC Hook', () => {
|
|
|
191
209
|
});
|
|
192
210
|
|
|
193
211
|
it('detects event app roles', async () => {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
})
|
|
206
|
-
}))
|
|
207
|
-
}))
|
|
208
|
-
}))
|
|
212
|
+
// Override the rpc mock for this test
|
|
213
|
+
mockSupabase.rpc.mockResolvedValue({
|
|
214
|
+
data: [
|
|
215
|
+
{
|
|
216
|
+
permission_type: 'event_app_access',
|
|
217
|
+
role_name: 'planner',
|
|
218
|
+
operation: 'read',
|
|
219
|
+
resource: 'users'
|
|
220
|
+
}
|
|
221
|
+
],
|
|
222
|
+
error: null
|
|
209
223
|
});
|
|
210
224
|
|
|
211
225
|
const { result } = renderHook(() => useRBAC());
|
|
@@ -216,21 +230,23 @@ describe('useRBAC Hook', () => {
|
|
|
216
230
|
});
|
|
217
231
|
|
|
218
232
|
it('handles role hierarchy correctly', async () => {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
233
|
+
// Override the rpc mock for this test
|
|
234
|
+
mockSupabase.rpc.mockResolvedValue({
|
|
235
|
+
data: [
|
|
236
|
+
{
|
|
237
|
+
permission_type: 'all_permissions',
|
|
238
|
+
role_name: 'super_admin',
|
|
239
|
+
operation: 'read',
|
|
240
|
+
resource: 'users'
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
permission_type: 'organisation_access',
|
|
244
|
+
role_name: 'org_admin',
|
|
245
|
+
operation: 'read',
|
|
246
|
+
resource: 'users'
|
|
247
|
+
}
|
|
248
|
+
],
|
|
249
|
+
error: null
|
|
234
250
|
});
|
|
235
251
|
|
|
236
252
|
const { result } = renderHook(() => useRBAC());
|
|
@@ -244,17 +260,17 @@ describe('useRBAC Hook', () => {
|
|
|
244
260
|
|
|
245
261
|
describe('Permission Checking', () => {
|
|
246
262
|
it('hasPermission returns true for super admin', async () => {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
263
|
+
// Override the rpc mock for this test
|
|
264
|
+
mockSupabase.rpc.mockResolvedValue({
|
|
265
|
+
data: [
|
|
266
|
+
{
|
|
267
|
+
permission_type: 'all_permissions',
|
|
268
|
+
role_name: 'super_admin',
|
|
269
|
+
operation: 'read',
|
|
270
|
+
resource: 'users'
|
|
271
|
+
}
|
|
272
|
+
],
|
|
273
|
+
error: null
|
|
258
274
|
});
|
|
259
275
|
|
|
260
276
|
const { result } = renderHook(() => useRBAC());
|
|
@@ -269,34 +285,50 @@ describe('useRBAC Hook', () => {
|
|
|
269
285
|
});
|
|
270
286
|
|
|
271
287
|
it('hasPermission checks database for regular users', async () => {
|
|
288
|
+
// Override the rpc mock for this test
|
|
289
|
+
mockSupabase.rpc.mockResolvedValue({
|
|
290
|
+
data: [
|
|
291
|
+
{
|
|
292
|
+
permission_type: 'organisation_access',
|
|
293
|
+
role_name: 'user',
|
|
294
|
+
operation: 'read',
|
|
295
|
+
resource: 'users'
|
|
296
|
+
}
|
|
297
|
+
],
|
|
298
|
+
error: null
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
const { result } = renderHook(() => useRBAC());
|
|
302
|
+
|
|
303
|
+
await waitFor(() => {
|
|
304
|
+
expect(result.current.organisationRole).toBe('user');
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// Mock the app lookup
|
|
272
308
|
mockSupabase.from.mockReturnValue({
|
|
273
309
|
select: vi.fn(() => ({
|
|
274
310
|
eq: vi.fn(() => ({
|
|
275
311
|
eq: vi.fn(() => ({
|
|
276
312
|
single: vi.fn().mockResolvedValue({
|
|
277
|
-
data: {
|
|
313
|
+
data: { id: 'app-123' },
|
|
278
314
|
error: null
|
|
279
315
|
})
|
|
280
316
|
}))
|
|
281
317
|
}))
|
|
282
|
-
}))
|
|
283
|
-
rpc: vi.fn().mockResolvedValue({
|
|
284
|
-
data: true,
|
|
285
|
-
error: null
|
|
286
|
-
})
|
|
318
|
+
}))
|
|
287
319
|
});
|
|
288
320
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
321
|
+
// Mock the permission check
|
|
322
|
+
mockSupabase.rpc.mockResolvedValue({
|
|
323
|
+
data: true,
|
|
324
|
+
error: null
|
|
293
325
|
});
|
|
294
326
|
|
|
295
327
|
const hasPermission = await result.current.hasPermission('read', 'dashboard');
|
|
296
328
|
expect(hasPermission).toBe(true);
|
|
297
329
|
expect(mockSupabase.rpc).toHaveBeenCalledWith('check_page_permission', {
|
|
298
330
|
p_user_id: 'user-123',
|
|
299
|
-
p_app_id:
|
|
331
|
+
p_app_id: 'app-123',
|
|
300
332
|
p_page_id: 'dashboard',
|
|
301
333
|
p_operation: 'read',
|
|
302
334
|
p_event_id: 'event-123',
|
|
@@ -305,25 +337,41 @@ describe('useRBAC Hook', () => {
|
|
|
305
337
|
});
|
|
306
338
|
|
|
307
339
|
it('hasPermission handles errors gracefully', async () => {
|
|
340
|
+
// Override the rpc mock for this test
|
|
341
|
+
mockSupabase.rpc.mockResolvedValue({
|
|
342
|
+
data: [
|
|
343
|
+
{
|
|
344
|
+
permission_type: 'organisation_access',
|
|
345
|
+
role_name: 'user',
|
|
346
|
+
operation: 'read',
|
|
347
|
+
resource: 'users'
|
|
348
|
+
}
|
|
349
|
+
],
|
|
350
|
+
error: null
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
const { result } = renderHook(() => useRBAC());
|
|
354
|
+
|
|
355
|
+
await waitFor(() => {
|
|
356
|
+
expect(result.current.organisationRole).toBe('user');
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
// Mock the app lookup
|
|
308
360
|
mockSupabase.from.mockReturnValue({
|
|
309
361
|
select: vi.fn(() => ({
|
|
310
362
|
eq: vi.fn(() => ({
|
|
311
363
|
eq: vi.fn(() => ({
|
|
312
364
|
single: vi.fn().mockResolvedValue({
|
|
313
|
-
data: {
|
|
365
|
+
data: { id: 'app-123' },
|
|
314
366
|
error: null
|
|
315
367
|
})
|
|
316
368
|
}))
|
|
317
369
|
}))
|
|
318
|
-
}))
|
|
319
|
-
rpc: vi.fn().mockRejectedValue(new Error('Database error'))
|
|
370
|
+
}))
|
|
320
371
|
});
|
|
321
372
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
await waitFor(() => {
|
|
325
|
-
expect(result.current.globalRole).toBe('user');
|
|
326
|
-
});
|
|
373
|
+
// Mock the permission check to fail
|
|
374
|
+
mockSupabase.rpc.mockRejectedValue(new Error('Database error'));
|
|
327
375
|
|
|
328
376
|
const hasPermission = await result.current.hasPermission('read', 'dashboard');
|
|
329
377
|
expect(hasPermission).toBe(false);
|