@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
|
@@ -10,17 +10,20 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import React from 'react';
|
|
13
|
-
import { screen
|
|
13
|
+
import { screen } from '@testing-library/react';
|
|
14
14
|
import userEvent from '@testing-library/user-event';
|
|
15
15
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
16
16
|
import { User } from '@supabase/supabase-js';
|
|
17
|
-
import { Header
|
|
17
|
+
import { Header } from './Header';
|
|
18
18
|
import { renderWithProviders } from '../../__tests__/helpers/test-utils';
|
|
19
19
|
import type { NavigationItem } from '../NavigationMenu';
|
|
20
|
+
import { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';
|
|
21
|
+
import { useOrganisations } from '../../hooks/useOrganisations';
|
|
22
|
+
import { useEvents } from '../../hooks/useEvents';
|
|
20
23
|
|
|
21
24
|
// Mock the child components
|
|
22
25
|
vi.mock('../NavigationMenu', () => ({
|
|
23
|
-
NavigationMenu: ({ items,
|
|
26
|
+
NavigationMenu: ({ items, _onNavigate, _currentPath, buttonText, className }: any) => (
|
|
24
27
|
<div data-testid="navigation-menu" className={className}>
|
|
25
28
|
<button data-testid="navigation-menu-trigger">{buttonText}</button>
|
|
26
29
|
{items?.map((item: any) => (
|
|
@@ -52,12 +55,23 @@ vi.mock('../UserMenu', () => ({
|
|
|
52
55
|
),
|
|
53
56
|
}));
|
|
54
57
|
|
|
55
|
-
vi.
|
|
56
|
-
|
|
57
|
-
<div
|
|
58
|
+
const mockContextSelector = vi.hoisted(() =>
|
|
59
|
+
vi.fn(({ placeholder, className, showOrganisations, showEvents, onOrganisationSelect, onEventSelect, 'data-testid': testId }: any) => (
|
|
60
|
+
<div
|
|
61
|
+
data-testid={testId || 'context-selector'}
|
|
62
|
+
className={className}
|
|
63
|
+
data-show-orgs={showOrganisations}
|
|
64
|
+
data-show-events={showEvents}
|
|
65
|
+
data-on-org-select={onOrganisationSelect ? 'present' : 'absent'}
|
|
66
|
+
data-on-event-select={onEventSelect ? 'present' : 'absent'}
|
|
67
|
+
>
|
|
58
68
|
<button>{placeholder || 'Select organisation or event'}</button>
|
|
59
69
|
</div>
|
|
60
|
-
)
|
|
70
|
+
))
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
vi.mock('../ContextSelector', () => ({
|
|
74
|
+
ContextSelector: mockContextSelector,
|
|
61
75
|
}));
|
|
62
76
|
|
|
63
77
|
// Mock useEventService to prevent provider requirement
|
|
@@ -72,6 +86,36 @@ vi.mock('../../hooks/services/useEventService', () => ({
|
|
|
72
86
|
}))
|
|
73
87
|
}));
|
|
74
88
|
|
|
89
|
+
// Mock useUnifiedAuth to prevent infinite loops and async calls
|
|
90
|
+
vi.mock('../../providers/services/UnifiedAuthProvider', () => ({
|
|
91
|
+
useUnifiedAuth: vi.fn(() => ({
|
|
92
|
+
user: null,
|
|
93
|
+
isAuthenticated: false,
|
|
94
|
+
appName: undefined,
|
|
95
|
+
session: null,
|
|
96
|
+
authLoading: false,
|
|
97
|
+
authError: null,
|
|
98
|
+
supabase: null,
|
|
99
|
+
})),
|
|
100
|
+
}));
|
|
101
|
+
|
|
102
|
+
// Mock AppSwitcher to prevent async hook calls that could hang
|
|
103
|
+
// AppSwitcher uses useAccessibleApps which makes async database queries
|
|
104
|
+
vi.mock('../AppSwitcher/AppSwitcher', () => ({
|
|
105
|
+
AppSwitcher: ({ trigger, currentAppName: _currentAppName, showSwitcher, className }: any) => {
|
|
106
|
+
// If showSwitcher is false, return null or trigger (matches actual behavior)
|
|
107
|
+
if (showSwitcher === false) {
|
|
108
|
+
return trigger || null;
|
|
109
|
+
}
|
|
110
|
+
// If trigger is provided, return it wrapped in a div (simulating Select component)
|
|
111
|
+
if (trigger) {
|
|
112
|
+
return <div data-testid="app-switcher" className={className}>{trigger}</div>;
|
|
113
|
+
}
|
|
114
|
+
// Otherwise return a div with testid (when no trigger, AppSwitcher renders its own trigger)
|
|
115
|
+
return <div data-testid="app-switcher" className={className}>App Switcher</div>;
|
|
116
|
+
},
|
|
117
|
+
}));
|
|
118
|
+
|
|
75
119
|
// Mock useOrganisations hook
|
|
76
120
|
vi.mock('../../hooks/useOrganisations', () => ({
|
|
77
121
|
useOrganisations: vi.fn(() => ({
|
|
@@ -100,6 +144,19 @@ vi.mock('../../hooks/useOrganisations', () => ({
|
|
|
100
144
|
}))
|
|
101
145
|
}));
|
|
102
146
|
|
|
147
|
+
// Mock useEvents hook
|
|
148
|
+
vi.mock('../../hooks/useEvents', () => ({
|
|
149
|
+
useEvents: vi.fn(() => ({
|
|
150
|
+
events: [],
|
|
151
|
+
selectedEvent: null,
|
|
152
|
+
selectedEventId: null,
|
|
153
|
+
eventLoading: false,
|
|
154
|
+
eventError: null,
|
|
155
|
+
setSelectedEvent: vi.fn(),
|
|
156
|
+
refreshEvents: vi.fn(),
|
|
157
|
+
})),
|
|
158
|
+
}));
|
|
159
|
+
|
|
103
160
|
// Test data
|
|
104
161
|
const mockUser: User = {
|
|
105
162
|
id: '123',
|
|
@@ -118,16 +175,7 @@ const mockNavItems: NavigationItem[] = [
|
|
|
118
175
|
{ id: 'settings', label: 'Settings', href: '/settings' },
|
|
119
176
|
];
|
|
120
177
|
|
|
121
|
-
|
|
122
|
-
logoUrl: '/test-logo.svg',
|
|
123
|
-
logoAlt: 'Test Logo',
|
|
124
|
-
navItems: mockNavItems,
|
|
125
|
-
user: mockUser,
|
|
126
|
-
onSignOut: vi.fn(),
|
|
127
|
-
onChangePassword: vi.fn(),
|
|
128
|
-
currentPath: '/dashboard',
|
|
129
|
-
onNavigate: vi.fn(),
|
|
130
|
-
};
|
|
178
|
+
// mockProps removed - not used in tests
|
|
131
179
|
|
|
132
180
|
describe('Header Component', () => {
|
|
133
181
|
beforeEach(() => {
|
|
@@ -175,44 +223,12 @@ describe('Header Component', () => {
|
|
|
175
223
|
expect(logo).toHaveAttribute('alt', 'Test Logo');
|
|
176
224
|
});
|
|
177
225
|
|
|
178
|
-
it('renders
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
renderWithProviders(<Header logo={<CustomLogo />} />);
|
|
182
|
-
|
|
183
|
-
expect(screen.getByTestId('custom-logo')).toBeInTheDocument();
|
|
184
|
-
expect(screen.queryByRole('img')).not.toBeInTheDocument();
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it('renders default logo when no logo props provided', () => {
|
|
188
|
-
renderWithProviders(<Header />);
|
|
189
|
-
|
|
190
|
-
const logo = screen.getByRole('img', { name: 'Logo' });
|
|
191
|
-
expect(logo).toBeInTheDocument();
|
|
192
|
-
expect(logo).toBeVisible();
|
|
193
|
-
expect(logo).toHaveAttribute('src', expect.stringContaining('data:image/svg+xml'));
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
it('uses logoAlt as fallback when logoUrl provided without logoAlt', () => {
|
|
197
|
-
renderWithProviders(<Header logoUrl="/test-logo.svg" />);
|
|
198
|
-
|
|
199
|
-
const logo = screen.getByRole('img', { name: 'Logo' });
|
|
200
|
-
expect(logo).toHaveAttribute('alt', 'Logo');
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
it('prioritizes custom logo over logoUrl', () => {
|
|
204
|
-
const CustomLogo = () => <div data-testid="custom-logo">Custom Logo</div>;
|
|
205
|
-
|
|
206
|
-
renderWithProviders(
|
|
207
|
-
<Header
|
|
208
|
-
logo={<CustomLogo />}
|
|
209
|
-
logoUrl="/test-logo.svg"
|
|
210
|
-
logoAlt="Test Logo"
|
|
211
|
-
/>
|
|
212
|
-
);
|
|
226
|
+
it('renders clickable logo when logoHref is provided with logoUrl', () => {
|
|
227
|
+
renderWithProviders(<Header logoUrl="/test-logo.svg" logoHref="/dashboard" />);
|
|
213
228
|
|
|
214
|
-
|
|
215
|
-
expect(
|
|
229
|
+
const logoLink = screen.getByRole('img', { name: 'Logo' }).closest('a');
|
|
230
|
+
expect(logoLink).toBeInTheDocument();
|
|
231
|
+
expect(logoLink).toHaveAttribute('href', '/dashboard');
|
|
216
232
|
});
|
|
217
233
|
});
|
|
218
234
|
|
|
@@ -223,16 +239,17 @@ describe('Header Component', () => {
|
|
|
223
239
|
|
|
224
240
|
expect(screen.getByTestId('navigation-menu')).toBeInTheDocument();
|
|
225
241
|
expect(screen.getByTestId('navigation-menu-trigger')).toHaveTextContent('Menu');
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
it('does not render navigation menu when navItems empty', () => {
|
|
229
|
-
renderWithProviders(<Header navItems={[]} />);
|
|
230
242
|
|
|
231
|
-
|
|
243
|
+
mockNavItems.forEach(item => {
|
|
244
|
+
expect(screen.getByTestId(`nav-item-${item.id}`)).toHaveTextContent(item.label);
|
|
245
|
+
});
|
|
232
246
|
});
|
|
233
247
|
|
|
234
|
-
it(
|
|
235
|
-
|
|
248
|
+
it.each([
|
|
249
|
+
{ navItems: [], description: 'empty array' },
|
|
250
|
+
{ navItems: undefined, description: 'undefined' },
|
|
251
|
+
])('does not render navigation menu when navItems is $description', ({ navItems }) => {
|
|
252
|
+
renderWithProviders(<Header navItems={navItems} />);
|
|
236
253
|
|
|
237
254
|
expect(screen.queryByTestId('navigation-menu')).not.toBeInTheDocument();
|
|
238
255
|
});
|
|
@@ -249,39 +266,26 @@ describe('Header Component', () => {
|
|
|
249
266
|
);
|
|
250
267
|
|
|
251
268
|
expect(screen.getByTestId('navigation-menu')).toBeInTheDocument();
|
|
252
|
-
// NavigationMenu component should receive the props
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
it('renders all navigation items', () => {
|
|
256
|
-
renderWithProviders(<Header navItems={mockNavItems} />);
|
|
257
|
-
|
|
258
|
-
mockNavItems.forEach(item => {
|
|
259
|
-
expect(screen.getByTestId(`nav-item-${item.id}`)).toHaveTextContent(item.label);
|
|
260
|
-
});
|
|
261
269
|
});
|
|
262
270
|
});
|
|
263
271
|
|
|
264
272
|
// User menu tests
|
|
265
273
|
describe('User Menu', () => {
|
|
266
|
-
it(
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
it('renders user menu by default when user provided', () => {
|
|
279
|
-
renderWithProviders(<Header user={mockUser} />);
|
|
280
|
-
|
|
281
|
-
expect(screen.getByTestId('user-menu')).toBeInTheDocument();
|
|
274
|
+
it.each([
|
|
275
|
+
{ showUserMenu: true, shouldRender: true },
|
|
276
|
+
{ showUserMenu: false, shouldRender: false },
|
|
277
|
+
{ showUserMenu: undefined, shouldRender: true }, // default is true
|
|
278
|
+
])('renders user menu based on showUserMenu prop ($showUserMenu)', ({ showUserMenu, shouldRender }) => {
|
|
279
|
+
renderWithProviders(<Header user={mockUser} showUserMenu={showUserMenu} />);
|
|
280
|
+
|
|
281
|
+
if (shouldRender) {
|
|
282
|
+
expect(screen.getByTestId('user-menu')).toBeInTheDocument();
|
|
283
|
+
} else {
|
|
284
|
+
expect(screen.queryByTestId('user-menu')).not.toBeInTheDocument();
|
|
285
|
+
}
|
|
282
286
|
});
|
|
283
287
|
|
|
284
|
-
it('displays user email
|
|
288
|
+
it('displays user email when user is provided', () => {
|
|
285
289
|
renderWithProviders(<Header user={mockUser} />);
|
|
286
290
|
|
|
287
291
|
expect(screen.getByTestId('user-menu-trigger')).toHaveTextContent('test@example.com');
|
|
@@ -293,7 +297,7 @@ describe('Header Component', () => {
|
|
|
293
297
|
expect(screen.getByTestId('user-menu-trigger')).toHaveTextContent('Sign In');
|
|
294
298
|
});
|
|
295
299
|
|
|
296
|
-
it('renders custom user menu when provided', () => {
|
|
300
|
+
it('renders custom user menu when provided (overrides default)', () => {
|
|
297
301
|
const CustomUserMenu = () => <div data-testid="custom-user-menu">Custom Menu</div>;
|
|
298
302
|
|
|
299
303
|
renderWithProviders(<Header user={mockUser} userMenu={<CustomUserMenu />} />);
|
|
@@ -320,36 +324,19 @@ describe('Header Component', () => {
|
|
|
320
324
|
|
|
321
325
|
// Context selector tests
|
|
322
326
|
describe('Context Selector', () => {
|
|
323
|
-
it(
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
})
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
renderWithProviders(<Header showContextSelector={true} />);
|
|
337
|
-
|
|
338
|
-
expect(screen.getByTestId('context-selector')).toBeInTheDocument();
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
it('applies correct className to context selector', () => {
|
|
342
|
-
renderWithProviders(<Header showContextSelector={true} />);
|
|
343
|
-
|
|
344
|
-
const contextSelector = screen.getByTestId('context-selector');
|
|
345
|
-
expect(contextSelector).toBeInTheDocument();
|
|
346
|
-
expect(contextSelector).toBeVisible();
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
it('shows correct placeholder text', () => {
|
|
350
|
-
renderWithProviders(<Header showContextSelector={true} />);
|
|
351
|
-
|
|
352
|
-
expect(screen.getByRole('button', { name: 'Select organisation or event' })).toBeInTheDocument();
|
|
327
|
+
it.each([
|
|
328
|
+
{ showContextSelector: true, shouldRender: true },
|
|
329
|
+
{ showContextSelector: false, shouldRender: false },
|
|
330
|
+
{ showContextSelector: undefined, shouldRender: true }, // default is true
|
|
331
|
+
])('renders context selector based on showContextSelector prop ($showContextSelector)', ({ showContextSelector, shouldRender }) => {
|
|
332
|
+
renderWithProviders(<Header showContextSelector={showContextSelector} />);
|
|
333
|
+
|
|
334
|
+
if (shouldRender) {
|
|
335
|
+
expect(screen.getByTestId('context-selector')).toBeInTheDocument();
|
|
336
|
+
expect(screen.getByRole('button', { name: 'Select organisation or event' })).toBeInTheDocument();
|
|
337
|
+
} else {
|
|
338
|
+
expect(screen.queryByTestId('context-selector')).not.toBeInTheDocument();
|
|
339
|
+
}
|
|
353
340
|
});
|
|
354
341
|
|
|
355
342
|
it('preserves layout when context selector is hidden', () => {
|
|
@@ -365,10 +352,7 @@ describe('Header Component', () => {
|
|
|
365
352
|
expect(nav).toBeInTheDocument();
|
|
366
353
|
expect(nav).toBeVisible();
|
|
367
354
|
|
|
368
|
-
// Context selector should not be rendered
|
|
369
355
|
expect(screen.queryByTestId('context-selector')).not.toBeInTheDocument();
|
|
370
|
-
|
|
371
|
-
// User menu should still be present and positioned correctly
|
|
372
356
|
expect(screen.getByTestId('user-menu')).toBeInTheDocument();
|
|
373
357
|
});
|
|
374
358
|
});
|
|
@@ -460,28 +444,16 @@ describe('Header Component', () => {
|
|
|
460
444
|
});
|
|
461
445
|
|
|
462
446
|
describe('Layout and Responsive Design', () => {
|
|
463
|
-
it('applies correct
|
|
464
|
-
renderWithProviders(<Header />);
|
|
465
|
-
|
|
466
|
-
const nav = screen.getByRole('navigation');
|
|
467
|
-
expect(nav).toBeInTheDocument();
|
|
468
|
-
expect(nav).toBeVisible();
|
|
469
|
-
});
|
|
470
|
-
|
|
471
|
-
it('applies correct container classes', () => {
|
|
447
|
+
it('applies correct layout structure', () => {
|
|
472
448
|
renderWithProviders(<Header />);
|
|
473
449
|
|
|
450
|
+
const header = screen.getByRole('banner');
|
|
474
451
|
const nav = screen.getByRole('navigation');
|
|
475
|
-
expect(nav).toBeInTheDocument();
|
|
476
|
-
expect(nav).toBeVisible();
|
|
477
|
-
});
|
|
478
|
-
|
|
479
|
-
it('maintains proper header height', () => {
|
|
480
|
-
renderWithProviders(<Header />);
|
|
481
452
|
|
|
482
|
-
const header = screen.getByRole('banner');
|
|
483
453
|
expect(header).toBeInTheDocument();
|
|
484
454
|
expect(header).toBeVisible();
|
|
455
|
+
expect(nav).toBeInTheDocument();
|
|
456
|
+
expect(nav).toBeVisible();
|
|
485
457
|
});
|
|
486
458
|
});
|
|
487
459
|
|
|
@@ -518,42 +490,51 @@ describe('Header Component', () => {
|
|
|
518
490
|
|
|
519
491
|
// Edge cases and error handling
|
|
520
492
|
describe('Edge Cases and Error Handling', () => {
|
|
521
|
-
it(
|
|
522
|
-
|
|
493
|
+
it.each([
|
|
494
|
+
{ user: null, description: 'null user' },
|
|
495
|
+
{ user: undefined, description: 'undefined user' },
|
|
496
|
+
])('handles $description gracefully', ({ user }) => {
|
|
497
|
+
renderWithProviders(<Header user={user} />);
|
|
523
498
|
|
|
524
499
|
expect(screen.getByTestId('user-menu-trigger')).toHaveTextContent('Sign In');
|
|
525
500
|
});
|
|
526
501
|
|
|
527
|
-
it(
|
|
528
|
-
|
|
502
|
+
it.each([
|
|
503
|
+
{ navItems: [], description: 'empty array' },
|
|
504
|
+
{ navItems: undefined, description: 'undefined' },
|
|
505
|
+
])('does not render navigation menu when navItems is $description', ({ navItems }) => {
|
|
506
|
+
renderWithProviders(<Header navItems={navItems} />);
|
|
529
507
|
|
|
530
|
-
expect(screen.
|
|
508
|
+
expect(screen.queryByTestId('navigation-menu')).not.toBeInTheDocument();
|
|
531
509
|
});
|
|
532
510
|
|
|
533
|
-
it('handles
|
|
534
|
-
renderWithProviders(<Header
|
|
511
|
+
it('handles missing logoUrl gracefully (uses default)', () => {
|
|
512
|
+
renderWithProviders(<Header logoAlt="Test Logo" />);
|
|
535
513
|
|
|
536
|
-
|
|
514
|
+
const logo = screen.getByRole('img', { name: 'Test Logo' });
|
|
515
|
+
expect(logo).toHaveAttribute('src', expect.stringContaining('data:image/svg+xml'));
|
|
537
516
|
});
|
|
538
517
|
|
|
539
|
-
it('handles
|
|
540
|
-
renderWithProviders(<Header
|
|
518
|
+
it('handles missing logoAlt gracefully (uses default)', () => {
|
|
519
|
+
renderWithProviders(<Header logoUrl="/test-logo.svg" />);
|
|
541
520
|
|
|
542
|
-
|
|
521
|
+
const logo = screen.getByRole('img', { name: 'Logo' });
|
|
522
|
+
expect(logo).toHaveAttribute('alt', 'Logo');
|
|
543
523
|
});
|
|
544
524
|
|
|
545
|
-
it('handles
|
|
546
|
-
renderWithProviders(<Header
|
|
525
|
+
it('handles logoHref for clickable logo', () => {
|
|
526
|
+
renderWithProviders(<Header logoUrl="/test-logo.svg" logoHref="/dashboard" />);
|
|
547
527
|
|
|
548
|
-
const
|
|
549
|
-
expect(
|
|
528
|
+
const logoLink = screen.getByRole('img', { name: 'Logo' }).closest('a');
|
|
529
|
+
expect(logoLink).toBeInTheDocument();
|
|
530
|
+
expect(logoLink).toHaveAttribute('href', '/dashboard');
|
|
550
531
|
});
|
|
551
532
|
|
|
552
|
-
it('
|
|
533
|
+
it('renders logo without link when logoHref is not provided', () => {
|
|
553
534
|
renderWithProviders(<Header logoUrl="/test-logo.svg" />);
|
|
554
535
|
|
|
555
536
|
const logo = screen.getByRole('img', { name: 'Logo' });
|
|
556
|
-
expect(logo
|
|
537
|
+
expect(logo.closest('a')).not.toBeInTheDocument();
|
|
557
538
|
});
|
|
558
539
|
});
|
|
559
540
|
|
|
@@ -639,4 +620,514 @@ describe('Header Component', () => {
|
|
|
639
620
|
expect(screen.getByTestId('user-menu')).toBeInTheDocument();
|
|
640
621
|
});
|
|
641
622
|
});
|
|
623
|
+
|
|
624
|
+
// AppSwitcher tests
|
|
625
|
+
describe('AppSwitcher Integration', () => {
|
|
626
|
+
beforeEach(() => {
|
|
627
|
+
// Reset to default mock state
|
|
628
|
+
vi.mocked(useUnifiedAuth).mockReturnValue({
|
|
629
|
+
user: null,
|
|
630
|
+
isAuthenticated: false,
|
|
631
|
+
appName: undefined,
|
|
632
|
+
session: null,
|
|
633
|
+
authLoading: false,
|
|
634
|
+
authError: null,
|
|
635
|
+
supabase: null,
|
|
636
|
+
});
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
it('renders AppSwitcher when authenticated and appName is provided', () => {
|
|
640
|
+
vi.mocked(useUnifiedAuth).mockReturnValue({
|
|
641
|
+
user: mockUser,
|
|
642
|
+
isAuthenticated: true,
|
|
643
|
+
appName: 'TEST',
|
|
644
|
+
session: null,
|
|
645
|
+
authLoading: false,
|
|
646
|
+
authError: null,
|
|
647
|
+
supabase: null,
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
renderWithProviders(<Header />);
|
|
651
|
+
|
|
652
|
+
expect(screen.getByTestId('app-switcher')).toBeInTheDocument();
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
it('does not render AppSwitcher when not authenticated', () => {
|
|
656
|
+
vi.mocked(useUnifiedAuth).mockReturnValue({
|
|
657
|
+
user: null,
|
|
658
|
+
isAuthenticated: false,
|
|
659
|
+
appName: undefined,
|
|
660
|
+
session: null,
|
|
661
|
+
authLoading: false,
|
|
662
|
+
authError: null,
|
|
663
|
+
supabase: null,
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
renderWithProviders(<Header />);
|
|
667
|
+
|
|
668
|
+
expect(screen.queryByTestId('app-switcher')).not.toBeInTheDocument();
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
it('does not render AppSwitcher when appName is not provided', () => {
|
|
672
|
+
vi.mocked(useUnifiedAuth).mockReturnValue({
|
|
673
|
+
user: mockUser,
|
|
674
|
+
isAuthenticated: true,
|
|
675
|
+
appName: undefined,
|
|
676
|
+
session: null,
|
|
677
|
+
authLoading: false,
|
|
678
|
+
authError: null,
|
|
679
|
+
supabase: null,
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
renderWithProviders(<Header />);
|
|
683
|
+
|
|
684
|
+
expect(screen.queryByTestId('app-switcher')).not.toBeInTheDocument();
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
it('renders AppSwitcher with correct className', () => {
|
|
688
|
+
vi.mocked(useUnifiedAuth).mockReturnValue({
|
|
689
|
+
user: mockUser,
|
|
690
|
+
isAuthenticated: true,
|
|
691
|
+
appName: 'TEST',
|
|
692
|
+
session: null,
|
|
693
|
+
authLoading: false,
|
|
694
|
+
authError: null,
|
|
695
|
+
supabase: null,
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
renderWithProviders(<Header />);
|
|
699
|
+
|
|
700
|
+
const appSwitcher = screen.getByTestId('app-switcher');
|
|
701
|
+
expect(appSwitcher).toBeInTheDocument();
|
|
702
|
+
expect(appSwitcher).toHaveClass('w-9');
|
|
703
|
+
});
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
// Default logo tests
|
|
707
|
+
describe('Default Logo Rendering', () => {
|
|
708
|
+
it('renders default logo when logoUrl is not provided and logoHref is provided', () => {
|
|
709
|
+
renderWithProviders(<Header logoHref="/dashboard" />);
|
|
710
|
+
|
|
711
|
+
const logo = screen.getByRole('img', { name: 'Logo' });
|
|
712
|
+
expect(logo).toBeInTheDocument();
|
|
713
|
+
expect(logo).toHaveAttribute('src', expect.stringContaining('data:image/svg+xml'));
|
|
714
|
+
|
|
715
|
+
const logoLink = logo.closest('a');
|
|
716
|
+
expect(logoLink).toBeInTheDocument();
|
|
717
|
+
expect(logoLink).toHaveAttribute('href', '/dashboard');
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
it('renders default logo when logoUrl is not provided and logoHref is not provided', () => {
|
|
721
|
+
renderWithProviders(<Header />);
|
|
722
|
+
|
|
723
|
+
const logo = screen.getByRole('img', { name: 'Logo' });
|
|
724
|
+
expect(logo).toBeInTheDocument();
|
|
725
|
+
expect(logo).toHaveAttribute('src', expect.stringContaining('data:image/svg+xml'));
|
|
726
|
+
|
|
727
|
+
const logoLink = logo.closest('a');
|
|
728
|
+
expect(logoLink).not.toBeInTheDocument();
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
it('renders default logo with custom alt text', () => {
|
|
732
|
+
renderWithProviders(<Header logoAlt="Custom Alt" />);
|
|
733
|
+
|
|
734
|
+
const logo = screen.getByRole('img', { name: 'Custom Alt' });
|
|
735
|
+
expect(logo).toHaveAttribute('alt', 'Custom Alt');
|
|
736
|
+
});
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
// ContextSelector integration tests
|
|
740
|
+
describe('ContextSelector Integration', () => {
|
|
741
|
+
beforeEach(() => {
|
|
742
|
+
mockContextSelector.mockClear();
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
it('passes showOrganisations prop to ContextSelector', () => {
|
|
746
|
+
renderWithProviders(<Header showContextSelector={true} showOrganisations={false} />);
|
|
747
|
+
|
|
748
|
+
const contextSelector = screen.getByTestId('context-selector');
|
|
749
|
+
expect(contextSelector).toHaveAttribute('data-show-orgs', 'false');
|
|
750
|
+
|
|
751
|
+
// Check that mockContextSelector was called with showOrganisations
|
|
752
|
+
const lastCall = mockContextSelector.mock.calls[mockContextSelector.mock.calls.length - 1];
|
|
753
|
+
expect(lastCall[0].showOrganisations).toBe(false);
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
it('passes showEvents prop to ContextSelector', () => {
|
|
757
|
+
renderWithProviders(<Header showContextSelector={true} showEvents={false} />);
|
|
758
|
+
|
|
759
|
+
const contextSelector = screen.getByTestId('context-selector');
|
|
760
|
+
expect(contextSelector).toHaveAttribute('data-show-events', 'false');
|
|
761
|
+
|
|
762
|
+
// Check that mockContextSelector was called with showEvents
|
|
763
|
+
const lastCall = mockContextSelector.mock.calls[mockContextSelector.mock.calls.length - 1];
|
|
764
|
+
expect(lastCall[0].showEvents).toBe(false);
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
it('uses default values for showOrganisations and showEvents', () => {
|
|
768
|
+
renderWithProviders(<Header showContextSelector={true} />);
|
|
769
|
+
|
|
770
|
+
const contextSelector = screen.getByTestId('context-selector');
|
|
771
|
+
expect(contextSelector).toHaveAttribute('data-show-orgs', 'true');
|
|
772
|
+
expect(contextSelector).toHaveAttribute('data-show-events', 'true');
|
|
773
|
+
|
|
774
|
+
// Check that mockContextSelector was called with default values
|
|
775
|
+
const lastCall = mockContextSelector.mock.calls[mockContextSelector.mock.calls.length - 1];
|
|
776
|
+
expect(lastCall[0].showOrganisations).toBe(true);
|
|
777
|
+
expect(lastCall[0].showEvents).toBe(true);
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
it('passes onOrganisationSelect callback to ContextSelector', () => {
|
|
781
|
+
const mockSwitchOrganisation = vi.fn().mockResolvedValue(undefined);
|
|
782
|
+
vi.mocked(useOrganisations).mockReturnValue({
|
|
783
|
+
organisations: [],
|
|
784
|
+
selectedOrganisation: null,
|
|
785
|
+
isContextReady: true,
|
|
786
|
+
isLoading: false,
|
|
787
|
+
error: null,
|
|
788
|
+
switchOrganisation: mockSwitchOrganisation,
|
|
789
|
+
refreshOrganisations: vi.fn(),
|
|
790
|
+
userMemberships: []
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
renderWithProviders(<Header showContextSelector={true} />);
|
|
794
|
+
|
|
795
|
+
// Check that mockContextSelector was called with onOrganisationSelect
|
|
796
|
+
const lastCall = mockContextSelector.mock.calls[mockContextSelector.mock.calls.length - 1];
|
|
797
|
+
expect(lastCall[0]).toHaveProperty('onOrganisationSelect');
|
|
798
|
+
expect(typeof lastCall[0].onOrganisationSelect).toBe('function');
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
it('passes onEventSelect callback to ContextSelector', () => {
|
|
802
|
+
vi.mocked(useEvents).mockReturnValue({
|
|
803
|
+
events: [],
|
|
804
|
+
selectedEvent: null,
|
|
805
|
+
selectedEventId: null,
|
|
806
|
+
eventLoading: false,
|
|
807
|
+
eventError: null,
|
|
808
|
+
setSelectedEvent: vi.fn(),
|
|
809
|
+
refreshEvents: vi.fn(),
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
renderWithProviders(<Header showContextSelector={true} />);
|
|
813
|
+
|
|
814
|
+
// Check that mockContextSelector was called with onEventSelect
|
|
815
|
+
const lastCall = mockContextSelector.mock.calls[mockContextSelector.mock.calls.length - 1];
|
|
816
|
+
expect(lastCall[0]).toHaveProperty('onEventSelect');
|
|
817
|
+
expect(typeof lastCall[0].onEventSelect).toBe('function');
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
it('calls setSelectedEvent(null) before switchOrganisation when organisation is selected', async () => {
|
|
821
|
+
const mockSwitchOrganisation = vi.fn().mockResolvedValue(undefined);
|
|
822
|
+
const mockSetSelectedEvent = vi.fn();
|
|
823
|
+
|
|
824
|
+
vi.mocked(useOrganisations).mockReturnValue({
|
|
825
|
+
organisations: [],
|
|
826
|
+
selectedOrganisation: null,
|
|
827
|
+
isContextReady: true,
|
|
828
|
+
isLoading: false,
|
|
829
|
+
error: null,
|
|
830
|
+
switchOrganisation: mockSwitchOrganisation,
|
|
831
|
+
refreshOrganisations: vi.fn(),
|
|
832
|
+
userMemberships: []
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
vi.mocked(useEvents).mockReturnValue({
|
|
836
|
+
events: [],
|
|
837
|
+
selectedEvent: null,
|
|
838
|
+
selectedEventId: null,
|
|
839
|
+
eventLoading: false,
|
|
840
|
+
eventError: null,
|
|
841
|
+
setSelectedEvent: mockSetSelectedEvent,
|
|
842
|
+
refreshEvents: vi.fn(),
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
renderWithProviders(<Header showContextSelector={true} />);
|
|
846
|
+
|
|
847
|
+
// Get the onOrganisationSelect callback from the mock call
|
|
848
|
+
const contextSelectorCall = mockContextSelector.mock.calls.find(
|
|
849
|
+
call => call[0].onOrganisationSelect
|
|
850
|
+
);
|
|
851
|
+
|
|
852
|
+
if (contextSelectorCall && contextSelectorCall[0].onOrganisationSelect) {
|
|
853
|
+
const onOrganisationSelect = contextSelectorCall[0].onOrganisationSelect;
|
|
854
|
+
|
|
855
|
+
// Call the callback
|
|
856
|
+
await onOrganisationSelect({ id: 'test-org-id', name: 'Test Organisation' });
|
|
857
|
+
|
|
858
|
+
// Verify setSelectedEvent is called first
|
|
859
|
+
expect(mockSetSelectedEvent).toHaveBeenCalledWith(null);
|
|
860
|
+
expect(mockSwitchOrganisation).toHaveBeenCalledWith('test-org-id');
|
|
861
|
+
}
|
|
862
|
+
});
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
// Grid layout tests
|
|
866
|
+
describe('Grid Layout', () => {
|
|
867
|
+
it('applies correct grid layout when authenticated with appName', () => {
|
|
868
|
+
vi.mocked(useUnifiedAuth).mockReturnValue({
|
|
869
|
+
user: mockUser,
|
|
870
|
+
isAuthenticated: true,
|
|
871
|
+
appName: 'TEST',
|
|
872
|
+
session: null,
|
|
873
|
+
authLoading: false,
|
|
874
|
+
authError: null,
|
|
875
|
+
supabase: null,
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
renderWithProviders(<Header />);
|
|
879
|
+
|
|
880
|
+
const nav = screen.getByRole('navigation');
|
|
881
|
+
// Check that the nav element has the grid class (may be in className string)
|
|
882
|
+
const className = nav.className;
|
|
883
|
+
expect(className).toContain('grid-cols-[auto_auto_1fr_auto_auto]');
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
it('applies correct grid layout when not authenticated', () => {
|
|
887
|
+
vi.mocked(useUnifiedAuth).mockReturnValue({
|
|
888
|
+
user: null,
|
|
889
|
+
isAuthenticated: false,
|
|
890
|
+
appName: undefined,
|
|
891
|
+
session: null,
|
|
892
|
+
authLoading: false,
|
|
893
|
+
authError: null,
|
|
894
|
+
supabase: null,
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
renderWithProviders(<Header />);
|
|
898
|
+
|
|
899
|
+
const nav = screen.getByRole('navigation');
|
|
900
|
+
const className = nav.className;
|
|
901
|
+
expect(className).toContain('grid-cols-[auto_1fr_auto_auto]');
|
|
902
|
+
});
|
|
903
|
+
|
|
904
|
+
it('applies correct grid layout when authenticated without appName', () => {
|
|
905
|
+
vi.mocked(useUnifiedAuth).mockReturnValue({
|
|
906
|
+
user: mockUser,
|
|
907
|
+
isAuthenticated: true,
|
|
908
|
+
appName: undefined,
|
|
909
|
+
session: null,
|
|
910
|
+
authLoading: false,
|
|
911
|
+
authError: null,
|
|
912
|
+
supabase: null,
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
renderWithProviders(<Header />);
|
|
916
|
+
|
|
917
|
+
const nav = screen.getByRole('navigation');
|
|
918
|
+
const className = nav.className;
|
|
919
|
+
expect(className).toContain('grid-cols-[auto_1fr_auto_auto]');
|
|
920
|
+
});
|
|
921
|
+
});
|
|
922
|
+
|
|
923
|
+
// Logo navigation tests
|
|
924
|
+
describe('Logo Navigation', () => {
|
|
925
|
+
it('renders logo link with correct href when logoHref is provided', () => {
|
|
926
|
+
renderWithProviders(<Header logoUrl="/test-logo.svg" logoHref="/dashboard" />);
|
|
927
|
+
|
|
928
|
+
const logoLink = screen.getByRole('img', { name: 'Logo' }).closest('a');
|
|
929
|
+
expect(logoLink).toBeInTheDocument();
|
|
930
|
+
expect(logoLink).toHaveAttribute('href', '/dashboard');
|
|
931
|
+
});
|
|
932
|
+
|
|
933
|
+
it('does not navigate when logoHref is not provided', () => {
|
|
934
|
+
renderWithProviders(<Header logoUrl="/test-logo.svg" />);
|
|
935
|
+
|
|
936
|
+
const logo = screen.getByRole('img', { name: 'Logo' });
|
|
937
|
+
const logoLink = logo.closest('a');
|
|
938
|
+
expect(logoLink).not.toBeInTheDocument();
|
|
939
|
+
});
|
|
940
|
+
|
|
941
|
+
it('handles logoHref with default logo', () => {
|
|
942
|
+
renderWithProviders(<Header logoHref="/home" />);
|
|
943
|
+
|
|
944
|
+
const logo = screen.getByRole('img', { name: 'Logo' });
|
|
945
|
+
const logoLink = logo.closest('a');
|
|
946
|
+
expect(logoLink).toBeInTheDocument();
|
|
947
|
+
expect(logoLink).toHaveAttribute('href', '/home');
|
|
948
|
+
});
|
|
949
|
+
});
|
|
950
|
+
|
|
951
|
+
// Additional edge cases
|
|
952
|
+
describe('Additional Edge Cases', () => {
|
|
953
|
+
it('handles className merging correctly', () => {
|
|
954
|
+
renderWithProviders(<Header className="custom-class" />);
|
|
955
|
+
|
|
956
|
+
const header = screen.getByRole('banner');
|
|
957
|
+
expect(header).toHaveClass('custom-class');
|
|
958
|
+
expect(header).toHaveClass('w-full'); // Default classes should still be present
|
|
959
|
+
});
|
|
960
|
+
|
|
961
|
+
it('handles empty navItems array', () => {
|
|
962
|
+
renderWithProviders(<Header navItems={[]} />);
|
|
963
|
+
|
|
964
|
+
expect(screen.queryByTestId('navigation-menu')).not.toBeInTheDocument();
|
|
965
|
+
});
|
|
966
|
+
|
|
967
|
+
it('handles logoUrl with empty string', () => {
|
|
968
|
+
renderWithProviders(<Header logoUrl="" />);
|
|
969
|
+
|
|
970
|
+
// Empty string should be treated as falsy, so default logo should render
|
|
971
|
+
const logo = screen.getByRole('img', { name: 'Logo' });
|
|
972
|
+
expect(logo).toHaveAttribute('src', expect.stringContaining('data:image/svg+xml'));
|
|
973
|
+
});
|
|
974
|
+
|
|
975
|
+
it('handles logoAlt with empty string', () => {
|
|
976
|
+
renderWithProviders(<Header logoUrl="/test-logo.svg" logoAlt="" />);
|
|
977
|
+
|
|
978
|
+
const logo = screen.getByRole('img', { name: 'Logo' }); // Falls back to default
|
|
979
|
+
expect(logo).toBeInTheDocument();
|
|
980
|
+
});
|
|
981
|
+
|
|
982
|
+
it('handles all optional props as undefined', () => {
|
|
983
|
+
renderWithProviders(
|
|
984
|
+
<Header
|
|
985
|
+
logoUrl={undefined}
|
|
986
|
+
logoAlt={undefined}
|
|
987
|
+
navItems={undefined}
|
|
988
|
+
user={undefined}
|
|
989
|
+
onSignOut={undefined}
|
|
990
|
+
onChangePassword={undefined}
|
|
991
|
+
actions={undefined}
|
|
992
|
+
userMenu={undefined}
|
|
993
|
+
className={undefined}
|
|
994
|
+
showContextSelector={undefined}
|
|
995
|
+
showOrganisations={undefined}
|
|
996
|
+
showEvents={undefined}
|
|
997
|
+
showUserMenu={undefined}
|
|
998
|
+
currentPath={undefined}
|
|
999
|
+
onNavigate={undefined}
|
|
1000
|
+
logoHref={undefined}
|
|
1001
|
+
/>
|
|
1002
|
+
);
|
|
1003
|
+
|
|
1004
|
+
const header = screen.getByRole('banner');
|
|
1005
|
+
expect(header).toBeInTheDocument();
|
|
1006
|
+
});
|
|
1007
|
+
|
|
1008
|
+
it('handles logoHref with special characters', () => {
|
|
1009
|
+
renderWithProviders(<Header logoUrl="/test-logo.svg" logoHref="/dashboard?tab=settings" />);
|
|
1010
|
+
|
|
1011
|
+
const logoLink = screen.getByRole('img', { name: 'Logo' }).closest('a');
|
|
1012
|
+
expect(logoLink).toHaveAttribute('href', '/dashboard?tab=settings');
|
|
1013
|
+
});
|
|
1014
|
+
|
|
1015
|
+
it('handles logoHref with hash', () => {
|
|
1016
|
+
renderWithProviders(<Header logoUrl="/test-logo.svg" logoHref="/dashboard#section" />);
|
|
1017
|
+
|
|
1018
|
+
const logoLink = screen.getByRole('img', { name: 'Logo' }).closest('a');
|
|
1019
|
+
expect(logoLink).toHaveAttribute('href', '/dashboard#section');
|
|
1020
|
+
});
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
// Comprehensive integration scenarios
|
|
1024
|
+
describe('Comprehensive Integration Scenarios', () => {
|
|
1025
|
+
it('renders full header with all features when authenticated', () => {
|
|
1026
|
+
vi.mocked(useUnifiedAuth).mockReturnValue({
|
|
1027
|
+
user: mockUser,
|
|
1028
|
+
isAuthenticated: true,
|
|
1029
|
+
appName: 'TEST',
|
|
1030
|
+
session: null,
|
|
1031
|
+
authLoading: false,
|
|
1032
|
+
authError: null,
|
|
1033
|
+
supabase: null,
|
|
1034
|
+
});
|
|
1035
|
+
|
|
1036
|
+
const customActions = <div data-testid="custom-actions">Actions</div>;
|
|
1037
|
+
|
|
1038
|
+
renderWithProviders(
|
|
1039
|
+
<Header
|
|
1040
|
+
logoUrl="/test-logo.svg"
|
|
1041
|
+
logoAlt="Test Logo"
|
|
1042
|
+
logoHref="/dashboard"
|
|
1043
|
+
navItems={mockNavItems}
|
|
1044
|
+
user={mockUser}
|
|
1045
|
+
actions={customActions}
|
|
1046
|
+
showContextSelector={true}
|
|
1047
|
+
showOrganisations={true}
|
|
1048
|
+
showEvents={true}
|
|
1049
|
+
showUserMenu={true}
|
|
1050
|
+
currentPath="/dashboard"
|
|
1051
|
+
/>
|
|
1052
|
+
);
|
|
1053
|
+
|
|
1054
|
+
// AppSwitcher
|
|
1055
|
+
expect(screen.getByTestId('app-switcher')).toBeInTheDocument();
|
|
1056
|
+
|
|
1057
|
+
// Logo
|
|
1058
|
+
expect(screen.getByRole('img', { name: 'Test Logo' })).toBeInTheDocument();
|
|
1059
|
+
|
|
1060
|
+
// Navigation
|
|
1061
|
+
expect(screen.getByTestId('navigation-menu')).toBeInTheDocument();
|
|
1062
|
+
|
|
1063
|
+
// Context Selector
|
|
1064
|
+
expect(screen.getByTestId('context-selector')).toBeInTheDocument();
|
|
1065
|
+
|
|
1066
|
+
// Custom Actions
|
|
1067
|
+
expect(screen.getByTestId('custom-actions')).toBeInTheDocument();
|
|
1068
|
+
|
|
1069
|
+
// User Menu
|
|
1070
|
+
expect(screen.getByTestId('user-menu')).toBeInTheDocument();
|
|
1071
|
+
});
|
|
1072
|
+
|
|
1073
|
+
it('renders minimal header when not authenticated', () => {
|
|
1074
|
+
vi.mocked(useUnifiedAuth).mockReturnValue({
|
|
1075
|
+
user: null,
|
|
1076
|
+
isAuthenticated: false,
|
|
1077
|
+
appName: undefined,
|
|
1078
|
+
session: null,
|
|
1079
|
+
authLoading: false,
|
|
1080
|
+
authError: null,
|
|
1081
|
+
supabase: null,
|
|
1082
|
+
});
|
|
1083
|
+
|
|
1084
|
+
renderWithProviders(
|
|
1085
|
+
<Header
|
|
1086
|
+
logoUrl="/test-logo.svg"
|
|
1087
|
+
showContextSelector={false}
|
|
1088
|
+
showUserMenu={false}
|
|
1089
|
+
/>
|
|
1090
|
+
);
|
|
1091
|
+
|
|
1092
|
+
// Should not have AppSwitcher
|
|
1093
|
+
expect(screen.queryByTestId('app-switcher')).not.toBeInTheDocument();
|
|
1094
|
+
|
|
1095
|
+
// Should have logo
|
|
1096
|
+
expect(screen.getByRole('img', { name: 'Logo' })).toBeInTheDocument();
|
|
1097
|
+
|
|
1098
|
+
// Should not have context selector
|
|
1099
|
+
expect(screen.queryByTestId('context-selector')).not.toBeInTheDocument();
|
|
1100
|
+
|
|
1101
|
+
// Should not have user menu
|
|
1102
|
+
expect(screen.queryByTestId('user-menu')).not.toBeInTheDocument();
|
|
1103
|
+
});
|
|
1104
|
+
|
|
1105
|
+
it('handles context selector with only organisations', () => {
|
|
1106
|
+
renderWithProviders(
|
|
1107
|
+
<Header
|
|
1108
|
+
showContextSelector={true}
|
|
1109
|
+
showOrganisations={true}
|
|
1110
|
+
showEvents={false}
|
|
1111
|
+
/>
|
|
1112
|
+
);
|
|
1113
|
+
|
|
1114
|
+
const contextSelector = screen.getByTestId('context-selector');
|
|
1115
|
+
expect(contextSelector).toHaveAttribute('data-show-orgs', 'true');
|
|
1116
|
+
expect(contextSelector).toHaveAttribute('data-show-events', 'false');
|
|
1117
|
+
});
|
|
1118
|
+
|
|
1119
|
+
it('handles context selector with only events', () => {
|
|
1120
|
+
renderWithProviders(
|
|
1121
|
+
<Header
|
|
1122
|
+
showContextSelector={true}
|
|
1123
|
+
showOrganisations={false}
|
|
1124
|
+
showEvents={true}
|
|
1125
|
+
/>
|
|
1126
|
+
);
|
|
1127
|
+
|
|
1128
|
+
const contextSelector = screen.getByTestId('context-selector');
|
|
1129
|
+
expect(contextSelector).toHaveAttribute('data-show-orgs', 'false');
|
|
1130
|
+
expect(contextSelector).toHaveAttribute('data-show-events', 'true');
|
|
1131
|
+
});
|
|
1132
|
+
});
|
|
642
1133
|
});
|