@jmruthers/pace-core 0.5.68 → 0.5.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DataTable-4IUY7BXB.js → DataTable-MPBSXUC6.js} +5 -6
- package/dist/{PublicLoadingSpinner-DdKXTkCZ.d.ts → PublicLoadingSpinner-BOdyU3u-.d.ts} +1 -1
- package/dist/{chunk-PXWEDX7Y.js → chunk-2ARQW6VX.js} +3 -3
- package/dist/{chunk-MOJXHWDE.js → chunk-6JILXFEA.js} +335 -5
- package/dist/chunk-6JILXFEA.js.map +1 -0
- package/dist/{chunk-D7ARGIA3.js → chunk-6RBH67W7.js} +23 -6
- package/dist/chunk-6RBH67W7.js.map +1 -0
- package/dist/{chunk-ZMS23NS5.js → chunk-FJTAWPAQ.js} +3 -5
- package/dist/{chunk-ZMS23NS5.js.map → chunk-FJTAWPAQ.js.map} +1 -1
- package/dist/{chunk-OPCWH3A4.js → chunk-NO5QHMDX.js} +7 -6
- package/dist/chunk-NO5QHMDX.js.map +1 -0
- package/dist/{chunk-ZPK5656W.js → chunk-O3NWNXDY.js} +4 -5
- package/dist/chunk-O3NWNXDY.js.map +1 -0
- package/dist/{chunk-UYA6U6H7.js → chunk-Q2UP3ZWQ.js} +4 -4
- package/dist/{chunk-KRCRNXPD.js → chunk-RVYGJPOD.js} +79 -18
- package/dist/chunk-RVYGJPOD.js.map +1 -0
- package/dist/{chunk-NN45OBIS.js → chunk-UCMHBF7Y.js} +3 -5
- package/dist/{chunk-NN45OBIS.js.map → chunk-UCMHBF7Y.js.map} +1 -1
- package/dist/{chunk-ZPG4XPV5.js → chunk-V3QO3LL7.js} +5 -7
- package/dist/chunk-V3QO3LL7.js.map +1 -0
- package/dist/{chunk-U6GPOF6J.js → chunk-ZXJGZLLO.js} +17 -17
- package/dist/{chunk-U6GPOF6J.js.map → chunk-ZXJGZLLO.js.map} +1 -1
- package/dist/components.d.ts +1 -1
- package/dist/components.js +8 -9
- package/dist/components.js.map +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +9 -6
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +16 -16
- package/dist/index.js.map +1 -1
- package/dist/providers.js +5 -7
- package/dist/rbac/index.js +5 -6
- package/dist/{usePublicRouteParams-CdoFxnJK.d.ts → usePublicRouteParams-Ua1Vz-HG.d.ts} +35 -1
- package/dist/utils.d.ts +4 -1
- package/dist/utils.js +3 -3
- package/docs/DOCUMENTATION_CHECKLIST.md +281 -0
- package/docs/README.md +22 -10
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +1 -1
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +1 -1
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +1 -1
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventContextType.md +1 -1
- package/docs/api/interfaces/EventLogoProps.md +1 -1
- package/docs/api/interfaces/EventProviderProps.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +2 -2
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACContextType.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RBACProviderProps.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +39 -14
- package/docs/architecture/services.md +374 -0
- package/docs/best-practices/README.md +1 -1
- package/docs/best-practices/testing.md +1 -1
- package/docs/breaking-changes.md +182 -0
- package/docs/common-patterns.md +445 -0
- package/docs/core-concepts/authentication.md +26 -11
- package/docs/core-concepts/events.md +2 -0
- package/docs/core-concepts/organisations.md +2 -0
- package/docs/core-concepts/permissions.md +2 -0
- package/docs/{INDEX.md → documentation-index.md} +26 -38
- package/docs/faq.md +286 -0
- package/docs/{FILE_REFERENCE_SYSTEM.md → file-reference-system.md} +1 -1
- package/docs/getting-started/installation-guide.md +284 -0
- package/docs/getting-started/quick-start.md +8 -1
- package/docs/implementation-guides/app-layout.md +3 -1
- package/docs/implementation-guides/data-tables.md +2 -0
- package/docs/implementation-guides/dynamic-colors.md +47 -2
- package/docs/implementation-guides/event-theming-summary.md +220 -0
- package/docs/implementation-guides/forms.md +9 -7
- package/docs/implementation-guides/navigation.md +2 -0
- package/docs/migration/service-architecture.md +351 -0
- package/docs/rbac/README-rbac-rls-integration.md +2 -2
- package/docs/rbac/README.md +1 -1
- package/docs/rbac/examples/rbac-rls-integration-example.md +3 -3
- package/docs/rbac/quick-start.md +2 -0
- package/docs/rbac/rbac-rls-integration.md +2 -2
- package/docs/style-guide.md +136 -1
- package/docs/testing/README.md +1 -1
- package/docs/troubleshooting/authentication-issues.md +334 -0
- package/docs/troubleshooting/common-issues.md +2 -0
- package/docs/troubleshooting/styling-issues.md +199 -144
- package/docs/usage.md +23 -2
- package/package.json +1 -1
- package/src/__tests__/{TESTING_GUIDELINES.md → TEST_GUIDE_CURSOR.md} +20 -0
- package/src/__tests__/TEST_GUIDE_HUMAN.md +103 -0
- package/src/__tests__/fixtures/test-data.ts +90 -0
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +260 -0
- package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +224 -0
- package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +273 -0
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +98 -0
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +436 -0
- package/src/__tests__/helpers/__tests__/timer-utils.test.ts +371 -0
- package/src/__tests__/helpers/component-test-utils.tsx +14 -4
- package/src/__tests__/helpers/optimized-test-setup.ts +68 -0
- package/src/__tests__/helpers/test-providers.tsx +329 -0
- package/src/__tests__/helpers/test-utils.tsx +91 -45
- package/src/__tests__/helpers/timer-utils.ts +71 -0
- package/src/__tests__/hooks/usePermissions.test.ts +1 -5
- package/src/__tests__/integration/UserProfile.test.tsx +1 -5
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +42 -12
- package/src/__tests__/setup.ts +34 -28
- package/src/components/Alert/Alert.test.tsx +1 -5
- package/src/components/Avatar/Avatar.test.tsx +1 -5
- package/src/components/Button/Button.test.tsx +4 -20
- package/src/components/Card/Card.test.tsx +1 -5
- package/src/components/Checkbox/Checkbox.test.tsx +1 -5
- package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +1 -5
- package/src/components/DataTable/__tests__/DataTable.test.tsx +45 -49
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +1 -5
- package/src/components/DataTable/__tests__/styles.test.ts +382 -0
- package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +409 -0
- package/src/components/DataTable/core/__tests__/ActionManager.test.ts +634 -0
- package/src/components/DataTable/core/__tests__/DataManager.test.ts +519 -0
- package/src/components/DataTable/core/__tests__/StateManager.test.ts +714 -0
- package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +592 -0
- package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +354 -0
- package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +539 -0
- package/src/components/Dialog/examples/__tests__/SmartDialogExample.unit.test.tsx +1 -5
- package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +1 -8
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +34 -38
- package/src/components/Footer/Footer.test.tsx +1 -5
- package/src/components/Form/Form.test.tsx +22 -35
- package/src/components/Header/Header.test.tsx +1 -9
- package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +1 -5
- package/src/components/Input/Input.test.tsx +2 -10
- package/src/components/LoginForm/LoginForm.test.tsx +1 -5
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +24 -24
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +1 -6
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +6 -16
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +1 -5
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.rbac.test.tsx +1 -5
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +1 -7
- package/src/components/PasswordReset/PasswordChangeForm.test.tsx +1 -9
- package/src/components/PasswordReset/PasswordResetForm.test.tsx +1 -9
- package/src/components/PublicLayout/PublicErrorBoundary.tsx +4 -5
- package/src/components/PublicLayout/PublicPageHeader.tsx +13 -9
- package/src/components/PublicLayout/__tests__/EventLogo.test.tsx +666 -0
- package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +457 -0
- package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +393 -0
- package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +351 -0
- package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +374 -0
- package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +388 -0
- package/src/components/Select/Select.bug-test.tsx +69 -0
- package/src/components/Select/Select.refactored.tsx +497 -0
- package/src/components/Select/Select.test.tsx +42 -49
- package/src/components/Select/Select.tsx +5 -2
- package/src/components/Select/hooks.ts +254 -0
- package/src/components/Switch/Switch.test.tsx +1 -5
- package/src/components/Table/__tests__/Table.test.tsx +775 -0
- package/src/components/Toast/Toast.test.tsx +15 -8
- package/src/components/Tooltip/Tooltip.test.tsx +1 -5
- package/src/components/UserMenu/UserMenu.test.tsx +3 -15
- package/src/components/__tests__/FileDisplay.test.tsx +575 -0
- package/src/components/__tests__/FileUpload.test.tsx +446 -0
- package/src/components/__tests__/SuperAdminGuard.test.tsx +422 -354
- package/src/hooks/__tests__/ServiceHooks.test.tsx +613 -0
- package/src/hooks/__tests__/hooks.integration.test.tsx +1 -10
- package/src/hooks/__tests__/useApiFetch.unit.test.ts +10 -14
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +307 -0
- package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +1 -6
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +1 -5
- package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +6 -9
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +321 -0
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +583 -0
- package/src/hooks/__tests__/usePublicEventLogo.unit.test.ts +640 -0
- package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +435 -0
- package/src/hooks/__tests__/useRBAC.unit.test.ts +10 -10
- package/src/hooks/__tests__/useStorage.unit.test.ts +751 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/public/usePublicEvent.ts +30 -9
- package/src/hooks/public/usePublicRouteParams.ts +13 -3
- package/src/hooks/services/useAuth.ts +50 -0
- package/src/hooks/services/useAuthService.ts +30 -0
- package/src/hooks/services/useCurrentEvent.ts +36 -0
- package/src/hooks/services/useCurrentOrganisation.ts +52 -0
- package/src/hooks/services/useEventService.ts +30 -0
- package/src/hooks/services/useInactivityService.ts +30 -0
- package/src/hooks/services/useOrganisationService.ts +30 -0
- package/src/hooks/services/usePermissions.ts +70 -0
- package/src/hooks/services/useRBACService.ts +30 -0
- package/src/hooks/useCounter.test.ts +1 -5
- package/src/hooks/useEventTheme.ts +86 -0
- package/src/hooks/useOrganisationPermissions.test.ts +2 -5
- package/src/hooks/useOrganisationSecurity.test.ts +1 -5
- package/src/hooks/usePermissionCache.test.ts +1 -5
- package/src/hooks/usePermissionCheck.ts +150 -0
- package/src/hooks/useSecureDataAccess.test.ts +1 -5
- package/src/index.ts +1 -0
- package/src/providers/OrganisationProvider.test.tsx +1 -5
- package/src/providers/OrganisationProvider.tsx +56 -4
- package/src/providers/UnifiedAuthProvider.test.tsx +1 -5
- package/src/providers/__tests__/AuthProvider.test.tsx +105 -439
- package/src/providers/__tests__/AuthProvider.test.tsx.backup +771 -0
- package/src/providers/__tests__/EventProvider.test.tsx +211 -110
- package/src/providers/__tests__/EventProvider.test.tsx.backup +824 -0
- package/src/providers/__tests__/InactivityProvider.test.tsx +1 -5
- package/src/providers/__tests__/OrganisationProvider.test.tsx +97 -261
- package/src/providers/__tests__/OrganisationProvider.test.tsx.backup +820 -0
- package/src/providers/__tests__/ServiceProviders.test.tsx +477 -0
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +72 -504
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx.backup +911 -0
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx.backup2 +166 -0
- package/src/providers/services/AuthServiceProvider.tsx +65 -0
- package/src/providers/services/EventServiceProvider.tsx +83 -0
- package/src/providers/services/InactivityServiceProvider.tsx +83 -0
- package/src/providers/services/OrganisationServiceProvider.tsx +77 -0
- package/src/providers/services/RBACServiceProvider.tsx +79 -0
- package/src/providers/services/UnifiedAuthProvider.tsx +368 -0
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +210 -0
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +269 -0
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +892 -0
- package/src/rbac/__tests__/engine.comprehensive.test.ts +954 -0
- package/src/rbac/__tests__/integration.authflow.test.tsx +1 -5
- package/src/rbac/__tests__/integration.navigation.test.tsx +1 -4
- package/src/rbac/__tests__/rbac-core.test.tsx +2 -7
- package/src/rbac/__tests__/rbac-functions.test.ts +1 -9
- package/src/rbac/__tests__/rbac-integration.test.ts +1 -9
- package/src/rbac/api.test.ts +1 -9
- package/src/rbac/cache.test.ts +10 -8
- package/src/rbac/cli/__tests__/policy-manager.test.ts +339 -0
- package/src/rbac/components/EnhancedNavigationMenu.test.tsx +1 -5
- package/src/rbac/components/NavigationProvider.test.tsx +1 -5
- package/src/rbac/components/PagePermissionProvider.test.tsx +1 -5
- package/src/rbac/components/SecureDataProvider.test.tsx +1 -5
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +25 -29
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +27 -30
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +23 -27
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +18 -22
- package/src/rbac/config.test.ts +1 -5
- package/src/rbac/hooks/useCan.test.ts +262 -9
- package/src/rbac/hooks/usePermissions.test.ts +246 -6
- package/src/rbac/hooks/useRBAC.simple.test.ts +1 -5
- package/src/rbac/hooks/useRBAC.test.ts +472 -198
- package/src/rbac/providers/__tests__/RBACProvider.test.tsx +1 -9
- package/src/services/AuthService.ts +416 -0
- package/src/services/EventService.ts +366 -0
- package/src/services/InactivityService.ts +388 -0
- package/src/services/OrganisationService.ts +592 -0
- package/src/services/RBACService.ts +522 -0
- package/src/services/__tests__/AuthService.test.ts +356 -0
- package/src/services/__tests__/BaseService.test.ts +314 -0
- package/src/services/__tests__/EventService.test.ts +489 -0
- package/src/services/__tests__/InactivityService.test.ts +403 -0
- package/src/services/__tests__/OrganisationService.test.ts +660 -0
- package/src/services/__tests__/RBACService.test.ts +492 -0
- package/src/services/base/BaseService.ts +87 -0
- package/src/services/interfaces/IAuthService.ts +39 -0
- package/src/services/interfaces/IEventService.ts +30 -0
- package/src/services/interfaces/IInactivityService.ts +31 -0
- package/src/services/interfaces/IOrganisationService.ts +41 -0
- package/src/services/interfaces/IRBACService.ts +62 -0
- package/src/theming/__tests__/runtime.test.ts +540 -0
- package/src/types/__tests__/file-reference.test.ts +447 -0
- package/src/types/__tests__/organisation.test.ts +1133 -0
- package/src/types/__tests__/theme.test.ts +830 -0
- package/src/types/__tests__/type-validation.test.ts +527 -0
- package/src/utils/__tests__/bundleAnalysis.unit.test.ts +1 -5
- package/src/utils/__tests__/debugLogger.test.ts +417 -0
- package/src/utils/__tests__/deviceFingerprint.unit.test.ts +1 -6
- package/src/utils/__tests__/dynamicUtils.unit.test.ts +1 -5
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +35 -35
- package/src/utils/__tests__/organisationContext.unit.test.ts +1 -5
- package/src/utils/__tests__/performanceBudgets.unit.test.ts +5 -11
- package/src/utils/__tests__/secureErrors.unit.test.ts +1 -6
- package/src/utils/__tests__/secureStorage.unit.test.ts +1 -5
- package/src/utils/__tests__/securityMonitor.unit.test.ts +1 -5
- package/src/utils/__tests__/sessionTracking.unit.test.ts +1 -5
- package/src/utils/appIdResolver.test.ts +6 -10
- package/src/utils/appNameResolver.simple.test.ts +142 -0
- package/src/utils/appNameResolver.test.ts +31 -458
- package/src/utils/appNameResolver.test.ts.backup +494 -0
- package/src/utils/debugLogger.ts +26 -5
- package/src/utils/formatDate.test.ts +1 -5
- package/src/utils/organisationContext.test.ts +1 -5
- package/src/utils/performanceBudgets.ts +3 -4
- package/src/utils/secureDataAccess.test.ts +1 -5
- package/src/utils/storage/__tests__/helpers.unit.test.ts +1 -5
- package/src/validation/__tests__/sqlInjectionProtection.unit.test.ts +1 -5
- package/dist/chunk-D7ARGIA3.js.map +0 -1
- package/dist/chunk-IPCH4YPT.js +0 -315
- package/dist/chunk-IPCH4YPT.js.map +0 -1
- package/dist/chunk-KRCRNXPD.js.map +0 -1
- package/dist/chunk-MOJXHWDE.js.map +0 -1
- package/dist/chunk-OPCWH3A4.js.map +0 -1
- package/dist/chunk-ZPG4XPV5.js.map +0 -1
- package/dist/chunk-ZPK5656W.js.map +0 -1
- package/docs/getting-started/installation.md +0 -269
- package/src/__tests__/REBUILD_PLAN.md +0 -223
- /package/dist/{DataTable-4IUY7BXB.js.map → DataTable-MPBSXUC6.js.map} +0 -0
- /package/dist/{chunk-PXWEDX7Y.js.map → chunk-2ARQW6VX.js.map} +0 -0
- /package/dist/{chunk-UYA6U6H7.js.map → chunk-Q2UP3ZWQ.js.map} +0 -0
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file PublicErrorBoundary Component Tests
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Components/PublicLayout/__tests__
|
|
5
|
+
* @since 1.0.0
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import { render, screen, fireEvent, act } from '@testing-library/react';
|
|
10
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
11
|
+
import {
|
|
12
|
+
PublicErrorBoundary,
|
|
13
|
+
useErrorBoundary,
|
|
14
|
+
DefaultPublicErrorFallback
|
|
15
|
+
} from '../PublicErrorBoundary';
|
|
16
|
+
|
|
17
|
+
// Store original console.error
|
|
18
|
+
const originalError = console.error;
|
|
19
|
+
let mockConsoleError: ReturnType<typeof vi.fn>;
|
|
20
|
+
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
// Create a fresh mock for each test
|
|
23
|
+
mockConsoleError = vi.fn();
|
|
24
|
+
vi.spyOn(console, 'error').mockImplementation((...args) => {
|
|
25
|
+
mockConsoleError(...args);
|
|
26
|
+
// Call original to allow React's error boundary to work
|
|
27
|
+
originalError(...args);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
afterEach(() => {
|
|
32
|
+
vi.restoreAllMocks();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Component that throws an error
|
|
36
|
+
const ThrowError = ({ shouldThrow }: { shouldThrow: boolean }) => {
|
|
37
|
+
if (shouldThrow) {
|
|
38
|
+
throw new Error('Test error');
|
|
39
|
+
}
|
|
40
|
+
return <div data-testid="no-error">No error</div>;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Component that throws a non-Error object
|
|
44
|
+
const ThrowNonError = ({ shouldThrow }: { shouldThrow: boolean }) => {
|
|
45
|
+
if (shouldThrow) {
|
|
46
|
+
throw 'String error';
|
|
47
|
+
}
|
|
48
|
+
return <div data-testid="no-error">No error</div>;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
describe('[component] PublicErrorBoundary', () => {
|
|
52
|
+
describe('Error Catching', () => {
|
|
53
|
+
it('catches errors in child components', () => {
|
|
54
|
+
render(
|
|
55
|
+
<PublicErrorBoundary>
|
|
56
|
+
<ThrowError shouldThrow={true} />
|
|
57
|
+
</PublicErrorBoundary>
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
expect(screen.getByText('Something went wrong')).toBeInTheDocument();
|
|
61
|
+
expect(screen.getByText('We encountered an error while loading this page. Please try again.')).toBeInTheDocument();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('renders children when no error occurs', () => {
|
|
65
|
+
render(
|
|
66
|
+
<PublicErrorBoundary>
|
|
67
|
+
<ThrowError shouldThrow={false} />
|
|
68
|
+
</PublicErrorBoundary>
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
expect(screen.getByTestId('no-error')).toBeInTheDocument();
|
|
72
|
+
expect(screen.queryByText('Something went wrong')).not.toBeInTheDocument();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('logs errors in development mode', () => {
|
|
76
|
+
render(
|
|
77
|
+
<PublicErrorBoundary>
|
|
78
|
+
<ThrowError shouldThrow={true} />
|
|
79
|
+
</PublicErrorBoundary>
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// Check that console.error was called (error boundary should trigger logging)
|
|
83
|
+
expect(mockConsoleError).toHaveBeenCalled();
|
|
84
|
+
// Just verify an error was logged, don't check for exact message
|
|
85
|
+
// as the development mode check might not be active in tests
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('does not log errors in production mode', () => {
|
|
89
|
+
// Note: This test checks that errors are caught regardless of mode
|
|
90
|
+
// Since we're running in development mode, the component will log errors
|
|
91
|
+
// In a real production environment, this would not log
|
|
92
|
+
const TestComponent = () => {
|
|
93
|
+
throw new Error('Test error');
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
render(
|
|
97
|
+
<PublicErrorBoundary>
|
|
98
|
+
<TestComponent />
|
|
99
|
+
</PublicErrorBoundary>
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// The error should be caught and UI displayed
|
|
103
|
+
expect(screen.getByText('Something went wrong')).toBeInTheDocument();
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
describe('Error Recovery', () => {
|
|
108
|
+
it('resets error state when Try Again is clicked', () => {
|
|
109
|
+
const TestComponent = () => {
|
|
110
|
+
const [shouldThrow, setShouldThrow] = React.useState(true);
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<PublicErrorBoundary>
|
|
114
|
+
<div>
|
|
115
|
+
<button
|
|
116
|
+
onClick={() => setShouldThrow(false)}
|
|
117
|
+
data-testid="fix-error"
|
|
118
|
+
>
|
|
119
|
+
Fix Error
|
|
120
|
+
</button>
|
|
121
|
+
<ThrowError shouldThrow={shouldThrow} />
|
|
122
|
+
</div>
|
|
123
|
+
</PublicErrorBoundary>
|
|
124
|
+
);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
render(<TestComponent />);
|
|
128
|
+
|
|
129
|
+
// Should show error initially
|
|
130
|
+
expect(screen.getByText('Something went wrong')).toBeInTheDocument();
|
|
131
|
+
|
|
132
|
+
// Click Try Again button
|
|
133
|
+
const tryAgainButton = screen.getByText('Try Again');
|
|
134
|
+
fireEvent.click(tryAgainButton);
|
|
135
|
+
|
|
136
|
+
// Should still show error because the component still throws
|
|
137
|
+
expect(screen.getByText('Something went wrong')).toBeInTheDocument();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('reloads page when Reload Page is clicked', () => {
|
|
141
|
+
const mockReload = vi.fn();
|
|
142
|
+
Object.defineProperty(window, 'location', {
|
|
143
|
+
value: { reload: mockReload },
|
|
144
|
+
writable: true
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
render(
|
|
148
|
+
<PublicErrorBoundary>
|
|
149
|
+
<ThrowError shouldThrow={true} />
|
|
150
|
+
</PublicErrorBoundary>
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const reloadButton = screen.getByText('Reload Page');
|
|
154
|
+
fireEvent.click(reloadButton);
|
|
155
|
+
|
|
156
|
+
expect(mockReload).toHaveBeenCalled();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('calls custom recovery action when provided', () => {
|
|
160
|
+
const mockRecover = vi.fn();
|
|
161
|
+
|
|
162
|
+
render(
|
|
163
|
+
<PublicErrorBoundary onRecover={mockRecover}>
|
|
164
|
+
<ThrowError shouldThrow={true} />
|
|
165
|
+
</PublicErrorBoundary>
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
const alternativeButton = screen.getByText('Alternative Action');
|
|
169
|
+
fireEvent.click(alternativeButton);
|
|
170
|
+
|
|
171
|
+
expect(mockRecover).toHaveBeenCalled();
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
describe('Custom Error UI', () => {
|
|
176
|
+
it('renders custom fallback component when provided', () => {
|
|
177
|
+
const CustomFallback = ({ error, resetError }: any) => (
|
|
178
|
+
<div data-testid="custom-fallback">
|
|
179
|
+
<span>Custom Error: {error.message}</span>
|
|
180
|
+
<button onClick={resetError}>Custom Reset</button>
|
|
181
|
+
</div>
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
render(
|
|
185
|
+
<PublicErrorBoundary fallback={CustomFallback}>
|
|
186
|
+
<ThrowError shouldThrow={true} />
|
|
187
|
+
</PublicErrorBoundary>
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
expect(screen.getByTestId('custom-fallback')).toBeInTheDocument();
|
|
191
|
+
expect(screen.getByText('Custom Error: Test error')).toBeInTheDocument();
|
|
192
|
+
expect(screen.getByText('Custom Reset')).toBeInTheDocument();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('renders custom error message when provided', () => {
|
|
196
|
+
render(
|
|
197
|
+
<PublicErrorBoundary customErrorMessage="Custom error message">
|
|
198
|
+
<ThrowError shouldThrow={true} />
|
|
199
|
+
</PublicErrorBoundary>
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
expect(screen.getByText('Custom error message')).toBeInTheDocument();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('applies custom className to error container', () => {
|
|
206
|
+
const { container } = render(
|
|
207
|
+
<PublicErrorBoundary className="custom-error-class">
|
|
208
|
+
<ThrowError shouldThrow={true} />
|
|
209
|
+
</PublicErrorBoundary>
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
const errorContainer = container.firstChild as HTMLElement;
|
|
213
|
+
expect(errorContainer).toHaveClass('custom-error-class');
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
describe('Error Details', () => {
|
|
218
|
+
it('shows error details in development when enabled', () => {
|
|
219
|
+
const originalMode = import.meta.env.MODE;
|
|
220
|
+
import.meta.env.MODE = 'development';
|
|
221
|
+
|
|
222
|
+
render(
|
|
223
|
+
<PublicErrorBoundary showErrorDetails={true}>
|
|
224
|
+
<ThrowError shouldThrow={true} />
|
|
225
|
+
</PublicErrorBoundary>
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
expect(screen.getByText('Error Details (Development Only)')).toBeInTheDocument();
|
|
229
|
+
expect(screen.getByText(/Test error/)).toBeInTheDocument();
|
|
230
|
+
|
|
231
|
+
import.meta.env.MODE = originalMode;
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('does not show error details when disabled', () => {
|
|
235
|
+
render(
|
|
236
|
+
<PublicErrorBoundary showErrorDetails={false}>
|
|
237
|
+
<ThrowError shouldThrow={true} />
|
|
238
|
+
</PublicErrorBoundary>
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
expect(screen.queryByText('Error Details (Development Only)')).not.toBeInTheDocument();
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('handles non-Error objects gracefully', () => {
|
|
245
|
+
render(
|
|
246
|
+
<PublicErrorBoundary showErrorDetails={true}>
|
|
247
|
+
<ThrowNonError shouldThrow={true} />
|
|
248
|
+
</PublicErrorBoundary>
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
expect(screen.getByText('Something went wrong')).toBeInTheDocument();
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
describe('Accessibility', () => {
|
|
256
|
+
it('has proper heading structure', () => {
|
|
257
|
+
render(
|
|
258
|
+
<PublicErrorBoundary>
|
|
259
|
+
<ThrowError shouldThrow={true} />
|
|
260
|
+
</PublicErrorBoundary>
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
const heading = screen.getByRole('heading', { level: 1 });
|
|
264
|
+
expect(heading).toHaveTextContent('Something went wrong');
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('has accessible buttons', () => {
|
|
268
|
+
render(
|
|
269
|
+
<PublicErrorBoundary>
|
|
270
|
+
<ThrowError shouldThrow={true} />
|
|
271
|
+
</PublicErrorBoundary>
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
const tryAgainButton = screen.getByRole('button', { name: 'Try Again' });
|
|
275
|
+
const reloadButton = screen.getByRole('button', { name: 'Reload Page' });
|
|
276
|
+
|
|
277
|
+
expect(tryAgainButton).toBeInTheDocument();
|
|
278
|
+
expect(reloadButton).toBeInTheDocument();
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('has proper focus management', () => {
|
|
282
|
+
render(
|
|
283
|
+
<PublicErrorBoundary>
|
|
284
|
+
<ThrowError shouldThrow={true} />
|
|
285
|
+
</PublicErrorBoundary>
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
const tryAgainButton = screen.getByRole('button', { name: 'Try Again' });
|
|
289
|
+
expect(tryAgainButton).toHaveClass('focus:outline-none', 'focus:ring-2', 'focus:ring-blue-500', 'focus:ring-offset-2');
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
describe('[hook] useErrorBoundary', () => {
|
|
295
|
+
it('provides captureError and resetError functions', () => {
|
|
296
|
+
const TestComponent = () => {
|
|
297
|
+
const { captureError, resetError } = useErrorBoundary();
|
|
298
|
+
|
|
299
|
+
return (
|
|
300
|
+
<div>
|
|
301
|
+
<button
|
|
302
|
+
onClick={() => captureError(new Error('Test error'))}
|
|
303
|
+
data-testid="capture-error"
|
|
304
|
+
>
|
|
305
|
+
Capture Error
|
|
306
|
+
</button>
|
|
307
|
+
<button
|
|
308
|
+
onClick={resetError}
|
|
309
|
+
data-testid="reset-error"
|
|
310
|
+
>
|
|
311
|
+
Reset Error
|
|
312
|
+
</button>
|
|
313
|
+
</div>
|
|
314
|
+
);
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
render(<TestComponent />);
|
|
318
|
+
|
|
319
|
+
expect(screen.getByTestId('capture-error')).toBeInTheDocument();
|
|
320
|
+
expect(screen.getByTestId('reset-error')).toBeInTheDocument();
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it('throws error when captureError is called', () => {
|
|
324
|
+
const TestComponent = () => {
|
|
325
|
+
const { captureError } = useErrorBoundary();
|
|
326
|
+
|
|
327
|
+
React.useEffect(() => {
|
|
328
|
+
captureError(new Error('Test error'));
|
|
329
|
+
}, [captureError]);
|
|
330
|
+
|
|
331
|
+
return <div>Should not render</div>;
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
// Wrap in error boundary to catch the thrown error
|
|
335
|
+
render(
|
|
336
|
+
<PublicErrorBoundary>
|
|
337
|
+
<TestComponent />
|
|
338
|
+
</PublicErrorBoundary>
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
// The error boundary should catch it and show error UI
|
|
342
|
+
expect(screen.getByText('Something went wrong')).toBeInTheDocument();
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('resets error state when resetError is called', () => {
|
|
346
|
+
const TestComponent = () => {
|
|
347
|
+
const { captureError, resetError } = useErrorBoundary();
|
|
348
|
+
const [shouldThrow, setShouldThrow] = React.useState(false);
|
|
349
|
+
|
|
350
|
+
const handleCapture = () => {
|
|
351
|
+
setShouldThrow(true);
|
|
352
|
+
captureError(new Error('Test error'));
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
const handleReset = () => {
|
|
356
|
+
resetError();
|
|
357
|
+
setShouldThrow(false);
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
if (shouldThrow) {
|
|
361
|
+
throw new Error('Test error');
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return (
|
|
365
|
+
<div>
|
|
366
|
+
<button onClick={handleCapture} data-testid="capture-error">
|
|
367
|
+
Capture Error
|
|
368
|
+
</button>
|
|
369
|
+
<button onClick={handleReset} data-testid="reset-error">
|
|
370
|
+
Reset Error
|
|
371
|
+
</button>
|
|
372
|
+
</div>
|
|
373
|
+
);
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
const { rerender } = render(
|
|
377
|
+
<PublicErrorBoundary>
|
|
378
|
+
<TestComponent />
|
|
379
|
+
</PublicErrorBoundary>
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
// Initially no error
|
|
383
|
+
expect(screen.queryByText('Something went wrong')).not.toBeInTheDocument();
|
|
384
|
+
expect(screen.getByTestId('capture-error')).toBeInTheDocument();
|
|
385
|
+
|
|
386
|
+
// Capture error - this will trigger error boundary
|
|
387
|
+
fireEvent.click(screen.getByTestId('capture-error'));
|
|
388
|
+
expect(screen.getByText('Something went wrong')).toBeInTheDocument();
|
|
389
|
+
|
|
390
|
+
// Reset error by clicking Try Again
|
|
391
|
+
fireEvent.click(screen.getByText('Try Again'));
|
|
392
|
+
|
|
393
|
+
// Component should reset, but since the component throws in render,
|
|
394
|
+
// this test demonstrates the error boundary reset functionality
|
|
395
|
+
expect(screen.getByTestId('capture-error')).toBeInTheDocument();
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
describe('[component] DefaultPublicErrorFallback', () => {
|
|
400
|
+
it('renders with error and resetError props', () => {
|
|
401
|
+
const mockResetError = vi.fn();
|
|
402
|
+
const mockError = new Error('Test error');
|
|
403
|
+
|
|
404
|
+
render(
|
|
405
|
+
<DefaultPublicErrorFallback
|
|
406
|
+
error={mockError}
|
|
407
|
+
resetError={mockResetError}
|
|
408
|
+
hasError={true}
|
|
409
|
+
errorInfo={null}
|
|
410
|
+
/>
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
expect(screen.getByText('Page Error')).toBeInTheDocument();
|
|
414
|
+
expect(screen.getByText('We encountered an error while loading this page.')).toBeInTheDocument();
|
|
415
|
+
expect(screen.getByText('Try Again')).toBeInTheDocument();
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
it('calls resetError when Try Again is clicked', () => {
|
|
419
|
+
const mockResetError = vi.fn();
|
|
420
|
+
const mockError = new Error('Test error');
|
|
421
|
+
|
|
422
|
+
render(
|
|
423
|
+
<DefaultPublicErrorFallback
|
|
424
|
+
error={mockError}
|
|
425
|
+
resetError={mockResetError}
|
|
426
|
+
hasError={true}
|
|
427
|
+
errorInfo={null}
|
|
428
|
+
/>
|
|
429
|
+
);
|
|
430
|
+
|
|
431
|
+
const tryAgainButton = screen.getByText('Try Again');
|
|
432
|
+
fireEvent.click(tryAgainButton);
|
|
433
|
+
|
|
434
|
+
expect(mockResetError).toHaveBeenCalled();
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
it('has proper accessibility attributes', () => {
|
|
438
|
+
const mockResetError = vi.fn();
|
|
439
|
+
const mockError = new Error('Test error');
|
|
440
|
+
|
|
441
|
+
render(
|
|
442
|
+
<DefaultPublicErrorFallback
|
|
443
|
+
error={mockError}
|
|
444
|
+
resetError={mockResetError}
|
|
445
|
+
hasError={true}
|
|
446
|
+
errorInfo={null}
|
|
447
|
+
/>
|
|
448
|
+
);
|
|
449
|
+
|
|
450
|
+
const heading = screen.getByRole('heading', { level: 1 });
|
|
451
|
+
expect(heading).toHaveTextContent('Page Error');
|
|
452
|
+
|
|
453
|
+
const button = screen.getByRole('button', { name: 'Try Again' });
|
|
454
|
+
expect(button).toBeInTheDocument();
|
|
455
|
+
expect(button).toBeVisible();
|
|
456
|
+
});
|
|
457
|
+
});
|