@jmruthers/pace-core 0.5.53 → 0.5.55
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/README.md +0 -4
- package/dist/{DataTable-7FMFXA7A.js → DataTable-4T627QFJ.js} +11 -11
- package/dist/{PublicLoadingSpinner-Bq_-BeK-.d.ts → PublicLoadingSpinner-SL8WaQN7.d.ts} +2 -21
- package/dist/{api-H5A3H4IR.js → api-LUNF5O6M.js} +3 -3
- package/dist/{appConfig-BVGyuvI7.d.ts → appConfig-DjpeG6P-.d.ts} +9 -1
- package/dist/{appNameResolver-7GHF5ED2.js → appNameResolver-UURKN7NF.js} +2 -2
- package/dist/{audit-BUW3LMJB.js → audit-6TOCAMKO.js} +2 -2
- package/dist/{chunk-MZBUOP4P.js → chunk-5BSLGBYI.js} +4 -3
- package/dist/chunk-5BSLGBYI.js.map +1 -0
- package/dist/{chunk-I5Z3QH5X.js → chunk-66C4BSAY.js} +2 -2
- package/dist/{chunk-I5Z3QH5X.js.map → chunk-66C4BSAY.js.map} +1 -1
- package/dist/{chunk-MYP2EGHX.js → chunk-AJ2KMES7.js} +21 -14
- package/dist/chunk-AJ2KMES7.js.map +1 -0
- package/dist/{chunk-EL2O4IUX.js → chunk-AQFRLC7K.js} +16 -24
- package/dist/{chunk-EL2O4IUX.js.map → chunk-AQFRLC7K.js.map} +1 -1
- package/dist/{chunk-7BNPOCLL.js → chunk-B2WTCLCV.js} +6 -2
- package/dist/chunk-B2WTCLCV.js.map +1 -0
- package/dist/{chunk-WJARTBCT.js → chunk-D7ARGIA3.js} +16 -7
- package/dist/chunk-D7ARGIA3.js.map +1 -0
- package/dist/{chunk-NRK4AIHQ.js → chunk-KBRACSJI.js} +3 -3
- package/dist/{chunk-NYUJ4FJR.js → chunk-KJDPSM64.js} +7 -7
- package/dist/chunk-KJDPSM64.js.map +1 -0
- package/dist/{chunk-GWSBHC4J.js → chunk-KLPVOPRI.js} +261 -38
- package/dist/chunk-KLPVOPRI.js.map +1 -0
- package/dist/{chunk-TRIZ7IB7.js → chunk-MPQDF75X.js} +148 -288
- package/dist/chunk-MPQDF75X.js.map +1 -0
- package/dist/{chunk-MSFACPQQ.js → chunk-PAEM3OWN.js} +11 -11
- package/dist/{chunk-MSFACPQQ.js.map → chunk-PAEM3OWN.js.map} +1 -1
- package/dist/{chunk-GIO7BFE7.js → chunk-RQD3D2CO.js} +66 -169
- package/dist/{chunk-GIO7BFE7.js.map → chunk-RQD3D2CO.js.map} +1 -1
- package/dist/{chunk-YDJW5XTN.js → chunk-STT7INZR.js} +25 -1
- package/dist/chunk-STT7INZR.js.map +1 -0
- package/dist/{chunk-6MTY77WU.js → chunk-TNMXZLDR.js} +3 -3
- package/dist/{chunk-BC3S53OZ.js → chunk-UQE2Y64H.js} +30 -14
- package/dist/chunk-UQE2Y64H.js.map +1 -0
- package/dist/{chunk-22KLBHPS.js → chunk-W66AZIOH.js} +2 -2
- package/dist/chunk-W66AZIOH.js.map +1 -0
- package/dist/{chunk-SS3E6QLB.js → chunk-YNUBMSMV.js} +2 -2
- package/dist/chunk-YNUBMSMV.js.map +1 -0
- package/dist/{chunk-NZ655MWE.js → chunk-ZOD2ZY6X.js} +5 -4
- package/dist/chunk-ZOD2ZY6X.js.map +1 -0
- package/dist/{chunk-74C6SNEC.js → chunk-ZPK5656W.js} +3 -3
- package/dist/{chunk-74C6SNEC.js.map → chunk-ZPK5656W.js.map} +1 -1
- package/dist/components.d.ts +22 -899
- package/dist/components.js +436 -3118
- package/dist/components.js.map +1 -1
- package/dist/file-reference-9xUOnwyt.d.ts +70 -0
- package/dist/hooks.d.ts +2 -2
- package/dist/hooks.js +10 -10
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +49 -9
- package/dist/index.js +190 -25
- package/dist/index.js.map +1 -1
- package/dist/{organisation-CO3Sh3_D.d.ts → organisation-t-vvQC3g.d.ts} +1 -8
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +5 -5
- package/dist/rbac/index.d.ts +65 -46
- package/dist/rbac/index.js +10 -12
- package/dist/styles/core.css +0 -125
- package/dist/types.d.ts +2 -1
- package/dist/types.js +3 -1
- package/dist/types.js.map +1 -1
- package/dist/{usePublicRouteParams-B2OcAsur.d.ts → usePublicRouteParams-CdoFxnJK.d.ts} +1 -1
- package/dist/utils.d.ts +3 -4
- package/dist/utils.js +44 -13
- package/dist/utils.js.map +1 -1
- package/docs/FILE_REFERENCE_SYSTEM.md +440 -0
- package/docs/INDEX.md +7 -5
- package/docs/README.md +0 -1
- package/docs/api/README.md +0 -4
- 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 +2 -2
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +12 -12
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +6 -6
- 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/classes/StorageUtils.md +281 -0
- 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 +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/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 +2 -2
- 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 +4 -4
- 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 +2 -2
- package/docs/api/interfaces/RouteConfig.md +2 -2
- 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 +204 -200
- package/docs/api-reference/components.md +141 -163
- package/docs/api-reference/hooks.md +347 -0
- package/docs/core-concepts/rbac-system.md +69 -16
- package/docs/getting-started/examples/basic-auth-app.md +0 -1
- package/docs/implementation-guides/datatable-rbac-usage.md +12 -11
- package/docs/implementation-guides/file-upload-storage.md +733 -0
- package/docs/implementation-guides/inactivity-tracking.md +779 -0
- package/docs/implementation-guides/organisation-security.md +748 -0
- package/docs/implementation-guides/public-pages-advanced.md +1022 -0
- package/docs/migration/MIGRATION_GUIDE.md +684 -0
- package/docs/migration/README.md +13 -2
- package/docs/migration/rbac-migration.md +73 -0
- package/docs/rbac/examples/rbac-rls-integration-example.md +11 -13
- package/docs/style-guide.md +269 -1
- package/package.json +1 -1
- package/src/__tests__/TESTING_GUIDELINES.md +331 -18
- package/src/__tests__/helpers/supabaseMock.ts +99 -0
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +10 -7
- package/src/__tests__/shared.ts +6 -0
- package/src/components/DataTable/components/ActionButtons.tsx +2 -2
- package/src/components/DataTable/components/DataTableCore.tsx +2 -2
- package/src/components/DataTable/components/UnifiedTableBody.tsx +1 -1
- package/src/components/DataTable/utils/debugTools.ts +2 -2
- package/src/components/Dialog/Dialog.test.tsx +12 -2
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +6 -6
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +2 -2
- package/src/components/FileDisplay.tsx +233 -0
- package/src/components/FileUpload.tsx +176 -0
- package/src/components/Footer/Footer.test.tsx +7 -7
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +13 -6
- package/src/components/OrganisationSelector/OrganisationSelector.test.tsx +30 -3
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +1 -1
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.rbac.test.tsx +558 -0
- package/src/components/PublicLayout/PublicErrorBoundary.tsx +1 -1
- package/src/components/PublicLayout/PublicPageDebugger.tsx +2 -2
- package/src/components/PublicLayout/PublicPageDiagnostic.tsx +2 -2
- package/src/components/PublicLayout/PublicPageProvider.tsx +2 -2
- package/src/components/Select/Select.test.tsx +50 -15
- package/src/components/SuperAdminGuard.tsx +2 -2
- package/src/components/__tests__/SuperAdminGuard.test.tsx +559 -0
- package/src/components/index.ts +0 -183
- package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +2 -2
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +1 -1
- package/src/hooks/__tests__/useRBAC.unit.test.ts +191 -138
- package/src/hooks/public/usePublicEvent.ts +2 -2
- package/src/hooks/useAppConfig.ts +3 -3
- package/src/hooks/useComponentPerformance.ts +1 -1
- package/src/hooks/useDataTablePerformance.ts +1 -1
- package/src/hooks/useFileReference.ts +232 -0
- package/src/hooks/useOrganisationPermissions.test.ts +254 -344
- package/src/hooks/useOrganisationPermissions.ts +15 -7
- package/src/hooks/useOrganisationSecurity.test.ts +390 -402
- package/src/hooks/usePerformanceMonitor.ts +1 -1
- package/src/hooks/usePermissionCache.test.ts +264 -395
- package/src/hooks/usePermissionCache.ts +34 -4
- package/src/hooks/useSecureDataAccess.test.ts +486 -0
- package/src/hooks/useSecureDataAccess.ts +4 -1
- package/src/providers/InactivityProvider.tsx +2 -2
- package/src/providers/OrganisationProvider.test.simple.tsx +168 -0
- package/src/providers/OrganisationProvider.test.tsx +168 -0
- package/src/providers/OrganisationProvider.tsx +18 -31
- package/src/providers/UnifiedAuthProvider.test.simple.tsx +205 -0
- package/src/providers/UnifiedAuthProvider.test.tsx +128 -0
- package/src/providers/__tests__/InactivityProvider.test.tsx +3 -4
- package/src/providers/__tests__/OrganisationProvider.test.tsx +19 -14
- package/src/rbac/__tests__/integration.authflow.test.tsx +123 -0
- package/src/rbac/__tests__/integration.navigation.test.tsx +72 -0
- package/src/rbac/__tests__/integration.securedata.test.tsx +92 -0
- package/src/rbac/__tests__/integration.smoke.test.tsx +73 -0
- package/src/rbac/__tests__/rbac-core.test.tsx +26 -22
- package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +411 -0
- package/src/rbac/__tests__/rbac-engine-simplified.test.ts +285 -0
- package/src/rbac/__tests__/rbac-functions.test.ts +655 -0
- package/src/rbac/__tests__/rbac-integration.test.ts +532 -0
- package/src/rbac/__tests__/scenarios.user-role.test.tsx +196 -0
- package/src/rbac/api.test.ts +6 -6
- package/src/rbac/api.ts +2 -2
- package/src/rbac/audit.test.ts +485 -0
- package/src/rbac/audit.ts +7 -1
- package/src/rbac/cache-invalidation.ts +318 -0
- package/src/rbac/cache.test.ts +286 -0
- package/src/rbac/components/EnhancedNavigationMenu.test.tsx +559 -0
- package/src/rbac/components/EnhancedNavigationMenu.tsx +29 -23
- package/src/rbac/components/NavigationProvider.test.tsx +449 -0
- package/src/rbac/components/PagePermissionGuard.tsx +4 -4
- package/src/rbac/components/PagePermissionProvider.test.tsx +479 -0
- package/src/rbac/components/SecureDataProvider.test.tsx +511 -0
- package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +159 -430
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +4 -5
- package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +112 -118
- package/src/rbac/config.test.ts +410 -0
- package/src/rbac/engine.test.simple.ts +237 -0
- package/src/rbac/engine.test.ts +233 -0
- package/src/rbac/engine.ts +37 -41
- package/src/rbac/examples/CompleteRBACExample.tsx +3 -3
- package/src/rbac/examples/EventBasedApp.tsx +4 -4
- package/src/rbac/hooks/useRBAC.simple.test.ts +16 -0
- package/src/rbac/hooks/useRBAC.test.ts +207 -455
- package/src/rbac/hooks/useRBAC.ts +30 -22
- package/src/rbac/permissions.test.ts +128 -0
- package/src/rbac/permissions.ts +56 -141
- package/src/rbac/providers/RBACProvider.tsx +1 -1
- package/src/rbac/secureClient.test.ts +444 -0
- package/src/rbac/security.test.ts +390 -0
- package/src/rbac/security.ts +1 -1
- package/src/rbac/types.test.ts +382 -0
- package/src/rbac/types.ts +2 -2
- package/src/styles/base.css +208 -0
- package/src/styles/core.css +0 -125
- package/src/styles/semantic.css +24 -0
- package/src/types/file-reference.ts +77 -0
- package/src/types/rbac-functions.ts +290 -0
- package/src/types/supabase.ts +10 -28
- package/src/types/unified.ts +4 -1
- package/src/utils/__tests__/bundleAnalysis.unit.test.ts +81 -55
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +21 -12
- package/src/utils/__tests__/organisationContext.unit.test.ts +13 -7
- package/src/utils/__tests__/performanceBudgets.unit.test.ts +3 -3
- package/src/utils/__tests__/sessionTracking.unit.test.ts +32 -12
- package/src/utils/appConfig.ts +1 -1
- package/src/utils/appIdResolver.test.ts +503 -0
- package/src/utils/appIdResolver.ts +1 -1
- package/src/utils/appNameResolver.test.ts +494 -0
- package/src/utils/appNameResolver.ts +3 -2
- package/src/utils/bundleAnalysis.ts +3 -3
- package/src/utils/debugLogger.ts +1 -1
- package/src/utils/file-reference.ts +263 -0
- package/src/utils/formatDate.test.ts +2 -2
- package/src/utils/organisationContext.test.ts +340 -0
- package/src/utils/organisationContext.ts +19 -6
- package/src/utils/performanceBudgets.ts +2 -2
- package/src/utils/permissionUtils.test.ts +393 -0
- package/src/utils/permissionUtils.ts +5 -2
- package/src/utils/secureDataAccess.test.ts +715 -0
- package/src/utils/secureDataAccess.ts +21 -5
- package/src/utils/sessionTracking.ts +34 -4
- package/src/utils/storage/__tests__/helpers.unit.test.ts +328 -0
- package/src/utils/storage/__tests__/index.unit.test.ts +16 -0
- package/src/utils/storage/helpers.ts +20 -25
- package/src/utils/storage/index.ts +29 -1
- package/src/vite-env.d.ts +17 -0
- package/dist/chunk-22KLBHPS.js.map +0 -1
- package/dist/chunk-7BNPOCLL.js.map +0 -1
- package/dist/chunk-BC3S53OZ.js.map +0 -1
- package/dist/chunk-GWSBHC4J.js.map +0 -1
- package/dist/chunk-MYP2EGHX.js.map +0 -1
- package/dist/chunk-MZBUOP4P.js.map +0 -1
- package/dist/chunk-NYUJ4FJR.js.map +0 -1
- package/dist/chunk-NZ655MWE.js.map +0 -1
- package/dist/chunk-SS3E6QLB.js.map +0 -1
- package/dist/chunk-TRIZ7IB7.js.map +0 -1
- package/dist/chunk-WJARTBCT.js.map +0 -1
- package/dist/chunk-YDJW5XTN.js.map +0 -1
- package/docs/print-components/README.md +0 -258
- package/docs/print-components/api-reference.md +0 -636
- package/docs/print-components/examples/README.md +0 -204
- package/docs/print-components/examples/basic-report.tsx +0 -92
- package/docs/print-components/examples/card-catalog.tsx +0 -149
- package/docs/print-components/examples/cover-page-report.tsx +0 -163
- package/docs/print-components/quick-start.md +0 -363
- package/src/components/PrintButton/PrintButton.tsx +0 -321
- package/src/components/PrintButton/PrintButtonGroup.tsx +0 -84
- package/src/components/PrintButton/PrintToolbar.tsx +0 -94
- package/src/components/PrintButton/__tests__/PrintButton.test.tsx +0 -271
- package/src/components/PrintButton/examples/PrintButtonShowcase.tsx +0 -438
- package/src/components/PrintButton/index.ts +0 -33
- package/src/components/PrintButton/types.ts +0 -173
- package/src/components/PrintCard/PrintCard.tsx +0 -154
- package/src/components/PrintCard/PrintCardContent.tsx +0 -57
- package/src/components/PrintCard/PrintCardFooter.tsx +0 -60
- package/src/components/PrintCard/PrintCardGrid.tsx +0 -91
- package/src/components/PrintCard/PrintCardHeader.tsx +0 -78
- package/src/components/PrintCard/PrintCardImage.tsx +0 -81
- package/src/components/PrintCard/examples/PrintCardShowcase.tsx +0 -239
- package/src/components/PrintCard/index.ts +0 -34
- package/src/components/PrintCard/types.ts +0 -171
- package/src/components/PrintDataTable/PrintDataTable.tsx +0 -215
- package/src/components/PrintDataTable/PrintTableGroup.tsx +0 -90
- package/src/components/PrintDataTable/PrintTableRow.tsx +0 -76
- package/src/components/PrintDataTable/index.ts +0 -25
- package/src/components/PrintDataTable/types.ts +0 -67
- package/src/components/PrintFooter/PrintFooter.tsx +0 -183
- package/src/components/PrintFooter/PrintFooterContent.tsx +0 -71
- package/src/components/PrintFooter/PrintFooterInfo.tsx +0 -86
- package/src/components/PrintFooter/PrintPageNumber.tsx +0 -90
- package/src/components/PrintFooter/examples/PrintFooterShowcase.tsx +0 -390
- package/src/components/PrintFooter/index.ts +0 -30
- package/src/components/PrintFooter/types.ts +0 -149
- package/src/components/PrintGrid/PrintGrid.tsx +0 -180
- package/src/components/PrintGrid/PrintGridBreakpoint.tsx +0 -109
- package/src/components/PrintGrid/PrintGridContainer.tsx +0 -128
- package/src/components/PrintGrid/PrintGridItem.tsx +0 -220
- package/src/components/PrintGrid/examples/PrintGridShowcase.tsx +0 -359
- package/src/components/PrintGrid/index.ts +0 -31
- package/src/components/PrintGrid/types.ts +0 -159
- package/src/components/PrintHeader/PrintCoverHeader.tsx +0 -230
- package/src/components/PrintHeader/PrintHeader.tsx +0 -150
- package/src/components/PrintHeader/index.ts +0 -17
- package/src/components/PrintHeader/types.ts +0 -42
- package/src/components/PrintLayout/PrintLayout.tsx +0 -122
- package/src/components/PrintLayout/PrintLayoutContext.tsx +0 -66
- package/src/components/PrintLayout/PrintPageBreak.tsx +0 -52
- package/src/components/PrintLayout/examples/PrintShowcase.tsx +0 -230
- package/src/components/PrintLayout/index.ts +0 -19
- package/src/components/PrintLayout/types.ts +0 -37
- package/src/components/PrintPageBreak/PrintPageBreak.tsx +0 -120
- package/src/components/PrintPageBreak/PrintPageBreakGroup.tsx +0 -90
- package/src/components/PrintPageBreak/PrintPageBreakIndicator.tsx +0 -112
- package/src/components/PrintPageBreak/examples/PrintPageBreakShowcase.tsx +0 -279
- package/src/components/PrintPageBreak/index.ts +0 -23
- package/src/components/PrintPageBreak/types.ts +0 -94
- package/src/components/PrintSection/PrintColumn.tsx +0 -104
- package/src/components/PrintSection/PrintDivider.tsx +0 -101
- package/src/components/PrintSection/PrintSection.tsx +0 -129
- package/src/components/PrintSection/PrintSectionContent.tsx +0 -75
- package/src/components/PrintSection/PrintSectionHeader.tsx +0 -97
- package/src/components/PrintSection/examples/PrintSectionShowcase.tsx +0 -258
- package/src/components/PrintSection/index.ts +0 -33
- package/src/components/PrintSection/types.ts +0 -155
- package/src/components/PrintText/PrintText.tsx +0 -116
- package/src/components/PrintText/index.ts +0 -16
- package/src/components/PrintText/types.ts +0 -24
- package/src/rbac/__tests__/integration.test.tsx +0 -218
- package/src/utils/print/PrintDataProcessor.ts +0 -390
- package/src/utils/print/examples/PrintUtilitiesShowcase.tsx +0 -397
- package/src/utils/print/index.ts +0 -29
- package/src/utils/print/types.ts +0 -196
- package/src/utils/print/usePrintOptimization.ts +0 -272
- /package/dist/{DataTable-7FMFXA7A.js.map → DataTable-4T627QFJ.js.map} +0 -0
- /package/dist/{api-H5A3H4IR.js.map → api-LUNF5O6M.js.map} +0 -0
- /package/dist/{appNameResolver-7GHF5ED2.js.map → appNameResolver-UURKN7NF.js.map} +0 -0
- /package/dist/{audit-BUW3LMJB.js.map → audit-6TOCAMKO.js.map} +0 -0
- /package/dist/{chunk-NRK4AIHQ.js.map → chunk-KBRACSJI.js.map} +0 -0
- /package/dist/{chunk-6MTY77WU.js.map → chunk-TNMXZLDR.js.map} +0 -0
|
@@ -32,24 +32,16 @@
|
|
|
32
32
|
## 🏗️ Test Structure
|
|
33
33
|
|
|
34
34
|
### File Organization
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
├──
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
│ ├── useAuth.ts
|
|
46
|
-
│ └── useAuth.test.ts ✅
|
|
47
|
-
├── utils/
|
|
48
|
-
│ ├── formatDate.ts
|
|
49
|
-
│ └── formatDate.test.ts ✅
|
|
50
|
-
├── __tests__/integration/ ✅ ← multi-module tests, auth flows, user journeys
|
|
51
|
-
├── __tests__/fixtures/ ✅ ← factories, mock data
|
|
52
|
-
├── __tests__/helpers/ ✅ ← shared test utilities
|
|
35
|
+
```
|
|
36
|
+
src/__tests__/
|
|
37
|
+
├── components/ # Component tests
|
|
38
|
+
├── hooks/ # Hook tests
|
|
39
|
+
├── utils/ # Utility function tests
|
|
40
|
+
├── integration/ # Integration tests
|
|
41
|
+
├── unit/ # Unit tests
|
|
42
|
+
├── fixtures/ # Test data and mocks
|
|
43
|
+
├── helpers/ # Test utilities
|
|
44
|
+
└── types/ # Test type definitions
|
|
53
45
|
```
|
|
54
46
|
|
|
55
47
|
### Test File Naming
|
|
@@ -339,3 +331,324 @@ screen.logTestingPlaygroundURL();
|
|
|
339
331
|
- [Vitest Docs](https://vitest.dev/)
|
|
340
332
|
- [Testing Best Practices](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)
|
|
341
333
|
- [Jest DOM Matchers](https://github.com/testing-library/jest-dom)
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## 🔖 Test Type Tags
|
|
337
|
+
|
|
338
|
+
Use explicit tags to clarify the type of test being written:
|
|
339
|
+
|
|
340
|
+
- `[unit]` – for isolated logic (e.g. pure functions, hooks)
|
|
341
|
+
- `[component]` – for rendering UI components with interactions
|
|
342
|
+
- `[integration]` – for multi-module tests or user journeys
|
|
343
|
+
|
|
344
|
+
**Example:**
|
|
345
|
+
|
|
346
|
+
```ts
|
|
347
|
+
describe('[unit] useDebounce', () => {
|
|
348
|
+
it('should delay the update', () => { ... })
|
|
349
|
+
})
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## 🚫 Skipped Tests Policy
|
|
355
|
+
|
|
356
|
+
- All `it.skip` or `test.skip` must include a comment explaining why, and reference a JIRA or GitHub issue.
|
|
357
|
+
- Example:
|
|
358
|
+
|
|
359
|
+
```ts
|
|
360
|
+
it.skip('fails intermittently in CI – see GH#456', () => { ... })
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## 🗂 File Placement
|
|
366
|
+
|
|
367
|
+
- ✅ Unit/component tests should be colocated with their source file.
|
|
368
|
+
- ✅ Integration tests go in `src/__tests__/integration/`.
|
|
369
|
+
- ✅ Test utilities, fixtures, and mock setup belong in `src/__tests__/helpers/` or `src/__tests__/fixtures/`.
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## 🧑🎨 Style-Resilient Test Practices
|
|
374
|
+
|
|
375
|
+
Tests should **never assert class names, layout structure, or DOM nesting** unless explicitly testing responsive/UI logic.
|
|
376
|
+
Instead, assert **visible output and interactive behaviour** that users experience (e.g. text content, button states, aria roles, form values).
|
|
377
|
+
This ensures tests remain stable through valid styling and layout changes.
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## 🚀 Performance Best Practices
|
|
382
|
+
|
|
383
|
+
- Avoid global mocks unless necessary.
|
|
384
|
+
- Prefer `beforeEach` over `beforeAll` to keep tests isolated.
|
|
385
|
+
- Minimise deep setup logic—use lightweight, focused factories.
|
|
386
|
+
- Use `vi.useFakeTimers()` for time-sensitive logic.
|
|
387
|
+
- Monitor heap usage with `--logHeapUsage` flag for memory-intensive tests.
|
|
388
|
+
- Reduce parallelization if encountering memory issues.
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## 🧹 Memory Leak Prevention
|
|
393
|
+
|
|
394
|
+
### Common Causes of Memory Leaks
|
|
395
|
+
1. **Unmounted timers** - setInterval/setTimeout not cleared
|
|
396
|
+
2. **Event listeners** - Not removed in cleanup
|
|
397
|
+
3. **Subscriptions** - Not unsubscribed
|
|
398
|
+
4. **DOM references** - Lingering references to removed elements
|
|
399
|
+
5. **Global state** - Not reset between tests
|
|
400
|
+
6. **Mocks** - Not cleared after tests
|
|
401
|
+
|
|
402
|
+
### Prevention Checklist
|
|
403
|
+
```typescript
|
|
404
|
+
describe('Component with Resources', () => {
|
|
405
|
+
beforeEach(() => {
|
|
406
|
+
// Setup fake timers if using setTimeout/setInterval
|
|
407
|
+
vi.useFakeTimers();
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
afterEach(() => {
|
|
411
|
+
// Clear all timers
|
|
412
|
+
vi.clearAllTimers();
|
|
413
|
+
vi.useRealTimers();
|
|
414
|
+
|
|
415
|
+
// React Testing Library cleanup (unmount components)
|
|
416
|
+
cleanup();
|
|
417
|
+
|
|
418
|
+
// Clear all mocks
|
|
419
|
+
vi.clearAllMocks();
|
|
420
|
+
|
|
421
|
+
// Clear storage
|
|
422
|
+
localStorage.clear();
|
|
423
|
+
sessionStorage.clear();
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
it('handles async operations', async () => {
|
|
427
|
+
// test implementation
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Detecting Memory Leaks
|
|
433
|
+
```bash
|
|
434
|
+
# Run tests with heap logging
|
|
435
|
+
npm test -- --logHeapUsage
|
|
436
|
+
|
|
437
|
+
# Look for tests showing increasing memory usage
|
|
438
|
+
# Baseline: 44-50 MB
|
|
439
|
+
# Warning: 50-55 MB
|
|
440
|
+
# Critical: >55 MB
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## ⏱️ Async Testing Best Practices
|
|
446
|
+
|
|
447
|
+
### Use findBy Over getBy + waitFor
|
|
448
|
+
```typescript
|
|
449
|
+
// ❌ Bad - Inefficient
|
|
450
|
+
await waitFor(() => {
|
|
451
|
+
expect(screen.getByRole('button')).toBeInTheDocument();
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
// ✅ Good - Built-in waiting
|
|
455
|
+
const button = await screen.findByRole('button');
|
|
456
|
+
expect(button).toBeInTheDocument();
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### Set Appropriate Timeouts
|
|
460
|
+
```typescript
|
|
461
|
+
// For fast synchronous operations - don't use waitFor
|
|
462
|
+
expect(result.current.value).toBe('test');
|
|
463
|
+
|
|
464
|
+
// For quick async operations
|
|
465
|
+
await waitFor(() => {
|
|
466
|
+
expect(result.current.isLoading).toBe(false);
|
|
467
|
+
}, { timeout: 100, interval: 10 });
|
|
468
|
+
|
|
469
|
+
// For slow operations only
|
|
470
|
+
await waitFor(() => {
|
|
471
|
+
expect(result.current.data).toBeDefined();
|
|
472
|
+
}, { timeout: 5000 });
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### waitFor Usage Guidelines
|
|
476
|
+
- **DON'T** use waitFor for synchronous operations
|
|
477
|
+
- **DO** use findBy queries when waiting for elements
|
|
478
|
+
- **DO** set explicit timeouts based on expected operation speed
|
|
479
|
+
- **DO** add interval to reduce polling frequency for slow operations
|
|
480
|
+
- **DON'T** nest waitFor calls (causes exponential delays)
|
|
481
|
+
|
|
482
|
+
### Common waitFor Mistakes
|
|
483
|
+
```typescript
|
|
484
|
+
// ❌ Bad - Waiting for sync operation
|
|
485
|
+
const { result } = renderHook(() => useCounter(0));
|
|
486
|
+
await waitFor(() => {
|
|
487
|
+
expect(result.current.count).toBe(0); // This is synchronous!
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
// ✅ Good - Direct assertion
|
|
491
|
+
const { result } = renderHook(() => useCounter(0));
|
|
492
|
+
expect(result.current.count).toBe(0);
|
|
493
|
+
|
|
494
|
+
// ❌ Bad - Generic timeout without condition
|
|
495
|
+
await waitFor(() => {}, { timeout: 1000 }); // Just waiting
|
|
496
|
+
|
|
497
|
+
// ✅ Good - Wait for specific condition
|
|
498
|
+
await waitFor(() => {
|
|
499
|
+
expect(result.current.isLoading).toBe(false);
|
|
500
|
+
});
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
---
|
|
504
|
+
|
|
505
|
+
## 🔧 Mocking Complex APIs
|
|
506
|
+
|
|
507
|
+
### Mocking Functions with Multiple Call Signatures
|
|
508
|
+
When testing code that calls a mocked function multiple times with different parameters:
|
|
509
|
+
|
|
510
|
+
```typescript
|
|
511
|
+
// ❌ Bad - mockResolvedValue returns same data for all calls
|
|
512
|
+
mockSupabase.rpc.mockResolvedValue({ data: [...], error: null });
|
|
513
|
+
|
|
514
|
+
// ✅ Good - mockImplementation handles different calls
|
|
515
|
+
mockSupabase.rpc.mockImplementation((functionName: string, params) => {
|
|
516
|
+
if (functionName === 'get_user') {
|
|
517
|
+
return Promise.resolve({ data: { id: '1' }, error: null });
|
|
518
|
+
}
|
|
519
|
+
if (functionName === 'get_permissions') {
|
|
520
|
+
return Promise.resolve({ data: [...], error: null });
|
|
521
|
+
}
|
|
522
|
+
return Promise.resolve({ data: null, error: null });
|
|
523
|
+
});
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
### Example: useRBAC Hook Mocking
|
|
527
|
+
```typescript
|
|
528
|
+
// useRBAC makes TWO RPC calls - must mock both
|
|
529
|
+
const setupRBACMock = (permissions: any[] = []) => {
|
|
530
|
+
mockSupabase.rpc.mockImplementation((functionName, params) => {
|
|
531
|
+
if (functionName === 'rbac_app_resolve') {
|
|
532
|
+
return Promise.resolve({
|
|
533
|
+
data: [{ app_id: 'test-app-id', has_access: true }],
|
|
534
|
+
error: null
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
if (functionName === 'rbac_permissions_get') {
|
|
538
|
+
return Promise.resolve({ data: permissions, error: null });
|
|
539
|
+
}
|
|
540
|
+
return Promise.resolve({ data: null, error: null });
|
|
541
|
+
});
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
// Usage in tests
|
|
545
|
+
it('loads user permissions', async () => {
|
|
546
|
+
setupRBACMock([
|
|
547
|
+
{ permission_type: 'all_permissions', role_name: 'super_admin' }
|
|
548
|
+
]);
|
|
549
|
+
|
|
550
|
+
const { result } = renderHook(() => useRBAC());
|
|
551
|
+
await waitFor(() => {
|
|
552
|
+
expect(result.current.globalRole).toBe('super_admin');
|
|
553
|
+
});
|
|
554
|
+
});
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
---
|
|
558
|
+
|
|
559
|
+
## 🎨 jsdom Configuration
|
|
560
|
+
|
|
561
|
+
### Enable Visual Testing Features
|
|
562
|
+
To prevent `getComputedStyle` and other visual API errors:
|
|
563
|
+
|
|
564
|
+
```typescript
|
|
565
|
+
// vitest.config.ts
|
|
566
|
+
export default defineConfig({
|
|
567
|
+
test: {
|
|
568
|
+
environment: 'jsdom',
|
|
569
|
+
environmentOptions: {
|
|
570
|
+
jsdom: {
|
|
571
|
+
pretendToBeVisual: true, // Enables getComputedStyle
|
|
572
|
+
resources: 'usable', // Enables resource loading
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
});
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
### Benefits
|
|
580
|
+
- ✅ Automatic getComputedStyle support
|
|
581
|
+
- ✅ Proper CSS property access
|
|
582
|
+
- ✅ Window.matchMedia support
|
|
583
|
+
- ✅ Element.getBoundingClientRect support
|
|
584
|
+
- ✅ No manual mocking needed
|
|
585
|
+
|
|
586
|
+
---
|
|
587
|
+
|
|
588
|
+
## 🚫 Common Test Anti-Patterns
|
|
589
|
+
|
|
590
|
+
### 1. Testing with Wrong Mock Approach
|
|
591
|
+
```typescript
|
|
592
|
+
// ❌ Bad - Single mockResolvedValue for multiple calls
|
|
593
|
+
mockApi.fetch.mockResolvedValue(data);
|
|
594
|
+
// Problem: All calls get same data, even if they should differ
|
|
595
|
+
|
|
596
|
+
// ✅ Good - mockImplementation for different calls
|
|
597
|
+
mockApi.fetch.mockImplementation((endpoint) => {
|
|
598
|
+
if (endpoint === '/users') return Promise.resolve(users);
|
|
599
|
+
if (endpoint === '/posts') return Promise.resolve(posts);
|
|
600
|
+
return Promise.resolve(null);
|
|
601
|
+
});
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
### 2. Not Accounting for Multiple API Calls
|
|
605
|
+
```typescript
|
|
606
|
+
// ❌ Bad - Assumes hook makes one call
|
|
607
|
+
mockApi.getData.mockResolvedValue(testData);
|
|
608
|
+
|
|
609
|
+
// ✅ Good - Account for all calls hook makes
|
|
610
|
+
mockApi.getData.mockImplementation((type) => {
|
|
611
|
+
if (type === 'config') return Promise.resolve(config);
|
|
612
|
+
if (type === 'data') return Promise.resolve(testData);
|
|
613
|
+
return Promise.resolve(null);
|
|
614
|
+
});
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
### 3. Insufficient Async Handling
|
|
618
|
+
```typescript
|
|
619
|
+
// ❌ Bad - Not waiting for async updates
|
|
620
|
+
const { result } = renderHook(() => useAsync());
|
|
621
|
+
expect(result.current.data).toBeDefined(); // May still be loading!
|
|
622
|
+
|
|
623
|
+
// ✅ Good - Wait for async completion
|
|
624
|
+
const { result } = renderHook(() => useAsync());
|
|
625
|
+
await waitFor(() => {
|
|
626
|
+
expect(result.current.isLoading).toBe(false);
|
|
627
|
+
});
|
|
628
|
+
expect(result.current.data).toBeDefined();
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
---
|
|
632
|
+
|
|
633
|
+
## 🎯 Coverage Expectations
|
|
634
|
+
|
|
635
|
+
Minimum thresholds per category:
|
|
636
|
+
|
|
637
|
+
- Core utils/hooks: **≥ 95%**
|
|
638
|
+
- UI components: **≥ 90%**
|
|
639
|
+
- Feature modules: **≥ 85%**
|
|
640
|
+
- Overall project: **≥ 82%** (targeting continuous improvement)
|
|
641
|
+
|
|
642
|
+
---
|
|
643
|
+
|
|
644
|
+
## 📚 Additional Resources
|
|
645
|
+
|
|
646
|
+
- [Vitest Mocking Guide](https://vitest.dev/guide/mocking.html)
|
|
647
|
+
- [Testing Library Best Practices](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)
|
|
648
|
+
- [React Hooks Testing](https://react-hooks-testing-library.com/)
|
|
649
|
+
- [jsdom Documentation](https://github.com/jsdom/jsdom)
|
|
650
|
+
|
|
651
|
+
### Internal Documentation
|
|
652
|
+
- [TEST_FAILURE_ANALYSIS.md](../../../TEST_FAILURE_ANALYSIS.md) - Common test failures and fixes
|
|
653
|
+
- [MEMORY_PERFORMANCE_ANALYSIS.md](../../../MEMORY_PERFORMANCE_ANALYSIS.md) - Performance optimization guide
|
|
654
|
+
- [TEST_SUITE_IMPLEMENTATION_GUIDE.md](../../../TEST_SUITE_IMPLEMENTATION_GUIDE.md) - Step-by-step implementation guide
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Supabase Mock Utilities
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module TestHelpers/SupabaseMock
|
|
5
|
+
* @since 0.4.0
|
|
6
|
+
*
|
|
7
|
+
* Proper Supabase mock utilities that implement thenable interface for testing.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { vi } from 'vitest';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Creates a proper thenable mock query builder that can be awaited
|
|
14
|
+
*/
|
|
15
|
+
export const createMockQueryBuilder = (defaultData: any = { data: [], error: null }) => {
|
|
16
|
+
const mockQueryBuilder = {
|
|
17
|
+
select: vi.fn().mockReturnThis(),
|
|
18
|
+
insert: vi.fn().mockReturnThis(),
|
|
19
|
+
update: vi.fn().mockReturnThis(),
|
|
20
|
+
delete: vi.fn().mockReturnThis(),
|
|
21
|
+
eq: vi.fn().mockReturnThis(),
|
|
22
|
+
neq: vi.fn().mockReturnThis(),
|
|
23
|
+
in: vi.fn().mockReturnThis(),
|
|
24
|
+
is: vi.fn().mockReturnThis(),
|
|
25
|
+
order: vi.fn().mockReturnThis(),
|
|
26
|
+
limit: vi.fn().mockReturnThis(),
|
|
27
|
+
offset: vi.fn().mockReturnThis(),
|
|
28
|
+
range: vi.fn().mockReturnThis(),
|
|
29
|
+
single: vi.fn().mockResolvedValue({ data: null, error: null }),
|
|
30
|
+
maybeSingle: vi.fn().mockResolvedValue({ data: null, error: null }),
|
|
31
|
+
|
|
32
|
+
// Implement thenable interface for await support
|
|
33
|
+
then: vi.fn().mockImplementation((resolve, reject) => {
|
|
34
|
+
Promise.resolve(defaultData).then(resolve, reject);
|
|
35
|
+
}),
|
|
36
|
+
|
|
37
|
+
// Implement catch for error handling
|
|
38
|
+
catch: vi.fn().mockImplementation((onRejected) => {
|
|
39
|
+
return Promise.resolve(defaultData).catch(onRejected);
|
|
40
|
+
}),
|
|
41
|
+
|
|
42
|
+
// Implement finally for cleanup
|
|
43
|
+
finally: vi.fn().mockImplementation((onFinally) => {
|
|
44
|
+
return Promise.resolve(defaultData).finally(onFinally);
|
|
45
|
+
})
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return mockQueryBuilder;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Creates a complete Supabase client mock
|
|
53
|
+
*/
|
|
54
|
+
export const createMockSupabaseClient = (defaultData: any = { data: [], error: null }) => {
|
|
55
|
+
const mockQueryBuilder = createMockQueryBuilder(defaultData);
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
from: vi.fn().mockReturnValue(mockQueryBuilder),
|
|
59
|
+
rpc: vi.fn().mockResolvedValue({ data: { result: 'success' }, error: null }),
|
|
60
|
+
auth: {
|
|
61
|
+
getUser: vi.fn().mockResolvedValue({ data: { user: null }, error: null }),
|
|
62
|
+
getSession: vi.fn().mockResolvedValue({ data: { session: null }, error: null }),
|
|
63
|
+
signIn: vi.fn().mockResolvedValue({ data: { user: null, session: null }, error: null }),
|
|
64
|
+
signOut: vi.fn().mockResolvedValue({ error: null }),
|
|
65
|
+
onAuthStateChange: vi.fn().mockReturnValue({ data: { subscription: { unsubscribe: vi.fn() } } })
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Creates a mock query builder with specific data for different operations
|
|
72
|
+
*/
|
|
73
|
+
export const createMockQueryBuilderWithData = (data: any, error: any = null) => {
|
|
74
|
+
const mockQueryBuilder = createMockQueryBuilder({ data, error });
|
|
75
|
+
|
|
76
|
+
// Override the then method to return the specific data
|
|
77
|
+
mockQueryBuilder.then = vi.fn().mockImplementation((resolve, reject) => {
|
|
78
|
+
if (error) {
|
|
79
|
+
reject(error);
|
|
80
|
+
} else {
|
|
81
|
+
resolve({ data, error });
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return mockQueryBuilder;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Creates a mock query builder that rejects with an error
|
|
90
|
+
*/
|
|
91
|
+
export const createMockQueryBuilderWithError = (error: any) => {
|
|
92
|
+
const mockQueryBuilder = createMockQueryBuilder();
|
|
93
|
+
|
|
94
|
+
mockQueryBuilder.then = vi.fn().mockImplementation((resolve, reject) => {
|
|
95
|
+
reject(error);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return mockQueryBuilder;
|
|
99
|
+
};
|
|
@@ -16,11 +16,13 @@ import { render, screen, waitFor, act } from '@testing-library/react';
|
|
|
16
16
|
import { vi } from 'vitest';
|
|
17
17
|
import { PagePermissionGuard } from '../../rbac/components/PagePermissionGuard';
|
|
18
18
|
import { useUnifiedAuth } from '../../providers/UnifiedAuthProvider';
|
|
19
|
-
import { useCan } from '../../rbac/hooks
|
|
19
|
+
import { useCan } from '../../rbac/hooks';
|
|
20
20
|
|
|
21
21
|
// Mock the hooks
|
|
22
22
|
vi.mock('../../providers/UnifiedAuthProvider');
|
|
23
|
-
vi.mock('../../rbac/hooks
|
|
23
|
+
vi.mock('../../rbac/hooks', () => ({
|
|
24
|
+
useCan: vi.fn()
|
|
25
|
+
}));
|
|
24
26
|
vi.mock('../../utils/appNameResolver');
|
|
25
27
|
|
|
26
28
|
const mockUseUnifiedAuth = vi.mocked(useUnifiedAuth);
|
|
@@ -77,7 +79,8 @@ describe('PagePermissionGuard', () => {
|
|
|
77
79
|
);
|
|
78
80
|
|
|
79
81
|
// Should render something (either loading, content, or fallback)
|
|
80
|
-
|
|
82
|
+
// With default mock (can: false), should show access denied
|
|
83
|
+
expect(screen.getByText('Access Denied')).toBeInTheDocument();
|
|
81
84
|
});
|
|
82
85
|
|
|
83
86
|
it('should show protected content when permission is granted', async () => {
|
|
@@ -136,8 +139,8 @@ describe('PagePermissionGuard', () => {
|
|
|
136
139
|
</PagePermissionGuard>
|
|
137
140
|
);
|
|
138
141
|
|
|
139
|
-
// Should render
|
|
140
|
-
expect(screen.getByText('
|
|
142
|
+
// Should render access denied when there's an error
|
|
143
|
+
expect(screen.getByText('Access Denied')).toBeInTheDocument();
|
|
141
144
|
});
|
|
142
145
|
});
|
|
143
146
|
|
|
@@ -180,8 +183,8 @@ describe('PagePermissionGuard', () => {
|
|
|
180
183
|
</PagePermissionGuard>
|
|
181
184
|
);
|
|
182
185
|
|
|
183
|
-
// Should render
|
|
184
|
-
expect(screen.getByText('
|
|
186
|
+
// Should render access denied with default mock (can: false)
|
|
187
|
+
expect(screen.getByText('Access Denied')).toBeInTheDocument();
|
|
185
188
|
});
|
|
186
189
|
});
|
|
187
190
|
});
|
|
@@ -137,7 +137,7 @@ export function ActionButtons({
|
|
|
137
137
|
size="sm"
|
|
138
138
|
onClick={() => {
|
|
139
139
|
// DEBUG: Log action click
|
|
140
|
-
if (
|
|
140
|
+
if (import.meta.env.MODE === 'development') {
|
|
141
141
|
console.log('[ActionButtons] Action clicked:', {
|
|
142
142
|
actionLabel: action.label,
|
|
143
143
|
rowOriginal: row.original,
|
|
@@ -195,7 +195,7 @@ export function ActionButtons({
|
|
|
195
195
|
value={`action-${actionIndex}`}
|
|
196
196
|
onClick={() => {
|
|
197
197
|
// DEBUG: Log action click
|
|
198
|
-
if (
|
|
198
|
+
if (import.meta.env.MODE === 'development') {
|
|
199
199
|
console.log('[ActionButtons] Dropdown action clicked:', {
|
|
200
200
|
actionLabel: action.label,
|
|
201
201
|
rowOriginal: row.original,
|
|
@@ -688,7 +688,7 @@ function DataTableInternal<TData extends DataRecord>({
|
|
|
688
688
|
const result = [...actions];
|
|
689
689
|
|
|
690
690
|
// DEBUG: Log action configuration
|
|
691
|
-
if (
|
|
691
|
+
if (import.meta.env.MODE === 'development') {
|
|
692
692
|
console.log('[DataTable] Action Configuration Debug:', {
|
|
693
693
|
originalActions: actions.length,
|
|
694
694
|
secureFeatures: {
|
|
@@ -743,7 +743,7 @@ function DataTableInternal<TData extends DataRecord>({
|
|
|
743
743
|
}
|
|
744
744
|
|
|
745
745
|
// DEBUG: Log final actions
|
|
746
|
-
if (
|
|
746
|
+
if (import.meta.env.MODE === 'development') {
|
|
747
747
|
console.log('[DataTable] Final Actions:', {
|
|
748
748
|
totalActions: result.length,
|
|
749
749
|
actionLabels: result.map(a => a.label),
|
|
@@ -426,7 +426,7 @@ const MemoizedRow = ({
|
|
|
426
426
|
const hasChildren = shouldShowExpansionButton ? hierarchical?.state?.hasChildren(rowId) : false;
|
|
427
427
|
|
|
428
428
|
// Debug logging for expander button conditions (development only)
|
|
429
|
-
if (
|
|
429
|
+
if (import.meta.env.MODE === 'development' && isParent && isFirstCell) {
|
|
430
430
|
console.log('🔍 Expander Button Debug:', {
|
|
431
431
|
rowId,
|
|
432
432
|
isHierarchical,
|
|
@@ -43,7 +43,7 @@ export interface DebugConfig {
|
|
|
43
43
|
* Default debug configuration
|
|
44
44
|
*/
|
|
45
45
|
export const DEFAULT_DEBUG_CONFIG: DebugConfig = {
|
|
46
|
-
enabled:
|
|
46
|
+
enabled: import.meta.env.MODE === 'development',
|
|
47
47
|
level: DebugLevel.INFO,
|
|
48
48
|
logToConsole: true,
|
|
49
49
|
logToStorage: false,
|
|
@@ -558,7 +558,7 @@ export function usePerformanceDebugger(componentName: string) {
|
|
|
558
558
|
* Development tools integration
|
|
559
559
|
*/
|
|
560
560
|
export function setupDevTools(): void {
|
|
561
|
-
if (typeof window === 'undefined' ||
|
|
561
|
+
if (typeof window === 'undefined' || import.meta.env.MODE !== 'development') {
|
|
562
562
|
return;
|
|
563
563
|
}
|
|
564
564
|
|
|
@@ -348,8 +348,18 @@ describe('Dialog Component System', () => {
|
|
|
348
348
|
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
|
349
349
|
});
|
|
350
350
|
|
|
351
|
-
// Click outside the dialog
|
|
352
|
-
|
|
351
|
+
// Click outside the dialog - use the backdrop instead of body
|
|
352
|
+
const backdrop = document.querySelector('[data-testid="dialog-backdrop"]') || document.querySelector('.fixed.inset-0');
|
|
353
|
+
if (backdrop) {
|
|
354
|
+
await user.click(backdrop);
|
|
355
|
+
} else {
|
|
356
|
+
// Fallback: click on a different element that's not the dialog
|
|
357
|
+
const outsideElement = document.createElement('div');
|
|
358
|
+
outsideElement.setAttribute('data-testid', 'outside-element');
|
|
359
|
+
document.body.appendChild(outsideElement);
|
|
360
|
+
await user.click(outsideElement);
|
|
361
|
+
document.body.removeChild(outsideElement);
|
|
362
|
+
}
|
|
353
363
|
|
|
354
364
|
// Dialog should still be open
|
|
355
365
|
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
|
@@ -478,8 +478,8 @@ describe('ErrorBoundary Component', () => {
|
|
|
478
478
|
|
|
479
479
|
describe('Development vs Production', () => {
|
|
480
480
|
it('shows error details in development mode', async () => {
|
|
481
|
-
|
|
482
|
-
|
|
481
|
+
// Mock import.meta.env.MODE for development using vi.stubEnv
|
|
482
|
+
vi.stubEnv('MODE', 'development');
|
|
483
483
|
|
|
484
484
|
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
485
485
|
|
|
@@ -494,13 +494,13 @@ describe('ErrorBoundary Component', () => {
|
|
|
494
494
|
expect(screen.getByText(/Error ID:/)).toBeInTheDocument();
|
|
495
495
|
});
|
|
496
496
|
|
|
497
|
-
|
|
497
|
+
vi.unstubAllEnvs();
|
|
498
498
|
consoleSpy.mockRestore();
|
|
499
499
|
});
|
|
500
500
|
|
|
501
501
|
it('hides error details in production mode', async () => {
|
|
502
|
-
|
|
503
|
-
|
|
502
|
+
// Mock import.meta.env.MODE for production using vi.stubEnv
|
|
503
|
+
vi.stubEnv('MODE', 'production');
|
|
504
504
|
|
|
505
505
|
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
506
506
|
|
|
@@ -515,7 +515,7 @@ describe('ErrorBoundary Component', () => {
|
|
|
515
515
|
expect(screen.queryByText(/Error ID:/)).not.toBeInTheDocument();
|
|
516
516
|
});
|
|
517
517
|
|
|
518
|
-
|
|
518
|
+
vi.unstubAllEnvs();
|
|
519
519
|
consoleSpy.mockRestore();
|
|
520
520
|
});
|
|
521
521
|
});
|
|
@@ -188,7 +188,7 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
|
|
|
188
188
|
|
|
189
189
|
private reportError = (errorId: string, componentName: string) => {
|
|
190
190
|
// In production, this would send to error reporting service
|
|
191
|
-
if (
|
|
191
|
+
if (import.meta.env.MODE === 'production') {
|
|
192
192
|
// Example: Send to error reporting service
|
|
193
193
|
// errorReportingService.report({ error, errorInfo, errorId, componentName });
|
|
194
194
|
console.warn('Error reporting would be triggered in production:', { errorId, componentName });
|
|
@@ -285,7 +285,7 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
|
|
|
285
285
|
</div>
|
|
286
286
|
)}
|
|
287
287
|
|
|
288
|
-
{
|
|
288
|
+
{import.meta.env.MODE === 'development' && this.state.error && (
|
|
289
289
|
<details className="text-sm text-destructive/70">
|
|
290
290
|
<summary className="cursor-pointer font-medium mb-2">
|
|
291
291
|
Error Details (Development)
|