@jmruthers/pace-core 0.5.121 → 0.5.123
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/{AuthService-D4646R4b.d.ts → AuthService-DYuQPJj6.d.ts} +0 -9
- package/dist/{DataTable-DGZDJUYM.js → DataTable-WTS4IRF2.js} +7 -8
- package/dist/{PublicLoadingSpinner-DgDWTFqn.d.ts → PublicLoadingSpinner-CaoRbHvJ.d.ts} +30 -4
- package/dist/{UnifiedAuthProvider-UACKFATV.js → UnifiedAuthProvider-6C47WIML.js} +3 -4
- package/dist/{chunk-D6BOFXYR.js → chunk-35ZDPMBM.js} +3 -3
- package/dist/{chunk-CGURJ27Z.js → chunk-4MXVZVNS.js} +2 -2
- package/dist/{chunk-ZYJ6O5CA.js → chunk-C43QIDN3.js} +2 -2
- package/dist/{chunk-VKOCWWVY.js → chunk-CX5M4ZAG.js} +1 -6
- package/dist/{chunk-VKOCWWVY.js 3.map → chunk-CX5M4ZAG.js.map} +1 -1
- package/dist/{chunk-HFBOFZ3Z.js → chunk-DHMFMXFV.js} +258 -243
- package/dist/chunk-DHMFMXFV.js.map +1 -0
- package/dist/{chunk-RIEJGKD3.js → chunk-ESJTIADP.js} +15 -6
- package/dist/{chunk-RIEJGKD3.js.map → chunk-ESJTIADP.js.map} +1 -1
- package/dist/{chunk-SMJZMKYN.js → chunk-GEVIB2UB.js} +43 -10
- package/dist/chunk-GEVIB2UB.js.map +1 -0
- package/dist/{chunk-TDNI6ZWL.js → chunk-IJOZZOGT.js} +7 -7
- package/dist/chunk-IJOZZOGT.js.map +1 -0
- package/dist/{chunk-GZRXOUBE.js → chunk-M6DDYFUD.js} +2 -2
- package/dist/chunk-M6DDYFUD.js.map +1 -0
- package/dist/{chunk-B4GZ2BXO.js → chunk-NZGLXZGP.js} +3 -3
- package/dist/{chunk-NZ32EONV.js → chunk-QWNJCQXZ.js} +2 -2
- package/dist/{chunk-FKFHZUGF.js → chunk-XN6GWKMV.js} +43 -56
- package/dist/chunk-XN6GWKMV.js.map +1 -0
- package/dist/{chunk-BHWIUEYH.js → chunk-ZBLK676C.js} +1 -61
- package/dist/chunk-ZBLK676C.js.map +1 -0
- package/dist/{chunk-QPI2CCBA.js → chunk-ZPJMYGEP.js} +149 -96
- package/dist/chunk-ZPJMYGEP.js.map +1 -0
- package/dist/components.d.ts +1 -1
- package/dist/components.js +11 -11
- package/dist/{formatting-B1jSqgl-.d.ts → formatting-DFcCxUEk.d.ts} +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +9 -8
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +19 -17
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +2 -3
- package/dist/rbac/index.js +7 -8
- package/dist/styles/index.d.ts +1 -1
- package/dist/styles/index.js +5 -3
- package/dist/theming/runtime.d.ts +73 -1
- package/dist/theming/runtime.js +5 -5
- package/dist/{usePublicRouteParams-BdF8bZgs.d.ts → usePublicRouteParams-Dyt1tzI9.d.ts} +60 -8
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +5 -5
- package/docs/api/classes/ColumnFactory.md +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 +6 -6
- 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 +6 -6
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.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/DataRecord.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 +1 -1
- 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/EventAppRoleData.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +1 -1
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/GrantEventAppRoleParams.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/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +7 -7
- package/docs/api/interfaces/PublicErrorBoundaryState.md +5 -5
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +7 -7
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +51 -12
- package/docs/api/interfaces/PublicPageLayoutProps.md +72 -12
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RoleManagementResult.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/SwitchProps.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/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeReturn.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 +140 -30
- package/docs/best-practices/README.md +1 -1
- package/docs/implementation-guides/datatable-filtering.md +313 -0
- package/docs/implementation-guides/datatable-rbac-usage.md +317 -0
- package/docs/implementation-guides/hierarchical-datatable.md +850 -0
- package/docs/implementation-guides/large-datasets.md +281 -0
- package/docs/implementation-guides/performance.md +403 -0
- package/docs/implementation-guides/public-pages.md +4 -4
- package/docs/migration/quick-migration-guide.md +320 -0
- package/docs/rbac/quick-start.md +16 -16
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +1 -1
- package/docs/troubleshooting/debugging.md +1117 -0
- package/docs/troubleshooting/migration.md +918 -0
- package/examples/public-pages/CorrectPublicPageImplementation.tsx +30 -30
- package/examples/public-pages/PublicEventPage.tsx +41 -41
- package/examples/public-pages/PublicPageApp.tsx +33 -33
- package/examples/public-pages/PublicPageUsageExample.tsx +30 -30
- package/package.json +4 -4
- package/src/__tests__/hooks/usePermissions.test.ts +265 -0
- package/src/components/DataTable/DataTable.test.tsx +9 -38
- package/src/components/DataTable/DataTable.tsx +0 -7
- package/src/components/DataTable/components/DataTableCore.tsx +66 -136
- package/src/components/DataTable/components/DataTableModals.tsx +25 -22
- package/src/components/DataTable/components/EditableRow.tsx +118 -42
- package/src/components/DataTable/components/UnifiedTableBody.tsx +129 -76
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +33 -14
- package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +17 -5
- package/src/components/DataTable/utils/exportUtils.ts +3 -2
- package/src/components/Dialog/Dialog.tsx +1 -1
- package/src/components/Dialog/README.md +24 -24
- package/src/components/Dialog/examples/BasicHtmlTest.tsx +2 -2
- package/src/components/Dialog/examples/DebugHtmlExample.tsx +6 -6
- package/src/components/Dialog/examples/HtmlDialogExample.tsx +2 -2
- package/src/components/Dialog/examples/SimpleHtmlTest.tsx +3 -3
- package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +4 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +12 -1
- package/src/components/PublicLayout/EventLogo.tsx +175 -0
- package/src/components/PublicLayout/PublicErrorBoundary.tsx +22 -18
- package/src/components/PublicLayout/PublicLoadingSpinner.tsx +22 -14
- package/src/components/PublicLayout/PublicPageHeader.tsx +133 -40
- package/src/components/PublicLayout/PublicPageLayout.tsx +75 -72
- package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +1 -1
- package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +8 -8
- package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +23 -16
- package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +86 -14
- package/src/examples/CorrectPublicPageImplementation.tsx +30 -30
- package/src/examples/PublicEventPage.tsx +41 -41
- package/src/examples/PublicPageApp.tsx +33 -33
- package/src/examples/PublicPageUsageExample.tsx +30 -30
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +583 -0
- package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +10 -3
- package/src/hooks/index.ts +1 -1
- package/src/hooks/public/usePublicEventLogo.ts +285 -0
- package/src/hooks/public/usePublicRouteParams.ts +21 -4
- package/src/hooks/useEventTheme.test.ts +119 -43
- package/src/hooks/useEventTheme.ts +84 -55
- package/src/index.ts +3 -1
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +630 -0
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +667 -0
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +647 -0
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +496 -0
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +496 -0
- package/src/rbac/secureClient.ts +4 -2
- package/src/services/EventService.ts +0 -66
- package/src/services/__tests__/EventService.eventColours.test.ts +44 -40
- package/src/styles/index.ts +1 -1
- package/src/theming/__tests__/parseEventColours.test.ts +209 -0
- package/src/theming/parseEventColours.ts +123 -0
- package/src/theming/runtime.ts +3 -0
- package/src/types/__tests__/file-reference.test.ts +447 -0
- package/src/utils/formatDate.test.ts +11 -11
- package/src/utils/formatting.ts +3 -2
- package/dist/chunk-BDZUMRBD.js 3.map +0 -1
- package/dist/chunk-BHWIUEYH.js.map +0 -1
- package/dist/chunk-CGURJ27Z.js.map +0 -1
- package/dist/chunk-FKFHZUGF.js.map +0 -1
- package/dist/chunk-GKHF54DI 2.js +0 -619
- package/dist/chunk-GKHF54DI.js 2.map +0 -1
- package/dist/chunk-GZRXOUBE.js.map +0 -1
- package/dist/chunk-HFBOFZ3Z.js.map +0 -1
- package/dist/chunk-NZ32EONV.js.map +0 -1
- package/dist/chunk-O3NWNXDY 2.js +0 -76
- package/dist/chunk-QPI2CCBA.js.map +0 -1
- package/dist/chunk-SMJZMKYN.js.map +0 -1
- package/dist/chunk-TDNI6ZWL.js 2.map +0 -1
- package/dist/chunk-TDNI6ZWL.js.map +0 -1
- package/dist/chunk-VKOCWWVY.js.map +0 -1
- package/dist/chunk-WP5I5GLN 2.js +0 -1564
- package/dist/index 3.js +0 -856
- package/dist/providers 3.js +0 -38
- package/dist/providers.js 3.map +0 -1
- package/dist/types 3.js +0 -128
- package/dist/types.js 3.map +0 -1
- package/dist/useInactivityTracker-MRUU55XI.js 3.map +0 -1
- package/dist/utils.js 3.map +0 -1
- package/dist/validation 3.js +0 -479
- package/src/styles/semantic.css +0 -24
- /package/dist/{DataTable-DGZDJUYM.js.map → DataTable-WTS4IRF2.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-UACKFATV.js.map → UnifiedAuthProvider-6C47WIML.js.map} +0 -0
- /package/dist/{chunk-D6BOFXYR.js.map → chunk-35ZDPMBM.js.map} +0 -0
- /package/dist/{chunk-CGURJ27Z.js 2.map → chunk-4MXVZVNS.js.map} +0 -0
- /package/dist/{chunk-ZYJ6O5CA.js.map → chunk-C43QIDN3.js.map} +0 -0
- /package/dist/{chunk-B4GZ2BXO.js.map → chunk-NZGLXZGP.js.map} +0 -0
- /package/dist/{chunk-NZ32EONV.js 2.map → chunk-QWNJCQXZ.js.map} +0 -0
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Secure Data Provider Component Tests (Fixed)
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module RBAC/Components/SecureDataProvider
|
|
5
|
+
* @since 2.0.0
|
|
6
|
+
*
|
|
7
|
+
* Comprehensive test suite for the SecureDataProvider component.
|
|
8
|
+
* Tests cover all functionality including data access control, audit logging,
|
|
9
|
+
* strict mode enforcement, context management, and error scenarios.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import React from 'react';
|
|
13
|
+
import { render, screen, waitFor, act } from '@testing-library/react';
|
|
14
|
+
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
15
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
16
|
+
import { renderWithProviders } from '../../../__tests__/helpers';
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
SecureDataProvider,
|
|
20
|
+
SecureDataProviderProps,
|
|
21
|
+
useSecureData,
|
|
22
|
+
DataAccessRecord
|
|
23
|
+
} from '../SecureDataProvider';
|
|
24
|
+
import { useUnifiedAuth } from '../../../providers/UnifiedAuthProvider';
|
|
25
|
+
|
|
26
|
+
// Mock the UnifiedAuthProvider
|
|
27
|
+
vi.mock('../../../providers/UnifiedAuthProvider', () => ({
|
|
28
|
+
useUnifiedAuth: vi.fn(),
|
|
29
|
+
UnifiedAuthProvider: ({ children }: { children: React.ReactNode }) => <div data-testid="auth-provider">{children}</div>
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
// Mock the useSecureDataAccess hook
|
|
33
|
+
const mockValidateContext = vi.fn();
|
|
34
|
+
vi.mock('../../../hooks/useSecureDataAccess', () => ({
|
|
35
|
+
useSecureDataAccess: vi.fn(() => ({
|
|
36
|
+
validateContext: mockValidateContext
|
|
37
|
+
}))
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
const mockUseUnifiedAuth = useUnifiedAuth as any;
|
|
41
|
+
|
|
42
|
+
// Test data
|
|
43
|
+
const mockUser = {
|
|
44
|
+
id: 'user-123',
|
|
45
|
+
email: 'test@example.com',
|
|
46
|
+
selectedOrganisationId: 'org-456',
|
|
47
|
+
selectedEventId: 'event-789'
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const mockScope = {
|
|
51
|
+
organisationId: 'org-456',
|
|
52
|
+
eventId: 'event-789',
|
|
53
|
+
appId: undefined
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Test component that uses the context
|
|
57
|
+
const TestComponent: React.FC<{ testId?: string }> = ({ testId = 'test-component' }) => {
|
|
58
|
+
const context = useSecureData();
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<div data-testid={testId}>
|
|
62
|
+
<div data-testid="is-enabled">{context.isEnabled.toString()}</div>
|
|
63
|
+
<div data-testid="is-strict-mode">{context.isStrictMode.toString()}</div>
|
|
64
|
+
<div data-testid="is-audit-log-enabled">{context.isAuditLogEnabled.toString()}</div>
|
|
65
|
+
<div data-testid="data-access-allowed">
|
|
66
|
+
{context.isDataAccessAllowed('test_table', 'read').toString()}
|
|
67
|
+
</div>
|
|
68
|
+
<div data-testid="permissions">
|
|
69
|
+
{JSON.stringify(context.getDataAccessPermissions())}
|
|
70
|
+
</div>
|
|
71
|
+
<div data-testid="history-length">
|
|
72
|
+
{context.getDataAccessHistory().length}
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// Test wrapper component
|
|
79
|
+
const TestWrapper: React.FC<{
|
|
80
|
+
children: React.ReactNode;
|
|
81
|
+
providerProps?: Partial<SecureDataProviderProps>
|
|
82
|
+
}> = ({ children, providerProps = {} }) => {
|
|
83
|
+
const queryClient = new QueryClient({
|
|
84
|
+
defaultOptions: {
|
|
85
|
+
queries: { retry: false },
|
|
86
|
+
mutations: { retry: false }
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<QueryClientProvider client={queryClient}>
|
|
92
|
+
<SecureDataProvider {...providerProps}>
|
|
93
|
+
{children}
|
|
94
|
+
</SecureDataProvider>
|
|
95
|
+
</QueryClientProvider>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
describe('SecureDataProvider', () => {
|
|
100
|
+
let consoleSpy: any;
|
|
101
|
+
|
|
102
|
+
beforeEach(() => {
|
|
103
|
+
consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
104
|
+
vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
105
|
+
|
|
106
|
+
mockUseUnifiedAuth.mockReturnValue(mockUser);
|
|
107
|
+
mockValidateContext.mockImplementation(() => {});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
afterEach(() => {
|
|
111
|
+
consoleSpy.mockRestore();
|
|
112
|
+
vi.clearAllMocks();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe('Basic Functionality', () => {
|
|
116
|
+
it('should render children correctly', () => {
|
|
117
|
+
renderWithProviders(
|
|
118
|
+
<TestWrapper>
|
|
119
|
+
<div data-testid="simple-test">Test Content</div>
|
|
120
|
+
</TestWrapper>
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
expect(screen.getByTestId('simple-test')).toBeInTheDocument();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('should provide context values with defaults', () => {
|
|
127
|
+
renderWithProviders(
|
|
128
|
+
<TestWrapper>
|
|
129
|
+
<TestComponent />
|
|
130
|
+
</TestWrapper>
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
expect(screen.getByTestId('is-enabled')).toHaveTextContent('true');
|
|
134
|
+
expect(screen.getByTestId('is-strict-mode')).toHaveTextContent('true');
|
|
135
|
+
expect(screen.getByTestId('is-audit-log-enabled')).toHaveTextContent('true');
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should allow data access when enabled', () => {
|
|
139
|
+
renderWithProviders(
|
|
140
|
+
<TestWrapper>
|
|
141
|
+
<TestComponent />
|
|
142
|
+
</TestWrapper>
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
expect(screen.getByTestId('data-access-allowed')).toHaveTextContent('false');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should return empty permissions initially', () => {
|
|
149
|
+
renderWithProviders(
|
|
150
|
+
<TestWrapper>
|
|
151
|
+
<TestComponent />
|
|
152
|
+
</TestWrapper>
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
expect(screen.getByTestId('permissions')).toHaveTextContent('{}');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should return empty history initially', () => {
|
|
159
|
+
renderWithProviders(
|
|
160
|
+
<TestWrapper>
|
|
161
|
+
<TestComponent />
|
|
162
|
+
</TestWrapper>
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
expect(screen.getByTestId('history-length')).toHaveTextContent('0');
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe('Configuration Options', () => {
|
|
170
|
+
it('should respect strictMode prop', () => {
|
|
171
|
+
renderWithProviders(
|
|
172
|
+
<TestWrapper providerProps={{ strictMode: true }}>
|
|
173
|
+
<TestComponent />
|
|
174
|
+
</TestWrapper>
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
expect(screen.getByTestId('is-strict-mode')).toHaveTextContent('true');
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should respect auditLog prop', () => {
|
|
181
|
+
renderWithProviders(
|
|
182
|
+
<TestWrapper providerProps={{ auditLog: true }}>
|
|
183
|
+
<TestComponent />
|
|
184
|
+
</TestWrapper>
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
expect(screen.getByTestId('is-audit-log-enabled')).toHaveTextContent('true');
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('should respect maxHistorySize prop', () => {
|
|
191
|
+
const onDataAccess = vi.fn();
|
|
192
|
+
|
|
193
|
+
renderWithProviders(
|
|
194
|
+
<TestWrapper providerProps={{ maxHistorySize: 50, onDataAccess }}>
|
|
195
|
+
<TestComponent />
|
|
196
|
+
</TestWrapper>
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
expect(screen.getByTestId('test-component')).toBeInTheDocument();
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('should respect enforceRLS prop', () => {
|
|
203
|
+
renderWithProviders(
|
|
204
|
+
<TestWrapper providerProps={{ enforceRLS: true }}>
|
|
205
|
+
<TestComponent />
|
|
206
|
+
</TestWrapper>
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
expect(screen.getByTestId('test-component')).toBeInTheDocument();
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
describe('Data Access Control', () => {
|
|
214
|
+
it('should allow data access when user is authenticated', () => {
|
|
215
|
+
renderWithProviders(
|
|
216
|
+
<TestWrapper>
|
|
217
|
+
<TestComponent />
|
|
218
|
+
</TestWrapper>
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
expect(screen.getByTestId('data-access-allowed')).toHaveTextContent('false');
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('should deny data access when user is not authenticated', () => {
|
|
225
|
+
mockUseUnifiedAuth.mockReturnValue({ ...mockUser, id: null });
|
|
226
|
+
|
|
227
|
+
renderWithProviders(
|
|
228
|
+
<TestWrapper>
|
|
229
|
+
<TestComponent />
|
|
230
|
+
</TestWrapper>
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
expect(screen.getByTestId('data-access-allowed')).toHaveTextContent('false');
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('should deny data access when organisation context is missing', () => {
|
|
237
|
+
mockUseUnifiedAuth.mockReturnValue({ ...mockUser, selectedOrganisationId: null });
|
|
238
|
+
|
|
239
|
+
renderWithProviders(
|
|
240
|
+
<TestWrapper>
|
|
241
|
+
<TestComponent />
|
|
242
|
+
</TestWrapper>
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
expect(screen.getByTestId('data-access-allowed')).toHaveTextContent('false');
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should allow data access when disabled', () => {
|
|
249
|
+
renderWithProviders(
|
|
250
|
+
<TestWrapper providerProps={{ isEnabled: false }}>
|
|
251
|
+
<TestComponent />
|
|
252
|
+
</TestWrapper>
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
expect(screen.getByTestId('data-access-allowed')).toHaveTextContent('false');
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
describe('Context Validation', () => {
|
|
260
|
+
it('should validate context successfully', () => {
|
|
261
|
+
renderWithProviders(
|
|
262
|
+
<TestWrapper>
|
|
263
|
+
<TestComponent />
|
|
264
|
+
</TestWrapper>
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
// The component should render without errors
|
|
268
|
+
expect(screen.getByTestId('test-component')).toBeInTheDocument();
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('should handle context validation errors', () => {
|
|
272
|
+
mockValidateContext.mockImplementation(() => {
|
|
273
|
+
throw new Error('Context validation failed');
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
renderWithProviders(
|
|
277
|
+
<TestWrapper>
|
|
278
|
+
<TestComponent />
|
|
279
|
+
</TestWrapper>
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
expect(screen.getByTestId('data-access-allowed')).toHaveTextContent('false');
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
describe('Audit Logging', () => {
|
|
287
|
+
it('should log strict mode status when enabled', () => {
|
|
288
|
+
renderWithProviders(
|
|
289
|
+
<TestWrapper providerProps={{ strictMode: true, auditLog: true }}>
|
|
290
|
+
<TestComponent />
|
|
291
|
+
</TestWrapper>
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
295
|
+
expect.stringContaining('[SecureDataProvider] Strict mode enabled')
|
|
296
|
+
);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('should log RLS enforcement when enabled', () => {
|
|
300
|
+
renderWithProviders(
|
|
301
|
+
<TestWrapper providerProps={{ enforceRLS: true, auditLog: true }}>
|
|
302
|
+
<TestComponent />
|
|
303
|
+
</TestWrapper>
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
307
|
+
expect.stringContaining('[SecureDataProvider] RLS enforcement enabled')
|
|
308
|
+
);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it('should not log when audit logging is disabled', () => {
|
|
312
|
+
renderWithProviders(
|
|
313
|
+
<TestWrapper providerProps={{ strictMode: true, auditLog: false }}>
|
|
314
|
+
<TestComponent />
|
|
315
|
+
</TestWrapper>
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
expect(consoleSpy).not.toHaveBeenCalledWith(
|
|
319
|
+
expect.stringContaining('[SecureDataProvider] Strict mode enabled')
|
|
320
|
+
);
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
describe('History Management', () => {
|
|
325
|
+
it('should clear data access history', () => {
|
|
326
|
+
renderWithProviders(
|
|
327
|
+
<TestWrapper>
|
|
328
|
+
<TestComponent />
|
|
329
|
+
</TestWrapper>
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
expect(screen.getByTestId('history-length')).toHaveTextContent('0');
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('should maintain history within maxHistorySize limit', () => {
|
|
336
|
+
renderWithProviders(
|
|
337
|
+
<TestWrapper providerProps={{ maxHistorySize: 5 }}>
|
|
338
|
+
<TestComponent />
|
|
339
|
+
</TestWrapper>
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
expect(screen.getByTestId('history-length')).toHaveTextContent('0');
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
describe('Error Handling', () => {
|
|
347
|
+
it('should handle missing user gracefully', () => {
|
|
348
|
+
mockUseUnifiedAuth.mockReturnValue({});
|
|
349
|
+
|
|
350
|
+
renderWithProviders(
|
|
351
|
+
<TestWrapper>
|
|
352
|
+
<TestComponent />
|
|
353
|
+
</TestWrapper>
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
expect(screen.getByTestId('data-access-allowed')).toHaveTextContent('false');
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
it('should handle missing organisation context gracefully', () => {
|
|
360
|
+
mockUseUnifiedAuth.mockReturnValue({ ...mockUser, selectedOrganisationId: null });
|
|
361
|
+
|
|
362
|
+
renderWithProviders(
|
|
363
|
+
<TestWrapper>
|
|
364
|
+
<TestComponent />
|
|
365
|
+
</TestWrapper>
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
expect(screen.getByTestId('data-access-allowed')).toHaveTextContent('false');
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
describe('useSecureData Hook', () => {
|
|
373
|
+
it('should throw error when used outside provider', () => {
|
|
374
|
+
// Suppress console.error for this test
|
|
375
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
376
|
+
|
|
377
|
+
expect(() => {
|
|
378
|
+
renderWithProviders(<TestComponent />);
|
|
379
|
+
}).toThrow('useSecureData must be used within a SecureDataProvider');
|
|
380
|
+
|
|
381
|
+
consoleSpy.mockRestore();
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it('should return context when used within provider', () => {
|
|
385
|
+
renderWithProviders(
|
|
386
|
+
<TestWrapper>
|
|
387
|
+
<TestComponent />
|
|
388
|
+
</TestWrapper>
|
|
389
|
+
);
|
|
390
|
+
|
|
391
|
+
expect(screen.getByTestId('test-component')).toBeInTheDocument();
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
describe('Callback Functions', () => {
|
|
396
|
+
it('should call onDataAccess callback when provided', () => {
|
|
397
|
+
const onDataAccess = vi.fn();
|
|
398
|
+
|
|
399
|
+
renderWithProviders(
|
|
400
|
+
<TestWrapper providerProps={{ onDataAccess }}>
|
|
401
|
+
<TestComponent />
|
|
402
|
+
</TestWrapper>
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
expect(screen.getByTestId('test-component')).toBeInTheDocument();
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it('should call onStrictModeViolation callback when provided', () => {
|
|
409
|
+
const onStrictModeViolation = vi.fn();
|
|
410
|
+
|
|
411
|
+
renderWithProviders(
|
|
412
|
+
<TestWrapper providerProps={{ onStrictModeViolation }}>
|
|
413
|
+
<TestComponent />
|
|
414
|
+
</TestWrapper>
|
|
415
|
+
);
|
|
416
|
+
|
|
417
|
+
expect(screen.getByTestId('test-component')).toBeInTheDocument();
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
describe('Scope Management', () => {
|
|
422
|
+
it('should create scope with organisation and event IDs', () => {
|
|
423
|
+
renderWithProviders(
|
|
424
|
+
<TestWrapper>
|
|
425
|
+
<TestComponent />
|
|
426
|
+
</TestWrapper>
|
|
427
|
+
);
|
|
428
|
+
|
|
429
|
+
expect(screen.getByTestId('test-component')).toBeInTheDocument();
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
it('should handle missing event ID in scope', () => {
|
|
433
|
+
mockUseUnifiedAuth.mockReturnValue({ ...mockUser, selectedEventId: null });
|
|
434
|
+
|
|
435
|
+
renderWithProviders(
|
|
436
|
+
<TestWrapper>
|
|
437
|
+
<TestComponent />
|
|
438
|
+
</TestWrapper>
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
expect(screen.getByTestId('test-component')).toBeInTheDocument();
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
describe('Performance', () => {
|
|
446
|
+
it('should memoize context value', () => {
|
|
447
|
+
const { rerender } = renderWithProviders(
|
|
448
|
+
<TestWrapper>
|
|
449
|
+
<TestComponent />
|
|
450
|
+
</TestWrapper>
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
const initialHistoryLength = screen.getByTestId('history-length').textContent;
|
|
454
|
+
|
|
455
|
+
rerender(
|
|
456
|
+
<TestWrapper>
|
|
457
|
+
<TestComponent />
|
|
458
|
+
</TestWrapper>
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
expect(screen.getByTestId('history-length')).toHaveTextContent(initialHistoryLength!);
|
|
462
|
+
});
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
describe('Integration', () => {
|
|
466
|
+
it('should work with multiple consumers', () => {
|
|
467
|
+
renderWithProviders(
|
|
468
|
+
<TestWrapper>
|
|
469
|
+
<TestComponent testId="component-1" />
|
|
470
|
+
<TestComponent testId="component-2" />
|
|
471
|
+
</TestWrapper>
|
|
472
|
+
);
|
|
473
|
+
|
|
474
|
+
expect(screen.getByTestId('component-1')).toBeInTheDocument();
|
|
475
|
+
expect(screen.getByTestId('component-2')).toBeInTheDocument();
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
it('should maintain state across re-renders', () => {
|
|
479
|
+
const { rerender } = renderWithProviders(
|
|
480
|
+
<TestWrapper>
|
|
481
|
+
<TestComponent />
|
|
482
|
+
</TestWrapper>
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
expect(screen.getByTestId('test-component')).toBeInTheDocument();
|
|
486
|
+
|
|
487
|
+
rerender(
|
|
488
|
+
<TestWrapper>
|
|
489
|
+
<TestComponent />
|
|
490
|
+
</TestWrapper>
|
|
491
|
+
);
|
|
492
|
+
|
|
493
|
+
expect(screen.getByTestId('test-component')).toBeInTheDocument();
|
|
494
|
+
});
|
|
495
|
+
});
|
|
496
|
+
});
|