@jmruthers/pace-core 0.4.1 → 0.5.1
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 +26 -1
- package/README.md +231 -229
- package/dist/{DataTable-2LB6HI6V.js → DataTable-GX3XERFJ.js} +14 -17
- package/dist/{DataTable-BDBqkU-i.d.ts → DataTable-ltTFXHS3.d.ts} +25 -51
- package/dist/{Table-CIm9IWqk.d.ts → PublicLoadingSpinner-DztrzuJr.d.ts} +635 -122
- package/dist/UnifiedAuthProvider-w66zSCUf.d.ts +160 -0
- package/dist/{api-AIJ3IJX3.js → api-ETQ6YJ3C.js} +6 -4
- package/dist/{appConfig-fB1pP_v3.d.ts → appConfig-BVGyuvI7.d.ts} +1 -1
- package/dist/appNameResolver-7GHF5ED2.js +22 -0
- package/dist/{audit-PD5L5ZSC.js → audit-BUW3LMJB.js} +3 -3
- package/dist/chunk-5EL3KHOQ.js +388 -0
- package/dist/chunk-5EL3KHOQ.js.map +1 -0
- package/dist/{chunk-4MCJAK7J.js → chunk-6CR3MRZN.js} +1827 -4886
- package/dist/chunk-6CR3MRZN.js.map +1 -0
- package/dist/{chunk-YNU5QJ4S.js → chunk-7BNPOCLL.js} +22 -5
- package/dist/chunk-7BNPOCLL.js.map +1 -0
- package/dist/chunk-AUE24LVR.js +268 -0
- package/dist/chunk-AUE24LVR.js.map +1 -0
- package/dist/chunk-C5G2A4PO.js +1349 -0
- package/dist/chunk-C5G2A4PO.js.map +1 -0
- package/dist/{chunk-4ZTIEYU2.js → chunk-CDQ3PX7L.js} +1 -1
- package/dist/chunk-CDQ3PX7L.js.map +1 -0
- package/dist/chunk-COBPIXXQ.js +379 -0
- package/dist/chunk-COBPIXXQ.js.map +1 -0
- package/dist/chunk-GSNM5D6H.js +5441 -0
- package/dist/chunk-GSNM5D6H.js.map +1 -0
- package/dist/chunk-MZBUOP4P.js +119 -0
- package/dist/chunk-MZBUOP4P.js.map +1 -0
- package/dist/chunk-N2EUGZRW.js +98 -0
- package/dist/chunk-N2EUGZRW.js.map +1 -0
- package/dist/chunk-NQ4TOOO6.js +20 -0
- package/dist/chunk-NQ4TOOO6.js.map +1 -0
- package/dist/{chunk-KK6WIDK6.js → chunk-OEGRKULD.js} +12 -2
- package/dist/{chunk-KK6WIDK6.js.map → chunk-OEGRKULD.js.map} +1 -1
- package/dist/chunk-OYRY44Q2.js +62 -0
- package/dist/chunk-OYRY44Q2.js.map +1 -0
- package/dist/{chunk-DC5AMYBS.js → chunk-PLDDJCW6.js} +15 -5
- package/dist/chunk-PLDDJCW6.js.map +1 -0
- package/dist/{chunk-WHLSWC6W.js → chunk-SS3E6QLB.js} +16 -61
- package/dist/chunk-SS3E6QLB.js.map +1 -0
- package/dist/chunk-T3XIA4AJ.js +3295 -0
- package/dist/chunk-T3XIA4AJ.js.map +1 -0
- package/dist/{chunk-H4PZ4B3Y.js → chunk-TGDCLPP2.js} +129 -28
- package/dist/chunk-TGDCLPP2.js.map +1 -0
- package/dist/{chunk-IOX76PSM.js → chunk-U6JDHVC2.js} +273 -29
- package/dist/chunk-U6JDHVC2.js.map +1 -0
- package/dist/{chunk-JUUNUW3O.js → chunk-XJK2J4N6.js} +17 -6
- package/dist/chunk-XJK2J4N6.js.map +1 -0
- package/dist/chunk-YDJW5XTN.js +84 -0
- package/dist/chunk-YDJW5XTN.js.map +1 -0
- package/dist/components.d.ts +906 -10
- package/dist/components.js +3263 -84
- package/dist/components.js.map +1 -1
- package/dist/{database-CAMsquLm.d.ts → database-C3Szpi5J.d.ts} +28 -11
- package/dist/hooks.d.ts +7 -6
- package/dist/hooks.js +35 -11
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +245 -111
- package/dist/index.js +195 -185
- package/dist/index.js.map +1 -1
- package/dist/{organisation-DLNNQhPB.d.ts → organisation-CO3Sh3_D.d.ts} +1 -1
- package/dist/providers.d.ts +4 -4
- package/dist/providers.js +21 -6
- package/dist/rbac/index.d.ts +862 -806
- package/dist/rbac/index.js +953 -1032
- package/dist/rbac/index.js.map +1 -1
- package/dist/styles/core.css +422 -0
- package/dist/styles/fonts/georama-italic.woff2 +0 -0
- package/dist/styles/fonts/georama.woff2 +0 -0
- package/dist/styles/fonts/open-sans-italic.woff2 +0 -0
- package/dist/styles/fonts/open-sans.woff2 +0 -0
- package/dist/styles/fonts/reddit-mono.woff2 +0 -0
- package/dist/styles/index.d.ts +36 -0
- package/dist/styles/index.js +24 -0
- package/dist/styles/index.js.map +1 -0
- package/dist/theming/runtime.d.ts +73 -0
- package/dist/theming/runtime.js +16 -0
- package/dist/theming/runtime.js.map +1 -0
- package/dist/{types-Bavn44NW.d.ts → types-BRDU7N6w.d.ts} +79 -33
- package/dist/types.d.ts +5 -5
- package/dist/types.js +7 -2
- package/dist/types.js.map +1 -1
- package/dist/{unified-BtRpPbmp.d.ts → unified-CM7T0aTK.d.ts} +1 -2
- package/dist/usePublicRouteParams-B6i0KtXW.d.ts +477 -0
- package/dist/utils.d.ts +83 -60
- package/dist/utils.js +301 -55657
- package/dist/utils.js.map +1 -1
- package/dist/validation.d.ts +1 -1
- package/dist/validation.js +1 -1
- package/docs/INDEX.md +192 -0
- package/docs/README.md +46 -32
- package/docs/api/README.md +231 -229
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +132 -0
- package/docs/api/interfaces/AggregateConfig.md +4 -4
- package/docs/api/interfaces/ButtonProps.md +2 -2
- package/docs/api/interfaces/CardProps.md +2 -2
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +98 -7
- package/docs/api/interfaces/DataTableColumn.md +131 -12
- package/docs/api/interfaces/DataTableProps.md +77 -274
- package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
- package/docs/api/interfaces/EmptyStateConfig.md +5 -5
- package/docs/api/interfaces/EventContextType.md +7 -7
- package/docs/api/interfaces/EventLogoProps.md +152 -0
- package/docs/api/interfaces/EventProviderProps.md +2 -2
- package/docs/api/interfaces/FileSizeLimits.md +7 -0
- package/docs/api/interfaces/FileUploadProps.md +154 -0
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +115 -0
- package/docs/api/interfaces/InputProps.md +2 -2
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +2 -2
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +26 -26
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +94 -0
- package/docs/api/interfaces/PublicErrorBoundaryState.md +68 -0
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +86 -0
- package/docs/api/interfaces/PublicPageFooterProps.md +112 -0
- package/docs/api/interfaces/PublicPageHeaderProps.md +138 -0
- package/docs/api/interfaces/PublicPageLayoutProps.md +138 -0
- package/docs/api/interfaces/StorageConfig.md +41 -0
- package/docs/api/interfaces/StorageFileInfo.md +74 -0
- package/docs/api/interfaces/StorageFileMetadata.md +140 -0
- package/docs/api/interfaces/StorageListOptions.md +86 -0
- package/docs/api/interfaces/StorageListResult.md +41 -0
- package/docs/api/interfaces/StorageUploadOptions.md +88 -0
- package/docs/api/interfaces/StorageUploadResult.md +63 -0
- package/docs/api/interfaces/StorageUrlOptions.md +47 -0
- package/docs/api/interfaces/StyleImport.md +2 -2
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +447 -46
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +95 -9
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +136 -0
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +123 -0
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +87 -0
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +81 -0
- package/docs/api/interfaces/UsePublicEventOptions.md +34 -0
- package/docs/api/interfaces/UsePublicEventReturn.md +68 -0
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +94 -0
- package/docs/api/interfaces/UserEventAccess.md +14 -14
- package/docs/api/interfaces/UserMenuProps.md +6 -6
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +1626 -768
- package/docs/api-reference/components.md +761 -43
- package/docs/api-reference/hooks.md +126 -0
- package/docs/api-reference/providers.md +141 -65
- package/docs/api-reference/types.md +66 -36
- package/docs/api-reference/utilities.md +1 -1
- package/docs/architecture/README.md +1 -2
- package/docs/best-practices/README.md +400 -0
- package/docs/consuming-app-example.md +42 -96
- package/docs/consuming-app-vite-config.md +233 -0
- package/docs/core-concepts/events.md +3 -3
- package/docs/core-concepts/organisations.md +0 -1
- package/docs/core-concepts/rbac-system.md +23 -10
- package/docs/documentation-style-checklist.md +8 -2
- package/docs/examples/navigation-menu-auth-fix.md +344 -0
- package/docs/getting-started/examples/README.md +15 -1
- package/docs/getting-started/examples/basic-auth-app.md +444 -119
- package/docs/getting-started/examples/full-featured-app.md +6 -6
- package/docs/getting-started/installation.md +231 -52
- package/docs/getting-started/quick-start.md +121 -24
- package/docs/implementation-guides/app-layout.md +133 -108
- package/docs/implementation-guides/data-tables.md +1011 -29
- package/docs/implementation-guides/forms.md +3 -3
- package/docs/implementation-guides/hierarchical-datatable.md +850 -0
- package/docs/implementation-guides/large-datasets.md +2 -2
- package/docs/implementation-guides/navigation.md +1 -1
- package/docs/implementation-guides/permission-enforcement.md +4 -4
- package/docs/implementation-guides/public-pages.md +752 -0
- package/docs/migration/README.md +18 -8
- package/docs/migration/quick-migration-guide.md +320 -0
- package/docs/migration/rbac-migration.md +50 -0
- package/docs/migration/v0.4.15-tailwind-scanning.md +272 -0
- package/docs/migration/v0.4.16-css-first-approach.md +306 -0
- package/docs/migration/v0.4.17-source-path-fix.md +229 -0
- package/docs/migration-guide.md +51 -104
- package/docs/performance/README.md +1 -4
- package/docs/print-components/README.md +258 -0
- package/docs/print-components/api-reference.md +636 -0
- package/docs/print-components/examples/README.md +204 -0
- package/docs/print-components/examples/basic-report.tsx +92 -0
- package/docs/print-components/examples/card-catalog.tsx +149 -0
- package/docs/print-components/examples/cover-page-report.tsx +163 -0
- package/docs/print-components/quick-start.md +363 -0
- package/docs/quick-reference.md +53 -36
- package/docs/rbac/README.md +136 -69
- package/docs/rbac/api-reference.md +39 -8
- package/docs/rbac/examples.md +237 -66
- package/docs/rbac/getting-started.md +131 -16
- package/docs/rbac/quick-start.md +499 -323
- package/docs/rbac/troubleshooting.md +240 -262
- package/docs/security/README.md +50 -1
- package/docs/styles/README.md +143 -117
- package/docs/testing/README.md +6 -10
- package/docs/troubleshooting/README.md +497 -0
- package/docs/troubleshooting/common-issues.md +604 -14
- package/docs/troubleshooting/styling-issues.md +219 -0
- package/docs/troubleshooting/tailwind-content-scanning.md +213 -0
- package/docs/usage.md +28 -90
- package/docs/visual-testing.md +0 -7
- package/package.json +46 -24
- package/src/__mocks__/lucide-react.ts +181 -0
- package/src/__tests__/REBUILD_PLAN.md +223 -0
- package/src/__tests__/TESTING_GUIDELINES.md +341 -0
- package/src/__tests__/fixtures/mocks.ts +93 -0
- package/src/__tests__/helpers/component-test-utils.tsx +145 -0
- package/src/__tests__/helpers/test-utils.tsx +117 -0
- package/src/__tests__/integration/UserProfile.test.tsx +128 -0
- package/src/__tests__/setup.ts +71 -0
- package/src/__tests__/templates/accessibility.test.template.tsx +279 -0
- package/src/__tests__/templates/component.test.template.tsx +144 -0
- package/src/__tests__/templates/hook.test.template.ts +173 -0
- package/src/__tests__/templates/integration.test.template.tsx +199 -0
- package/src/__tests__/types/test.types.ts +106 -0
- package/src/components/Alert/Alert.test.tsx +496 -0
- package/src/components/Alert/Alert.tsx +134 -0
- package/src/components/Alert/index.ts +2 -0
- package/src/components/Avatar/Avatar.test.tsx +484 -0
- package/src/components/Avatar/Avatar.tsx +84 -0
- package/src/components/Avatar/index.ts +2 -0
- package/src/components/Button/Button.test.tsx +662 -0
- package/src/components/Button/Button.tsx +270 -0
- package/src/components/Button/index.ts +2 -0
- package/src/components/Card/Card.test.tsx +593 -0
- package/src/components/Card/Card.tsx +271 -0
- package/src/components/Card/index.ts +1 -0
- package/src/components/Checkbox/Checkbox.test.tsx +461 -0
- package/src/components/Checkbox/Checkbox.tsx +75 -0
- package/src/components/Checkbox/__mocks__/Checkbox.tsx +2 -0
- package/src/components/Checkbox/index.ts +2 -0
- package/src/components/DataTable/DataTable.tsx +446 -0
- package/src/components/DataTable/__tests__/README.md +145 -0
- package/src/components/DataTable/__tests__/mocks/MockRBACProvider.tsx +66 -0
- package/src/components/DataTable/__tests__/test-utils/dataFactories.ts +103 -0
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +381 -0
- package/src/components/DataTable/__tests__/test-utils.ts +94 -0
- package/src/components/DataTable/components/AccessDeniedPage.tsx +168 -0
- package/src/components/DataTable/components/ActionButtons.tsx +194 -0
- package/src/components/DataTable/components/BulkOperationsDropdown.tsx +160 -0
- package/src/components/DataTable/components/ColumnFilter.tsx +114 -0
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +100 -0
- package/src/components/DataTable/components/DataTableBody.tsx +461 -0
- package/src/components/DataTable/components/DataTableCore.tsx +1027 -0
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +214 -0
- package/src/components/DataTable/components/DataTableModals.tsx +87 -0
- package/src/components/DataTable/components/DataTableToolbar.tsx +262 -0
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +144 -0
- package/src/components/DataTable/components/EditableRow.tsx +159 -0
- package/src/components/DataTable/components/EmptyState.tsx +64 -0
- package/src/components/DataTable/components/ExpandButton.tsx +113 -0
- package/src/components/DataTable/components/FilterRow.tsx +100 -0
- package/src/components/DataTable/components/GroupHeader.tsx +42 -0
- package/src/components/DataTable/components/GroupingDropdown.tsx +96 -0
- package/src/components/DataTable/components/ImportModal.tsx +345 -0
- package/src/components/DataTable/components/LoadingState.tsx +12 -0
- package/src/components/DataTable/components/PaginationControls.tsx +332 -0
- package/src/components/DataTable/components/UnifiedTableBody.tsx +742 -0
- package/src/components/DataTable/components/ViewRowModal.tsx +68 -0
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +513 -0
- package/src/components/DataTable/components/index.ts +16 -0
- package/src/components/DataTable/context/DataTableContext.tsx +97 -0
- package/src/components/DataTable/core/ActionManager.ts +235 -0
- package/src/components/DataTable/core/ColumnFactory.ts +268 -0
- package/src/components/DataTable/core/ColumnManager.ts +205 -0
- package/src/components/DataTable/core/DataManager.ts +188 -0
- package/src/components/DataTable/core/DataTableContext.tsx +181 -0
- package/src/components/DataTable/core/LocalDataAdapter.ts +264 -0
- package/src/components/DataTable/core/PluginRegistry.ts +229 -0
- package/src/components/DataTable/core/StateManager.ts +311 -0
- package/src/components/DataTable/core/index.ts +8 -0
- package/src/components/DataTable/core/interfaces.ts +338 -0
- package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +419 -0
- package/src/components/DataTable/examples/HierarchicalExample.tsx +475 -0
- package/src/components/DataTable/examples/InitialPageSizeExample.tsx +176 -0
- package/src/components/DataTable/examples/PerformanceExample.tsx +505 -0
- package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +95 -0
- package/src/components/DataTable/hooks/useColumnReordering.ts +110 -0
- package/src/components/DataTable/hooks/useDataTableState.ts +325 -0
- package/src/components/DataTable/hooks/useHierarchicalState.ts +174 -0
- package/src/components/DataTable/index.ts +68 -0
- package/src/components/DataTable/styles.ts +171 -0
- package/src/components/DataTable/types.ts +511 -0
- package/src/components/DataTable/utils/debugTools.ts +583 -0
- package/src/components/DataTable/utils/errorHandling.ts +494 -0
- package/src/components/DataTable/utils/exportUtils.ts +126 -0
- package/src/components/DataTable/utils/flexibleImport.ts +510 -0
- package/src/components/DataTable/utils/hierarchicalSorting.ts +151 -0
- package/src/components/DataTable/utils/hierarchicalUtils.ts +218 -0
- package/src/components/DataTable/utils/index.ts +1 -0
- package/src/components/DataTable/utils/performanceUtils.ts +351 -0
- package/src/components/Dialog/Dialog.test.tsx +1139 -0
- package/src/components/Dialog/Dialog.tsx +782 -0
- package/src/components/Dialog/README.md +804 -0
- package/src/components/Dialog/examples/BasicHtmlTest.tsx +55 -0
- package/src/components/Dialog/examples/DebugHtmlExample.tsx +68 -0
- package/src/components/Dialog/examples/HtmlDialogExample.tsx +202 -0
- package/src/components/Dialog/examples/SimpleHtmlTest.tsx +61 -0
- package/src/components/Dialog/examples/SmartDialogExample.tsx +322 -0
- package/src/components/Dialog/index.ts +12 -0
- package/src/components/Dialog/utils/safeHtml.ts +185 -0
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +752 -0
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +312 -0
- package/src/components/ErrorBoundary/index.ts +8 -0
- package/src/components/EventSelector/EventSelector.tsx +360 -0
- package/src/components/EventSelector/index.ts +3 -0
- package/src/components/EventSelector/types.ts +79 -0
- package/src/components/FileUpload/FileUpload.example.tsx +218 -0
- package/src/components/FileUpload/FileUpload.test.tsx +665 -0
- package/src/components/FileUpload/FileUpload.tsx +237 -0
- package/src/components/FileUpload/index.ts +6 -0
- package/src/components/Footer/Footer.tsx +197 -0
- package/src/components/Footer/index.ts +17 -0
- package/src/components/Form/Form.tsx +166 -0
- package/src/components/Form/FormErrorSummary.tsx +113 -0
- package/src/components/Form/FormField.tsx +249 -0
- package/src/components/Form/FormFieldset.tsx +127 -0
- package/src/components/Form/FormLiveRegion.tsx +198 -0
- package/src/components/Form/index.ts +26 -0
- package/src/components/Header/Header.tsx +301 -0
- package/src/components/Header/index.ts +4 -0
- package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +164 -0
- package/src/components/InactivityWarningModal/index.ts +9 -0
- package/src/components/Input/Input.tsx +201 -0
- package/src/components/Input/__mocks__/Input.tsx +2 -0
- package/src/components/Input/index.ts +9 -0
- package/src/components/Label/Label.tsx +186 -0
- package/src/components/Label/index.ts +2 -0
- package/src/components/LoadingSpinner/LoadingSpinner.tsx +98 -0
- package/src/components/LoadingSpinner/index.ts +3 -0
- package/src/components/LoginForm/LoginForm.tsx +273 -0
- package/src/components/LoginForm/index.ts +3 -0
- package/src/components/NavigationMenu/NavigationMenu.tsx +698 -0
- package/src/components/NavigationMenu/index.ts +10 -0
- package/src/components/NavigationMenu/types.ts +85 -0
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +304 -0
- package/src/components/OrganisationSelector/index.ts +9 -0
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +699 -0
- package/src/components/PaceAppLayout/README.md +278 -0
- package/src/components/PaceAppLayout/index.ts +1 -0
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +221 -0
- package/src/components/PaceLoginPage/index.ts +1 -0
- package/src/components/PasswordReset/PasswordChangeForm.tsx +186 -0
- package/src/components/PasswordReset/PasswordResetForm.tsx +201 -0
- package/src/components/PasswordReset/index.ts +4 -0
- package/src/components/PrintButton/PrintButton.tsx +321 -0
- package/src/components/PrintButton/PrintButtonGroup.tsx +84 -0
- package/src/components/PrintButton/PrintToolbar.tsx +94 -0
- package/src/components/PrintButton/examples/PrintButtonShowcase.tsx +438 -0
- package/src/components/PrintButton/index.ts +33 -0
- package/src/components/PrintButton/types.ts +173 -0
- package/src/components/PrintCard/PrintCard.tsx +154 -0
- package/src/components/PrintCard/PrintCardContent.tsx +57 -0
- package/src/components/PrintCard/PrintCardFooter.tsx +60 -0
- package/src/components/PrintCard/PrintCardGrid.tsx +91 -0
- package/src/components/PrintCard/PrintCardHeader.tsx +78 -0
- package/src/components/PrintCard/PrintCardImage.tsx +81 -0
- package/src/components/PrintCard/examples/PrintCardShowcase.tsx +239 -0
- package/src/components/PrintCard/index.ts +34 -0
- package/src/components/PrintCard/types.ts +171 -0
- package/src/components/PrintDataTable/PrintDataTable.tsx +215 -0
- package/src/components/PrintDataTable/PrintTableGroup.tsx +90 -0
- package/src/components/PrintDataTable/PrintTableRow.tsx +76 -0
- package/src/components/PrintDataTable/index.ts +25 -0
- package/src/components/PrintDataTable/types.ts +67 -0
- package/src/components/PrintFooter/PrintFooter.tsx +183 -0
- package/src/components/PrintFooter/PrintFooterContent.tsx +71 -0
- package/src/components/PrintFooter/PrintFooterInfo.tsx +86 -0
- package/src/components/PrintFooter/PrintPageNumber.tsx +90 -0
- package/src/components/PrintFooter/examples/PrintFooterShowcase.tsx +390 -0
- package/src/components/PrintFooter/index.ts +30 -0
- package/src/components/PrintFooter/types.ts +149 -0
- package/src/components/PrintGrid/PrintGrid.tsx +180 -0
- package/src/components/PrintGrid/PrintGridBreakpoint.tsx +109 -0
- package/src/components/PrintGrid/PrintGridContainer.tsx +128 -0
- package/src/components/PrintGrid/PrintGridItem.tsx +220 -0
- package/src/components/PrintGrid/examples/PrintGridShowcase.tsx +359 -0
- package/src/components/PrintGrid/index.ts +31 -0
- package/src/components/PrintGrid/types.ts +159 -0
- package/src/components/PrintHeader/PrintCoverHeader.tsx +230 -0
- package/src/components/PrintHeader/PrintHeader.tsx +150 -0
- package/src/components/PrintHeader/index.ts +17 -0
- package/src/components/PrintHeader/types.ts +42 -0
- package/src/components/PrintLayout/PrintLayout.tsx +122 -0
- package/src/components/PrintLayout/PrintLayoutContext.tsx +66 -0
- package/src/components/PrintLayout/PrintPageBreak.tsx +52 -0
- package/src/components/PrintLayout/examples/PrintShowcase.tsx +230 -0
- package/src/components/PrintLayout/index.ts +19 -0
- package/src/components/PrintLayout/types.ts +37 -0
- package/src/components/PrintPageBreak/PrintPageBreak.tsx +120 -0
- package/src/components/PrintPageBreak/PrintPageBreakGroup.tsx +90 -0
- package/src/components/PrintPageBreak/PrintPageBreakIndicator.tsx +112 -0
- package/src/components/PrintPageBreak/examples/PrintPageBreakShowcase.tsx +279 -0
- package/src/components/PrintPageBreak/index.ts +23 -0
- package/src/components/PrintPageBreak/types.ts +94 -0
- package/src/components/PrintSection/PrintColumn.tsx +104 -0
- package/src/components/PrintSection/PrintDivider.tsx +101 -0
- package/src/components/PrintSection/PrintSection.tsx +129 -0
- package/src/components/PrintSection/PrintSectionContent.tsx +75 -0
- package/src/components/PrintSection/PrintSectionHeader.tsx +97 -0
- package/src/components/PrintSection/examples/PrintSectionShowcase.tsx +258 -0
- package/src/components/PrintSection/index.ts +33 -0
- package/src/components/PrintSection/types.ts +155 -0
- package/src/components/PrintText/PrintText.tsx +116 -0
- package/src/components/PrintText/index.ts +16 -0
- package/src/components/PrintText/types.ts +24 -0
- package/src/components/Progress/Progress.tsx +116 -0
- package/src/components/Progress/index.ts +3 -0
- package/src/components/PublicLayout/EventLogo.tsx +287 -0
- package/src/components/PublicLayout/PublicErrorBoundary.tsx +279 -0
- package/src/components/PublicLayout/PublicLoadingSpinner.tsx +208 -0
- package/src/components/PublicLayout/PublicPageContextChecker.tsx +130 -0
- package/src/components/PublicLayout/PublicPageDebugger.tsx +104 -0
- package/src/components/PublicLayout/PublicPageDiagnostic.tsx +162 -0
- package/src/components/PublicLayout/PublicPageFooter.tsx +124 -0
- package/src/components/PublicLayout/PublicPageHeader.tsx +178 -0
- package/src/components/PublicLayout/PublicPageLayout.tsx +232 -0
- package/src/components/PublicLayout/PublicPageProvider.tsx +137 -0
- package/src/components/PublicLayout/index.ts +51 -0
- package/src/components/RBAC/PagePermissionGuard.tsx +287 -0
- package/src/components/RBAC/RBACGuard.tsx +143 -0
- package/src/components/RBAC/RBACProvider.tsx +186 -0
- package/src/components/RBAC/RoleBasedContent.tsx +129 -0
- package/src/components/RBAC/index.ts +23 -0
- package/src/components/Select/Select.tsx +660 -0
- package/src/components/Select/index.ts +1 -0
- package/src/components/SuperAdminGuard.tsx +116 -0
- package/src/components/Table/Table.tsx +222 -0
- package/src/components/Table/index.ts +11 -0
- package/src/components/Toast/Toast.tsx +339 -0
- package/src/components/Toast/index.ts +14 -0
- package/src/components/Tooltip/Tooltip.tsx +167 -0
- package/src/components/Tooltip/index.ts +7 -0
- package/src/components/UserMenu/UserMenu.tsx +243 -0
- package/src/components/UserMenu/index.ts +3 -0
- package/src/components/examples/PermissionExample.tsx +150 -0
- package/src/components/index.ts +434 -0
- package/src/components.ts +19 -0
- package/src/constants/performance.ts +14 -0
- package/src/examples/CorrectPublicPageImplementation.tsx +301 -0
- package/src/examples/PublicEventPage.tsx +274 -0
- package/src/examples/PublicPageApp.tsx +308 -0
- package/src/examples/PublicPageUsageExample.tsx +216 -0
- package/src/hooks/index.ts +56 -0
- package/src/hooks/public/index.ts +34 -0
- package/src/hooks/public/usePublicEvent.ts +261 -0
- package/src/hooks/public/usePublicEventLogo.ts +285 -0
- package/src/hooks/public/usePublicRouteParams.ts +259 -0
- package/src/hooks/useAppConfig.ts +94 -0
- package/src/hooks/useComponentPerformance.ts +39 -0
- package/src/hooks/useCounter.test.ts +135 -0
- package/src/hooks/useDataTablePerformance.ts +387 -0
- package/src/hooks/useDataTableState.ts +110 -0
- package/src/hooks/useDebounce.ts +18 -0
- package/src/hooks/useFocusManagement.ts +161 -0
- package/src/hooks/useFocusTrap.ts +155 -0
- package/src/hooks/useInactivityTracker.ts +372 -0
- package/src/hooks/useIsMobile.ts +42 -0
- package/src/hooks/useKeyboardShortcuts.ts +237 -0
- package/src/hooks/useOrganisationPermissions.ts +208 -0
- package/src/hooks/useOrganisationSecurity.ts +262 -0
- package/src/hooks/usePerformanceMonitor.ts +128 -0
- package/src/hooks/usePermissionCache.ts +455 -0
- package/src/hooks/useRBAC.ts +262 -0
- package/src/hooks/useSecureDataAccess.ts +586 -0
- package/src/hooks/useStorage.ts +274 -0
- package/src/hooks/useToast.ts +242 -0
- package/src/hooks/useZodForm.ts +28 -0
- package/src/index.ts +200 -0
- package/src/providers/AuthProvider.tsx +369 -0
- package/src/providers/EventProvider.tsx +324 -0
- package/src/providers/InactivityProvider.tsx +238 -0
- package/src/providers/OrganisationProvider.tsx +588 -0
- package/src/providers/RBACProvider.tsx +634 -0
- package/src/providers/UnifiedAuthProvider.tsx +327 -0
- package/src/providers/index.ts +15 -0
- package/src/rbac/README.md +885 -0
- package/src/rbac/adapters.tsx +726 -0
- package/src/rbac/api.ts +339 -0
- package/src/rbac/audit-enhanced.ts +339 -0
- package/src/rbac/audit.ts +338 -0
- package/src/rbac/cache.ts +215 -0
- package/src/rbac/components/EnhancedNavigationMenu.tsx +294 -0
- package/src/rbac/components/NavigationGuard.tsx +294 -0
- package/src/rbac/components/NavigationProvider.tsx +314 -0
- package/src/rbac/components/PagePermissionGuard.tsx +430 -0
- package/src/rbac/components/PagePermissionProvider.tsx +274 -0
- package/src/rbac/components/PermissionEnforcer.tsx +307 -0
- package/src/rbac/components/RoleBasedRouter.tsx +425 -0
- package/src/rbac/components/SecureDataProvider.tsx +319 -0
- package/src/rbac/components/index.ts +64 -0
- package/src/rbac/config.ts +133 -0
- package/src/rbac/docs/event-based-apps.md +285 -0
- package/src/rbac/engine.ts +1026 -0
- package/src/rbac/eslint-rules.js +285 -0
- package/src/rbac/examples/CompleteRBACExample.tsx +323 -0
- package/src/rbac/examples/EventBasedApp.tsx +238 -0
- package/src/rbac/hooks.ts +570 -0
- package/src/rbac/index.ts +114 -0
- package/src/rbac/permissions.ts +293 -0
- package/src/rbac/secureClient.ts +244 -0
- package/src/rbac/security.ts +346 -0
- package/src/rbac/testing/index.tsx +340 -0
- package/src/rbac/types.ts +343 -0
- package/src/rbac/utils/eventContext.ts +83 -0
- package/src/styles/core.css +422 -0
- package/src/styles/index.ts +51 -0
- package/src/theming/runtime.ts +187 -0
- package/src/types/database.ts +472 -0
- package/src/types/guards.ts +30 -0
- package/src/types/index.ts +25 -0
- package/src/types/organisation.ts +184 -0
- package/src/types/security.ts +70 -0
- package/src/types/supabase.ts +166 -0
- package/src/types/theme.ts +6 -0
- package/src/types/unified.ts +262 -0
- package/src/types/validation.ts +164 -0
- package/src/types/vitest-globals.d.ts +43 -0
- package/src/utils/__mocks__/supabaseMock.ts +75 -0
- package/src/utils/__mocks__/supabaseMock.tsx +198 -0
- package/src/utils/appConfig.ts +47 -0
- package/src/utils/appIdResolver.ts +130 -0
- package/src/utils/appNameResolver.ts +190 -0
- package/src/utils/audit.ts +127 -0
- package/src/utils/auth-utils.ts +96 -0
- package/src/utils/bundleAnalysis.ts +129 -0
- package/src/utils/cn.ts +7 -0
- package/src/utils/debugLogger.ts +46 -0
- package/src/utils/deviceFingerprint.ts +215 -0
- package/src/utils/dynamicUtils.ts +105 -0
- package/src/utils/formatting.ts +77 -0
- package/src/utils/index.ts +145 -0
- package/src/utils/lazyLoad.tsx +44 -0
- package/src/utils/organisationContext.ts +135 -0
- package/src/utils/performanceBenchmark.ts +64 -0
- package/src/utils/performanceBudgets.ts +111 -0
- package/src/utils/permissionTypes.ts +37 -0
- package/src/utils/permissionUtils.ts +31 -0
- package/src/utils/print/PrintDataProcessor.ts +390 -0
- package/src/utils/print/examples/PrintUtilitiesShowcase.tsx +397 -0
- package/src/utils/print/index.ts +29 -0
- package/src/utils/print/types.ts +196 -0
- package/src/utils/print/usePrintOptimization.ts +272 -0
- package/src/utils/sanitization.ts +264 -0
- package/src/utils/schemaUtils.ts +37 -0
- package/src/utils/secureDataAccess.ts +361 -0
- package/src/utils/secureErrors.ts +79 -0
- package/src/utils/secureStorage.ts +244 -0
- package/src/utils/security.ts +156 -0
- package/src/utils/securityMonitor.ts +45 -0
- package/src/utils/sessionTracking.ts +170 -0
- package/src/utils/storage/README.md +348 -0
- package/src/utils/storage/config.ts +100 -0
- package/src/utils/storage/helpers.ts +359 -0
- package/src/utils/storage/index.ts +36 -0
- package/src/utils/storage/types.ts +90 -0
- package/src/utils/validation.ts +111 -0
- package/src/utils/validationUtils.ts +120 -0
- package/src/validation/common.ts +53 -0
- package/src/validation/csrf.ts +214 -0
- package/src/validation/index.ts +43 -0
- package/src/validation/passwordSchema.ts +125 -0
- package/src/validation/sanitization.ts +96 -0
- package/src/validation/schemaUtils.ts +42 -0
- package/src/validation/sqlInjectionProtection.ts +242 -0
- package/src/validation/user.ts +34 -0
- package/dist/UnifiedAuthProvider-V7y63NjT.d.ts +0 -88
- package/dist/chunk-4MCJAK7J.js.map +0 -1
- package/dist/chunk-4ZTIEYU2.js.map +0 -1
- package/dist/chunk-H4PZ4B3Y.js.map +0 -1
- package/dist/chunk-IOX76PSM.js.map +0 -1
- package/dist/chunk-JUUNUW3O.js.map +0 -1
- package/dist/chunk-U7DY5T33.js +0 -11
- package/dist/chunk-U7DY5T33.js.map +0 -1
- package/dist/chunk-WHLSWC6W.js.map +0 -1
- package/dist/chunk-XI7QFSSC.js +0 -790
- package/dist/chunk-XI7QFSSC.js.map +0 -1
- package/dist/chunk-XIJMMBDD.js +0 -73
- package/dist/chunk-XIJMMBDD.js.map +0 -1
- package/dist/chunk-YNU5QJ4S.js.map +0 -1
- package/dist/chunk-YWYCNGWH.js +0 -2070
- package/dist/chunk-YWYCNGWH.js.map +0 -1
- package/dist/chunk-ZJ3UKPIW.js +0 -952
- package/dist/chunk-ZJ3UKPIW.js.map +0 -1
- package/dist/useAppConfig-CZNJJsT_.d.ts +0 -148
- package/dist/{DataTable-2LB6HI6V.js.map → DataTable-GX3XERFJ.js.map} +0 -0
- package/dist/{api-AIJ3IJX3.js.map → api-ETQ6YJ3C.js.map} +0 -0
- package/dist/{audit-PD5L5ZSC.js.map → appNameResolver-7GHF5ED2.js.map} +0 -0
- package/dist/{chunk-DC5AMYBS.js.map → audit-BUW3LMJB.js.map} +0 -0
- package/dist/{validation-D2-NNCCE.d.ts → validation-PM_iOaTI.d.ts} +6 -6
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file User Profile Integration Tests
|
|
3
|
+
* @description Example integration test patterns
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { screen, waitFor } from '@testing-library/react';
|
|
8
|
+
import userEvent from '@testing-library/user-event';
|
|
9
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
10
|
+
import { renderWithProviders } from '../helpers/test-utils';
|
|
11
|
+
import { testData } from '../fixtures/mocks';
|
|
12
|
+
|
|
13
|
+
// Mock components for demonstration
|
|
14
|
+
const UserProfile = ({ userId }: { userId: string }) => {
|
|
15
|
+
const [user, setUser] = React.useState<any>(null);
|
|
16
|
+
const [loading, setLoading] = React.useState(true);
|
|
17
|
+
const [error, setError] = React.useState<string | null>(null);
|
|
18
|
+
|
|
19
|
+
React.useEffect(() => {
|
|
20
|
+
// Simulate API call
|
|
21
|
+
const fetchUser = async () => {
|
|
22
|
+
try {
|
|
23
|
+
setLoading(true);
|
|
24
|
+
const userData = testData.users.find(u => u.id === userId);
|
|
25
|
+
if (userData) {
|
|
26
|
+
setUser(userData);
|
|
27
|
+
} else {
|
|
28
|
+
setError('User not found');
|
|
29
|
+
}
|
|
30
|
+
} catch (err) {
|
|
31
|
+
setError('Failed to fetch user');
|
|
32
|
+
} finally {
|
|
33
|
+
setLoading(false);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
fetchUser();
|
|
38
|
+
}, [userId]);
|
|
39
|
+
|
|
40
|
+
if (loading) return <div>Loading...</div>;
|
|
41
|
+
if (error) return <div>Error: {error}</div>;
|
|
42
|
+
if (!user) return <div>No user found</div>;
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div data-testid="user-profile">
|
|
46
|
+
<h1>{user.name}</h1>
|
|
47
|
+
<p>{user.email}</p>
|
|
48
|
+
<button onClick={() => setUser({ ...user, name: 'Updated Name' })}>
|
|
49
|
+
Update Name
|
|
50
|
+
</button>
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
describe('User Profile Integration Tests', () => {
|
|
56
|
+
beforeEach(() => {
|
|
57
|
+
vi.clearAllMocks();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe('Data Loading', () => {
|
|
61
|
+
it('loads and displays user data', async () => {
|
|
62
|
+
renderWithProviders(<UserProfile userId="1" />);
|
|
63
|
+
|
|
64
|
+
// The component loads data synchronously in this mock, so we just check the final state
|
|
65
|
+
await waitFor(() => {
|
|
66
|
+
expect(screen.getByText('John Doe')).toBeInTheDocument();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
expect(screen.getByText('john@example.com')).toBeInTheDocument();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('handles user not found', async () => {
|
|
73
|
+
renderWithProviders(<UserProfile userId="999" />);
|
|
74
|
+
|
|
75
|
+
await waitFor(() => {
|
|
76
|
+
expect(screen.getByText('Error: User not found')).toBeInTheDocument();
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('User Interactions', () => {
|
|
82
|
+
it('allows updating user name', async () => {
|
|
83
|
+
const user = userEvent.setup();
|
|
84
|
+
renderWithProviders(<UserProfile userId="1" />);
|
|
85
|
+
|
|
86
|
+
await waitFor(() => {
|
|
87
|
+
expect(screen.getByText('John Doe')).toBeInTheDocument();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
await user.click(screen.getByText('Update Name'));
|
|
91
|
+
|
|
92
|
+
expect(screen.getByText('Updated Name')).toBeInTheDocument();
|
|
93
|
+
expect(screen.queryByText('John Doe')).not.toBeInTheDocument();
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe('Component State Management', () => {
|
|
98
|
+
it('maintains state across re-renders', async () => {
|
|
99
|
+
const { rerender } = renderWithProviders(<UserProfile userId="1" />);
|
|
100
|
+
|
|
101
|
+
await waitFor(() => {
|
|
102
|
+
expect(screen.getByText('John Doe')).toBeInTheDocument();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
rerender(<UserProfile userId="1" />);
|
|
106
|
+
|
|
107
|
+
expect(screen.getByText('John Doe')).toBeInTheDocument();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Example of testing with different user IDs
|
|
113
|
+
describe('User Profile - Different Users', () => {
|
|
114
|
+
const testCases = [
|
|
115
|
+
{ userId: '1', expectedName: 'John Doe' },
|
|
116
|
+
{ userId: '2', expectedName: 'Jane Smith' },
|
|
117
|
+
];
|
|
118
|
+
|
|
119
|
+
testCases.forEach(({ userId, expectedName }) => {
|
|
120
|
+
it(`displays correct data for user ${userId}`, async () => {
|
|
121
|
+
renderWithProviders(<UserProfile userId={userId} />);
|
|
122
|
+
|
|
123
|
+
await waitFor(() => {
|
|
124
|
+
expect(screen.getByText(expectedName)).toBeInTheDocument();
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Test Setup Configuration
|
|
3
|
+
* @description Global test setup, mocks, and utilities
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import '@testing-library/jest-dom';
|
|
7
|
+
import { vi } from 'vitest';
|
|
8
|
+
import { cleanup } from '@testing-library/react';
|
|
9
|
+
|
|
10
|
+
// Global test setup
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
// Clear all mocks before each test
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
// Clean up DOM after each test
|
|
18
|
+
cleanup();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Mock console methods to reduce noise in tests
|
|
22
|
+
global.console = {
|
|
23
|
+
...console,
|
|
24
|
+
// Uncomment to suppress console.log in tests
|
|
25
|
+
// log: vi.fn(),
|
|
26
|
+
// warn: vi.fn(),
|
|
27
|
+
// error: vi.fn(),
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Mock IntersectionObserver
|
|
31
|
+
global.IntersectionObserver = vi.fn().mockImplementation(() => ({
|
|
32
|
+
observe: vi.fn(),
|
|
33
|
+
unobserve: vi.fn(),
|
|
34
|
+
disconnect: vi.fn(),
|
|
35
|
+
}));
|
|
36
|
+
|
|
37
|
+
// Mock ResizeObserver
|
|
38
|
+
global.ResizeObserver = vi.fn().mockImplementation(() => ({
|
|
39
|
+
observe: vi.fn(),
|
|
40
|
+
unobserve: vi.fn(),
|
|
41
|
+
disconnect: vi.fn(),
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
// Mock matchMedia
|
|
45
|
+
Object.defineProperty(window, 'matchMedia', {
|
|
46
|
+
writable: true,
|
|
47
|
+
value: vi.fn().mockImplementation(query => ({
|
|
48
|
+
matches: false,
|
|
49
|
+
media: query,
|
|
50
|
+
onchange: null,
|
|
51
|
+
addListener: vi.fn(),
|
|
52
|
+
removeListener: vi.fn(),
|
|
53
|
+
addEventListener: vi.fn(),
|
|
54
|
+
removeEventListener: vi.fn(),
|
|
55
|
+
dispatchEvent: vi.fn(),
|
|
56
|
+
})),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Mock scrollTo
|
|
60
|
+
Object.defineProperty(window, 'scrollTo', {
|
|
61
|
+
writable: true,
|
|
62
|
+
value: vi.fn(),
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Mock getComputedStyle
|
|
66
|
+
Object.defineProperty(window, 'getComputedStyle', {
|
|
67
|
+
writable: true,
|
|
68
|
+
value: vi.fn().mockImplementation(() => ({
|
|
69
|
+
getPropertyValue: vi.fn().mockReturnValue(''),
|
|
70
|
+
})),
|
|
71
|
+
});
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* @file Template for accessibility tests
|
|
4
|
+
* Copy this file and replace ComponentName with your actual component
|
|
5
|
+
*
|
|
6
|
+
* Instructions:
|
|
7
|
+
* 1. Copy this file to your component's __tests__ folder
|
|
8
|
+
* 2. Rename to YourComponent.accessibility.test.tsx
|
|
9
|
+
* 3. Replace all instances of "ComponentName" with your actual component name
|
|
10
|
+
* 4. Uncomment and fix the import paths below
|
|
11
|
+
* 5. Customize the tests for your component's accessibility requirements
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// Uncomment and update these imports for your component:
|
|
15
|
+
// import React from 'react';
|
|
16
|
+
// import { render, screen, within } from '@testing-library/react';
|
|
17
|
+
// import userEvent from '@testing-library/user-event';
|
|
18
|
+
// import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
19
|
+
// import { ComponentName } from '../ComponentName';
|
|
20
|
+
// import { renderWithProviders } from '../../utils/renderHelpers';
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
describe('ComponentName Accessibility Tests', () => {
|
|
24
|
+
const user = userEvent.setup();
|
|
25
|
+
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
vi.clearAllMocks();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('Semantic Structure', () => {
|
|
31
|
+
it('has proper semantic HTML', () => {
|
|
32
|
+
renderWithProviders(<ComponentName>Content</ComponentName>);
|
|
33
|
+
|
|
34
|
+
// Check for proper semantic elements
|
|
35
|
+
expect(screen.getByRole('main')).toBeInTheDocument();
|
|
36
|
+
// or: expect(screen.getByRole('button')).toBeInTheDocument();
|
|
37
|
+
// or: expect(screen.getByRole('textbox')).toBeInTheDocument();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('has proper heading hierarchy', () => {
|
|
41
|
+
renderWithProviders(<ComponentName title="Main Title" subtitle="Subtitle" />);
|
|
42
|
+
|
|
43
|
+
const mainHeading = screen.getByRole('heading', { level: 1 });
|
|
44
|
+
const subHeading = screen.getByRole('heading', { level: 2 });
|
|
45
|
+
|
|
46
|
+
expect(mainHeading).toHaveTextContent('Main Title');
|
|
47
|
+
expect(subHeading).toHaveTextContent('Subtitle');
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('ARIA Attributes', () => {
|
|
52
|
+
it('has proper ARIA labels', () => {
|
|
53
|
+
renderWithProviders(<ComponentName aria-label="Component description" />);
|
|
54
|
+
|
|
55
|
+
const component = screen.getByLabelText('Component description');
|
|
56
|
+
expect(component).toBeInTheDocument();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('has proper ARIA roles', () => {
|
|
60
|
+
renderWithProviders(<ComponentName role="dialog" />);
|
|
61
|
+
|
|
62
|
+
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('uses ARIA describedby for additional information', () => {
|
|
66
|
+
renderWithProviders(
|
|
67
|
+
<ComponentName
|
|
68
|
+
aria-describedby="help-text"
|
|
69
|
+
helperText="This is helpful information"
|
|
70
|
+
/>
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const component = screen.getByRole('main'); // adjust role as needed
|
|
74
|
+
const helpText = screen.getByText('This is helpful information');
|
|
75
|
+
|
|
76
|
+
expect(component).toHaveAttribute('aria-describedby', 'help-text');
|
|
77
|
+
expect(helpText).toHaveAttribute('id', 'help-text');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('announces state changes', async () => {
|
|
81
|
+
renderWithProviders(<ComponentName />);
|
|
82
|
+
|
|
83
|
+
const button = screen.getByRole('button');
|
|
84
|
+
await user.click(button);
|
|
85
|
+
|
|
86
|
+
// Check for live region announcements
|
|
87
|
+
const status = screen.getByRole('status');
|
|
88
|
+
expect(status).toHaveAttribute('aria-live', 'polite');
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe('Keyboard Navigation', () => {
|
|
93
|
+
it('supports tab navigation', async () => {
|
|
94
|
+
renderWithProviders(
|
|
95
|
+
<div>
|
|
96
|
+
<ComponentName />
|
|
97
|
+
<button>Next focusable element</button>
|
|
98
|
+
</div>
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const firstElement = screen.getByRole('button', { name: /component/i });
|
|
102
|
+
const secondElement = screen.getByRole('button', { name: /next focusable/i });
|
|
103
|
+
|
|
104
|
+
firstElement.focus();
|
|
105
|
+
expect(firstElement).toHaveFocus();
|
|
106
|
+
|
|
107
|
+
await user.tab();
|
|
108
|
+
expect(secondElement).toHaveFocus();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('supports Enter and Space key activation', async () => {
|
|
112
|
+
const handleClick = vi.fn();
|
|
113
|
+
renderWithProviders(<ComponentName onClick={handleClick} />);
|
|
114
|
+
|
|
115
|
+
const element = screen.getByRole('button');
|
|
116
|
+
element.focus();
|
|
117
|
+
|
|
118
|
+
await user.keyboard('[Enter]');
|
|
119
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
120
|
+
|
|
121
|
+
await user.keyboard('[Space]');
|
|
122
|
+
expect(handleClick).toHaveBeenCalledTimes(2);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('supports arrow key navigation for menus', async () => {
|
|
126
|
+
renderWithProviders(<ComponentName type="menu" />);
|
|
127
|
+
|
|
128
|
+
const menu = screen.getByRole('menu');
|
|
129
|
+
const menuItems = within(menu).getAllByRole('menuitem');
|
|
130
|
+
|
|
131
|
+
menuItems[0].focus();
|
|
132
|
+
expect(menuItems[0]).toHaveFocus();
|
|
133
|
+
|
|
134
|
+
await user.keyboard('[ArrowDown]');
|
|
135
|
+
expect(menuItems[1]).toHaveFocus();
|
|
136
|
+
|
|
137
|
+
await user.keyboard('[ArrowUp]');
|
|
138
|
+
expect(menuItems[0]).toHaveFocus();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('traps focus in modal dialogs', async () => {
|
|
142
|
+
renderWithProviders(<ComponentName isModal open />);
|
|
143
|
+
|
|
144
|
+
const dialog = screen.getByRole('dialog');
|
|
145
|
+
const focusableElements = within(dialog).getAllByRole('button');
|
|
146
|
+
|
|
147
|
+
// Focus should be trapped within modal
|
|
148
|
+
focusableElements[0].focus();
|
|
149
|
+
|
|
150
|
+
// Tab through all focusable elements
|
|
151
|
+
for (let i = 1; i < focusableElements.length; i++) {
|
|
152
|
+
await user.tab();
|
|
153
|
+
expect(focusableElements[i]).toHaveFocus();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Should wrap back to first element
|
|
157
|
+
await user.tab();
|
|
158
|
+
expect(focusableElements[0]).toHaveFocus();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('supports Escape key to close modals', async () => {
|
|
162
|
+
const handleClose = vi.fn();
|
|
163
|
+
renderWithProviders(<ComponentName isModal open onClose={handleClose} />);
|
|
164
|
+
|
|
165
|
+
await user.keyboard('[Escape]');
|
|
166
|
+
expect(handleClose).toHaveBeenCalled();
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe('Screen Reader Support', () => {
|
|
171
|
+
it('provides meaningful text alternatives for images', () => {
|
|
172
|
+
renderWithProviders(<ComponentName image="/test.jpg" alt="Descriptive alt text" />);
|
|
173
|
+
|
|
174
|
+
const image = screen.getByRole('img');
|
|
175
|
+
expect(image).toHaveAttribute('alt', 'Descriptive alt text');
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('uses proper form labels', () => {
|
|
179
|
+
renderWithProviders(<ComponentName type="form" />);
|
|
180
|
+
|
|
181
|
+
const input = screen.getByLabelText('Input Label');
|
|
182
|
+
expect(input).toBeInTheDocument();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('announces loading states', () => {
|
|
186
|
+
renderWithProviders(<ComponentName isLoading />);
|
|
187
|
+
|
|
188
|
+
const loadingIndicator = screen.getByRole('status');
|
|
189
|
+
expect(loadingIndicator).toHaveAttribute('aria-live', 'polite');
|
|
190
|
+
expect(loadingIndicator).toHaveTextContent(/loading/i);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('announces error states', () => {
|
|
194
|
+
renderWithProviders(<ComponentName error="Something went wrong" />);
|
|
195
|
+
|
|
196
|
+
const errorAlert = screen.getByRole('alert');
|
|
197
|
+
expect(errorAlert).toHaveAttribute('aria-live', 'assertive');
|
|
198
|
+
expect(errorAlert).toHaveTextContent('Something went wrong');
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
describe('Color and Contrast', () => {
|
|
203
|
+
it('does not rely solely on color for information', () => {
|
|
204
|
+
renderWithProviders(<ComponentName status="error" />);
|
|
205
|
+
|
|
206
|
+
// Should have text indicator, not just color
|
|
207
|
+
expect(screen.getByText(/error/i)).toBeInTheDocument();
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('maintains focus indicators', async () => {
|
|
211
|
+
renderWithProviders(<ComponentName />);
|
|
212
|
+
|
|
213
|
+
const element = screen.getByRole('button');
|
|
214
|
+
element.focus();
|
|
215
|
+
|
|
216
|
+
// Focus should be visible (actual contrast testing would require visual testing tools)
|
|
217
|
+
expect(element).toHaveFocus();
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
describe('Form Accessibility', () => {
|
|
222
|
+
it('associates form controls with labels', () => {
|
|
223
|
+
renderWithProviders(<ComponentName type="form" />);
|
|
224
|
+
|
|
225
|
+
const input = screen.getByLabelText('Required Field');
|
|
226
|
+
expect(input).toHaveAttribute('required');
|
|
227
|
+
expect(input).toHaveAttribute('aria-required', 'true');
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('provides validation feedback', async () => {
|
|
231
|
+
renderWithProviders(<ComponentName type="form" />);
|
|
232
|
+
|
|
233
|
+
const input = screen.getByLabelText('Email');
|
|
234
|
+
await user.type(input, 'invalid-email');
|
|
235
|
+
|
|
236
|
+
const errorMessage = await screen.findByRole('alert');
|
|
237
|
+
expect(errorMessage).toHaveTextContent(/invalid email/i);
|
|
238
|
+
expect(input).toHaveAttribute('aria-describedby', expect.stringContaining('error'));
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('groups related form controls', () => {
|
|
242
|
+
renderWithProviders(<ComponentName type="form" />);
|
|
243
|
+
|
|
244
|
+
const fieldset = screen.getByRole('group');
|
|
245
|
+
const legend = within(fieldset).getByText('Contact Information');
|
|
246
|
+
|
|
247
|
+
expect(fieldset).toContainElement(legend);
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
describe('Dynamic Content', () => {
|
|
252
|
+
it('announces dynamic content changes', async () => {
|
|
253
|
+
renderWithProviders(<ComponentName />);
|
|
254
|
+
|
|
255
|
+
const button = screen.getByRole('button', { name: /load more/i });
|
|
256
|
+
await user.click(button);
|
|
257
|
+
|
|
258
|
+
// Check for announcement of new content
|
|
259
|
+
const announcement = await screen.findByRole('status');
|
|
260
|
+
expect(announcement).toHaveTextContent(/content loaded/i);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('maintains focus after content updates', async () => {
|
|
264
|
+
renderWithProviders(<ComponentName />);
|
|
265
|
+
|
|
266
|
+
const trigger = screen.getByRole('button');
|
|
267
|
+
trigger.focus();
|
|
268
|
+
|
|
269
|
+
await user.click(trigger);
|
|
270
|
+
|
|
271
|
+
// Focus should remain on trigger or move to logical next element
|
|
272
|
+
expect(document.activeElement).toBe(trigger);
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
*/
|
|
277
|
+
|
|
278
|
+
// This file is a template - copy and uncomment the code above to use it
|
|
279
|
+
export {};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Component Test Template
|
|
3
|
+
* @description Template for creating component tests
|
|
4
|
+
* @usage Copy this template and replace ComponentName with your component
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import { screen } from '@testing-library/react';
|
|
9
|
+
import userEvent from '@testing-library/user-event';
|
|
10
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
11
|
+
import { ComponentName } from '../../components/ComponentName/ComponentName';
|
|
12
|
+
import { renderWithProviders } from '../helpers/test-utils';
|
|
13
|
+
|
|
14
|
+
describe('ComponentName Component', () => {
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
vi.clearAllMocks();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// Basic rendering tests
|
|
20
|
+
describe('Rendering', () => {
|
|
21
|
+
it('renders with default props', () => {
|
|
22
|
+
renderWithProviders(<ComponentName />);
|
|
23
|
+
expect(screen.getByRole('generic')).toBeInTheDocument();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('renders with custom props', () => {
|
|
27
|
+
renderWithProviders(<ComponentName customProp="value" />);
|
|
28
|
+
expect(screen.getByRole('generic')).toBeInTheDocument();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('renders with children', () => {
|
|
32
|
+
renderWithProviders(
|
|
33
|
+
<ComponentName>
|
|
34
|
+
<span>Child content</span>
|
|
35
|
+
</ComponentName>
|
|
36
|
+
);
|
|
37
|
+
expect(screen.getByText('Child content')).toBeInTheDocument();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Event handling tests
|
|
42
|
+
describe('Event Handling', () => {
|
|
43
|
+
it('handles click events', async () => {
|
|
44
|
+
const handleClick = vi.fn();
|
|
45
|
+
const user = userEvent.setup();
|
|
46
|
+
|
|
47
|
+
renderWithProviders(<ComponentName onClick={handleClick} />);
|
|
48
|
+
|
|
49
|
+
await user.click(screen.getByRole('generic'));
|
|
50
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('handles keyboard events', async () => {
|
|
54
|
+
const handleKeyDown = vi.fn();
|
|
55
|
+
const user = userEvent.setup();
|
|
56
|
+
|
|
57
|
+
renderWithProviders(<ComponentName onKeyDown={handleKeyDown} />);
|
|
58
|
+
|
|
59
|
+
screen.getByRole('generic').focus();
|
|
60
|
+
await user.keyboard('{Enter}');
|
|
61
|
+
expect(handleKeyDown).toHaveBeenCalledTimes(1);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// State management tests
|
|
66
|
+
describe('State Management', () => {
|
|
67
|
+
it('handles controlled state', () => {
|
|
68
|
+
const { rerender } = renderWithProviders(
|
|
69
|
+
<ComponentName value="initial" />
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
expect(screen.getByDisplayValue('initial')).toBeInTheDocument();
|
|
73
|
+
|
|
74
|
+
rerender(<ComponentName value="updated" />);
|
|
75
|
+
expect(screen.getByDisplayValue('updated')).toBeInTheDocument();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('handles uncontrolled state', () => {
|
|
79
|
+
renderWithProviders(<ComponentName defaultValue="default" />);
|
|
80
|
+
expect(screen.getByDisplayValue('default')).toBeInTheDocument();
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Accessibility tests
|
|
85
|
+
describe('Accessibility', () => {
|
|
86
|
+
it('has proper ARIA attributes', () => {
|
|
87
|
+
renderWithProviders(<ComponentName aria-label="Test component" />);
|
|
88
|
+
expect(screen.getByRole('generic')).toHaveAttribute('aria-label', 'Test component');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('is keyboard accessible', () => {
|
|
92
|
+
renderWithProviders(<ComponentName />);
|
|
93
|
+
expect(screen.getByRole('generic')).not.toHaveAttribute('tabindex', '-1');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('supports screen readers', () => {
|
|
97
|
+
renderWithProviders(<ComponentName />);
|
|
98
|
+
// Add specific screen reader tests here
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Error handling tests
|
|
103
|
+
describe('Error Handling', () => {
|
|
104
|
+
it('handles invalid props gracefully', () => {
|
|
105
|
+
// @ts-expect-error Testing invalid prop
|
|
106
|
+
renderWithProviders(<ComponentName invalidProp="test" />);
|
|
107
|
+
expect(screen.getByRole('generic')).toBeInTheDocument();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('displays error states', () => {
|
|
111
|
+
renderWithProviders(<ComponentName error="Something went wrong" />);
|
|
112
|
+
expect(screen.getByText('Something went wrong')).toBeInTheDocument();
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Integration tests
|
|
117
|
+
describe('Integration', () => {
|
|
118
|
+
it('works with other components', () => {
|
|
119
|
+
renderWithProviders(
|
|
120
|
+
<div>
|
|
121
|
+
<ComponentName />
|
|
122
|
+
<ComponentName />
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
expect(screen.getAllByRole('generic')).toHaveLength(2);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('works with forms', async () => {
|
|
130
|
+
const handleSubmit = vi.fn((e) => e.preventDefault());
|
|
131
|
+
const user = userEvent.setup();
|
|
132
|
+
|
|
133
|
+
renderWithProviders(
|
|
134
|
+
<form onSubmit={handleSubmit}>
|
|
135
|
+
<ComponentName />
|
|
136
|
+
<button type="submit">Submit</button>
|
|
137
|
+
</form>
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
await user.click(screen.getByRole('button', { name: 'Submit' }));
|
|
141
|
+
expect(handleSubmit).toHaveBeenCalledTimes(1);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
});
|