@jmruthers/pace-core 0.6.8 → 0.6.10
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/CHANGELOG.md +3 -0
- package/audit-tool/audits/02-project-structure.cjs +97 -32
- package/audit-tool/audits/03-architecture.cjs +145 -19
- package/audit-tool/audits/04-code-quality.cjs +86 -1
- package/audit-tool/audits/06-security-rbac.cjs +109 -11
- package/cursor-rules/02-project-structure.mdc +2 -26
- package/cursor-rules/05-styling.mdc +84 -6
- package/cursor-rules/06-security-rbac.mdc +124 -1
- package/dist/{DataTable-6RMSCQJ6.js → DataTable-SAXFG4XI.js} +11 -13
- package/dist/{AuthService-DmfO5rGS.d.ts → InactivityServiceProvider-DHryoh6K.d.ts} +24 -249
- package/dist/UnifiedAuthProvider-BBD2PS3Q.js +7 -0
- package/dist/{UnifiedAuthProvider-CKvHP1MK.d.ts → UnifiedAuthProvider-CiBAl9-s.d.ts} +34 -22
- package/dist/{api-7P7DI652.js → api-F47QJ7FX.js} +3 -3
- package/dist/assets/app-icons/admin_favicon.svg +462 -0
- package/dist/assets/app-icons/base_favicon.svg +85 -0
- package/dist/assets/app-icons/cake_favicon.svg +68 -0
- package/dist/assets/app-icons/core_favicon.svg +256 -0
- package/dist/assets/app-icons/gear_favicon.svg +91 -0
- package/dist/assets/app-icons/medi_favicon.svg +92 -0
- package/dist/assets/app-icons/mint_favicon.svg +83 -0
- package/dist/assets/app-icons/pace_favicon.svg +49 -0
- package/dist/assets/app-icons/pump_favicon.svg +68 -0
- package/dist/assets/app-icons/seed_favicon.svg +91 -0
- package/dist/assets/app-icons/team_favicon.svg +67 -0
- package/dist/assets/app-icons/trac_favicon.svg +112 -0
- package/dist/assets/app-icons/trip_favicon.svg +102 -0
- package/dist/audit-Z6ZZBWLU.js +3 -0
- package/dist/chunk-3GWSPISD.js +61 -0
- package/dist/{chunk-4DDCYDQ3.js → chunk-66R6RLUZ.js} +12 -27
- package/dist/{chunk-FYHN4DD5.js → chunk-7YDC7LMU.js} +80 -8
- package/dist/{chunk-S7DKJPLT.js → chunk-BCTXBU6U.js} +22 -17
- package/dist/{chunk-TTRFSOKR.js → chunk-BTHN5MKC.js} +4 -4
- package/dist/{chunk-A3W6LW53.js → chunk-DDMPHZ3D.js} +6 -18
- package/dist/{chunk-MPBLMWVR.js → chunk-FBZ7U3ID.js} +140 -92
- package/dist/chunk-FN52B75D.js +246 -0
- package/dist/{chunk-5W2A3DRC.js → chunk-JJEYZ3DX.js} +5 -4
- package/dist/chunk-KPYQWGFQ.js +183 -0
- package/dist/{chunk-IUBRCBSY.js → chunk-KSNLMI7N.js} +14 -8
- package/dist/chunk-KYURMOQM.js +977 -0
- package/dist/{chunk-LX6U42O3.js → chunk-LNHFAF4X.js} +160 -58
- package/dist/{chunk-NKHKXPI4.js → chunk-MPY44PWB.js} +683 -627
- package/dist/{chunk-AHU7G2R5.js → chunk-NIU6DPQV.js} +10 -6
- package/dist/{chunk-HF6O3O37.js → chunk-RMLY6KB5.js} +1 -1
- package/dist/{chunk-6GLLNA6U.js → chunk-SACF5YSM.js} +1 -1
- package/dist/{chunk-EURB7QFZ.js → chunk-TFIPNIPE.js} +867 -534
- package/dist/{chunk-OJ4SKRSV.js → chunk-UZNAFKGW.js} +25 -5
- package/dist/chunk-W46INAVW.js +1216 -0
- package/dist/chunk-X5EAU5G7.js +793 -0
- package/dist/{chunk-T5CVK4R3.js → chunk-Y4PF6HIM.js} +110 -64
- package/dist/components.d.ts +8 -86
- package/dist/components.js +21 -55
- package/dist/{database.generated-CcnC_DRc.d.ts → database.generated-DT8JTZiP.d.ts} +12 -12
- package/dist/eslint-rules/rules/05-styling.cjs +507 -0
- package/dist/eslint-rules/rules/06-security-rbac.cjs +10 -0
- package/dist/{event-CW5YB_2p.d.ts → event-WTAQuGcq.d.ts} +1 -1
- package/dist/{functions-lBy5L2ry.d.ts → functions-DH45k8ec.d.ts} +1 -1
- package/dist/hooks.d.ts +12 -11
- package/dist/hooks.js +69 -44
- package/dist/index.d.ts +380 -32
- package/dist/index.js +46 -32
- package/dist/papaparseLoader-WG2UXQ22.js +7 -0
- package/dist/providers.d.ts +28 -14
- package/dist/providers.js +5 -5
- package/dist/rbac/eslint-rules.js +2 -2
- package/dist/rbac/index.d.ts +58 -214
- package/dist/rbac/index.js +11 -11
- package/dist/theming/runtime.d.ts +9 -3
- package/dist/theming/runtime.js +2 -2
- package/dist/{timezone-BZe_eUxx.d.ts → timezone-K-ptz3HO.d.ts} +22 -23
- package/dist/{types-t9H8qKRw.d.ts → types-BE2sEHKd.d.ts} +1 -1
- package/dist/{types-BeoeWV5I.d.ts → types-CvOPXWWZ.d.ts} +6 -5
- package/dist/{types-DXstZpNI.d.ts → types-D05dCGma.d.ts} +56 -149
- package/dist/types-Dr8sNhER.d.ts +50 -0
- package/dist/types.d.ts +5 -5
- package/dist/{PublicPageProvider-CIGSujI2.d.ts → usePublicPageContext-vxBlEHO9.d.ts} +294 -151
- package/dist/{usePublicRouteParams-MamNgwqe.d.ts → usePublicRouteParams-G3Ks53mk.d.ts} +8 -7
- package/dist/utils.d.ts +301 -137
- package/dist/utils.js +42 -41
- package/dist/{validation-643vUDZW.d.ts → validation-g5n0hDkh.d.ts} +2 -2
- package/docs/api/modules.md +542 -549
- package/docs/api-reference/components.md +5 -5
- package/docs/api-reference/rpc-functions.md +3 -3
- package/docs/implementation-guides/data-tables.md +256 -8
- package/docs/rbac/RBAC_CONTRACT.md +0 -12
- package/docs/standards/2-project-structure-standards.md +12 -74
- package/docs/standards/6-security-rbac-standards.md +222 -7
- package/docs/standards/7-api-tech-stack-standards.md +91 -3
- package/docs/testing/README.md +10 -0
- package/docs/testing/test-setup-for-consumers.md +914 -0
- package/eslint-config-pace-core.cjs +4 -0
- package/package.json +1 -1
- package/scripts/eslint-audit.cjs +110 -11
- package/src/__mocks__/lucide-react.ts +0 -2
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +0 -2
- package/src/__tests__/index.test.ts +532 -0
- package/src/__tests__/integration/UserProfile.test.tsx +1 -1
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +10 -8
- package/src/__tests__/rls-policies.test.ts +3 -2
- package/src/assets/app-icons/admin_favicon.svg +462 -0
- package/src/assets/app-icons/base_favicon.svg +85 -0
- package/src/assets/app-icons/cake_favicon.svg +68 -0
- package/src/assets/app-icons/core_favicon.svg +256 -0
- package/src/assets/app-icons/gear_favicon.svg +91 -0
- package/src/assets/app-icons/index.ts +83 -0
- package/src/assets/app-icons/medi_favicon.svg +92 -0
- package/src/assets/app-icons/mint_favicon.svg +83 -0
- package/src/assets/app-icons/pace_favicon.svg +49 -0
- package/src/assets/app-icons/pump_favicon.svg +68 -0
- package/src/assets/app-icons/seed_favicon.svg +91 -0
- package/src/assets/app-icons/team_favicon.svg +67 -0
- package/src/assets/app-icons/trac_favicon.svg +112 -0
- package/src/assets/app-icons/trip_favicon.svg +102 -0
- package/src/components/AddressField/AddressField.test.tsx +378 -3
- package/src/components/AddressField/AddressField.tsx +2 -2
- package/src/components/AddressField/types.ts +2 -2
- package/src/components/Alert/Alert.test.tsx +35 -25
- package/src/components/Alert/Alert.tsx +8 -8
- package/src/components/AppSwitcher/AppSwitcher.test.tsx +1250 -0
- package/src/components/AppSwitcher/AppSwitcher.tsx +315 -0
- package/src/components/Avatar/Avatar.test.tsx +11 -1
- package/src/components/Avatar/Avatar.tsx +3 -2
- package/src/components/Badge/Badge.test.tsx +11 -1
- package/src/components/Button/Button.test.tsx +13 -3
- package/src/components/Calendar/Calendar.test.tsx +523 -131
- package/src/components/Calendar/Calendar.tsx +107 -488
- package/src/components/Card/Card.test.tsx +220 -249
- package/src/components/Checkbox/Checkbox.test.tsx +58 -174
- package/src/components/ContextSelector/ContextSelector.tsx +3 -3
- package/src/components/ContextSelector/__tests__/ContextSelector.test.tsx +360 -0
- package/src/components/DataTable/DataTable.tsx +2 -2
- package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +1 -1
- package/src/components/DataTable/__tests__/DataTable.export.test.tsx +2 -2
- package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +1 -1
- package/src/components/DataTable/__tests__/DataTable.select-label-display.test.tsx +485 -0
- package/src/components/DataTable/__tests__/DataTable.test.tsx +2 -2
- package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +1 -1
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +76 -580
- package/src/components/DataTable/__tests__/README.md +1 -1
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +1 -1
- package/src/components/DataTable/__tests__/keyboard.test.tsx +1 -1
- package/src/components/DataTable/__tests__/pagination.modes.test.tsx +1 -3
- package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +0 -6
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +14 -6
- package/src/components/DataTable/components/ActionButtons.tsx +9 -4
- package/src/components/DataTable/components/BulkOperationsDropdown.tsx +3 -3
- package/src/components/DataTable/components/ColumnFilter.tsx +2 -7
- package/src/components/DataTable/components/DataTableCore.tsx +44 -52
- package/src/components/DataTable/components/DataTableLayout.tsx +37 -26
- package/src/components/DataTable/components/DataTableModals.tsx +118 -30
- package/src/components/DataTable/components/DataTableToolbar.tsx +2 -2
- package/src/components/DataTable/components/EditFields.tsx +6 -47
- package/src/components/DataTable/components/EditableRow.tsx +8 -8
- package/src/components/DataTable/components/EmptyState.tsx +6 -3
- package/src/components/DataTable/components/FilterRow.tsx +18 -11
- package/src/components/DataTable/components/GroupingDropdown.tsx +0 -1
- package/src/components/DataTable/components/ImportModal.tsx +305 -133
- package/src/components/DataTable/components/LoadingState.tsx +2 -2
- package/src/components/DataTable/components/PaginationControls.tsx +0 -4
- package/src/components/DataTable/components/RowComponent.tsx +42 -22
- package/src/components/DataTable/components/UnifiedTableBody.tsx +52 -12
- package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +51 -463
- package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +122 -116
- package/src/components/DataTable/components/__tests__/BulkOperationsDropdown.test.tsx +40 -68
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +9 -137
- package/src/components/DataTable/components/__tests__/ColumnVisibilityDropdown.test.tsx +57 -17
- package/src/components/DataTable/components/__tests__/DataTableCore.test.tsx +792 -0
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +24 -65
- package/src/components/DataTable/components/__tests__/DataTableLayout.test.tsx +467 -0
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +8 -125
- package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +528 -56
- package/src/components/DataTable/components/__tests__/EditFields.test.tsx +526 -0
- package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +1 -68
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +8 -25
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +3 -62
- package/src/components/DataTable/components/__tests__/GroupingDropdown.test.tsx +9 -14
- package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +50 -186
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +39 -97
- package/src/components/DataTable/components/__tests__/PaginationControls.test.tsx +13 -103
- package/src/components/DataTable/components/__tests__/RowComponent.test.tsx +629 -0
- package/src/components/DataTable/components/__tests__/SortIndicator.test.tsx +135 -0
- package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +31 -171
- package/src/components/DataTable/components/__tests__/cellValueUtils.test.ts +453 -0
- package/src/components/DataTable/components/hooks/useImportModalFocus.test.ts +184 -0
- package/src/components/DataTable/components/hooks/usePermissionTracking.test.ts +381 -0
- package/src/components/DataTable/context/DataTableContext.tsx +9 -10
- package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +12 -26
- package/src/components/DataTable/core/ColumnFactory.ts +3 -3
- package/src/components/DataTable/core/ColumnManager.ts +0 -1
- package/src/components/DataTable/core/DataManager.ts +4 -2
- package/src/components/DataTable/core/LocalDataAdapter.ts +1 -1
- package/src/components/DataTable/core/PluginRegistry.ts +2 -2
- package/src/components/DataTable/core/__tests__/ActionManager.test.ts +114 -2
- package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +103 -5
- package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +57 -0
- package/src/components/DataTable/core/__tests__/DataManager.test.ts +63 -0
- package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +42 -9
- package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +29 -7
- package/src/components/DataTable/core/__tests__/StateManager.test.ts +58 -4
- package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +16 -21
- package/src/components/DataTable/hooks/__tests__/useColumnVisibilityPersistence.test.ts +93 -4
- package/src/components/DataTable/hooks/__tests__/useDataTableConfiguration.test.ts +227 -54
- package/src/components/DataTable/hooks/__tests__/useDataTableDataPipeline.test.ts +215 -62
- package/src/components/DataTable/hooks/__tests__/useDataTablePermissions.test.ts +217 -39
- package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +101 -6
- package/src/components/DataTable/hooks/__tests__/useEffectiveColumnOrder.test.ts +157 -27
- package/src/components/DataTable/hooks/__tests__/useHierarchicalState.test.ts +80 -0
- package/src/components/DataTable/hooks/__tests__/useKeyboardNavigation.test.ts +787 -0
- package/src/components/DataTable/hooks/__tests__/useServerSideDataEffect.test.ts +258 -0
- package/src/components/DataTable/hooks/__tests__/useTableColumns.test.ts +298 -23
- package/src/components/DataTable/hooks/__tests__/useTableHandlers.test.ts +440 -0
- package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +12 -9
- package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +12 -9
- package/src/components/DataTable/hooks/useDataTableConfiguration.ts +1 -1
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +11 -22
- package/src/components/DataTable/hooks/useDataTableState.ts +20 -24
- package/src/components/DataTable/hooks/useKeyboardNavigation.ts +5 -5
- package/src/components/DataTable/hooks/useServerSideDataEffect.ts +13 -1
- package/src/components/DataTable/hooks/useTableColumns.ts +36 -38
- package/src/components/DataTable/hooks/useTableHandlers.ts +8 -20
- package/src/components/DataTable/index.ts +24 -2
- package/src/components/DataTable/types.ts +6 -3
- package/src/components/DataTable/utils/__tests__/a11yUtils.test.ts +3 -67
- package/src/components/DataTable/utils/__tests__/aggregationUtils.test.ts +288 -0
- package/src/components/DataTable/utils/__tests__/errorHandling.test.ts +3 -60
- package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +1 -1
- package/src/components/DataTable/utils/__tests__/hierarchicalSorting.test.ts +9 -21
- package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +102 -86
- package/src/components/DataTable/utils/__tests__/paginationUtils.test.ts +593 -0
- package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +33 -49
- package/src/components/DataTable/utils/__tests__/selectFieldUtils.test.ts +208 -0
- package/src/components/DataTable/utils/a11yUtils.ts +1 -1
- package/src/components/DataTable/utils/aggregationUtils.ts +5 -5
- package/src/components/DataTable/utils/errorHandling.ts +3 -1
- package/src/components/DataTable/utils/exportUtils.ts +1 -1
- package/src/components/DataTable/utils/flexibleImport.ts +2 -2
- package/src/components/DataTable/utils/hierarchicalSorting.ts +3 -3
- package/src/components/DataTable/utils/paginationUtils.ts +1 -1
- package/src/components/DataTable/utils/performanceUtils.ts +1 -1
- package/src/components/DataTable/utils/selectFieldUtils.ts +127 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +17 -24
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +1 -1
- package/src/components/DateTimeField/DateTimeField.test.tsx +2 -15
- package/src/components/DateTimeField/DateTimeField.tsx +1 -1
- package/src/components/Dialog/Dialog.test.tsx +2007 -407
- package/src/components/Dialog/Dialog.tsx +97 -192
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +2 -62
- package/src/components/ErrorBoundary/ErrorBoundaryContext.context.ts +17 -0
- package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +2 -45
- package/src/components/ErrorBoundary/ErrorBoundaryContext.types.ts +41 -0
- package/src/components/ErrorBoundary/index.ts +3 -4
- package/src/components/ErrorBoundary/useErrorBoundaryContext.ts +20 -0
- package/src/components/FileDisplay/FileDisplay.test.tsx +454 -222
- package/src/components/FileDisplay/FileDisplay.tsx +14 -12
- package/src/components/FileDisplay/index.tsx +1 -1
- package/src/components/FileUpload/FileUpload.test.tsx +54 -18
- package/src/components/FileUpload/FileUpload.tsx +10 -7
- package/src/components/FileUpload/index.tsx +1 -1
- package/src/components/Footer/Footer.test.tsx +33 -114
- package/src/components/Form/Form.test.tsx +388 -68
- package/src/components/Form/Form.tsx +57 -42
- package/src/components/Header/Header.test.tsx +645 -154
- package/src/components/Header/Header.tsx +52 -43
- package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +35 -76
- package/src/components/Input/Input.test.tsx +34 -120
- package/src/components/Label/Label.test.tsx +47 -46
- package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +9 -12
- package/src/components/LoginForm/LoginForm.test.tsx +0 -1
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +1399 -82
- package/src/components/NavigationMenu/NavigationMenu.tsx +2 -2
- package/src/components/NavigationMenu/__tests__/useNavigationFiltering.test.ts +1934 -0
- package/src/components/NavigationMenu/useNavigationFiltering.ts +5 -15
- package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +1307 -0
- package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +47 -46
- package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +81 -38
- package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +87 -66
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +245 -39
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +14 -20
- package/src/components/PaceAppLayout/README.md +0 -9
- package/src/components/PaceAppLayout/test-setup.tsx +15 -9
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +759 -3
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +2 -3
- package/src/components/PasswordChange/PasswordChangeForm.test.tsx +1 -1
- package/src/components/Progress/Progress.test.tsx +127 -1
- package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +1196 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +24 -6
- package/src/components/PublicLayout/PublicLayout.test.tsx +1435 -14
- package/src/components/PublicLayout/PublicPageContext.ts +28 -0
- package/src/components/PublicLayout/PublicPageLayout.tsx +6 -6
- package/src/components/PublicLayout/PublicPageProvider.tsx +2 -41
- package/src/components/PublicLayout/usePublicPageContext.ts +36 -0
- package/src/components/Select/Select.test.tsx +46 -9
- package/src/components/Select/Select.tsx +31 -24
- package/src/components/Select/__tests__/context.test.tsx +56 -0
- package/src/components/Select/hooks/__tests__/useSelectEvents.test.ts +279 -0
- package/src/components/Select/hooks/__tests__/useSelectSearch.test.tsx +295 -0
- package/src/components/Select/hooks/__tests__/useSelectState.test.ts +254 -0
- package/src/components/Select/hooks/useSelectState.ts +16 -16
- package/src/components/Select/types.ts +3 -0
- package/src/components/Select/utils/__tests__/text.test.tsx +104 -0
- package/src/components/SessionRestorationLoader/SessionRestorationLoader.test.tsx +28 -112
- package/src/components/Switch/Switch.test.tsx +57 -153
- package/src/components/Table/Table.test.tsx +47 -317
- package/src/components/Tabs/Tabs.tsx +3 -3
- package/src/components/Textarea/Textarea.test.tsx +11 -38
- package/src/components/Toast/Toast.test.tsx +78 -569
- package/src/components/Tooltip/Tooltip.test.tsx +4 -21
- package/src/components/UserMenu/UserMenu.test.tsx +1 -21
- package/src/components/UserMenu/UserMenu.tsx +3 -6
- package/src/components/__tests__/index.test.ts +346 -0
- package/src/components/index.ts +12 -1
- package/src/constants/__tests__/performance.test.ts +91 -0
- package/src/hooks/__tests__/ServiceHooks.test.tsx +239 -129
- package/src/hooks/__tests__/hooks.integration.test.tsx +4 -3
- package/src/hooks/__tests__/useApiFetch.unit.test.ts +1 -1
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +88 -29
- package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +282 -98
- package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +53 -109
- package/src/hooks/__tests__/useDataTableState.test.ts +143 -49
- package/src/hooks/__tests__/useDebounce.unit.test.ts +94 -19
- package/src/hooks/__tests__/useEvents.unit.test.ts +100 -125
- package/src/hooks/__tests__/useFileDisplay.test.ts +540 -0
- package/src/hooks/__tests__/useFileDisplay.unit.test.ts +1 -4
- package/src/hooks/__tests__/useFileUrl.unit.test.ts +27 -247
- package/src/hooks/__tests__/useFileUrlCache.test.ts +246 -56
- package/src/hooks/__tests__/useFocusManagement.unit.test.ts +442 -68
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +345 -560
- package/src/hooks/__tests__/useFormDialog.test.ts +51 -222
- package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +1 -1
- package/src/hooks/__tests__/useKeyboardShortcuts.unit.test.ts +1 -4
- package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +0 -1
- package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +1 -1
- package/src/hooks/__tests__/usePermissionCache.test.ts +506 -0
- package/src/hooks/__tests__/usePreventTabReload.test.ts +255 -36
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +17 -8
- package/src/hooks/__tests__/usePublicEvent.test.ts +16 -24
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +12 -4
- package/src/hooks/__tests__/usePublicFileDisplay.test.ts +3 -6
- package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +1 -2
- package/src/hooks/__tests__/useQueryCache.test.ts +313 -66
- package/src/hooks/__tests__/useSessionDraft.test.ts +496 -103
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +2 -2
- package/src/hooks/__tests__/useStorage.unit.test.ts +72 -102
- package/src/hooks/__tests__/useToast.test.ts +413 -0
- package/src/hooks/__tests__/useToast.unit.test.tsx +1 -1
- package/src/hooks/__tests__/useZodForm.unit.test.tsx +175 -21
- package/src/hooks/index.ts +13 -1
- package/src/hooks/public/usePublicEvent.test.ts +304 -0
- package/src/hooks/public/usePublicEvent.ts +11 -11
- package/src/hooks/public/usePublicEventLogo.test.ts +655 -120
- package/src/hooks/public/usePublicEventLogo.ts +2 -2
- package/src/hooks/public/usePublicFileDisplay.test.ts +723 -0
- package/src/hooks/public/usePublicFileDisplay.ts +79 -49
- package/src/hooks/public/usePublicRouteParams.test.ts +595 -0
- package/src/hooks/public/usePublicRouteParams.ts +2 -2
- package/src/hooks/services/useAuthService.ts +1 -1
- package/src/hooks/services/useEventService.ts +1 -1
- package/src/hooks/useAccessibleApps.test.ts +400 -0
- package/src/hooks/useAccessibleApps.ts +264 -0
- package/src/hooks/useAddressAutocomplete.test.ts +165 -42
- package/src/hooks/useAddressAutocomplete.ts +41 -28
- package/src/hooks/useAppConfig.ts +13 -3
- package/src/hooks/useDataTablePerformance.ts +13 -12
- package/src/hooks/useDataTableState.ts +5 -5
- package/src/hooks/useEventTheme.test.ts +66 -17
- package/src/hooks/useEventTheme.ts +1 -1
- package/src/hooks/useEvents.ts +8 -1
- package/src/hooks/useFileDisplay.ts +66 -33
- package/src/hooks/useFileReference.test.ts +365 -87
- package/src/hooks/useFileReference.ts +2 -6
- package/src/hooks/useFileUrlCache.ts +4 -1
- package/src/hooks/useFormDialog.ts +2 -2
- package/src/hooks/useInactivityTracker.ts +3 -3
- package/src/hooks/useOrganisationPermissions.test.ts +1 -2
- package/src/hooks/useOrganisationPermissions.ts +1 -4
- package/src/hooks/useOrganisationSecurity.test.ts +1 -30
- package/src/hooks/useOrganisationSecurity.ts +3 -3
- package/src/hooks/useOrganisations.ts +1 -1
- package/src/hooks/usePerformanceMonitor.ts +1 -1
- package/src/hooks/usePermissionCache.ts +2 -6
- package/src/hooks/useQueryCache.ts +7 -7
- package/src/hooks/useSessionDraft.ts +14 -11
- package/src/hooks/useSessionRestoration.ts +1 -1
- package/src/hooks/useStorage.ts +75 -40
- package/src/hooks/useToast.ts +2 -2
- package/src/hooks/useZodForm.ts +3 -3
- package/src/icons/__tests__/index.test.ts +133 -0
- package/src/icons/index.ts +1 -1
- package/src/index.ts +43 -4
- package/src/providers/OrganisationProvider.test.tsx +40 -0
- package/src/providers/OrganisationProvider.tsx +5 -5
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +7 -12
- package/src/providers/__tests__/AuthProvider.test.tsx +22 -91
- package/src/providers/__tests__/EventProvider.test.tsx +16 -80
- package/src/providers/__tests__/InactivityProvider.test.tsx +29 -173
- package/src/providers/__tests__/OrganisationProvider.test.tsx +4 -5
- package/src/providers/__tests__/OrganisationProvider.wrapper.test.tsx +591 -0
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +80 -196
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +40 -133
- package/src/providers/__tests__/index.test.ts +138 -0
- package/src/providers/services/AuthServiceContext.ts +27 -0
- package/src/providers/services/AuthServiceProvider.tsx +81 -20
- package/src/providers/services/EventServiceContext.ts +25 -0
- package/src/providers/services/EventServiceProvider.tsx +11 -20
- package/src/providers/services/InactivityServiceContext.ts +25 -0
- package/src/providers/services/InactivityServiceProvider.tsx +7 -17
- package/src/providers/services/OrganisationServiceContext.ts +25 -0
- package/src/providers/services/OrganisationServiceProvider.tsx +7 -17
- package/src/providers/services/UnifiedAuthContext.ts +99 -0
- package/src/providers/services/UnifiedAuthProvider.test.tsx +212 -0
- package/src/providers/services/UnifiedAuthProvider.tsx +38 -143
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +61 -95
- package/src/providers/services/__tests__/AuthServiceProvider.test.tsx +638 -0
- package/src/providers/services/__tests__/EventServiceProvider.test.tsx +839 -0
- package/src/providers/services/__tests__/InactivityServiceProvider.test.tsx +662 -0
- package/src/providers/services/__tests__/OrganisationServiceProvider.test.tsx +440 -0
- package/src/providers/services/__tests__/UnifiedAuthProvider.advanced.test.tsx +435 -0
- package/src/providers/services/__tests__/UnifiedAuthProvider.appId.test.tsx +408 -0
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +55 -48
- package/src/providers/services/__tests__/contexts.test.tsx +281 -0
- package/src/providers/services/__tests__/useUnifiedAuth.test.tsx +251 -0
- package/src/providers/services/useUnifiedAuth.ts +29 -0
- package/src/rbac/README.md +5 -5
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +9 -14
- package/src/rbac/__tests__/audit-batched.test.ts +550 -0
- package/src/rbac/__tests__/auth-rbac-security.integration.test.tsx +1 -14
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +43 -12
- package/src/rbac/__tests__/cache-invalidation.test.ts +8 -14
- package/src/rbac/__tests__/engine.comprehensive.test.ts +2 -7
- package/src/rbac/__tests__/index.test.ts +107 -0
- package/src/rbac/__tests__/performance.test.ts +451 -0
- package/src/rbac/__tests__/rbac-core.test.tsx +2 -2
- package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +0 -5
- package/src/rbac/__tests__/rbac-engine-simplified.test.ts +1 -7
- package/src/rbac/__tests__/rbac-functions.test.ts +0 -1
- package/src/rbac/__tests__/rbac-integration.test.ts +0 -1
- package/src/rbac/__tests__/scenarios.user-role.test.tsx +21 -32
- package/src/rbac/adapters.test.tsx +654 -0
- package/src/rbac/adapters.tsx +24 -9
- package/src/rbac/api.test.ts +13 -217
- package/src/rbac/api.ts +85 -16
- package/src/rbac/audit-batched.ts +5 -4
- package/src/rbac/audit.test.ts +225 -28
- package/src/rbac/audit.ts +22 -17
- package/src/rbac/cache-invalidation.ts +18 -15
- package/src/rbac/cache.test.ts +123 -63
- package/src/rbac/cache.ts +3 -4
- package/src/rbac/components/AccessDenied.tsx +20 -18
- package/src/rbac/components/NavigationGuard.tsx +10 -8
- package/src/rbac/components/PagePermissionGuard.tsx +27 -25
- package/src/rbac/components/__tests__/AccessDenied.test.tsx +324 -0
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +242 -71
- package/src/rbac/components/__tests__/PagePermissionGuard.performance.test.tsx +20 -37
- package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +18 -17
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +452 -129
- package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +14 -13
- package/src/rbac/config.test.ts +131 -48
- package/src/rbac/config.ts +11 -8
- package/src/rbac/docs/event-based-apps.md +26 -13
- package/src/rbac/engine.test.ts +496 -146
- package/src/rbac/engine.ts +53 -13
- package/src/rbac/errors.test.ts +99 -87
- package/src/rbac/eslint-rules.js +2 -2
- package/src/rbac/hooks/__tests__/usePermissions.integration.test.ts +0 -5
- package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +601 -1
- package/src/rbac/hooks/permissions/__tests__/useAccessLevel.test.ts +622 -0
- package/src/rbac/hooks/permissions/__tests__/useCan.test.ts +798 -0
- package/src/rbac/hooks/permissions/__tests__/useMultiplePermissions.test.ts +843 -0
- package/src/rbac/hooks/permissions/__tests__/usePermissions.test.ts +545 -0
- package/src/rbac/hooks/permissions/useAccessLevel.ts +7 -8
- package/src/rbac/hooks/permissions/useCan.ts +12 -10
- package/src/rbac/hooks/permissions/useMultiplePermissions.ts +57 -8
- package/src/rbac/hooks/permissions/usePermissions.ts +15 -14
- package/src/rbac/hooks/useCan.test.ts +319 -3
- package/src/rbac/hooks/usePermissions.test.ts +426 -0
- package/src/rbac/hooks/usePermissions.ts +5 -7
- package/src/rbac/hooks/useRBAC.test.ts +1669 -2
- package/src/rbac/hooks/useRBAC.ts +7 -11
- package/src/rbac/hooks/useResolvedScope.test.ts +442 -5
- package/src/rbac/hooks/useResolvedScope.ts +4 -1
- package/src/rbac/hooks/useResourcePermissions.test.ts +538 -1
- package/src/rbac/hooks/useResourcePermissions.ts +9 -7
- package/src/rbac/hooks/useRoleManagement.test.ts +659 -1
- package/src/rbac/hooks/useRoleManagement.ts +16 -12
- package/src/rbac/hooks/useSecureSupabase.ts +11 -12
- package/src/rbac/index.ts +32 -32
- package/src/rbac/permissions.test.ts +149 -68
- package/src/rbac/permissions.ts +0 -3
- package/src/rbac/request-deduplication.test.ts +347 -0
- package/src/rbac/secureClient.test.ts +112 -159
- package/src/rbac/secureClient.ts +46 -26
- package/src/rbac/security.test.ts +125 -44
- package/src/rbac/security.ts +7 -6
- package/src/rbac/types.test.ts +236 -0
- package/src/rbac/types.ts +7 -5
- package/src/rbac/utils/__tests__/clientSecurity.test.ts +192 -0
- package/src/rbac/utils/__tests__/contextValidator.test.ts +1 -3
- package/src/rbac/utils/__tests__/deep-equal.test.ts +23 -0
- package/src/rbac/utils/__tests__/eventContext.test.ts +10 -57
- package/src/rbac/utils/clientSecurity.ts +6 -4
- package/src/rbac/utils/contextValidator.ts +1 -2
- package/src/rbac/utils/eventContext.ts +2 -2
- package/src/services/AuthService.ts +13 -11
- package/src/services/EventService.ts +4 -5
- package/src/services/OrganisationService.ts +13 -30
- package/src/services/__tests__/AuthService.edge-cases.test.ts +746 -0
- package/src/services/__tests__/AuthService.restoreSession.test.ts +23 -3
- package/src/services/__tests__/AuthService.test.ts +4 -8
- package/src/services/__tests__/BaseService.edge-cases.test.ts +506 -0
- package/src/services/__tests__/BaseService.test.ts +49 -0
- package/src/services/__tests__/EventService.edge-cases.test.ts +633 -0
- package/src/services/__tests__/EventService.eventColours.test.ts +0 -12
- package/src/services/__tests__/EventService.test.ts +0 -7
- package/src/services/__tests__/InactivityService.edge-cases.test.ts +492 -0
- package/src/services/__tests__/InactivityService.lifecycle.test.ts +0 -5
- package/src/services/__tests__/OrganisationService.edge-cases.test.ts +633 -0
- package/src/services/base/BaseService.test.ts +214 -0
- package/src/services/interfaces/IOrganisationService.ts +0 -1
- package/src/services/interfaces/__tests__/IAuthService.test.ts +190 -0
- package/src/services/interfaces/__tests__/IEventService.test.ts +176 -0
- package/src/services/interfaces/__tests__/IInactivityService.test.ts +183 -0
- package/src/services/interfaces/__tests__/IOrganisationService.test.ts +207 -0
- package/src/styles/core.css +1 -0
- package/src/theming/__tests__/runtime.test.ts +29 -94
- package/src/theming/parseEventColours.ts +18 -9
- package/src/theming/runtime.ts +1 -5
- package/src/types/__tests__/core.test.ts +397 -0
- package/src/types/__tests__/database-generated.test.ts +78 -0
- package/src/types/__tests__/file-reference.test.ts +270 -366
- package/src/types/__tests__/guards.test.ts +26 -26
- package/src/types/__tests__/index.test.ts +265 -0
- package/src/types/__tests__/type-validation.test.ts +3 -3
- package/src/types/__tests__/validation.test.ts +0 -2
- package/src/types/auth.ts +0 -1
- package/src/types/database.generated.ts +9 -9
- package/src/types/event.ts +1 -1
- package/src/types/rpc-responses.ts +33 -0
- package/src/types/supabase.ts +1 -2
- package/src/types/vitest-globals.d.ts +1 -1
- package/src/utils/__tests__/bundleAnalysis.unit.test.ts +64 -77
- package/src/utils/__tests__/dynamicUtils.unit.test.ts +13 -0
- package/src/utils/__tests__/formatDate.unit.test.ts +1 -1
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +0 -1
- package/src/utils/__tests__/logger.unit.test.ts +1 -1
- package/src/utils/__tests__/performanceBenchmark.test.ts +1 -2
- package/src/utils/__tests__/performanceBudgets.unit.test.ts +48 -13
- package/src/utils/__tests__/request-deduplication.test.ts +349 -0
- package/src/utils/__tests__/secureDataAccess.unit.test.ts +0 -1
- package/src/utils/__tests__/timezone.test.ts +1 -1
- package/src/utils/__tests__/validation.unit.test.ts +1 -2
- package/src/utils/__tests__/validationUtils.unit.test.ts +1 -1
- package/src/utils/app/appConfig.test.ts +235 -0
- package/src/utils/app/appIdResolver.test.ts +188 -20
- package/src/utils/app/appNameResolver.test.ts +18 -10
- package/src/utils/app/appNameResolver.ts +11 -9
- package/src/utils/app/appPortMap.test.ts +125 -0
- package/src/utils/app/appPortMap.ts +51 -0
- package/src/utils/app/buildAppUrl.test.ts +273 -0
- package/src/utils/app/buildAppUrl.ts +114 -0
- package/src/utils/audit/audit.test.ts +354 -39
- package/src/utils/context/organisationContext.test.ts +10 -4
- package/src/utils/context/organisationContext.ts +5 -5
- package/src/utils/context/sessionTracking.test.ts +354 -0
- package/src/utils/core/__tests__/cn.test.ts +66 -0
- package/src/utils/core/__tests__/debugLogger.test.ts +113 -0
- package/src/utils/core/__tests__/logger.test.ts +217 -0
- package/src/utils/core/debugLogger.ts +15 -8
- package/src/utils/core/logger.ts +20 -16
- package/src/utils/device/deviceFingerprint.test.ts +8 -5
- package/src/utils/device/deviceFingerprint.ts +3 -3
- package/src/utils/dynamic/__tests__/dynamicUtils.test.ts +185 -0
- package/src/utils/dynamic/__tests__/lazyLoad.test.tsx +156 -0
- package/src/utils/dynamic/createLazyComponent.tsx +38 -0
- package/src/utils/dynamic/dynamicUtils.ts +6 -6
- package/src/utils/dynamic/lazyLoad.tsx +8 -36
- package/src/utils/dynamic/papaparseLoader.ts +7 -0
- package/src/utils/file-reference/__tests__/file-reference.test.ts +583 -145
- package/src/utils/file-reference/index.ts +0 -1
- package/src/utils/formatting/formatDate.test.ts +22 -148
- package/src/utils/formatting/formatDateTime.test.ts +41 -119
- package/src/utils/formatting/formatDateTimeTimezone.test.ts +40 -84
- package/src/utils/formatting/formatNumber.test.ts +259 -0
- package/src/utils/formatting/formatTime.test.ts +36 -128
- package/src/utils/formatting/formatting.ts +1 -1
- package/src/utils/google-places/googlePlacesUtils.test.ts +72 -3
- package/src/utils/google-places/googlePlacesUtils.ts +15 -2
- package/src/utils/google-places/loadGoogleMapsScript.test.ts +58 -1
- package/src/utils/google-places/loadGoogleMapsScript.ts +2 -1
- package/src/utils/index.ts +52 -11
- package/src/utils/location/location.test.ts +18 -115
- package/src/utils/performance/__tests__/bundleAnalysis.test.ts +148 -0
- package/src/utils/performance/__tests__/performanceBenchmark.test.ts +251 -0
- package/src/utils/performance/__tests__/performanceBudgets.test.ts +241 -0
- package/src/utils/performance/bundleAnalysis.ts +16 -22
- package/src/utils/performance/performanceBenchmark.ts +12 -4
- package/src/utils/performance/performanceBudgets.ts +9 -6
- package/src/utils/permissions/__tests__/permissionTypes.test.ts +149 -0
- package/src/utils/permissions/permissionUtils.test.ts +20 -42
- package/src/utils/persistence/__tests__/keyDerivation.test.ts +180 -9
- package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +164 -16
- package/src/utils/persistence/sensitiveFieldDetection.ts +2 -2
- package/src/utils/request-deduplication.ts +6 -4
- package/src/utils/security/auth-utils.ts +7 -7
- package/src/utils/security/secureDataAccess.test.ts +22 -191
- package/src/utils/security/secureErrors.test.ts +163 -0
- package/src/utils/security/secureStorage.test.ts +156 -0
- package/src/utils/security/secureStorage.ts +1 -1
- package/src/utils/security/security.test.ts +204 -0
- package/src/utils/security/securityMonitor.test.ts +90 -0
- package/src/utils/security/securityMonitor.ts +1 -1
- package/src/utils/storage/__tests__/config.unit.test.ts +239 -0
- package/src/utils/storage/__tests__/index.unit.test.ts +64 -12
- package/src/utils/storage/helpers.test.ts +757 -430
- package/src/utils/storage/helpers.ts +1 -2
- package/src/utils/storage/{index.ts → storageUtils.ts} +1 -36
- package/src/utils/storage/types.ts +2 -2
- package/src/utils/supabase/createBaseClient.test.ts +201 -0
- package/src/utils/supabase/createBaseClient.ts +27 -8
- package/src/utils/timezone/timezone.test.ts +25 -43
- package/src/utils/validation/__tests__/common.test.ts +115 -0
- package/src/utils/validation/__tests__/csrf.test.ts +65 -0
- package/src/utils/validation/__tests__/htmlSanitization.unit.test.ts +27 -7
- package/src/utils/validation/__tests__/passwordSchema.test.ts +164 -0
- package/src/utils/validation/__tests__/schema.test.ts +127 -0
- package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +76 -3
- package/src/utils/validation/__tests__/user.test.ts +173 -0
- package/src/utils/validation/__tests__/validation.test.ts +197 -0
- package/src/utils/validation/__tests__/validationUtils.test.ts +265 -43
- package/src/utils/validation/htmlSanitization.ts +27 -31
- package/src/utils/validation/schema.ts +6 -3
- package/src/utils/validation/sqlInjectionProtection.ts +2 -2
- package/src/vite-env.d.ts +6 -0
- package/dist/DataTable-DRUIgtUH.d.ts +0 -166
- package/dist/UnifiedAuthProvider-7SNDOWYD.js +0 -7
- package/dist/audit-MYQXYZFU.js +0 -3
- package/dist/chunk-7ILTDCL2.js +0 -80
- package/dist/chunk-EF2UGZWY.js +0 -611
- package/dist/chunk-FEJLJNWA.js +0 -181
- package/dist/chunk-GS5672WG.js +0 -2003
- package/dist/chunk-S6ZQKDY6.js +0 -62
- package/dist/chunk-Z2FNRKF3.js +0 -994
- package/dist/useToast-AyaT-x7p.d.ts +0 -68
- package/src/components/DataTable/components/index.ts +0 -16
- package/src/components/DataTable/core/index.ts +0 -1
- package/src/components/DataTable/hooks/index.ts +0 -13
- package/src/components/DataTable/utils/index.ts +0 -9
- package/src/components/PublicLayout/index.ts +0 -32
- package/src/hooks/__tests__/usePermissionCache.simple.test.ts +0 -192
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +0 -741
- package/src/hooks/public/index.ts +0 -36
- package/src/hooks/usePermissionCache.test.ts +0 -536
- package/src/rbac/__tests__/isSuperAdmin.real.test.ts +0 -82
- package/src/rbac/audit-enhanced.ts +0 -384
- package/src/rbac/compliance/database-validator.ts +0 -165
- package/src/rbac/compliance/index.ts +0 -48
- package/src/rbac/compliance/pattern-detector.ts +0 -553
- package/src/rbac/compliance/quick-fix-suggestions.ts +0 -209
- package/src/rbac/compliance/runtime-compliance.ts +0 -99
- package/src/rbac/compliance/setup-validator.ts +0 -131
- package/src/rbac/components/index.ts +0 -26
- package/src/rbac/hooks/index.ts +0 -34
- package/src/rbac/hooks/permissions/index.ts +0 -4
- package/src/rbac/hooks/useRBAC.simple.test.ts +0 -95
- package/src/rbac/utils/__tests__/eventContext.unit.test.ts +0 -490
- package/src/utils/app/appNameResolver.simple.test.ts +0 -212
- package/src/utils/google-places/index.ts +0 -26
- package/src/utils/location/index.ts +0 -16
- package/src/utils/storage/__tests__/helpers.unit.test.ts +0 -332
- package/src/utils/timezone/index.ts +0 -17
- package/src/utils/validation/index.ts +0 -73
|
@@ -13,10 +13,16 @@ const mockUseIsPublicPage = vi.hoisted(() => vi.fn(() => false));
|
|
|
13
13
|
const publicPageContextStore = vi.hoisted(() => ({ value: null as React.Context<any> | null }));
|
|
14
14
|
|
|
15
15
|
// Mock useIsPublicPage to return false so FileDisplay uses authenticated version by default
|
|
16
|
-
vi.mock('../PublicLayout/
|
|
17
|
-
publicPageContextStore.value = React.createContext(null);
|
|
16
|
+
vi.mock('../PublicLayout/usePublicPageContext', () => {
|
|
18
17
|
return {
|
|
19
18
|
useIsPublicPage: (...args: unknown[]) => mockUseIsPublicPage(...args),
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Mock PublicPageContext
|
|
23
|
+
vi.mock('../PublicLayout/PublicPageContext', () => {
|
|
24
|
+
publicPageContextStore.value = React.createContext(null);
|
|
25
|
+
return {
|
|
20
26
|
PublicPageContext: publicPageContextStore.value,
|
|
21
27
|
};
|
|
22
28
|
});
|
|
@@ -212,7 +218,7 @@ describe('[component] FileDisplay', () => {
|
|
|
212
218
|
try {
|
|
213
219
|
const dialog = screen.getByRole('dialog');
|
|
214
220
|
expect(dialog).toBeInTheDocument();
|
|
215
|
-
} catch (
|
|
221
|
+
} catch (_e) {
|
|
216
222
|
// Fallback for test environments - just check that dialog exists in DOM
|
|
217
223
|
const dialog = document.querySelector('dialog[role="dialog"]');
|
|
218
224
|
if (!dialog) {
|
|
@@ -409,7 +415,7 @@ describe('[component] FileDisplay', () => {
|
|
|
409
415
|
try {
|
|
410
416
|
const dialog = screen.getByRole('dialog');
|
|
411
417
|
expect(dialog).toBeInTheDocument();
|
|
412
|
-
} catch (
|
|
418
|
+
} catch (_e) {
|
|
413
419
|
// Fallback for test environments - just check that dialog exists in DOM
|
|
414
420
|
const dialog = document.querySelector('dialog[role="dialog"]');
|
|
415
421
|
if (!dialog) {
|
|
@@ -587,16 +593,19 @@ describe('[component] FileDisplay', () => {
|
|
|
587
593
|
});
|
|
588
594
|
|
|
589
595
|
describe('Document link rendering in displayOnly mode', () => {
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
596
|
+
const createNonImageFile = (id: string, fileName: string, fileType: string) => ({
|
|
597
|
+
id,
|
|
598
|
+
table_name: 'person',
|
|
599
|
+
record_id: 'rec-1',
|
|
600
|
+
organisation_id: 'org-1',
|
|
601
|
+
file_path: `bucket/path/${fileName}`,
|
|
602
|
+
is_public: false,
|
|
603
|
+
file_metadata: { fileName, fileSize: 2048, fileType },
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
it('renders non-image files as clickable links with correct attributes', async () => {
|
|
607
|
+
const pdfFile = createNonImageFile('fr-pdf', 'document.pdf', 'application/pdf');
|
|
608
|
+
const fileUrlsMap = new Map([['fr-pdf', 'https://signed.example.com/document.pdf']]);
|
|
600
609
|
|
|
601
610
|
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
602
611
|
useFileDisplay.mockReturnValue({
|
|
@@ -606,88 +615,59 @@ describe('[component] FileDisplay', () => {
|
|
|
606
615
|
fileReference: pdfFile,
|
|
607
616
|
fileReferences: [pdfFile],
|
|
608
617
|
fileCount: 1,
|
|
609
|
-
fileUrls:
|
|
618
|
+
fileUrls: fileUrlsMap,
|
|
610
619
|
refetch: vi.fn(),
|
|
611
620
|
});
|
|
612
621
|
|
|
613
|
-
// Mock useFileUrl to return URL from map (since it's in the map, hook won't be used, but mock it anyway)
|
|
614
|
-
const useFileUrl = (await import('../../hooks/useFileUrl')).useFileUrl as unknown as vi.Mock;
|
|
615
|
-
useFileUrl.mockReturnValue({
|
|
616
|
-
url: null,
|
|
617
|
-
isLoading: false,
|
|
618
|
-
error: null,
|
|
619
|
-
clear: vi.fn(),
|
|
620
|
-
});
|
|
621
|
-
|
|
622
622
|
renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly />);
|
|
623
623
|
|
|
624
624
|
const link = await screen.findByRole('link', { name: /Open document\.pdf in new tab/i });
|
|
625
|
-
expect(link).toBeInTheDocument();
|
|
626
625
|
expect(link).toHaveAttribute('href', 'https://signed.example.com/document.pdf');
|
|
626
|
+
expect(link).toHaveAttribute('target', '_blank');
|
|
627
|
+
expect(link).toHaveAttribute('rel', 'noopener noreferrer');
|
|
628
|
+
expect(link).toHaveTextContent('document.pdf');
|
|
627
629
|
});
|
|
628
630
|
|
|
629
|
-
it('renders
|
|
630
|
-
const
|
|
631
|
-
|
|
632
|
-
table_name: 'person',
|
|
633
|
-
record_id: 'rec-1',
|
|
634
|
-
organisation_id: 'org-1',
|
|
635
|
-
file_path: 'bucket/path/file.docx',
|
|
636
|
-
is_public: false,
|
|
637
|
-
file_metadata: { fileName: 'file.docx', fileSize: 4096, fileType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' },
|
|
638
|
-
};
|
|
631
|
+
it('renders icons in document links', async () => {
|
|
632
|
+
const pdfFile = createNonImageFile('fr-pdf', 'doc.pdf', 'application/pdf');
|
|
633
|
+
const fileUrlsMap = new Map([['fr-pdf', 'https://signed.example.com/doc.pdf']]);
|
|
639
634
|
|
|
640
635
|
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
641
636
|
useFileDisplay.mockReturnValue({
|
|
642
637
|
isLoading: false,
|
|
643
638
|
error: null,
|
|
644
|
-
fileUrl: 'https://signed.example.com/
|
|
645
|
-
fileReference:
|
|
646
|
-
fileReferences: [
|
|
639
|
+
fileUrl: 'https://signed.example.com/doc.pdf',
|
|
640
|
+
fileReference: pdfFile,
|
|
641
|
+
fileReferences: [pdfFile],
|
|
647
642
|
fileCount: 1,
|
|
648
|
-
fileUrls:
|
|
643
|
+
fileUrls: fileUrlsMap,
|
|
649
644
|
refetch: vi.fn(),
|
|
650
645
|
});
|
|
651
646
|
|
|
652
|
-
// Mock useFileUrl (won't be used since URL is in map, but mock it anyway)
|
|
653
|
-
const useFileUrl = (await import('../../hooks/useFileUrl')).useFileUrl as unknown as vi.Mock;
|
|
654
|
-
useFileUrl.mockReturnValue({
|
|
655
|
-
url: null,
|
|
656
|
-
isLoading: false,
|
|
657
|
-
error: null,
|
|
658
|
-
clear: vi.fn(),
|
|
659
|
-
});
|
|
660
|
-
|
|
661
647
|
renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly />);
|
|
662
648
|
|
|
663
649
|
const link = await screen.findByRole('link');
|
|
664
|
-
|
|
650
|
+
const fileTextIcon = link.querySelector('[data-testid="lucide-filetext"]');
|
|
651
|
+
const externalLinkIcon = link.querySelector('[data-testid="lucide-externallink"]');
|
|
652
|
+
expect(fileTextIcon).toBeInTheDocument();
|
|
653
|
+
expect(externalLinkIcon).toBeInTheDocument();
|
|
665
654
|
});
|
|
666
655
|
|
|
667
|
-
it('
|
|
668
|
-
const
|
|
669
|
-
id: 'fr-xls',
|
|
670
|
-
table_name: 'person',
|
|
671
|
-
record_id: 'rec-1',
|
|
672
|
-
organisation_id: 'org-1',
|
|
673
|
-
file_path: 'bucket/path/spreadsheet.xlsx',
|
|
674
|
-
is_public: false,
|
|
675
|
-
file_metadata: { fileName: 'spreadsheet.xlsx', fileSize: 8192, fileType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' },
|
|
676
|
-
};
|
|
656
|
+
it('falls back to fallback UI when fileUrl is null', async () => {
|
|
657
|
+
const pdfFile = createNonImageFile('fr-pdf', 'doc.pdf', 'application/pdf');
|
|
677
658
|
|
|
678
659
|
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
679
660
|
useFileDisplay.mockReturnValue({
|
|
680
661
|
isLoading: false,
|
|
681
662
|
error: null,
|
|
682
|
-
fileUrl:
|
|
683
|
-
fileReference:
|
|
684
|
-
fileReferences: [
|
|
663
|
+
fileUrl: null,
|
|
664
|
+
fileReference: pdfFile,
|
|
665
|
+
fileReferences: [pdfFile],
|
|
685
666
|
fileCount: 1,
|
|
686
|
-
fileUrls: new Map(
|
|
667
|
+
fileUrls: new Map(),
|
|
687
668
|
refetch: vi.fn(),
|
|
688
669
|
});
|
|
689
670
|
|
|
690
|
-
// Mock useFileUrl (won't be used since URL is in map, but mock it anyway)
|
|
691
671
|
const useFileUrl = (await import('../../hooks/useFileUrl')).useFileUrl as unknown as vi.Mock;
|
|
692
672
|
useFileUrl.mockReturnValue({
|
|
693
673
|
url: null,
|
|
@@ -696,133 +676,269 @@ describe('[component] FileDisplay', () => {
|
|
|
696
676
|
clear: vi.fn(),
|
|
697
677
|
});
|
|
698
678
|
|
|
699
|
-
renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly />);
|
|
679
|
+
renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly showFallback fallbackText="View Document" />);
|
|
700
680
|
|
|
701
|
-
|
|
702
|
-
expect(
|
|
681
|
+
expect(await screen.findByText('View Document')).toBeInTheDocument();
|
|
682
|
+
expect(screen.queryByRole('link')).not.toBeInTheDocument();
|
|
703
683
|
});
|
|
704
684
|
|
|
705
|
-
it('
|
|
706
|
-
const
|
|
707
|
-
id: 'fr-
|
|
685
|
+
it('renders images inline in displayOnly mode (not as links)', async () => {
|
|
686
|
+
const imageFile = {
|
|
687
|
+
id: 'fr-img',
|
|
708
688
|
table_name: 'person',
|
|
709
689
|
record_id: 'rec-1',
|
|
710
690
|
organisation_id: 'org-1',
|
|
711
|
-
file_path: 'bucket/path/
|
|
691
|
+
file_path: 'bucket/path/image.png',
|
|
712
692
|
is_public: false,
|
|
713
|
-
file_metadata: { fileName: '
|
|
693
|
+
file_metadata: { fileName: 'image.png', fileSize: 1024, fileType: 'image/png' },
|
|
714
694
|
};
|
|
715
695
|
|
|
716
696
|
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
717
697
|
useFileDisplay.mockReturnValue({
|
|
718
698
|
isLoading: false,
|
|
719
699
|
error: null,
|
|
720
|
-
fileUrl: 'https://signed.example.com/
|
|
721
|
-
fileReference:
|
|
722
|
-
fileReferences: [
|
|
700
|
+
fileUrl: 'https://signed.example.com/image.png',
|
|
701
|
+
fileReference: imageFile,
|
|
702
|
+
fileReferences: [imageFile],
|
|
723
703
|
fileCount: 1,
|
|
724
|
-
fileUrls: new Map([['fr-
|
|
704
|
+
fileUrls: new Map([['fr-img', 'https://signed.example.com/image.png']]),
|
|
725
705
|
refetch: vi.fn(),
|
|
726
706
|
});
|
|
727
707
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
708
|
+
renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly />);
|
|
709
|
+
|
|
710
|
+
const image = await screen.findByRole('img', { name: /image\.png/i });
|
|
711
|
+
expect(image).toBeInTheDocument();
|
|
712
|
+
expect(screen.queryByRole('link')).not.toBeInTheDocument();
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
it('uses wrapper behavior when showDelete is true', async () => {
|
|
716
|
+
const pdfFile = createNonImageFile('fr-pdf', 'doc.pdf', 'application/pdf');
|
|
717
|
+
|
|
718
|
+
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
719
|
+
useFileDisplay.mockReturnValue({
|
|
732
720
|
isLoading: false,
|
|
733
721
|
error: null,
|
|
734
|
-
|
|
722
|
+
fileUrl: 'https://signed.example.com/doc.pdf',
|
|
723
|
+
fileReference: pdfFile,
|
|
724
|
+
fileReferences: [pdfFile],
|
|
725
|
+
fileCount: 1,
|
|
726
|
+
fileUrls: new Map([['fr-pdf', 'https://signed.example.com/doc.pdf']]),
|
|
727
|
+
refetch: vi.fn(),
|
|
735
728
|
});
|
|
736
729
|
|
|
737
|
-
renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly />);
|
|
730
|
+
renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly showDelete />);
|
|
738
731
|
|
|
739
|
-
|
|
740
|
-
expect(
|
|
732
|
+
expect(screen.getByText('doc.pdf')).toBeInTheDocument();
|
|
733
|
+
expect(screen.getByRole('button', { name: /Delete file/i })).toBeInTheDocument();
|
|
734
|
+
expect(screen.queryByRole('link', { name: /Open.*in new tab/i })).not.toBeInTheDocument();
|
|
741
735
|
});
|
|
742
736
|
|
|
743
|
-
it('renders
|
|
737
|
+
it('renders document links in public context', async () => {
|
|
738
|
+
mockUseIsPublicPage.mockReturnValueOnce(true);
|
|
739
|
+
|
|
744
740
|
const pdfFile = {
|
|
745
|
-
id: '
|
|
746
|
-
table_name: '
|
|
747
|
-
record_id: '
|
|
741
|
+
id: 'pub-pdf',
|
|
742
|
+
table_name: 'event',
|
|
743
|
+
record_id: 'event-1',
|
|
748
744
|
organisation_id: 'org-1',
|
|
749
|
-
file_path: 'bucket/path/doc.pdf',
|
|
750
|
-
is_public:
|
|
751
|
-
file_metadata: { fileName: 'doc.pdf', fileSize: 2048, fileType: 'application/pdf' },
|
|
745
|
+
file_path: 'bucket/path/public-doc.pdf',
|
|
746
|
+
is_public: true,
|
|
747
|
+
file_metadata: { fileName: 'public-doc.pdf', fileSize: 2048, fileType: 'application/pdf' },
|
|
752
748
|
};
|
|
753
749
|
|
|
754
|
-
const
|
|
755
|
-
|
|
750
|
+
const fileUrlsMap = new Map<string, string>([['pub-pdf', 'https://public.example.com/public-doc.pdf']]);
|
|
751
|
+
const usePublicFileDisplay = (await import('../../hooks/public/usePublicFileDisplay')).usePublicFileDisplay as unknown as vi.Mock;
|
|
752
|
+
usePublicFileDisplay.mockReturnValue({
|
|
756
753
|
isLoading: false,
|
|
757
754
|
error: null,
|
|
758
|
-
fileUrl: 'https://
|
|
755
|
+
fileUrl: 'https://public.example.com/public-doc.pdf',
|
|
759
756
|
fileReference: pdfFile,
|
|
760
757
|
fileReferences: [pdfFile],
|
|
761
758
|
fileCount: 1,
|
|
762
|
-
fileUrls:
|
|
759
|
+
fileUrls: fileUrlsMap,
|
|
763
760
|
refetch: vi.fn(),
|
|
764
761
|
});
|
|
765
762
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
763
|
+
renderWithPublicContext(
|
|
764
|
+
<FileDisplay {...baseProps} displayOnly />,
|
|
765
|
+
{ supabase }
|
|
766
|
+
);
|
|
767
|
+
|
|
768
|
+
const link = await screen.findByRole('link', { name: /Open public-doc\.pdf in new tab/i });
|
|
769
|
+
expect(link).toHaveAttribute('href', 'https://public.example.com/public-doc.pdf');
|
|
770
|
+
expect(link).toHaveAttribute('target', '_blank');
|
|
771
|
+
expect(link).toHaveAttribute('rel', 'noopener noreferrer');
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
it('uses fallback text "Document" when fileName is missing', async () => {
|
|
775
|
+
const pdfFile = createNonImageFile('fr-pdf', '', 'application/pdf');
|
|
776
|
+
pdfFile.file_metadata.fileName = '';
|
|
777
|
+
|
|
778
|
+
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
779
|
+
useFileDisplay.mockReturnValue({
|
|
770
780
|
isLoading: false,
|
|
771
781
|
error: null,
|
|
772
|
-
|
|
782
|
+
fileUrl: 'https://signed.example.com/file.pdf',
|
|
783
|
+
fileReference: pdfFile,
|
|
784
|
+
fileReferences: [pdfFile],
|
|
785
|
+
fileCount: 1,
|
|
786
|
+
fileUrls: new Map([['fr-pdf', 'https://signed.example.com/file.pdf']]),
|
|
787
|
+
refetch: vi.fn(),
|
|
773
788
|
});
|
|
774
789
|
|
|
775
790
|
renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly />);
|
|
776
791
|
|
|
777
|
-
const link = await screen.findByRole('link');
|
|
778
|
-
|
|
779
|
-
// Icons are mocked as divs with data-testid in tests
|
|
780
|
-
const fileTextIcon = link.querySelector('[data-testid="lucide-filetext"]');
|
|
781
|
-
const externalLinkIcon = link.querySelector('[data-testid="lucide-externallink"]');
|
|
782
|
-
expect(fileTextIcon).toBeInTheDocument();
|
|
783
|
-
expect(externalLinkIcon).toBeInTheDocument();
|
|
792
|
+
const link = await screen.findByRole('link', { name: /Open Document in new tab/i });
|
|
793
|
+
expect(link).toHaveTextContent('Document');
|
|
784
794
|
});
|
|
795
|
+
});
|
|
785
796
|
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
797
|
+
describe('Loading States', () => {
|
|
798
|
+
it('renders loading spinner when isLoading is true', async () => {
|
|
799
|
+
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
800
|
+
useFileDisplay.mockReturnValue({
|
|
801
|
+
isLoading: true,
|
|
802
|
+
error: null,
|
|
803
|
+
fileUrl: null,
|
|
804
|
+
fileReference: null,
|
|
805
|
+
fileReferences: [],
|
|
806
|
+
fileCount: 0,
|
|
807
|
+
fileUrls: new Map(),
|
|
808
|
+
refetch: vi.fn(),
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
renderWithUnifiedAuth(<FileDisplay {...baseProps} />);
|
|
812
|
+
|
|
813
|
+
// LoadingSpinner should be rendered
|
|
814
|
+
const spinner = screen.getByRole('status', { hidden: true }) || document.querySelector('[data-testid="loading-spinner"]');
|
|
815
|
+
expect(spinner || screen.getByText(/loading/i)).toBeDefined();
|
|
816
|
+
});
|
|
796
817
|
|
|
818
|
+
it('uses custom loading component when provided', async () => {
|
|
819
|
+
const CustomLoader = () => <div data-testid="custom-loader">Custom Loading...</div>;
|
|
820
|
+
|
|
821
|
+
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
822
|
+
useFileDisplay.mockReturnValue({
|
|
823
|
+
isLoading: true,
|
|
824
|
+
error: null,
|
|
825
|
+
fileUrl: null,
|
|
826
|
+
fileReference: null,
|
|
827
|
+
fileReferences: [],
|
|
828
|
+
fileCount: 0,
|
|
829
|
+
fileUrls: new Map(),
|
|
830
|
+
refetch: vi.fn(),
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
renderWithUnifiedAuth(<FileDisplay {...baseProps} loadingComponent={CustomLoader} />);
|
|
834
|
+
|
|
835
|
+
expect(screen.getByTestId('custom-loader')).toBeInTheDocument();
|
|
836
|
+
expect(screen.getByText('Custom Loading...')).toBeInTheDocument();
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
it('shows fallback during loading when showFallback is enabled and fileCount is 0', async () => {
|
|
840
|
+
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
841
|
+
useFileDisplay.mockReturnValue({
|
|
842
|
+
isLoading: true,
|
|
843
|
+
error: null,
|
|
844
|
+
fileUrl: null,
|
|
845
|
+
fileReference: null,
|
|
846
|
+
fileReferences: [],
|
|
847
|
+
fileCount: 0,
|
|
848
|
+
fileUrls: new Map(),
|
|
849
|
+
refetch: vi.fn(),
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
renderWithUnifiedAuth(<FileDisplay {...baseProps} showFallback fallbackText="Loading..." />);
|
|
853
|
+
|
|
854
|
+
expect(screen.getByText('Loading...')).toBeInTheDocument();
|
|
855
|
+
});
|
|
856
|
+
});
|
|
857
|
+
|
|
858
|
+
describe('Fallback UI', () => {
|
|
859
|
+
it('generates fallback text from filename when generateFallbackText is provided', async () => {
|
|
797
860
|
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
798
861
|
useFileDisplay.mockReturnValue({
|
|
799
862
|
isLoading: false,
|
|
800
863
|
error: null,
|
|
801
864
|
fileUrl: null,
|
|
802
|
-
fileReference:
|
|
803
|
-
fileReferences: [
|
|
804
|
-
fileCount:
|
|
865
|
+
fileReference: null,
|
|
866
|
+
fileReferences: [],
|
|
867
|
+
fileCount: 0,
|
|
805
868
|
fileUrls: new Map(),
|
|
806
869
|
refetch: vi.fn(),
|
|
807
870
|
});
|
|
808
871
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
872
|
+
const generateFallback = vi.fn((fileName?: string) => fileName ? fileName.toUpperCase() : 'NO FILE');
|
|
873
|
+
|
|
874
|
+
renderWithUnifiedAuth(
|
|
875
|
+
<FileDisplay
|
|
876
|
+
{...baseProps}
|
|
877
|
+
showFallback
|
|
878
|
+
generateFallbackText={generateFallback}
|
|
879
|
+
/>
|
|
880
|
+
);
|
|
881
|
+
|
|
882
|
+
expect(generateFallback).toHaveBeenCalled();
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
it('uses fallbackSourceText when provided', async () => {
|
|
886
|
+
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
887
|
+
useFileDisplay.mockReturnValue({
|
|
813
888
|
isLoading: false,
|
|
814
889
|
error: null,
|
|
815
|
-
|
|
890
|
+
fileUrl: null,
|
|
891
|
+
fileReference: null,
|
|
892
|
+
fileReferences: [],
|
|
893
|
+
fileCount: 0,
|
|
894
|
+
fileUrls: new Map(),
|
|
895
|
+
refetch: vi.fn(),
|
|
816
896
|
});
|
|
817
897
|
|
|
818
|
-
|
|
898
|
+
const generateFallback = vi.fn((sourceText?: string) => sourceText || 'DEFAULT');
|
|
819
899
|
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
900
|
+
renderWithUnifiedAuth(
|
|
901
|
+
<FileDisplay
|
|
902
|
+
{...baseProps}
|
|
903
|
+
showFallback
|
|
904
|
+
fallbackSourceText="Custom Source"
|
|
905
|
+
generateFallbackText={generateFallback}
|
|
906
|
+
/>
|
|
907
|
+
);
|
|
908
|
+
|
|
909
|
+
expect(generateFallback).toHaveBeenCalledWith('Custom Source');
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
it('applies correct fallback size classes', async () => {
|
|
913
|
+
const sizes: Array<'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'> = ['xs', 'sm', 'md', 'lg', 'xl', '2xl'];
|
|
914
|
+
|
|
915
|
+
for (const size of sizes) {
|
|
916
|
+
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
917
|
+
useFileDisplay.mockReturnValue({
|
|
918
|
+
isLoading: false,
|
|
919
|
+
error: null,
|
|
920
|
+
fileUrl: null,
|
|
921
|
+
fileReference: null,
|
|
922
|
+
fileReferences: [],
|
|
923
|
+
fileCount: 0,
|
|
924
|
+
fileUrls: new Map(),
|
|
925
|
+
refetch: vi.fn(),
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
const { unmount } = renderWithUnifiedAuth(
|
|
929
|
+
<FileDisplay {...baseProps} showFallback fallbackText="Test" fallbackSize={size} />
|
|
930
|
+
);
|
|
931
|
+
|
|
932
|
+
const fallback = screen.getByText('Test');
|
|
933
|
+
expect(fallback).toBeInTheDocument();
|
|
934
|
+
// Check that size class is applied (classes contain size-specific text)
|
|
935
|
+
expect(fallback.className).toContain('grid');
|
|
936
|
+
|
|
937
|
+
unmount();
|
|
938
|
+
}
|
|
823
939
|
});
|
|
824
940
|
|
|
825
|
-
it('
|
|
941
|
+
it('shows fallback when image fails to load and showFallback is enabled', async () => {
|
|
826
942
|
const imageFile = {
|
|
827
943
|
id: 'fr-img',
|
|
828
944
|
table_name: 'person',
|
|
@@ -837,184 +953,300 @@ describe('[component] FileDisplay', () => {
|
|
|
837
953
|
useFileDisplay.mockReturnValue({
|
|
838
954
|
isLoading: false,
|
|
839
955
|
error: null,
|
|
840
|
-
fileUrl: 'https://
|
|
956
|
+
fileUrl: 'https://example.com/image.png',
|
|
841
957
|
fileReference: imageFile,
|
|
842
958
|
fileReferences: [imageFile],
|
|
843
959
|
fileCount: 1,
|
|
844
|
-
fileUrls: new Map([['fr-img', 'https://
|
|
960
|
+
fileUrls: new Map([['fr-img', 'https://example.com/image.png']]),
|
|
845
961
|
refetch: vi.fn(),
|
|
846
962
|
});
|
|
847
963
|
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
964
|
+
renderWithUnifiedAuth(
|
|
965
|
+
<FileDisplay {...baseProps} showFallback fallbackText="IMG" category={FileCategory.IMAGES} />
|
|
966
|
+
);
|
|
967
|
+
|
|
968
|
+
const image = await screen.findByRole('img', { name: /image\.png/i });
|
|
969
|
+
|
|
970
|
+
// Simulate image error
|
|
971
|
+
act(() => {
|
|
972
|
+
const errorEvent = new Event('error', { bubbles: true });
|
|
973
|
+
image.dispatchEvent(errorEvent);
|
|
974
|
+
});
|
|
975
|
+
|
|
976
|
+
// Should show fallback after error
|
|
977
|
+
await waitFor(() => {
|
|
978
|
+
expect(screen.getByText('IMG')).toBeInTheDocument();
|
|
979
|
+
}, { timeout: 2000 });
|
|
980
|
+
});
|
|
981
|
+
});
|
|
982
|
+
|
|
983
|
+
describe('Metadata Display', () => {
|
|
984
|
+
it('shows metadata by default', async () => {
|
|
985
|
+
const file = {
|
|
986
|
+
id: 'fr-1',
|
|
987
|
+
table_name: 'person',
|
|
988
|
+
record_id: 'rec-1',
|
|
989
|
+
organisation_id: 'org-1',
|
|
990
|
+
file_path: 'bucket/path/file.pdf',
|
|
991
|
+
is_public: false,
|
|
992
|
+
file_metadata: { fileName: 'file.pdf', fileSize: 2048, fileType: 'application/pdf' },
|
|
993
|
+
};
|
|
994
|
+
|
|
995
|
+
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
996
|
+
useFileDisplay.mockReturnValue({
|
|
852
997
|
isLoading: false,
|
|
853
998
|
error: null,
|
|
854
|
-
|
|
999
|
+
fileUrl: null,
|
|
1000
|
+
fileReference: file,
|
|
1001
|
+
fileReferences: [file],
|
|
1002
|
+
fileCount: 1,
|
|
1003
|
+
fileUrls: new Map(),
|
|
1004
|
+
refetch: vi.fn(),
|
|
855
1005
|
});
|
|
856
1006
|
|
|
857
|
-
renderWithUnifiedAuth(<FileDisplay {...baseProps}
|
|
1007
|
+
renderWithUnifiedAuth(<FileDisplay {...baseProps} category={FileCategory.IMAGES} />);
|
|
858
1008
|
|
|
859
|
-
|
|
860
|
-
expect(
|
|
861
|
-
expect(screen.queryByRole('link')).not.toBeInTheDocument();
|
|
1009
|
+
expect(await screen.findByText('file.pdf')).toBeInTheDocument();
|
|
1010
|
+
expect(screen.getByText(/application\/pdf/i)).toBeInTheDocument();
|
|
862
1011
|
});
|
|
863
1012
|
|
|
864
|
-
it('
|
|
865
|
-
const
|
|
866
|
-
id: 'fr-
|
|
1013
|
+
it('hides metadata when showMetadata is false', async () => {
|
|
1014
|
+
const file = {
|
|
1015
|
+
id: 'fr-1',
|
|
867
1016
|
table_name: 'person',
|
|
868
1017
|
record_id: 'rec-1',
|
|
869
1018
|
organisation_id: 'org-1',
|
|
870
|
-
file_path: 'bucket/path/
|
|
1019
|
+
file_path: 'bucket/path/file.pdf',
|
|
871
1020
|
is_public: false,
|
|
872
|
-
file_metadata: { fileName: '
|
|
1021
|
+
file_metadata: { fileName: 'file.pdf', fileSize: 2048, fileType: 'application/pdf' },
|
|
873
1022
|
};
|
|
874
1023
|
|
|
875
1024
|
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
876
1025
|
useFileDisplay.mockReturnValue({
|
|
877
1026
|
isLoading: false,
|
|
878
1027
|
error: null,
|
|
879
|
-
fileUrl:
|
|
880
|
-
fileReference:
|
|
881
|
-
fileReferences: [
|
|
1028
|
+
fileUrl: null,
|
|
1029
|
+
fileReference: file,
|
|
1030
|
+
fileReferences: [file],
|
|
882
1031
|
fileCount: 1,
|
|
883
|
-
fileUrls: new Map(
|
|
1032
|
+
fileUrls: new Map(),
|
|
884
1033
|
refetch: vi.fn(),
|
|
885
1034
|
});
|
|
886
1035
|
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
1036
|
+
renderWithUnifiedAuth(<FileDisplay {...baseProps} category={FileCategory.IMAGES} showMetadata={false} />);
|
|
1037
|
+
|
|
1038
|
+
// File name might still be in alt text or title, but metadata section should not be visible
|
|
1039
|
+
const figcaption = document.querySelector('figcaption');
|
|
1040
|
+
expect(figcaption).not.toBeInTheDocument();
|
|
1041
|
+
});
|
|
1042
|
+
});
|
|
1043
|
+
|
|
1044
|
+
describe('Children Rendering', () => {
|
|
1045
|
+
it('renders children in empty state', async () => {
|
|
1046
|
+
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
1047
|
+
useFileDisplay.mockReturnValue({
|
|
891
1048
|
isLoading: false,
|
|
892
1049
|
error: null,
|
|
893
|
-
|
|
1050
|
+
fileUrl: null,
|
|
1051
|
+
fileReference: null,
|
|
1052
|
+
fileReferences: [],
|
|
1053
|
+
fileCount: 0,
|
|
1054
|
+
fileUrls: new Map(),
|
|
1055
|
+
refetch: vi.fn(),
|
|
894
1056
|
});
|
|
895
1057
|
|
|
896
|
-
renderWithUnifiedAuth(
|
|
1058
|
+
renderWithUnifiedAuth(
|
|
1059
|
+
<FileDisplay {...baseProps}>
|
|
1060
|
+
<button>Custom Action</button>
|
|
1061
|
+
</FileDisplay>
|
|
1062
|
+
);
|
|
897
1063
|
|
|
898
|
-
|
|
899
|
-
expect(screen.getByText('doc.pdf')).toBeInTheDocument();
|
|
900
|
-
expect(screen.getByRole('button', { name: /Delete file/i })).toBeInTheDocument();
|
|
901
|
-
// Should not be a simplified link (no link with target="_blank" in simplified form)
|
|
902
|
-
const link = screen.queryByRole('link', { name: /Open.*in new tab/i });
|
|
903
|
-
expect(link).not.toBeInTheDocument();
|
|
1064
|
+
expect(screen.getByRole('button', { name: 'Custom Action' })).toBeInTheDocument();
|
|
904
1065
|
});
|
|
905
1066
|
|
|
906
|
-
it('renders
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
table_name: 'event',
|
|
912
|
-
record_id: 'event-1',
|
|
1067
|
+
it('renders children in single file display', async () => {
|
|
1068
|
+
const file = {
|
|
1069
|
+
id: 'fr-1',
|
|
1070
|
+
table_name: 'person',
|
|
1071
|
+
record_id: 'rec-1',
|
|
913
1072
|
organisation_id: 'org-1',
|
|
914
|
-
file_path: 'bucket/path/
|
|
915
|
-
is_public:
|
|
916
|
-
file_metadata: { fileName: '
|
|
1073
|
+
file_path: 'bucket/path/file.png',
|
|
1074
|
+
is_public: false,
|
|
1075
|
+
file_metadata: { fileName: 'file.png', fileSize: 1024, fileType: 'image/png' },
|
|
917
1076
|
};
|
|
918
1077
|
|
|
919
|
-
const
|
|
920
|
-
|
|
921
|
-
usePublicFileDisplay.mockReturnValue({
|
|
1078
|
+
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
1079
|
+
useFileDisplay.mockReturnValue({
|
|
922
1080
|
isLoading: false,
|
|
923
1081
|
error: null,
|
|
924
|
-
fileUrl: 'https://
|
|
925
|
-
fileReference:
|
|
926
|
-
fileReferences: [
|
|
1082
|
+
fileUrl: 'https://example.com/file.png',
|
|
1083
|
+
fileReference: file,
|
|
1084
|
+
fileReferences: [file],
|
|
927
1085
|
fileCount: 1,
|
|
928
|
-
fileUrls:
|
|
1086
|
+
fileUrls: new Map([['fr-1', 'https://example.com/file.png']]),
|
|
929
1087
|
refetch: vi.fn(),
|
|
930
1088
|
});
|
|
931
1089
|
|
|
932
|
-
|
|
933
|
-
<FileDisplay {...baseProps}
|
|
934
|
-
|
|
1090
|
+
renderWithUnifiedAuth(
|
|
1091
|
+
<FileDisplay {...baseProps} category={FileCategory.IMAGES}>
|
|
1092
|
+
<button>Custom Button</button>
|
|
1093
|
+
</FileDisplay>
|
|
935
1094
|
);
|
|
936
1095
|
|
|
937
|
-
|
|
938
|
-
expect(
|
|
939
|
-
expect(link).toHaveAttribute('href', 'https://public.example.com/public-doc.pdf');
|
|
940
|
-
expect(link).toHaveAttribute('target', '_blank');
|
|
941
|
-
expect(link).toHaveAttribute('rel', 'noopener noreferrer');
|
|
1096
|
+
expect(await screen.findByRole('img', { name: /file\.png/i })).toBeInTheDocument();
|
|
1097
|
+
expect(screen.getByRole('button', { name: 'Custom Button' })).toBeInTheDocument();
|
|
942
1098
|
});
|
|
943
1099
|
|
|
944
|
-
it('
|
|
945
|
-
const
|
|
946
|
-
id: 'fr-
|
|
1100
|
+
it('renders children in displayOnly mode when enableChildren is true', async () => {
|
|
1101
|
+
const file = {
|
|
1102
|
+
id: 'fr-1',
|
|
947
1103
|
table_name: 'person',
|
|
948
1104
|
record_id: 'rec-1',
|
|
949
1105
|
organisation_id: 'org-1',
|
|
950
|
-
file_path: 'bucket/path/
|
|
1106
|
+
file_path: 'bucket/path/file.png',
|
|
951
1107
|
is_public: false,
|
|
952
|
-
file_metadata: { fileName: '
|
|
1108
|
+
file_metadata: { fileName: 'file.png', fileSize: 1024, fileType: 'image/png' },
|
|
953
1109
|
};
|
|
954
1110
|
|
|
955
1111
|
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
956
1112
|
useFileDisplay.mockReturnValue({
|
|
957
1113
|
isLoading: false,
|
|
958
1114
|
error: null,
|
|
959
|
-
fileUrl: 'https://
|
|
960
|
-
fileReference:
|
|
961
|
-
fileReferences: [
|
|
1115
|
+
fileUrl: 'https://example.com/file.png',
|
|
1116
|
+
fileReference: file,
|
|
1117
|
+
fileReferences: [file],
|
|
962
1118
|
fileCount: 1,
|
|
963
|
-
fileUrls: new Map([['fr-
|
|
1119
|
+
fileUrls: new Map([['fr-1', 'https://example.com/file.png']]),
|
|
964
1120
|
refetch: vi.fn(),
|
|
965
1121
|
});
|
|
966
1122
|
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
1123
|
+
renderWithUnifiedAuth(
|
|
1124
|
+
<FileDisplay {...baseProps} displayOnly enableChildren>
|
|
1125
|
+
<button>Child Button</button>
|
|
1126
|
+
</FileDisplay>
|
|
1127
|
+
);
|
|
1128
|
+
|
|
1129
|
+
expect(await screen.findByRole('img', { name: /file\.png/i })).toBeInTheDocument();
|
|
1130
|
+
expect(screen.getByRole('button', { name: 'Child Button' })).toBeInTheDocument();
|
|
1131
|
+
});
|
|
1132
|
+
});
|
|
1133
|
+
|
|
1134
|
+
describe('Error Handling', () => {
|
|
1135
|
+
it('uses custom error component when provided', async () => {
|
|
1136
|
+
const CustomError = ({ error, retry }: { error: Error | string | null; retry?: () => void }) => (
|
|
1137
|
+
<div data-testid="custom-error">
|
|
1138
|
+
<p>Custom Error: {error instanceof Error ? error.message : String(error)}</p>
|
|
1139
|
+
{retry && <button onClick={retry}>Retry</button>}
|
|
1140
|
+
</div>
|
|
1141
|
+
);
|
|
1142
|
+
|
|
1143
|
+
const refetch = vi.fn();
|
|
1144
|
+
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
1145
|
+
useFileDisplay.mockReturnValue({
|
|
971
1146
|
isLoading: false,
|
|
972
|
-
error:
|
|
973
|
-
|
|
1147
|
+
error: new Error('Test error'),
|
|
1148
|
+
fileUrl: null,
|
|
1149
|
+
fileReference: null,
|
|
1150
|
+
fileReferences: [],
|
|
1151
|
+
fileCount: 0,
|
|
1152
|
+
fileUrls: new Map(),
|
|
1153
|
+
refetch,
|
|
974
1154
|
});
|
|
975
1155
|
|
|
976
|
-
renderWithUnifiedAuth(<FileDisplay {...baseProps}
|
|
1156
|
+
renderWithUnifiedAuth(<FileDisplay {...baseProps} errorComponent={CustomError} />);
|
|
977
1157
|
|
|
978
|
-
|
|
979
|
-
expect(
|
|
1158
|
+
expect(screen.getByTestId('custom-error')).toBeInTheDocument();
|
|
1159
|
+
expect(screen.getByText(/Custom Error: Test error/i)).toBeInTheDocument();
|
|
1160
|
+
|
|
1161
|
+
const retryButton = screen.getByRole('button', { name: 'Retry' });
|
|
1162
|
+
await userEvent.click(retryButton);
|
|
1163
|
+
expect(refetch).toHaveBeenCalled();
|
|
980
1164
|
});
|
|
981
1165
|
|
|
982
|
-
it('
|
|
983
|
-
const
|
|
984
|
-
|
|
1166
|
+
it('handles string error messages', async () => {
|
|
1167
|
+
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
1168
|
+
useFileDisplay.mockReturnValue({
|
|
1169
|
+
isLoading: false,
|
|
1170
|
+
error: 'String error message',
|
|
1171
|
+
fileUrl: null,
|
|
1172
|
+
fileReference: null,
|
|
1173
|
+
fileReferences: [],
|
|
1174
|
+
fileCount: 0,
|
|
1175
|
+
fileUrls: new Map(),
|
|
1176
|
+
refetch: vi.fn(),
|
|
1177
|
+
});
|
|
1178
|
+
|
|
1179
|
+
renderWithUnifiedAuth(<FileDisplay {...baseProps} />);
|
|
1180
|
+
|
|
1181
|
+
expect(screen.getByText(/Error loading file: String error message/i)).toBeInTheDocument();
|
|
1182
|
+
});
|
|
1183
|
+
});
|
|
1184
|
+
|
|
1185
|
+
describe('Category Filtering', () => {
|
|
1186
|
+
it('filters files by category when category is specified', async () => {
|
|
1187
|
+
const imageFile = {
|
|
1188
|
+
id: 'fr-img',
|
|
985
1189
|
table_name: 'person',
|
|
986
1190
|
record_id: 'rec-1',
|
|
987
1191
|
organisation_id: 'org-1',
|
|
988
|
-
file_path: 'bucket/path/
|
|
1192
|
+
file_path: 'bucket/path/image.png',
|
|
989
1193
|
is_public: false,
|
|
990
|
-
file_metadata: { fileName: '', fileSize:
|
|
1194
|
+
file_metadata: { fileName: 'image.png', fileSize: 1024, fileType: 'image/png', category: FileCategory.IMAGES },
|
|
991
1195
|
};
|
|
992
1196
|
|
|
993
1197
|
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
994
1198
|
useFileDisplay.mockReturnValue({
|
|
995
1199
|
isLoading: false,
|
|
996
1200
|
error: null,
|
|
997
|
-
fileUrl: 'https://
|
|
998
|
-
fileReference:
|
|
999
|
-
fileReferences: [
|
|
1201
|
+
fileUrl: 'https://example.com/image.png',
|
|
1202
|
+
fileReference: imageFile,
|
|
1203
|
+
fileReferences: [imageFile],
|
|
1000
1204
|
fileCount: 1,
|
|
1001
|
-
fileUrls: new Map([['fr-
|
|
1205
|
+
fileUrls: new Map([['fr-img', 'https://example.com/image.png']]),
|
|
1002
1206
|
refetch: vi.fn(),
|
|
1003
1207
|
});
|
|
1004
1208
|
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1209
|
+
renderWithUnifiedAuth(<FileDisplay {...baseProps} category={FileCategory.IMAGES} />);
|
|
1210
|
+
|
|
1211
|
+
expect(await screen.findByRole('img', { name: /image\.png/i })).toBeInTheDocument();
|
|
1212
|
+
});
|
|
1213
|
+
});
|
|
1214
|
+
|
|
1215
|
+
describe('Organisation ID Handling', () => {
|
|
1216
|
+
it('handles undefined organisation_id', async () => {
|
|
1217
|
+
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
1218
|
+
useFileDisplay.mockReturnValue({
|
|
1009
1219
|
isLoading: false,
|
|
1010
1220
|
error: null,
|
|
1011
|
-
|
|
1221
|
+
fileUrl: null,
|
|
1222
|
+
fileReference: null,
|
|
1223
|
+
fileReferences: [],
|
|
1224
|
+
fileCount: 0,
|
|
1225
|
+
fileUrls: new Map(),
|
|
1226
|
+
refetch: vi.fn(),
|
|
1012
1227
|
});
|
|
1013
1228
|
|
|
1014
|
-
renderWithUnifiedAuth(<FileDisplay
|
|
1229
|
+
renderWithUnifiedAuth(<FileDisplay table_name="person" record_id="rec-1" />);
|
|
1015
1230
|
|
|
1016
|
-
|
|
1017
|
-
|
|
1231
|
+
expect(screen.getByText(/No files found/i)).toBeInTheDocument();
|
|
1232
|
+
});
|
|
1233
|
+
|
|
1234
|
+
it('handles null organisation_id', async () => {
|
|
1235
|
+
const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
|
|
1236
|
+
useFileDisplay.mockReturnValue({
|
|
1237
|
+
isLoading: false,
|
|
1238
|
+
error: null,
|
|
1239
|
+
fileUrl: null,
|
|
1240
|
+
fileReference: null,
|
|
1241
|
+
fileReferences: [],
|
|
1242
|
+
fileCount: 0,
|
|
1243
|
+
fileUrls: new Map(),
|
|
1244
|
+
refetch: vi.fn(),
|
|
1245
|
+
});
|
|
1246
|
+
|
|
1247
|
+
renderWithUnifiedAuth(<FileDisplay table_name="person" record_id="rec-1" organisation_id={null} />);
|
|
1248
|
+
|
|
1249
|
+
expect(screen.getByText(/No files found/i)).toBeInTheDocument();
|
|
1018
1250
|
});
|
|
1019
1251
|
});
|
|
1020
1252
|
});
|