@jmruthers/pace-core 0.2.7 → 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/dist/{DataTable-EEUDXPE5.js → DataTable-GX3XERFJ.js} +8 -4
- package/dist/{DataTable-C1AEm9Cx.d.ts → DataTable-ltTFXHS3.d.ts} +3 -1
- package/dist/{chunk-VYG4AXYW.js → chunk-5EL3KHOQ.js} +2 -2
- package/dist/{chunk-ETEJVKYK.js → chunk-6CR3MRZN.js} +1426 -62
- package/dist/chunk-6CR3MRZN.js.map +1 -0
- package/dist/chunk-AUE24LVR.js +268 -0
- package/dist/chunk-AUE24LVR.js.map +1 -0
- package/dist/chunk-COBPIXXQ.js +379 -0
- package/dist/chunk-COBPIXXQ.js.map +1 -0
- package/dist/{chunk-EWKPTNPO.js → chunk-GSNM5D6H.js} +388 -86
- package/dist/chunk-GSNM5D6H.js.map +1 -0
- package/dist/{chunk-2V3Y6YBC.js → chunk-OEGRKULD.js} +1 -42
- package/dist/chunk-OEGRKULD.js.map +1 -0
- package/dist/chunk-OYRY44Q2.js +62 -0
- package/dist/chunk-OYRY44Q2.js.map +1 -0
- package/dist/{chunk-RRUYHORU.js → chunk-T3XIA4AJ.js} +297 -433
- package/dist/chunk-T3XIA4AJ.js.map +1 -0
- package/dist/{chunk-HEMJ4SUJ.js → chunk-TGDCLPP2.js} +11 -7
- package/dist/{chunk-HEMJ4SUJ.js.map → chunk-TGDCLPP2.js.map} +1 -1
- package/dist/{chunk-HNDFPXUU.js → chunk-U6JDHVC2.js} +6 -4
- package/dist/{chunk-HNDFPXUU.js.map → chunk-U6JDHVC2.js.map} +1 -1
- package/dist/{chunk-TIVL4UQ7.js → chunk-XJK2J4N6.js} +6 -4
- package/dist/{chunk-TIVL4UQ7.js.map → chunk-XJK2J4N6.js.map} +1 -1
- package/dist/components.d.ts +2 -2
- package/dist/components.js +21 -20
- package/dist/components.js.map +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +7 -7
- package/dist/index.d.ts +2 -2
- package/dist/index.js +26 -25
- package/dist/index.js.map +1 -1
- package/dist/providers.js +8 -7
- package/dist/rbac/index.d.ts +806 -806
- package/dist/rbac/index.js +937 -1179
- package/dist/rbac/index.js.map +1 -1
- package/dist/{types-DiRQsGJs.d.ts → types-BRDU7N6w.d.ts} +12 -1
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +6 -6
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +4 -4
- 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/DataTableAction.md +21 -8
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +46 -33
- package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
- package/docs/api/interfaces/EmptyStateConfig.md +5 -5
- 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/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 +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PaletteData.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 +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +3 -3
- package/package.json +5 -2
- 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 +37 -225
- package/src/__tests__/templates/component.test.template.tsx +97 -75
- package/src/__tests__/templates/hook.test.template.ts +173 -0
- package/src/__tests__/types/test.types.ts +106 -0
- package/src/components/Alert/Alert.test.tsx +496 -0
- package/src/components/Avatar/Avatar.test.tsx +484 -0
- package/src/components/Button/Button.test.tsx +662 -0
- package/src/components/Card/Card.test.tsx +593 -0
- package/src/components/Checkbox/Checkbox.test.tsx +461 -0
- package/src/components/DataTable/DataTable.tsx +9 -1
- package/src/components/DataTable/components/AccessDeniedPage.tsx +168 -0
- package/src/components/DataTable/components/ActionButtons.tsx +18 -1
- package/src/components/DataTable/components/DataTableCore.tsx +97 -11
- package/src/components/DataTable/components/DataTableToolbar.tsx +22 -10
- package/src/components/DataTable/components/UnifiedTableBody.tsx +33 -4
- package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +1 -0
- package/src/components/DataTable/examples/HierarchicalExample.tsx +3 -0
- package/src/components/DataTable/examples/InitialPageSizeExample.tsx +3 -0
- package/src/components/DataTable/examples/PerformanceExample.tsx +3 -0
- package/src/components/DataTable/types.ts +39 -1
- package/src/components/Dialog/Dialog.test.tsx +1139 -0
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +752 -0
- package/src/components/FileUpload/FileUpload.test.tsx +665 -0
- package/src/hooks/useCounter.test.ts +135 -0
- package/src/rbac/index.ts +3 -3
- package/dist/chunk-2V3Y6YBC.js.map +0 -1
- package/dist/chunk-BEZRLNK3.js +0 -1744
- package/dist/chunk-BEZRLNK3.js.map +0 -1
- package/dist/chunk-ETEJVKYK.js.map +0 -1
- package/dist/chunk-EWKPTNPO.js.map +0 -1
- package/dist/chunk-OHXGNT3K.js +0 -21
- package/dist/chunk-OHXGNT3K.js.map +0 -1
- package/dist/chunk-RRUYHORU.js.map +0 -1
- package/src/__tests__/README.md +0 -404
- package/src/__tests__/debug-provider.unit.test.tsx +0 -67
- package/src/__tests__/e2e/workflows.test.tsx +0 -373
- package/src/__tests__/hybridPermissions.unit.test.tsx +0 -474
- package/src/__tests__/index.integration.test.ts +0 -491
- package/src/__tests__/mocks/MockAuthProvider-standalone.tsx +0 -47
- package/src/__tests__/mocks/MockAuthProvider.tsx +0 -63
- package/src/__tests__/mocks/enhancedSupabaseMock.ts +0 -252
- package/src/__tests__/mocks/index.test.ts +0 -23
- package/src/__tests__/mocks/index.ts +0 -16
- package/src/__tests__/mocks/mockAuth.ts +0 -155
- package/src/__tests__/mocks/mockSupabase.ts +0 -83
- package/src/__tests__/mocks/mockSupabaseClient.ts +0 -63
- package/src/__tests__/mocks/providers.tsx +0 -22
- package/src/__tests__/patterns/__tests__/testPatterns.test.ts +0 -394
- package/src/__tests__/patterns/testPatterns.ts +0 -124
- package/src/__tests__/performance/componentPerformance.performance.test.ts +0 -27
- package/src/__tests__/performance/index.ts +0 -24
- package/src/__tests__/performance/performanceValidation.performance.test.ts +0 -15
- package/src/__tests__/security/security.unit.test.tsx +0 -7
- package/src/__tests__/security/securityValidation.security.test.tsx +0 -153
- package/src/__tests__/setupTests.d.ts +0 -1
- package/src/__tests__/shared/componentTestUtils.tsx +0 -475
- package/src/__tests__/shared/errorHandlingTestUtils.ts +0 -107
- package/src/__tests__/shared/index.ts +0 -81
- package/src/__tests__/shared/integrationTestUtils.tsx +0 -375
- package/src/__tests__/shared/performanceTestUtils.tsx +0 -476
- package/src/__tests__/shared/testUtils.optimized.tsx +0 -685
- package/src/__tests__/simple.test.tsx +0 -20
- package/src/__tests__/test-utils/dataFactories.ts +0 -60
- package/src/__tests__/test-utils/index.ts +0 -6
- package/src/__tests__/typeSafety.unit.test.ts +0 -65
- package/src/__tests__/unifiedAuth.unit.test.tsx +0 -151
- package/src/__tests__/utils/accessibilityHelpers.ts +0 -254
- package/src/__tests__/utils/assertions.ts +0 -50
- package/src/__tests__/utils/deterministicHelpers.ts +0 -31
- package/src/__tests__/utils/edgeCaseConfig.test.ts +0 -75
- package/src/__tests__/utils/edgeCaseConfig.ts +0 -98
- package/src/__tests__/utils/mockHelpers.ts +0 -149
- package/src/__tests__/utils/mockLoader.ts +0 -101
- package/src/__tests__/utils/performanceHelpers.ts +0 -55
- package/src/__tests__/utils/performanceTestHelpers.ts +0 -68
- package/src/__tests__/utils/testDataFactories.ts +0 -28
- package/src/__tests__/utils/testIsolation.ts +0 -67
- package/src/__tests__/utils/visualTestHelpers.ts +0 -20
- package/src/__tests__/visual/__snapshots__/componentSnapshots.visual.test.tsx.snap +0 -68
- package/src/__tests__/visual/__snapshots__/componentVisuals.visual.test.tsx.snap +0 -14
- package/src/__tests__/visual/__snapshots__/visualRegression.test.tsx.snap +0 -217
- package/src/__tests__/visual/__snapshots__/visualRegression.visual.test.tsx.snap +0 -24
- package/src/__tests__/visual/componentSnapshots.visual.test.tsx +0 -33
- package/src/__tests__/visual/componentVisuals.visual.test.tsx +0 -12
- package/src/__tests__/visual/visualRegression.visual.test.tsx +0 -20
- package/src/components/Alert/__tests__/Alert.unit.test.tsx +0 -381
- package/src/components/Avatar/__tests__/Avatar.unit.test.tsx +0 -232
- package/src/components/Button/__tests__/Button.accessibility.test.tsx +0 -131
- package/src/components/Button/__tests__/Button.comprehensive.test.tsx +0 -721
- package/src/components/Button/__tests__/Button.unit.test.tsx +0 -189
- package/src/components/Button/__tests__/EventSelector.integration.test.tsx +0 -285
- package/src/components/Card/__tests__/Card.accessibility.test.tsx +0 -394
- package/src/components/Card/__tests__/Card.comprehensive.test.tsx +0 -599
- package/src/components/Card/__tests__/Card.integration.test.tsx +0 -673
- package/src/components/Card/__tests__/Card.performance.test.tsx +0 -546
- package/src/components/Card/__tests__/Card.unit.test.tsx +0 -330
- package/src/components/Card/__tests__/Card.visual.test.tsx +0 -599
- package/src/components/Card/__tests__/README.md +0 -211
- package/src/components/Checkbox/__tests__/Checkbox.unit.test.tsx +0 -520
- package/src/components/DataTable/__tests__/DataTable.errorHandling.test.tsx +0 -251
- package/src/components/DataTable/__tests__/DataTable.hierarchical.test.tsx +0 -680
- package/src/components/DataTable/__tests__/DataTable.infinite-loop.test.tsx +0 -323
- package/src/components/DataTable/__tests__/DataTable.integration.test.tsx +0 -716
- package/src/components/DataTable/__tests__/DataTable.performance.test.tsx +0 -589
- package/src/components/DataTable/__tests__/DataTable.permissions.test.tsx +0 -316
- package/src/components/DataTable/__tests__/DataTable.regressionFixes.test.tsx +0 -546
- package/src/components/DataTable/__tests__/DataTable.selection.controlled.test.tsx +0 -386
- package/src/components/DataTable/__tests__/DataTable.selection.test.tsx +0 -338
- package/src/components/DataTable/__tests__/DataTable.sorting.test.tsx +0 -321
- package/src/components/DataTable/__tests__/DataTable.userWorkflows.test.tsx +0 -320
- package/src/components/DataTable/__tests__/DataTable.workflowValidation.test.tsx +0 -583
- package/src/components/DataTable/__tests__/DataTable.workflows.test.tsx +0 -711
- package/src/components/DataTable/__tests__/performance-regression.test.tsx +0 -777
- package/src/components/DataTable/__tests__/performance.test.tsx +0 -365
- package/src/components/DataTable/components/__tests__/ActionButtons.unit.test.tsx +0 -150
- package/src/components/DataTable/components/__tests__/BulkOperationsDropdown.test.tsx +0 -224
- package/src/components/DataTable/components/__tests__/ColumnVisibilityDropdown.unit.test.tsx +0 -244
- package/src/components/DataTable/components/__tests__/DataTable.accessibility.test.tsx +0 -629
- package/src/components/DataTable/components/__tests__/DataTable.integration.test.tsx +0 -470
- package/src/components/DataTable/components/__tests__/DataTable.performance.test.tsx +0 -160
- package/src/components/DataTable/components/__tests__/DataTable.real.test.tsx +0 -251
- package/src/components/DataTable/components/__tests__/DataTable.security.test.tsx +0 -171
- package/src/components/DataTable/components/__tests__/DataTable.unit.test.tsx +0 -290
- package/src/components/DataTable/components/__tests__/DataTableBody.unit.test.tsx +0 -147
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.unit.test.tsx +0 -182
- package/src/components/DataTable/components/__tests__/DataTableModals.unit.test.tsx +0 -123
- package/src/components/DataTable/components/__tests__/EditableRow.unit.test.tsx +0 -660
- package/src/components/DataTable/components/__tests__/EmptyState.unit.test.tsx +0 -256
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -498
- package/src/components/DataTable/components/__tests__/FilterRow.unit.test.tsx +0 -112
- package/src/components/DataTable/components/__tests__/FilteringToggle.unit.test.tsx +0 -133
- package/src/components/DataTable/components/__tests__/GroupHeader.unit.test.tsx +0 -172
- package/src/components/DataTable/components/__tests__/GroupingDropdown.unit.test.tsx +0 -222
- package/src/components/DataTable/components/__tests__/ImportModal.unit.test.tsx +0 -780
- package/src/components/DataTable/components/__tests__/LoadingState.unit.test.tsx +0 -65
- package/src/components/DataTable/components/__tests__/PaginationControls.unit.test.tsx +0 -634
- package/src/components/DataTable/components/__tests__/StateComponents.unit.test.tsx +0 -48
- package/src/components/DataTable/components/__tests__/UnifiedTableBody.hierarchical.test.tsx +0 -541
- package/src/components/DataTable/components/__tests__/ViewRowModal.unit.test.tsx +0 -228
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.unit.test.tsx +0 -568
- package/src/components/DataTable/core/__tests__/ActionManager.unit.test.ts +0 -405
- package/src/components/DataTable/core/__tests__/ArchitectureIntegration.unit.test.tsx +0 -445
- package/src/components/DataTable/core/__tests__/ColumnFactory.unit.test.ts +0 -288
- package/src/components/DataTable/core/__tests__/ColumnManager.unit.test.ts +0 -623
- package/src/components/DataTable/core/__tests__/DataManager.unit.test.ts +0 -431
- package/src/components/DataTable/core/__tests__/DataTableContext.unit.test.tsx +0 -433
- package/src/components/DataTable/core/__tests__/LocalDataAdapter.unit.test.ts +0 -422
- package/src/components/DataTable/core/__tests__/PluginRegistry.unit.test.tsx +0 -207
- package/src/components/DataTable/core/__tests__/StateManager.unit.test.ts +0 -278
- package/src/components/DataTable/examples/__tests__/PerformanceExample.unit.test.tsx +0 -281
- package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.unit.test.ts +0 -407
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.unit.test.ts +0 -679
- package/src/components/DataTable/utils/__tests__/debugTools.unit.test.ts +0 -267
- package/src/components/DataTable/utils/__tests__/errorHandling.unit.test.ts +0 -467
- package/src/components/DataTable/utils/__tests__/exportUtils.unit.test.ts +0 -380
- package/src/components/DataTable/utils/__tests__/flexibleImport.unit.test.ts +0 -233
- package/src/components/DataTable/utils/__tests__/performanceUtils.unit.test.ts +0 -414
- package/src/components/Dialog/__tests__/Dialog.accessibility.test.tsx +0 -521
- package/src/components/Dialog/__tests__/Dialog.auto-size.example.tsx +0 -157
- package/src/components/Dialog/__tests__/Dialog.enhanced.test.tsx +0 -538
- package/src/components/Dialog/__tests__/Dialog.unit.test.tsx +0 -1373
- package/src/components/Dialog/examples/__tests__/SmartDialogExample.unit.test.tsx +0 -151
- package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +0 -611
- package/src/components/ErrorBoundary/__tests__/ErrorBoundary.accessibility.test.tsx +0 -517
- package/src/components/ErrorBoundary/__tests__/ErrorBoundary.integration.test.tsx +0 -572
- package/src/components/ErrorBoundary/__tests__/ErrorBoundary.unit.test.tsx +0 -579
- package/src/components/EventSelector/__tests__/EventSelector.test.tsx +0 -528
- package/src/components/FileUpload/__tests__/FileUpload.integration.test.tsx +0 -992
- package/src/components/FileUpload/__tests__/FileUpload.real.test.tsx +0 -927
- package/src/components/FileUpload/__tests__/FileUpload.test.tsx +0 -855
- package/src/components/FileUpload/__tests__/FileUpload.unit.test.tsx +0 -1311
- package/src/components/FileUpload/__tests__/FileUpload.unmocked.test.tsx +0 -937
- package/src/components/Footer/__tests__/Footer.accessibility.test.tsx +0 -359
- package/src/components/Footer/__tests__/Footer.integration.test.tsx +0 -353
- package/src/components/Footer/__tests__/Footer.performance.test.tsx +0 -309
- package/src/components/Footer/__tests__/Footer.unit.test.tsx +0 -309
- package/src/components/Footer/__tests__/Footer.visual.test.tsx +0 -335
- package/src/components/Form/__tests__/Form.accessibility.test.tsx +0 -820
- package/src/components/Form/__tests__/Form.unit.test.tsx +0 -305
- package/src/components/Form/__tests__/FormErrorSummary.unit.test.tsx +0 -285
- package/src/components/Form/__tests__/FormFieldset.unit.test.tsx +0 -241
- package/src/components/Header/__tests__/Header.accessibility.test.tsx +0 -382
- package/src/components/Header/__tests__/Header.comprehensive.test.tsx +0 -509
- package/src/components/Header/__tests__/Header.unit.test.tsx +0 -335
- package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +0 -196
- package/src/components/InactivityWarningModal/__tests__/InactivityWarningModal.unit.test.tsx +0 -224
- package/src/components/Input/__tests__/Input.accessibility.test.tsx +0 -632
- package/src/components/Input/__tests__/Input.unit.test.tsx +0 -1121
- package/src/components/Label/__tests__/Label.accessibility.test.tsx +0 -239
- package/src/components/Label/__tests__/Label.unit.test.tsx +0 -331
- package/src/components/LoadingSpinner/__tests__/LoadingSpinner.accessibility.test.tsx +0 -116
- package/src/components/LoadingSpinner/__tests__/LoadingSpinner.unit.test.tsx +0 -144
- package/src/components/LoginForm/__tests__/LoginForm.accessibility.test.tsx +0 -201
- package/src/components/LoginForm/__tests__/LoginForm.unit.test.tsx +0 -119
- package/src/components/NavigationMenu/__tests__/NavigationMenu.accessibility.test.tsx +0 -378
- package/src/components/NavigationMenu/__tests__/NavigationMenu.enhanced.test.tsx +0 -768
- package/src/components/NavigationMenu/__tests__/NavigationMenu.integration.test.tsx +0 -576
- package/src/components/NavigationMenu/__tests__/NavigationMenu.performance.test.tsx +0 -585
- package/src/components/NavigationMenu/__tests__/NavigationMenu.real.component.test.tsx +0 -783
- package/src/components/NavigationMenu/__tests__/NavigationMenu.security.enhanced.test.tsx +0 -810
- package/src/components/NavigationMenu/__tests__/NavigationMenu.security.test.tsx +0 -494
- package/src/components/NavigationMenu/__tests__/NavigationMenu.unit.test.tsx +0 -331
- package/src/components/NavigationMenu/__tests__/NavigationMenu.userWorkflows.test.tsx +0 -347
- package/src/components/NavigationMenu/__tests__/NavigationMenu.workflows.test.tsx +0 -584
- package/src/components/OrganisationSelector/__tests__/OrganisationSelector.unit.test.tsx +0 -664
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +0 -288
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +0 -893
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +0 -629
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +0 -782
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +0 -904
- package/src/components/PaceLoginPage/__tests__/PaceLoginPage.accessibility.test.tsx +0 -463
- package/src/components/PaceLoginPage/__tests__/PaceLoginPage.integration.test.tsx +0 -586
- package/src/components/PaceLoginPage/__tests__/PaceLoginPage.unit.test.tsx +0 -533
- package/src/components/PasswordReset/__tests__/PasswordChangeForm.accessibility.test.tsx +0 -408
- package/src/components/PasswordReset/__tests__/PasswordChangeForm.unit.test.tsx +0 -561
- package/src/components/PasswordReset/__tests__/PasswordReset.integration.test.tsx +0 -304
- package/src/components/PasswordReset/__tests__/PasswordResetForm.accessibility.test.tsx +0 -20
- package/src/components/PasswordReset/__tests__/PasswordResetForm.unit.test.tsx +0 -523
- package/src/components/PasswordReset/__tests__/__mocks__/UnifiedAuthProvider.ts +0 -29
- package/src/components/Print/__tests__/Print.comprehensive.test.tsx +0 -331
- package/src/components/PrintButton/__tests__/PrintButton.unit.test.tsx +0 -429
- package/src/components/PrintButton/__tests__/PrintButtonGroup.unit.test.tsx +0 -277
- package/src/components/PrintButton/__tests__/PrintToolbar.unit.test.tsx +0 -264
- package/src/components/PrintCard/__tests__/PrintCard.unit.test.tsx +0 -233
- package/src/components/PrintCard/__tests__/PrintCardContent.test.tsx +0 -284
- package/src/components/PrintCard/__tests__/PrintCardGrid.unit.test.tsx +0 -214
- package/src/components/PrintCard/__tests__/PrintCardImage.unit.test.tsx +0 -264
- package/src/components/PrintDataTable/__tests__/PrintDataTable.unit.test.tsx +0 -361
- package/src/components/PrintDataTable/__tests__/PrintTableGroup.unit.test.tsx +0 -314
- package/src/components/PrintDataTable/__tests__/PrintTableRow.unit.test.tsx +0 -362
- package/src/components/PrintFooter/__tests__/PrintFooter.unit.test.tsx +0 -500
- package/src/components/PrintFooter/__tests__/PrintFooterContent.unit.test.tsx +0 -321
- package/src/components/PrintFooter/__tests__/PrintFooterInfo.unit.test.tsx +0 -335
- package/src/components/PrintFooter/__tests__/PrintPageNumber.unit.test.tsx +0 -340
- package/src/components/PrintGrid/__tests__/PrintGrid.unit.test.tsx +0 -340
- package/src/components/PrintGrid/__tests__/PrintGridBreakpoint.unit.test.tsx +0 -261
- package/src/components/PrintGrid/__tests__/PrintGridContainer.unit.test.tsx +0 -338
- package/src/components/PrintGrid/__tests__/PrintGridItem.unit.test.tsx +0 -338
- package/src/components/PrintHeader/__tests__/PrintCoverHeader.unit.test.tsx +0 -309
- package/src/components/PrintHeader/__tests__/PrintHeader.unit.test.tsx +0 -202
- package/src/components/PrintLayout/__tests__/PrintLayout.unit.test.tsx +0 -238
- package/src/components/PrintPageBreak/__tests__/PrintPageBreak.unit.test.tsx +0 -263
- package/src/components/PrintPageBreak/__tests__/PrintPageBreakGroup.unit.test.tsx +0 -239
- package/src/components/PrintPageBreak/__tests__/PrintPageBreakIndicator.unit.test.tsx +0 -235
- package/src/components/PrintSection/__tests__/PrintColumn.unit.test.tsx +0 -385
- package/src/components/PrintSection/__tests__/PrintDivider.unit.test.tsx +0 -373
- package/src/components/PrintSection/__tests__/PrintSection.unit.test.tsx +0 -390
- package/src/components/PrintSection/__tests__/PrintSectionContent.unit.test.tsx +0 -321
- package/src/components/PrintSection/__tests__/PrintSectionHeader.unit.test.tsx +0 -334
- package/src/components/PrintText/__tests__/PrintText.unit.test.tsx +0 -351
- package/src/components/Progress/__tests__/Progress.accessibility.test.tsx +0 -240
- package/src/components/Progress/__tests__/Progress.unit.test.tsx +0 -242
- package/src/components/PublicLayout/__tests__/EventLogo.test.tsx +0 -761
- package/src/components/PublicLayout/__tests__/PublicErrorBoundary.simplified.test.tsx +0 -228
- package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +0 -228
- package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +0 -459
- package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +0 -362
- package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +0 -522
- package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +0 -599
- package/src/components/PublicLayout/__tests__/PublicPageProvider.test.tsx +0 -513
- package/src/components/RBAC/__tests__/PagePermissionGuard.unit.test.tsx +0 -683
- package/src/components/RBAC/__tests__/RBAC.integration.test.tsx +0 -573
- package/src/components/RBAC/__tests__/RBACGuard.unit.test.tsx +0 -467
- package/src/components/RBAC/__tests__/RBACProvider.accessibility.test.tsx +0 -475
- package/src/components/RBAC/__tests__/RBACProvider.advanced.test.tsx +0 -569
- package/src/components/RBAC/__tests__/RBACProvider.integration.test.tsx +0 -352
- package/src/components/RBAC/__tests__/RBACProvider.unit.test.tsx +0 -128
- package/src/components/RBAC/__tests__/RoleBasedContent.unit.test.tsx +0 -657
- package/src/components/Select/__tests__/SearchableSelect.unit.test.tsx +0 -437
- package/src/components/Select/__tests__/Select.accessibility.test.tsx +0 -1202
- package/src/components/Select/__tests__/Select.actual.test.tsx +0 -774
- package/src/components/Select/__tests__/Select.comprehensive.test.tsx +0 -837
- package/src/components/Select/__tests__/Select.enhanced.test.tsx +0 -1101
- package/src/components/Select/__tests__/Select.integration.test.tsx +0 -772
- package/src/components/Select/__tests__/Select.performance.test.tsx +0 -695
- package/src/components/Select/__tests__/Select.real-world.test.tsx +0 -1046
- package/src/components/Select/__tests__/Select.search-algorithms.test.tsx +0 -968
- package/src/components/Select/__tests__/Select.unit.test.tsx +0 -647
- package/src/components/Select/__tests__/Select.utils.test.tsx +0 -890
- package/src/components/Table/__tests__/Table.accessibility.test.tsx +0 -233
- package/src/components/Table/__tests__/Table.unit.test.tsx +0 -235
- package/src/components/Toast/__tests__/Toast.accessibility.test.tsx +0 -238
- package/src/components/Toast/__tests__/Toast.integration.test.tsx +0 -699
- package/src/components/Toast/__tests__/Toast.unit.test.tsx +0 -750
- package/src/components/Tooltip/__tests__/Tooltip.accessibility.test.tsx +0 -121
- package/src/components/Tooltip/__tests__/Tooltip.unit.test.tsx +0 -185
- package/src/components/UserMenu/__tests__/UserMenu.accessibility.test.tsx +0 -139
- package/src/components/UserMenu/__tests__/UserMenu.integration.test.tsx +0 -188
- package/src/components/UserMenu/__tests__/UserMenu.unit.test.tsx +0 -458
- package/src/components/__tests__/EdgeCaseTesting.enhanced.test.tsx +0 -524
- package/src/components/__tests__/ErrorTesting.enhanced.test.tsx +0 -455
- package/src/components/__tests__/SuperAdminGuard.test.tsx +0 -456
- package/src/components/__tests__/SuperAdminGuard.unit.test.tsx +0 -456
- package/src/components/examples/__tests__/PermissionExample.unit.test.tsx +0 -360
- package/src/hooks/__tests__/hooks.integration.test.tsx +0 -575
- package/src/hooks/__tests__/useApiFetch.unit.test.ts +0 -115
- package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +0 -133
- package/src/hooks/__tests__/useDebounce.unit.test.ts +0 -82
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +0 -293
- package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +0 -385
- package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +0 -286
- package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +0 -838
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +0 -627
- package/src/hooks/__tests__/useRBAC.unit.test.ts +0 -911
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +0 -537
- package/src/hooks/__tests__/useToast.unit.test.tsx +0 -62
- package/src/hooks/__tests__/useZodForm.unit.test.tsx +0 -37
- package/src/hooks/public/__tests__/usePublicEvent.test.tsx +0 -397
- package/src/hooks/public/__tests__/usePublicEventLogo.test.tsx +0 -690
- package/src/hooks/public/__tests__/usePublicRouteParams.test.tsx +0 -449
- package/src/providers/__tests__/EventProvider.unit.test.tsx +0 -768
- package/src/providers/__tests__/OrganisationProvider.basic.test.tsx +0 -116
- package/src/providers/__tests__/OrganisationProvider.unit.test.tsx +0 -1312
- package/src/providers/__tests__/UnifiedAuthProvider.inactivity.test.tsx +0 -601
- package/src/providers/__tests__/UnifiedAuthProvider.unit.test.tsx +0 -683
- package/src/providers/__tests__/index.unit.test.ts +0 -78
- package/src/rbac/__tests__/PagePermissionGuard.test.tsx +0 -673
- package/src/rbac/__tests__/README.md +0 -170
- package/src/rbac/__tests__/RoleBasedRouter.test.tsx +0 -709
- package/src/rbac/__tests__/TestContext.tsx +0 -72
- package/src/rbac/__tests__/__mocks__/cache.ts +0 -144
- package/src/rbac/__tests__/__mocks__/supabase.ts +0 -152
- package/src/rbac/__tests__/adapters-hooks-comprehensive.test.tsx +0 -782
- package/src/rbac/__tests__/adapters-hooks.test.tsx +0 -561
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +0 -963
- package/src/rbac/__tests__/adapters.test.tsx +0 -444
- package/src/rbac/__tests__/api.test.ts +0 -620
- package/src/rbac/__tests__/audit-observability-comprehensive.test.ts +0 -792
- package/src/rbac/__tests__/audit-observability.test.ts +0 -549
- package/src/rbac/__tests__/audit.test.ts +0 -616
- package/src/rbac/__tests__/build-contract-compliance-simple.test.ts +0 -230
- package/src/rbac/__tests__/cache-invalidation-comprehensive.test.ts +0 -889
- package/src/rbac/__tests__/cache-invalidation.test.ts +0 -457
- package/src/rbac/__tests__/cache.test.ts +0 -458
- package/src/rbac/__tests__/components-navigation-guard.enhanced.test.tsx +0 -859
- package/src/rbac/__tests__/components-navigation-guard.test.tsx +0 -895
- package/src/rbac/__tests__/components-navigation-provider.test.tsx +0 -692
- package/src/rbac/__tests__/components-page-permission-guard.test.tsx +0 -673
- package/src/rbac/__tests__/components-page-permission-provider.test.tsx +0 -614
- package/src/rbac/__tests__/components-permission-enforcer.enhanced.fixed.test.tsx +0 -836
- package/src/rbac/__tests__/components-permission-enforcer.enhanced.test.tsx +0 -837
- package/src/rbac/__tests__/components-permission-enforcer.test.tsx +0 -825
- package/src/rbac/__tests__/components-role-based-router.test.tsx +0 -709
- package/src/rbac/__tests__/components-secure-data-provider.test.tsx +0 -607
- package/src/rbac/__tests__/config.test.ts +0 -583
- package/src/rbac/__tests__/core-logic-unit.test.ts +0 -190
- package/src/rbac/__tests__/core-permission-logic-comprehensive.test.ts +0 -1467
- package/src/rbac/__tests__/core-permission-logic-fixed.test.ts +0 -151
- package/src/rbac/__tests__/core-permission-logic-simple.test.ts +0 -968
- package/src/rbac/__tests__/core-permission-logic.test.ts +0 -966
- package/src/rbac/__tests__/edge-cases-comprehensive.test.ts +0 -988
- package/src/rbac/__tests__/edge-cases.test.ts +0 -654
- package/src/rbac/__tests__/engine.test.ts +0 -361
- package/src/rbac/__tests__/engine.unit.test.ts +0 -361
- package/src/rbac/__tests__/hooks.enhanced.test.tsx +0 -979
- package/src/rbac/__tests__/hooks.fixed.test.tsx +0 -475
- package/src/rbac/__tests__/hooks.test.tsx +0 -385
- package/src/rbac/__tests__/index.test.ts +0 -269
- package/src/rbac/__tests__/integration.enhanced.test.tsx +0 -824
- package/src/rbac/__tests__/page-permission-guard-super-admin.test.tsx +0 -261
- package/src/rbac/__tests__/performance.enhanced.test.tsx +0 -724
- package/src/rbac/__tests__/permissions.test.ts +0 -383
- package/src/rbac/__tests__/requires-event.test.ts +0 -330
- package/src/rbac/__tests__/scope-isolation-comprehensive.test.ts +0 -1349
- package/src/rbac/__tests__/scope-isolation.test.ts +0 -755
- package/src/rbac/__tests__/secure-client-rls-comprehensive.test.ts +0 -592
- package/src/rbac/__tests__/secure-client-rls.test.ts +0 -377
- package/src/rbac/__tests__/security.test.ts +0 -296
- package/src/rbac/__tests__/setup.ts +0 -228
- package/src/rbac/__tests__/test-utils-enhanced.tsx +0 -400
- package/src/rbac/__tests__/types.test.ts +0 -685
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -631
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -667
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -647
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -496
- package/src/rbac/testing/__tests__/index.test.tsx +0 -342
- package/src/rbac/utils/__tests__/eventContext.test.ts +0 -428
- package/src/rbac/utils/__tests__/eventContext.unit.test.ts +0 -428
- package/src/styles/__tests__/styles.unit.test.ts +0 -164
- package/src/test-dom-cleanup.test.tsx +0 -38
- package/src/theming/__tests__/README.md +0 -335
- package/src/theming/__tests__/runtime.accessibility.test.ts +0 -474
- package/src/theming/__tests__/runtime.error.test.ts +0 -616
- package/src/theming/__tests__/runtime.integration.test.ts +0 -376
- package/src/theming/__tests__/runtime.performance.test.ts +0 -411
- package/src/theming/__tests__/runtime.unit.test.ts +0 -470
- package/src/types/__tests__/database.unit.test.ts +0 -489
- package/src/types/__tests__/guards.unit.test.ts +0 -146
- package/src/types/__tests__/index.unit.test.ts +0 -77
- package/src/types/__tests__/organisation.unit.test.ts +0 -713
- package/src/types/__tests__/rbac.unit.test.ts +0 -621
- package/src/types/__tests__/security.unit.test.ts +0 -347
- package/src/types/__tests__/supabase.unit.test.ts +0 -658
- package/src/types/__tests__/theme.unit.test.ts +0 -218
- package/src/types/__tests__/unified.unit.test.ts +0 -537
- package/src/types/__tests__/validation.unit.test.ts +0 -616
- package/src/utils/__tests__/appConfig.unit.test.ts +0 -55
- package/src/utils/__tests__/appNameResolver.unit.test.ts +0 -137
- package/src/utils/__tests__/audit.unit.test.ts +0 -69
- package/src/utils/__tests__/auth-utils.unit.test.ts +0 -70
- package/src/utils/__tests__/bundleAnalysis.unit.test.ts +0 -317
- package/src/utils/__tests__/cn.unit.test.ts +0 -34
- package/src/utils/__tests__/deviceFingerprint.unit.test.ts +0 -480
- package/src/utils/__tests__/dynamicUtils.unit.test.ts +0 -322
- package/src/utils/__tests__/formatDate.unit.test.ts +0 -109
- package/src/utils/__tests__/formatting.unit.test.ts +0 -66
- package/src/utils/__tests__/index.unit.test.ts +0 -251
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +0 -304
- package/src/utils/__tests__/organisationContext.unit.test.ts +0 -192
- package/src/utils/__tests__/performanceBudgets.unit.test.ts +0 -259
- package/src/utils/__tests__/permissionTypes.unit.test.ts +0 -250
- package/src/utils/__tests__/permissionUtils.unit.test.ts +0 -362
- package/src/utils/__tests__/sanitization.unit.test.ts +0 -346
- package/src/utils/__tests__/schemaUtils.unit.test.ts +0 -441
- package/src/utils/__tests__/secureDataAccess.unit.test.ts +0 -334
- package/src/utils/__tests__/secureErrors.unit.test.ts +0 -377
- package/src/utils/__tests__/secureStorage.unit.test.ts +0 -293
- package/src/utils/__tests__/security.unit.test.ts +0 -127
- package/src/utils/__tests__/securityMonitor.unit.test.ts +0 -280
- package/src/utils/__tests__/sessionTracking.unit.test.ts +0 -370
- package/src/utils/__tests__/validation.unit.test.ts +0 -84
- package/src/utils/__tests__/validationUtils.unit.test.ts +0 -571
- package/src/utils/print/__tests__/PrintDataProcessor.unit.test.ts +0 -219
- package/src/utils/print/__tests__/usePrintOptimization.unit.test.tsx +0 -353
- package/src/utils/storage/__tests__/config.unit.test.ts +0 -206
- package/src/utils/storage/__tests__/helpers.unit.test.ts +0 -648
- package/src/utils/storage/__tests__/index.unit.test.ts +0 -167
- package/src/utils/storage/__tests__/types.unit.test.ts +0 -441
- package/src/validation/__tests__/common.unit.test.ts +0 -101
- package/src/validation/__tests__/csrf.unit.test.ts +0 -302
- package/src/validation/__tests__/passwordSchema.unit.test.ts +0 -98
- package/src/validation/__tests__/sqlInjectionProtection.unit.test.ts +0 -466
- /package/dist/{DataTable-EEUDXPE5.js.map → DataTable-GX3XERFJ.js.map} +0 -0
- /package/dist/{chunk-VYG4AXYW.js.map → chunk-5EL3KHOQ.js.map} +0 -0
|
@@ -1,1373 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { screen, fireEvent } from '@testing-library/react';
|
|
3
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
4
|
-
import { renderWithProviders } from '../../../__tests__/shared';
|
|
5
|
-
import {
|
|
6
|
-
Dialog,
|
|
7
|
-
DialogTrigger,
|
|
8
|
-
DialogContent,
|
|
9
|
-
DialogHeader,
|
|
10
|
-
DialogFooter,
|
|
11
|
-
DialogTitle,
|
|
12
|
-
DialogDescription,
|
|
13
|
-
DialogClose,
|
|
14
|
-
type DialogSize,
|
|
15
|
-
DialogBody,
|
|
16
|
-
} from '../Dialog';
|
|
17
|
-
import { renderWithProviders, testComponentRendering, testComponentAccessibility } from '../../../__tests__/shared';
|
|
18
|
-
|
|
19
|
-
// Mock Radix UI Dialog primitives
|
|
20
|
-
vi.mock('@radix-ui/react-dialog', () => ({
|
|
21
|
-
Root: ({ children, open, onOpenChange }: { children: React.ReactNode; open?: boolean; onOpenChange?: (open: boolean) => void }) => (
|
|
22
|
-
<div data-testid="dialog-root" data-open={open === undefined ? 'false' : String(open)}>
|
|
23
|
-
{children}
|
|
24
|
-
</div>
|
|
25
|
-
),
|
|
26
|
-
Trigger: React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttributes<HTMLButtonElement>>(({ children, ...props }, ref) => (
|
|
27
|
-
<button ref={ref} data-testid="dialog-trigger" {...props}>
|
|
28
|
-
{children}
|
|
29
|
-
</button>
|
|
30
|
-
)),
|
|
31
|
-
Portal: ({ children }: { children: React.ReactNode }) => (
|
|
32
|
-
<div data-testid="dialog-portal">{children}</div>
|
|
33
|
-
),
|
|
34
|
-
Overlay: React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(({ className, ...props }, ref) => {
|
|
35
|
-
const baseClasses = 'fixed inset-0 z-50 bg-main-950/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0';
|
|
36
|
-
const finalClassName = className ? `${baseClasses} ${className}` : baseClasses;
|
|
37
|
-
return <div ref={ref} className={finalClassName} data-testid="dialog-overlay" {...props} />;
|
|
38
|
-
}),
|
|
39
|
-
Content: React.forwardRef<HTMLDialogElement, React.HTMLAttributes<HTMLDialogElement> & {
|
|
40
|
-
onEscapeKeyDown?: (event: KeyboardEvent) => void;
|
|
41
|
-
onPointerDownOutside?: (event: Event) => void;
|
|
42
|
-
asChild?: boolean;
|
|
43
|
-
}>(({ children, className, onEscapeKeyDown, onPointerDownOutside, asChild, ...props }, ref) => {
|
|
44
|
-
// Handle asChild pattern for semantic HTML implementation
|
|
45
|
-
if (asChild && React.isValidElement(children)) {
|
|
46
|
-
const child = React.Children.only(children) as React.ReactElement<any>;
|
|
47
|
-
const mergedClassName = [child.props.className, className].filter(Boolean).join(' ');
|
|
48
|
-
return React.cloneElement(child, {
|
|
49
|
-
...child.props,
|
|
50
|
-
...props,
|
|
51
|
-
className: mergedClassName,
|
|
52
|
-
ref,
|
|
53
|
-
"data-testid": "dialog-content",
|
|
54
|
-
style: { ...child.props.style, ...props.style },
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return (
|
|
59
|
-
<dialog ref={ref} className={className} data-testid="dialog-content" {...props}>
|
|
60
|
-
{children}
|
|
61
|
-
</dialog>
|
|
62
|
-
);
|
|
63
|
-
}),
|
|
64
|
-
Title: React.forwardRef<HTMLHeadingElement, React.HTMLAttributes<HTMLHeadingElement>>(({ children, className, ...props }, ref) => (
|
|
65
|
-
<h2 ref={ref} className={className} data-testid="dialog-title" {...props}>
|
|
66
|
-
{children}
|
|
67
|
-
</h2>
|
|
68
|
-
)),
|
|
69
|
-
Description: React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(({ children, className, ...props }, ref) => (
|
|
70
|
-
<p ref={ref} className={className} data-testid="dialog-description" {...props}>
|
|
71
|
-
{children}
|
|
72
|
-
</p>
|
|
73
|
-
)),
|
|
74
|
-
Close: React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttributes<HTMLButtonElement>>(({ children, className, ...props }, ref) => (
|
|
75
|
-
<button ref={ref} className={className} data-testid="dialog-close" {...props}>
|
|
76
|
-
{children}
|
|
77
|
-
</button>
|
|
78
|
-
)),
|
|
79
|
-
}));
|
|
80
|
-
|
|
81
|
-
// Mock lucide-react X icon
|
|
82
|
-
vi.mock('lucide-react', () => ({
|
|
83
|
-
X: ({ className }: { className?: string }) => (
|
|
84
|
-
<svg className={className} data-testid="close-icon" />
|
|
85
|
-
),
|
|
86
|
-
}));
|
|
87
|
-
|
|
88
|
-
describe('Dialog Component', () => {
|
|
89
|
-
describe('Dialog Root', () => {
|
|
90
|
-
it('renders with default state', () => {
|
|
91
|
-
renderWithProviders(
|
|
92
|
-
<Dialog>
|
|
93
|
-
<DialogTrigger>Open Dialog</DialogTrigger>
|
|
94
|
-
<DialogContent>Dialog content</DialogContent>
|
|
95
|
-
</Dialog>
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
expect(screen.getByTestId('dialog-root')).toBeInTheDocument();
|
|
99
|
-
expect(screen.getByTestId('dialog-root')).toHaveAttribute('data-open', 'false');
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('renders with open state', () => {
|
|
103
|
-
renderWithProviders(
|
|
104
|
-
<Dialog open>
|
|
105
|
-
<DialogTrigger>Open Dialog</DialogTrigger>
|
|
106
|
-
<DialogContent>Dialog content</DialogContent>
|
|
107
|
-
</Dialog>
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
expect(screen.getByTestId('dialog-root')).toHaveAttribute('data-open', 'true');
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('calls onOpenChange when state changes', () => {
|
|
114
|
-
const handleOpenChange = vi.fn();
|
|
115
|
-
renderWithProviders(
|
|
116
|
-
<Dialog onOpenChange={handleOpenChange}>
|
|
117
|
-
<DialogTrigger>Open Dialog</DialogTrigger>
|
|
118
|
-
<DialogContent>Dialog content</DialogContent>
|
|
119
|
-
</Dialog>
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
// This would be tested with actual dialog interactions
|
|
123
|
-
expect(handleOpenChange).toBeDefined();
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
describe('DialogTrigger', () => {
|
|
128
|
-
it('renders trigger button', () => {
|
|
129
|
-
renderWithProviders(<DialogTrigger>Open Dialog</DialogTrigger>);
|
|
130
|
-
const trigger = screen.getByTestId('dialog-trigger');
|
|
131
|
-
expect(trigger).toBeInTheDocument();
|
|
132
|
-
expect(trigger).toHaveTextContent('Open Dialog');
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it('applies custom className', () => {
|
|
136
|
-
renderWithProviders(<DialogTrigger className="custom-trigger">Open</DialogTrigger>);
|
|
137
|
-
const trigger = screen.getByTestId('dialog-trigger');
|
|
138
|
-
expect(trigger).toHaveClass('custom-trigger');
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it('forwards ref correctly', () => {
|
|
142
|
-
const ref = vi.fn();
|
|
143
|
-
renderWithProviders(<DialogTrigger ref={ref}>Open</DialogTrigger>);
|
|
144
|
-
expect(ref).toHaveBeenCalled();
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it('spreads additional props', () => {
|
|
148
|
-
renderWithProviders(<DialogTrigger data-testid="custom-trigger" aria-label="Open dialog">Open</DialogTrigger>);
|
|
149
|
-
const trigger = screen.getByTestId('custom-trigger');
|
|
150
|
-
expect(trigger).toHaveAttribute('aria-label', 'Open dialog');
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
describe('DialogContent', () => {
|
|
155
|
-
it('renders content with portal and overlay', () => {
|
|
156
|
-
renderWithProviders(<DialogContent>Dialog content</DialogContent>);
|
|
157
|
-
|
|
158
|
-
expect(screen.getByTestId('dialog-portal')).toBeInTheDocument();
|
|
159
|
-
expect(screen.getByTestId('dialog-overlay')).toBeInTheDocument();
|
|
160
|
-
expect(screen.getByTestId('dialog-content')).toBeInTheDocument();
|
|
161
|
-
expect(screen.getByText('Dialog content')).toBeInTheDocument();
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('applies default styling with md size', () => {
|
|
165
|
-
renderWithProviders(<DialogContent>Content</DialogContent>);
|
|
166
|
-
const content = screen.getByTestId('dialog-content');
|
|
167
|
-
expect(content).toHaveClass(
|
|
168
|
-
'fixed',
|
|
169
|
-
'z-50',
|
|
170
|
-
'duration-200',
|
|
171
|
-
'data-[state=open]:animate-in',
|
|
172
|
-
'data-[state=closed]:animate-out',
|
|
173
|
-
'data-[state=closed]:fade-out-0',
|
|
174
|
-
'data-[state=open]:fade-in-0',
|
|
175
|
-
'data-[state=closed]:zoom-out-95',
|
|
176
|
-
'data-[state=open]:zoom-in-95',
|
|
177
|
-
'data-[state=closed]:slide-out-to-left-1/2',
|
|
178
|
-
'data-[state=closed]:slide-out-to-top-[48%]',
|
|
179
|
-
'data-[state=open]:slide-in-from-left-1/2',
|
|
180
|
-
'data-[state=open]:slide-in-from-top-[48%]',
|
|
181
|
-
'sm:rounded-lg',
|
|
182
|
-
'm-0',
|
|
183
|
-
'max-h-none',
|
|
184
|
-
'w-auto',
|
|
185
|
-
'h-auto',
|
|
186
|
-
'outline-none',
|
|
187
|
-
'border',
|
|
188
|
-
'bg-background',
|
|
189
|
-
'shadow-lg',
|
|
190
|
-
'grid',
|
|
191
|
-
'gap-4',
|
|
192
|
-
'p-6',
|
|
193
|
-
'max-w-md'
|
|
194
|
-
);
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
it('applies size variant classes', () => {
|
|
198
|
-
const sizes: DialogSize[] = ['sm', 'md', 'lg', 'xl', 'full'];
|
|
199
|
-
const expectedClasses = ['max-w-sm', 'max-w-md', 'max-w-lg', 'max-w-xl', 'max-w-full'];
|
|
200
|
-
|
|
201
|
-
sizes.forEach((size, index) => {
|
|
202
|
-
const { unmount } = renderWithProviders(<DialogContent size={size}>Content</DialogContent>);
|
|
203
|
-
const content = screen.getByTestId('dialog-content');
|
|
204
|
-
expect(content).toHaveClass(expectedClasses[index]);
|
|
205
|
-
unmount();
|
|
206
|
-
});
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
it('applies full size special styling', () => {
|
|
210
|
-
renderWithProviders(<DialogContent size="full">Content</DialogContent>);
|
|
211
|
-
const content = screen.getByTestId('dialog-content');
|
|
212
|
-
expect(content).toHaveClass(
|
|
213
|
-
'fixed',
|
|
214
|
-
'z-50',
|
|
215
|
-
'duration-200',
|
|
216
|
-
'data-[state=open]:animate-in',
|
|
217
|
-
'data-[state=closed]:animate-out',
|
|
218
|
-
'data-[state=closed]:fade-out-0',
|
|
219
|
-
'data-[state=open]:fade-in-0',
|
|
220
|
-
'data-[state=closed]:zoom-out-95',
|
|
221
|
-
'data-[state=open]:zoom-in-95',
|
|
222
|
-
'data-[state=closed]:slide-out-to-left-1/2',
|
|
223
|
-
'data-[state=closed]:slide-out-to-top-[48%]',
|
|
224
|
-
'data-[state=open]:slide-in-from-left-1/2',
|
|
225
|
-
'data-[state=open]:slide-in-from-top-[48%]',
|
|
226
|
-
'm-0',
|
|
227
|
-
'max-h-none',
|
|
228
|
-
'w-auto',
|
|
229
|
-
'outline-none',
|
|
230
|
-
'border',
|
|
231
|
-
'bg-background',
|
|
232
|
-
'shadow-lg',
|
|
233
|
-
'max-w-full',
|
|
234
|
-
'grid',
|
|
235
|
-
'gap-4',
|
|
236
|
-
'p-6',
|
|
237
|
-
'sm:left-[50%]',
|
|
238
|
-
'sm:top-[50%]',
|
|
239
|
-
'sm:translate-x-[-50%]',
|
|
240
|
-
'sm:translate-y-[-50%]',
|
|
241
|
-
'left-0',
|
|
242
|
-
'top-0',
|
|
243
|
-
'translate-x-0',
|
|
244
|
-
'translate-y-0',
|
|
245
|
-
'h-full',
|
|
246
|
-
'rounded-none',
|
|
247
|
-
'sm:h-auto',
|
|
248
|
-
'sm:rounded-lg'
|
|
249
|
-
);
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
it('applies custom className', () => {
|
|
253
|
-
renderWithProviders(<DialogContent className="custom-content">Content</DialogContent>);
|
|
254
|
-
const content = screen.getByTestId('dialog-content');
|
|
255
|
-
expect(content).toHaveClass('custom-content');
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
it('forwards ref correctly', () => {
|
|
259
|
-
const ref = vi.fn();
|
|
260
|
-
renderWithProviders(<DialogContent ref={ref}>Content</DialogContent>);
|
|
261
|
-
expect(ref).toHaveBeenCalled();
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
it('has correct role', () => {
|
|
265
|
-
renderWithProviders(<DialogContent>Content</DialogContent>);
|
|
266
|
-
const content = screen.getByTestId('dialog-content');
|
|
267
|
-
expect(content).toBeInTheDocument();
|
|
268
|
-
expect(content.tagName.toLowerCase()).toBe('dialog');
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
it('includes close button by default', () => {
|
|
272
|
-
renderWithProviders(<DialogContent>Content</DialogContent>);
|
|
273
|
-
const closeButton = screen.getByTestId('dialog-close');
|
|
274
|
-
expect(closeButton).toBeInTheDocument();
|
|
275
|
-
expect(closeButton).toHaveTextContent('Close');
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
it('hides close button when showCloseButton is false', () => {
|
|
279
|
-
renderWithProviders(<DialogContent showCloseButton={false}>Content</DialogContent>);
|
|
280
|
-
const closeButton = screen.queryByTestId('dialog-close');
|
|
281
|
-
expect(closeButton).not.toBeInTheDocument();
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
it('applies custom overlay className', () => {
|
|
285
|
-
renderWithProviders(<DialogContent overlayClassName="custom-overlay">Content</DialogContent>);
|
|
286
|
-
const overlay = screen.getByTestId('dialog-overlay');
|
|
287
|
-
expect(overlay).toHaveClass('custom-overlay');
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
it('handles preventCloseOnEscape prop', () => {
|
|
291
|
-
const mockPreventDefault = vi.fn();
|
|
292
|
-
const mockKeyboardEvent = { preventDefault: mockPreventDefault } as unknown as KeyboardEvent;
|
|
293
|
-
|
|
294
|
-
renderWithProviders(<DialogContent preventCloseOnEscape>Content</DialogContent>);
|
|
295
|
-
|
|
296
|
-
// The component should be set up to prevent escape, but testing the actual behavior
|
|
297
|
-
// would require more complex mocking of the Radix UI event system
|
|
298
|
-
expect(screen.getByTestId('dialog-content')).toBeInTheDocument();
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
it('handles preventCloseOnOutsideClick prop', () => {
|
|
302
|
-
const mockPreventDefault = vi.fn();
|
|
303
|
-
const mockEvent = { preventDefault: mockPreventDefault } as unknown as Event;
|
|
304
|
-
|
|
305
|
-
renderWithProviders(<DialogContent preventCloseOnOutsideClick>Content</DialogContent>);
|
|
306
|
-
|
|
307
|
-
// The component should be set up to prevent outside clicks, but testing the actual behavior
|
|
308
|
-
// would require more complex mocking of the Radix UI event system
|
|
309
|
-
expect(screen.getByTestId('dialog-content')).toBeInTheDocument();
|
|
310
|
-
});
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
describe('DialogOverlay', () => {
|
|
314
|
-
it('renders with default styling', () => {
|
|
315
|
-
renderWithProviders(<DialogContent>Content</DialogContent>);
|
|
316
|
-
const overlay = screen.getByTestId('dialog-overlay');
|
|
317
|
-
expect(overlay).toHaveClass(
|
|
318
|
-
'fixed',
|
|
319
|
-
'inset-0',
|
|
320
|
-
'z-50',
|
|
321
|
-
'bg-main-950/80',
|
|
322
|
-
'data-[state=open]:animate-in',
|
|
323
|
-
'data-[state=closed]:animate-out',
|
|
324
|
-
'data-[state=closed]:fade-out-0',
|
|
325
|
-
'data-[state=open]:fade-in-0'
|
|
326
|
-
);
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
it('applies custom className via overlayClassName', () => {
|
|
330
|
-
renderWithProviders(<DialogContent overlayClassName="custom-overlay-class">Content</DialogContent>);
|
|
331
|
-
const overlay = screen.getByTestId('dialog-overlay');
|
|
332
|
-
expect(overlay).toHaveClass('custom-overlay-class');
|
|
333
|
-
});
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
describe('DialogHeader', () => {
|
|
337
|
-
it('renders header with default styling', () => {
|
|
338
|
-
renderWithProviders(<DialogHeader>Header content</DialogHeader>);
|
|
339
|
-
const header = screen.getByText('Header content');
|
|
340
|
-
expect(header).toBeInTheDocument();
|
|
341
|
-
expect(header).toHaveClass(
|
|
342
|
-
'flex',
|
|
343
|
-
'flex-col',
|
|
344
|
-
'space-y-1.5',
|
|
345
|
-
'text-center',
|
|
346
|
-
'sm:text-left'
|
|
347
|
-
);
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
it('applies custom className', () => {
|
|
351
|
-
renderWithProviders(<DialogHeader className="custom-header">Header</DialogHeader>);
|
|
352
|
-
const header = screen.getByText('Header');
|
|
353
|
-
expect(header).toHaveClass('custom-header');
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
it('spreads additional props', () => {
|
|
357
|
-
renderWithProviders(<DialogHeader data-testid="header" aria-label="Dialog header">Header</DialogHeader>);
|
|
358
|
-
const header = screen.getByTestId('header');
|
|
359
|
-
expect(header).toHaveAttribute('aria-label', 'Dialog header');
|
|
360
|
-
});
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
describe('DialogFooter', () => {
|
|
364
|
-
it('renders footer with default styling', () => {
|
|
365
|
-
renderWithProviders(<DialogFooter>Footer content</DialogFooter>);
|
|
366
|
-
const footer = screen.getByText('Footer content');
|
|
367
|
-
expect(footer).toBeInTheDocument();
|
|
368
|
-
expect(footer).toHaveClass(
|
|
369
|
-
'flex',
|
|
370
|
-
'flex-col-reverse',
|
|
371
|
-
'sm:flex-row',
|
|
372
|
-
'sm:justify-end',
|
|
373
|
-
'sm:space-x-2'
|
|
374
|
-
);
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
it('applies custom className', () => {
|
|
378
|
-
renderWithProviders(<DialogFooter className="custom-footer">Footer</DialogFooter>);
|
|
379
|
-
const footer = screen.getByText('Footer');
|
|
380
|
-
expect(footer).toHaveClass('custom-footer');
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
it('spreads additional props', () => {
|
|
384
|
-
renderWithProviders(<DialogFooter data-testid="footer" aria-label="Dialog footer">Footer</DialogFooter>);
|
|
385
|
-
const footer = screen.getByTestId('footer');
|
|
386
|
-
expect(footer).toHaveAttribute('aria-label', 'Dialog footer');
|
|
387
|
-
});
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
describe('DialogTitle', () => {
|
|
391
|
-
it('renders title with default styling', () => {
|
|
392
|
-
renderWithProviders(<DialogTitle>Title content</DialogTitle>);
|
|
393
|
-
const title = screen.getByTestId('dialog-title');
|
|
394
|
-
expect(title).toBeInTheDocument();
|
|
395
|
-
expect(title).toHaveTextContent('Title content');
|
|
396
|
-
expect(title).toHaveClass(
|
|
397
|
-
'text-lg',
|
|
398
|
-
'font-semibold',
|
|
399
|
-
'leading-none',
|
|
400
|
-
'tracking-tight'
|
|
401
|
-
);
|
|
402
|
-
});
|
|
403
|
-
|
|
404
|
-
it('applies custom className', () => {
|
|
405
|
-
renderWithProviders(<DialogTitle className="custom-title">Title</DialogTitle>);
|
|
406
|
-
const title = screen.getByTestId('dialog-title');
|
|
407
|
-
expect(title).toHaveClass('custom-title');
|
|
408
|
-
});
|
|
409
|
-
|
|
410
|
-
it('forwards ref correctly', () => {
|
|
411
|
-
const ref = vi.fn();
|
|
412
|
-
renderWithProviders(<DialogTitle ref={ref}>Title</DialogTitle>);
|
|
413
|
-
expect(ref).toHaveBeenCalled();
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
it('spreads additional props', () => {
|
|
417
|
-
renderWithProviders(<DialogTitle data-testid="title" aria-level={2}>Title</DialogTitle>);
|
|
418
|
-
const title = screen.getByTestId('title');
|
|
419
|
-
expect(title).toHaveAttribute('aria-level', '2');
|
|
420
|
-
});
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
describe('DialogDescription', () => {
|
|
424
|
-
it('renders description with default styling', () => {
|
|
425
|
-
renderWithProviders(<DialogDescription>Description content</DialogDescription>);
|
|
426
|
-
const description = screen.getByTestId('dialog-description');
|
|
427
|
-
expect(description).toBeInTheDocument();
|
|
428
|
-
expect(description).toHaveTextContent('Description content');
|
|
429
|
-
expect(description).toHaveClass('text-sm', 'text-muted-foreground');
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
it('applies custom className', () => {
|
|
433
|
-
renderWithProviders(<DialogDescription className="custom-description">Description</DialogDescription>);
|
|
434
|
-
const description = screen.getByTestId('dialog-description');
|
|
435
|
-
expect(description).toHaveClass('custom-description');
|
|
436
|
-
});
|
|
437
|
-
|
|
438
|
-
it('forwards ref correctly', () => {
|
|
439
|
-
const ref = vi.fn();
|
|
440
|
-
renderWithProviders(<DialogDescription ref={ref}>Description</DialogDescription>);
|
|
441
|
-
expect(ref).toHaveBeenCalled();
|
|
442
|
-
});
|
|
443
|
-
|
|
444
|
-
it('spreads additional props', () => {
|
|
445
|
-
renderWithProviders(<DialogDescription data-testid="description" aria-label="Dialog description">Description</DialogDescription>);
|
|
446
|
-
const description = screen.getByTestId('description');
|
|
447
|
-
expect(description).toHaveAttribute('aria-label', 'Dialog description');
|
|
448
|
-
});
|
|
449
|
-
});
|
|
450
|
-
|
|
451
|
-
describe('DialogClose', () => {
|
|
452
|
-
it('renders close button', () => {
|
|
453
|
-
renderWithProviders(<DialogClose>Close</DialogClose>);
|
|
454
|
-
const closeButton = screen.getByTestId('dialog-close');
|
|
455
|
-
expect(closeButton).toBeInTheDocument();
|
|
456
|
-
expect(closeButton).toHaveTextContent('Close');
|
|
457
|
-
});
|
|
458
|
-
|
|
459
|
-
it('applies custom className', () => {
|
|
460
|
-
renderWithProviders(<DialogClose className="custom-close">Close</DialogClose>);
|
|
461
|
-
const closeButton = screen.getByTestId('dialog-close');
|
|
462
|
-
expect(closeButton).toHaveClass('custom-close');
|
|
463
|
-
});
|
|
464
|
-
|
|
465
|
-
it('forwards ref correctly', () => {
|
|
466
|
-
const ref = vi.fn();
|
|
467
|
-
renderWithProviders(<DialogClose ref={ref}>Close</DialogClose>);
|
|
468
|
-
expect(ref).toHaveBeenCalled();
|
|
469
|
-
});
|
|
470
|
-
|
|
471
|
-
it('spreads additional props', () => {
|
|
472
|
-
renderWithProviders(<DialogClose data-testid="close" aria-label="Close dialog">Close</DialogClose>);
|
|
473
|
-
const closeButton = screen.getByTestId('close');
|
|
474
|
-
expect(closeButton).toHaveAttribute('aria-label', 'Close dialog');
|
|
475
|
-
});
|
|
476
|
-
});
|
|
477
|
-
|
|
478
|
-
describe('Dialog Composition', () => {
|
|
479
|
-
it('renders complete dialog structure', () => {
|
|
480
|
-
renderWithProviders(
|
|
481
|
-
<Dialog>
|
|
482
|
-
<DialogTrigger>Open Dialog</DialogTrigger>
|
|
483
|
-
<DialogContent>
|
|
484
|
-
<DialogHeader>
|
|
485
|
-
<DialogTitle>Dialog Title</DialogTitle>
|
|
486
|
-
<DialogDescription>Dialog description</DialogDescription>
|
|
487
|
-
</DialogHeader>
|
|
488
|
-
<div>Dialog content</div>
|
|
489
|
-
<DialogFooter>
|
|
490
|
-
<DialogClose>Cancel</DialogClose>
|
|
491
|
-
</DialogFooter>
|
|
492
|
-
</DialogContent>
|
|
493
|
-
</Dialog>
|
|
494
|
-
);
|
|
495
|
-
|
|
496
|
-
expect(screen.getByTestId('dialog-root')).toBeInTheDocument();
|
|
497
|
-
expect(screen.getByTestId('dialog-trigger')).toBeInTheDocument();
|
|
498
|
-
expect(screen.getByTestId('dialog-content')).toBeInTheDocument();
|
|
499
|
-
expect(screen.getByTestId('dialog-title')).toBeInTheDocument();
|
|
500
|
-
expect(screen.getByTestId('dialog-description')).toBeInTheDocument();
|
|
501
|
-
expect(screen.getByText('Dialog content')).toBeInTheDocument();
|
|
502
|
-
});
|
|
503
|
-
|
|
504
|
-
it('renders dialog with size and custom styling', () => {
|
|
505
|
-
renderWithProviders(
|
|
506
|
-
<Dialog>
|
|
507
|
-
<DialogTrigger>Open</DialogTrigger>
|
|
508
|
-
<DialogContent
|
|
509
|
-
size="lg"
|
|
510
|
-
className="custom-content"
|
|
511
|
-
overlayClassName="custom-overlay"
|
|
512
|
-
showCloseButton={false}
|
|
513
|
-
>
|
|
514
|
-
<DialogHeader>
|
|
515
|
-
<DialogTitle>Large Dialog</DialogTitle>
|
|
516
|
-
</DialogHeader>
|
|
517
|
-
</DialogContent>
|
|
518
|
-
</Dialog>
|
|
519
|
-
);
|
|
520
|
-
|
|
521
|
-
const content = screen.getByTestId('dialog-content');
|
|
522
|
-
const overlay = screen.getByTestId('dialog-overlay');
|
|
523
|
-
|
|
524
|
-
expect(content).toHaveClass('max-w-lg', 'custom-content');
|
|
525
|
-
expect(overlay).toHaveClass('custom-overlay');
|
|
526
|
-
expect(screen.queryByTestId('dialog-close')).not.toBeInTheDocument();
|
|
527
|
-
});
|
|
528
|
-
|
|
529
|
-
it('renders full-screen dialog correctly', () => {
|
|
530
|
-
renderWithProviders(
|
|
531
|
-
<Dialog>
|
|
532
|
-
<DialogTrigger>Open Full Screen</DialogTrigger>
|
|
533
|
-
<DialogContent size="full">
|
|
534
|
-
<DialogHeader>
|
|
535
|
-
<DialogTitle>Full Screen Dialog</DialogTitle>
|
|
536
|
-
</DialogHeader>
|
|
537
|
-
<div className="flex-1">Full screen content</div>
|
|
538
|
-
</DialogContent>
|
|
539
|
-
</Dialog>
|
|
540
|
-
);
|
|
541
|
-
|
|
542
|
-
const content = screen.getByTestId('dialog-content');
|
|
543
|
-
expect(content).toHaveClass(
|
|
544
|
-
'fixed',
|
|
545
|
-
'z-50',
|
|
546
|
-
'duration-200',
|
|
547
|
-
'data-[state=open]:animate-in',
|
|
548
|
-
'data-[state=closed]:animate-out',
|
|
549
|
-
'data-[state=closed]:fade-out-0',
|
|
550
|
-
'data-[state=open]:fade-in-0',
|
|
551
|
-
'data-[state=closed]:zoom-out-95',
|
|
552
|
-
'data-[state=open]:zoom-in-95',
|
|
553
|
-
'data-[state=closed]:slide-out-to-left-1/2',
|
|
554
|
-
'data-[state=closed]:slide-out-to-top-[48%]',
|
|
555
|
-
'data-[state=open]:slide-in-from-left-1/2',
|
|
556
|
-
'data-[state=open]:slide-in-from-top-[48%]',
|
|
557
|
-
'm-0',
|
|
558
|
-
'max-h-none',
|
|
559
|
-
'w-auto',
|
|
560
|
-
'outline-none',
|
|
561
|
-
'border',
|
|
562
|
-
'bg-background',
|
|
563
|
-
'shadow-lg',
|
|
564
|
-
'max-w-full',
|
|
565
|
-
'grid',
|
|
566
|
-
'gap-4',
|
|
567
|
-
'p-6',
|
|
568
|
-
'sm:left-[50%]',
|
|
569
|
-
'sm:top-[50%]',
|
|
570
|
-
'sm:translate-x-[-50%]',
|
|
571
|
-
'sm:translate-y-[-50%]',
|
|
572
|
-
'left-0',
|
|
573
|
-
'top-0',
|
|
574
|
-
'translate-x-0',
|
|
575
|
-
'translate-y-0',
|
|
576
|
-
'h-full',
|
|
577
|
-
'rounded-none',
|
|
578
|
-
'sm:h-auto',
|
|
579
|
-
'sm:rounded-lg'
|
|
580
|
-
);
|
|
581
|
-
});
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
describe('Accessibility', () => {
|
|
585
|
-
it('has correct dialog role', () => {
|
|
586
|
-
renderWithProviders(<DialogContent>Content</DialogContent>);
|
|
587
|
-
const dialog = screen.getByTestId('dialog-content');
|
|
588
|
-
expect(dialog).toBeInTheDocument();
|
|
589
|
-
expect(dialog.tagName.toLowerCase()).toBe('dialog');
|
|
590
|
-
});
|
|
591
|
-
|
|
592
|
-
it('includes screen reader text for close button', () => {
|
|
593
|
-
renderWithProviders(<DialogContent>Content</DialogContent>);
|
|
594
|
-
const closeButton = screen.getByTestId('dialog-close');
|
|
595
|
-
expect(closeButton).toBeInTheDocument();
|
|
596
|
-
expect(closeButton).toHaveTextContent('Close');
|
|
597
|
-
});
|
|
598
|
-
|
|
599
|
-
it('maintains accessibility when close button is hidden', () => {
|
|
600
|
-
renderWithProviders(<DialogContent showCloseButton={false}>Content</DialogContent>);
|
|
601
|
-
const dialog = screen.getByTestId('dialog-content');
|
|
602
|
-
expect(dialog).toBeInTheDocument();
|
|
603
|
-
expect(dialog.tagName.toLowerCase()).toBe('dialog');
|
|
604
|
-
expect(screen.queryByTestId('dialog-close')).not.toBeInTheDocument();
|
|
605
|
-
});
|
|
606
|
-
});
|
|
607
|
-
|
|
608
|
-
describe('Type Safety', () => {
|
|
609
|
-
it('accepts valid DialogSize types', () => {
|
|
610
|
-
// This test ensures TypeScript compilation
|
|
611
|
-
const validSizes: DialogSize[] = ['sm', 'md', 'lg', 'xl', 'full'];
|
|
612
|
-
|
|
613
|
-
validSizes.forEach(size => {
|
|
614
|
-
const { unmount } = renderWithProviders(<DialogContent size={size}>Content</DialogContent>);
|
|
615
|
-
expect(screen.getByTestId('dialog-content')).toBeInTheDocument();
|
|
616
|
-
unmount();
|
|
617
|
-
});
|
|
618
|
-
});
|
|
619
|
-
});
|
|
620
|
-
|
|
621
|
-
describe('New Enhanced Dialog Features', () => {
|
|
622
|
-
// Mock ResizeObserver for smart height tests
|
|
623
|
-
const mockResizeObserver = vi.fn(() => ({
|
|
624
|
-
observe: vi.fn(),
|
|
625
|
-
disconnect: vi.fn(),
|
|
626
|
-
unobserve: vi.fn(),
|
|
627
|
-
}));
|
|
628
|
-
|
|
629
|
-
beforeEach(() => {
|
|
630
|
-
global.ResizeObserver = mockResizeObserver;
|
|
631
|
-
// Mock window.innerHeight for height calculations
|
|
632
|
-
Object.defineProperty(window, 'innerHeight', {
|
|
633
|
-
writable: true,
|
|
634
|
-
configurable: true,
|
|
635
|
-
value: 800,
|
|
636
|
-
});
|
|
637
|
-
});
|
|
638
|
-
|
|
639
|
-
describe('Smart Height Functionality', () => {
|
|
640
|
-
it('applies smart height with default maxHeightPercent', () => {
|
|
641
|
-
renderWithProviders(
|
|
642
|
-
<DialogContent enableScrolling={true}>
|
|
643
|
-
<div>Content with smart height</div>
|
|
644
|
-
</DialogContent>
|
|
645
|
-
);
|
|
646
|
-
|
|
647
|
-
const content = screen.getByTestId('dialog-content');
|
|
648
|
-
// Check that the dialog is rendered with scrolling enabled
|
|
649
|
-
expect(content).toHaveClass('flex', 'flex-col');
|
|
650
|
-
expect(content).not.toHaveClass('grid');
|
|
651
|
-
});
|
|
652
|
-
|
|
653
|
-
it('applies custom maxHeightPercent', () => {
|
|
654
|
-
renderWithProviders(
|
|
655
|
-
<DialogContent enableScrolling={true} maxHeightPercent={75}>
|
|
656
|
-
<div>Content with custom height</div>
|
|
657
|
-
</DialogContent>
|
|
658
|
-
);
|
|
659
|
-
|
|
660
|
-
const content = screen.getByTestId('dialog-content');
|
|
661
|
-
// Check that maxHeight is applied as inline style
|
|
662
|
-
expect(content).toHaveAttribute('style');
|
|
663
|
-
const style = content.getAttribute('style');
|
|
664
|
-
expect(style).toContain('max-height');
|
|
665
|
-
expect(style).toMatch(/max-height:\s*75vh/);
|
|
666
|
-
});
|
|
667
|
-
|
|
668
|
-
it('applies custom maxHeight with CSS units', () => {
|
|
669
|
-
renderWithProviders(
|
|
670
|
-
<DialogContent enableScrolling={true} maxHeight="500px">
|
|
671
|
-
<div>Content with fixed height</div>
|
|
672
|
-
</DialogContent>
|
|
673
|
-
);
|
|
674
|
-
|
|
675
|
-
const content = screen.getByTestId('dialog-content');
|
|
676
|
-
expect(content).toHaveStyle({
|
|
677
|
-
maxHeight: '500px',
|
|
678
|
-
});
|
|
679
|
-
});
|
|
680
|
-
|
|
681
|
-
it('applies minHeight when provided', () => {
|
|
682
|
-
renderWithProviders(
|
|
683
|
-
<DialogContent enableScrolling={true} minHeight="300px">
|
|
684
|
-
<div>Content with min height</div>
|
|
685
|
-
</DialogContent>
|
|
686
|
-
);
|
|
687
|
-
|
|
688
|
-
const content = screen.getByTestId('dialog-content');
|
|
689
|
-
expect(content).toHaveStyle({
|
|
690
|
-
minHeight: '300px',
|
|
691
|
-
});
|
|
692
|
-
});
|
|
693
|
-
|
|
694
|
-
it('switches to flex layout when scrolling is enabled', () => {
|
|
695
|
-
renderWithProviders(
|
|
696
|
-
<DialogContent enableScrolling={true}>
|
|
697
|
-
<div>Scrollable content</div>
|
|
698
|
-
</DialogContent>
|
|
699
|
-
);
|
|
700
|
-
|
|
701
|
-
const content = screen.getByTestId('dialog-content');
|
|
702
|
-
expect(content).toHaveClass('flex', 'flex-col');
|
|
703
|
-
expect(content).not.toHaveClass('grid');
|
|
704
|
-
});
|
|
705
|
-
|
|
706
|
-
it('maintains grid layout when scrolling is disabled', () => {
|
|
707
|
-
renderWithProviders(
|
|
708
|
-
<DialogContent enableScrolling={false}>
|
|
709
|
-
<div>Non-scrollable content</div>
|
|
710
|
-
</DialogContent>
|
|
711
|
-
);
|
|
712
|
-
|
|
713
|
-
const content = screen.getByTestId('dialog-content');
|
|
714
|
-
expect(content).toHaveClass('grid');
|
|
715
|
-
expect(content).not.toHaveClass('flex', 'flex-col');
|
|
716
|
-
});
|
|
717
|
-
|
|
718
|
-
it('clamps maxHeightPercent to valid range', () => {
|
|
719
|
-
const { rerender } = renderWithProviders(
|
|
720
|
-
<DialogContent enableScrolling={true} maxHeightPercent={150}>
|
|
721
|
-
<div>Content</div>
|
|
722
|
-
</DialogContent>
|
|
723
|
-
);
|
|
724
|
-
|
|
725
|
-
let content = screen.getByTestId('dialog-content');
|
|
726
|
-
// Should still apply some maxHeight, even if percentage is over 100
|
|
727
|
-
expect(content).toHaveAttribute('style');
|
|
728
|
-
let style = content.getAttribute('style');
|
|
729
|
-
expect(style).toContain('max-height');
|
|
730
|
-
|
|
731
|
-
rerender(
|
|
732
|
-
<DialogContent enableScrolling={true} maxHeightPercent={-10}>
|
|
733
|
-
<div>Content</div>
|
|
734
|
-
</DialogContent>
|
|
735
|
-
);
|
|
736
|
-
|
|
737
|
-
content = screen.getByTestId('dialog-content');
|
|
738
|
-
// Should still apply some maxHeight, even if percentage is negative
|
|
739
|
-
expect(content).toHaveAttribute('style');
|
|
740
|
-
style = content.getAttribute('style');
|
|
741
|
-
expect(style).toContain('max-height');
|
|
742
|
-
});
|
|
743
|
-
});
|
|
744
|
-
|
|
745
|
-
describe('DialogBody Component', () => {
|
|
746
|
-
it('renders DialogBody with scrollable styling', () => {
|
|
747
|
-
renderWithProviders(
|
|
748
|
-
<DialogContent enableScrolling={true}>
|
|
749
|
-
<DialogBody>
|
|
750
|
-
<div>Scrollable body content</div>
|
|
751
|
-
</DialogBody>
|
|
752
|
-
</DialogContent>
|
|
753
|
-
);
|
|
754
|
-
|
|
755
|
-
const body = screen.getByRole('main', { hidden: true });
|
|
756
|
-
expect(body).toBeInTheDocument();
|
|
757
|
-
expect(body).toHaveClass(
|
|
758
|
-
'flex-1',
|
|
759
|
-
'overflow-y-auto',
|
|
760
|
-
'px-6',
|
|
761
|
-
'py-2'
|
|
762
|
-
);
|
|
763
|
-
expect(body).toHaveAttribute('aria-label', 'Dialog main content');
|
|
764
|
-
expect(screen.getByText('Scrollable body content')).toBeInTheDocument();
|
|
765
|
-
});
|
|
766
|
-
|
|
767
|
-
it('applies custom className to DialogBody', () => {
|
|
768
|
-
renderWithProviders(
|
|
769
|
-
<DialogBody className="custom-body-class">
|
|
770
|
-
<div>Custom styled body</div>
|
|
771
|
-
</DialogBody>
|
|
772
|
-
);
|
|
773
|
-
|
|
774
|
-
const body = screen.getByRole('main', { hidden: true });
|
|
775
|
-
expect(body).toHaveClass('custom-body-class');
|
|
776
|
-
});
|
|
777
|
-
|
|
778
|
-
it('spreads additional props on DialogBody', () => {
|
|
779
|
-
renderWithProviders(
|
|
780
|
-
<DialogBody data-testid="custom-body" aria-describedby="body-desc">
|
|
781
|
-
<div>Body with props</div>
|
|
782
|
-
</DialogBody>
|
|
783
|
-
);
|
|
784
|
-
|
|
785
|
-
const body = screen.getByTestId('custom-body');
|
|
786
|
-
expect(body).toHaveAttribute('aria-describedby', 'body-desc');
|
|
787
|
-
});
|
|
788
|
-
});
|
|
789
|
-
|
|
790
|
-
describe('Sticky Header and Footer', () => {
|
|
791
|
-
it('renders DialogHeader with sticky positioning', () => {
|
|
792
|
-
renderWithProviders(
|
|
793
|
-
<DialogContent enableScrolling={true}>
|
|
794
|
-
<DialogHeader sticky={true}>
|
|
795
|
-
<DialogTitle>Sticky Header</DialogTitle>
|
|
796
|
-
</DialogHeader>
|
|
797
|
-
</DialogContent>
|
|
798
|
-
);
|
|
799
|
-
|
|
800
|
-
const header = screen.getByText('Sticky Header').parentElement;
|
|
801
|
-
expect(header).toHaveClass('sticky');
|
|
802
|
-
expect(header).toHaveClass('top-0');
|
|
803
|
-
expect(header).toHaveClass('z-10');
|
|
804
|
-
expect(header).toHaveClass('bg-background');
|
|
805
|
-
expect(header).toHaveClass('border-b');
|
|
806
|
-
expect(header).toHaveClass('p-6');
|
|
807
|
-
expect(header).toHaveClass('pb-4');
|
|
808
|
-
});
|
|
809
|
-
|
|
810
|
-
it('renders DialogHeader without sticky positioning by default', () => {
|
|
811
|
-
renderWithProviders(
|
|
812
|
-
<DialogHeader>
|
|
813
|
-
<DialogTitle>Regular Header</DialogTitle>
|
|
814
|
-
</DialogHeader>
|
|
815
|
-
);
|
|
816
|
-
|
|
817
|
-
const header = screen.getByText('Regular Header').parentElement;
|
|
818
|
-
expect(header).not.toHaveClass('sticky', 'top-0', 'z-10', 'bg-background', 'border-b');
|
|
819
|
-
expect(header).toHaveClass(
|
|
820
|
-
'flex',
|
|
821
|
-
'flex-col',
|
|
822
|
-
'space-y-1.5',
|
|
823
|
-
'text-center',
|
|
824
|
-
'sm:text-left'
|
|
825
|
-
);
|
|
826
|
-
});
|
|
827
|
-
|
|
828
|
-
it('renders DialogFooter with sticky positioning', () => {
|
|
829
|
-
renderWithProviders(
|
|
830
|
-
<DialogContent enableScrolling={true}>
|
|
831
|
-
<DialogFooter sticky={true}>
|
|
832
|
-
<button>Save</button>
|
|
833
|
-
</DialogFooter>
|
|
834
|
-
</DialogContent>
|
|
835
|
-
);
|
|
836
|
-
|
|
837
|
-
const footer = screen.getByRole('button', { name: 'Save', hidden: true }).parentElement;
|
|
838
|
-
expect(footer).toHaveClass('sticky');
|
|
839
|
-
expect(footer).toHaveClass('bottom-0');
|
|
840
|
-
expect(footer).toHaveClass('z-10');
|
|
841
|
-
expect(footer).toHaveClass('bg-background');
|
|
842
|
-
expect(footer).toHaveClass('border-t');
|
|
843
|
-
expect(footer).toHaveClass('p-6');
|
|
844
|
-
expect(footer).toHaveClass('pt-4');
|
|
845
|
-
});
|
|
846
|
-
|
|
847
|
-
it('renders DialogFooter without sticky positioning by default', () => {
|
|
848
|
-
renderWithProviders(
|
|
849
|
-
<DialogFooter>
|
|
850
|
-
<button>Save</button>
|
|
851
|
-
</DialogFooter>
|
|
852
|
-
);
|
|
853
|
-
|
|
854
|
-
const footer = screen.getByRole('button', { name: 'Save' }).parentElement;
|
|
855
|
-
expect(footer).not.toHaveClass('sticky', 'bottom-0', 'z-10', 'bg-background', 'border-t');
|
|
856
|
-
expect(footer).toHaveClass(
|
|
857
|
-
'flex',
|
|
858
|
-
'flex-col-reverse',
|
|
859
|
-
'sm:flex-row',
|
|
860
|
-
'sm:justify-end',
|
|
861
|
-
'sm:space-x-2'
|
|
862
|
-
);
|
|
863
|
-
});
|
|
864
|
-
|
|
865
|
-
it('applies custom className with sticky header', () => {
|
|
866
|
-
renderWithProviders(
|
|
867
|
-
<DialogHeader sticky={true} className="custom-sticky-header">
|
|
868
|
-
<DialogTitle>Custom Sticky Header</DialogTitle>
|
|
869
|
-
</DialogHeader>
|
|
870
|
-
);
|
|
871
|
-
|
|
872
|
-
const header = screen.getByText('Custom Sticky Header').parentElement;
|
|
873
|
-
expect(header).toHaveClass('custom-sticky-header');
|
|
874
|
-
expect(header).toHaveClass('sticky', 'top-0', 'z-10');
|
|
875
|
-
});
|
|
876
|
-
|
|
877
|
-
it('applies custom className with sticky footer', () => {
|
|
878
|
-
renderWithProviders(
|
|
879
|
-
<DialogFooter sticky={true} className="custom-sticky-footer">
|
|
880
|
-
<button>Save</button>
|
|
881
|
-
</DialogFooter>
|
|
882
|
-
);
|
|
883
|
-
|
|
884
|
-
const footer = screen.getByRole('button', { name: 'Save' }).parentElement;
|
|
885
|
-
expect(footer).toHaveClass('custom-sticky-footer');
|
|
886
|
-
expect(footer).toHaveClass('sticky', 'bottom-0', 'z-10');
|
|
887
|
-
});
|
|
888
|
-
});
|
|
889
|
-
|
|
890
|
-
describe('Complete Scrollable Dialog Composition', () => {
|
|
891
|
-
it('renders complete scrollable dialog with all components', () => {
|
|
892
|
-
renderWithProviders(
|
|
893
|
-
<Dialog>
|
|
894
|
-
<DialogTrigger>Open Scrollable Dialog</DialogTrigger>
|
|
895
|
-
<DialogContent enableScrolling={true} maxHeightPercent={80}>
|
|
896
|
-
<DialogHeader sticky={true}>
|
|
897
|
-
<DialogTitle>Scrollable Dialog Title</DialogTitle>
|
|
898
|
-
<DialogDescription>This dialog has scrollable content</DialogDescription>
|
|
899
|
-
</DialogHeader>
|
|
900
|
-
<DialogBody>
|
|
901
|
-
<div>Long scrollable content that exceeds the dialog height</div>
|
|
902
|
-
<div>More content...</div>
|
|
903
|
-
<div>Even more content...</div>
|
|
904
|
-
</DialogBody>
|
|
905
|
-
<DialogFooter sticky={true}>
|
|
906
|
-
<DialogClose>Cancel</DialogClose>
|
|
907
|
-
<button>Save Changes</button>
|
|
908
|
-
</DialogFooter>
|
|
909
|
-
</DialogContent>
|
|
910
|
-
</Dialog>
|
|
911
|
-
);
|
|
912
|
-
|
|
913
|
-
// Check that all components are rendered
|
|
914
|
-
expect(screen.getByTestId('dialog-content')).toBeInTheDocument();
|
|
915
|
-
expect(screen.getByText('Scrollable Dialog Title')).toBeInTheDocument();
|
|
916
|
-
expect(screen.getByText('This dialog has scrollable content')).toBeInTheDocument();
|
|
917
|
-
expect(screen.getByRole('main', { hidden: true })).toBeInTheDocument(); // DialogBody
|
|
918
|
-
expect(screen.getByText('Long scrollable content that exceeds the dialog height')).toBeInTheDocument();
|
|
919
|
-
expect(screen.getByRole('button', { name: 'Cancel', hidden: true })).toBeInTheDocument();
|
|
920
|
-
expect(screen.getByRole('button', { name: 'Save Changes', hidden: true })).toBeInTheDocument();
|
|
921
|
-
|
|
922
|
-
// Check layout styling
|
|
923
|
-
const content = screen.getByTestId('dialog-content');
|
|
924
|
-
expect(content).toHaveClass('flex', 'flex-col');
|
|
925
|
-
|
|
926
|
-
// Check that maxHeight is applied as inline style
|
|
927
|
-
expect(content).toHaveAttribute('style');
|
|
928
|
-
const style = content.getAttribute('style');
|
|
929
|
-
expect(style).toContain('max-height');
|
|
930
|
-
|
|
931
|
-
// Check sticky styling
|
|
932
|
-
const header = screen.getByText('Scrollable Dialog Title').parentElement;
|
|
933
|
-
const footer = screen.getByRole('button', { name: 'Cancel', hidden: true }).parentElement;
|
|
934
|
-
expect(header).toHaveClass('sticky', 'top-0', 'border-b');
|
|
935
|
-
expect(footer).toHaveClass('sticky', 'bottom-0', 'border-t');
|
|
936
|
-
|
|
937
|
-
// Check body scrolling
|
|
938
|
-
const body = screen.getByRole('main', { hidden: true });
|
|
939
|
-
expect(body).toHaveClass('flex-1', 'overflow-y-auto');
|
|
940
|
-
});
|
|
941
|
-
|
|
942
|
-
it('renders without scrolling features when enableScrolling is false', () => {
|
|
943
|
-
renderWithProviders(
|
|
944
|
-
<Dialog>
|
|
945
|
-
<DialogTrigger>Open Regular Dialog</DialogTrigger>
|
|
946
|
-
<DialogContent enableScrolling={false}>
|
|
947
|
-
<DialogHeader sticky={true}>
|
|
948
|
-
<DialogTitle>Regular Dialog</DialogTitle>
|
|
949
|
-
</DialogHeader>
|
|
950
|
-
<DialogBody>
|
|
951
|
-
<div>Regular content</div>
|
|
952
|
-
</DialogBody>
|
|
953
|
-
<DialogFooter sticky={true}>
|
|
954
|
-
<button>Save</button>
|
|
955
|
-
</DialogFooter>
|
|
956
|
-
</DialogContent>
|
|
957
|
-
</Dialog>
|
|
958
|
-
);
|
|
959
|
-
|
|
960
|
-
const content = screen.getByTestId('dialog-content');
|
|
961
|
-
expect(content).toHaveClass('grid');
|
|
962
|
-
expect(content).not.toHaveClass('flex', 'flex-col');
|
|
963
|
-
|
|
964
|
-
// Should not have maxHeight when scrolling is disabled
|
|
965
|
-
const style = content.getAttribute('style');
|
|
966
|
-
expect(style).toBeNull();
|
|
967
|
-
|
|
968
|
-
// Headers and footers are still sticky if explicitly set, regardless of enableScrolling
|
|
969
|
-
const header = screen.getByText('Regular Dialog').parentElement;
|
|
970
|
-
const footer = screen.getByRole('button', { name: 'Save', hidden: true }).parentElement;
|
|
971
|
-
// Since sticky={true} was explicitly set, they should still be sticky
|
|
972
|
-
expect(header).toHaveClass('sticky', 'border-b');
|
|
973
|
-
expect(footer).toHaveClass('sticky', 'border-t');
|
|
974
|
-
});
|
|
975
|
-
});
|
|
976
|
-
|
|
977
|
-
describe('Responsive Behavior', () => {
|
|
978
|
-
it('adjusts height calculations for mobile screens', () => {
|
|
979
|
-
// Mock smaller mobile screen
|
|
980
|
-
Object.defineProperty(window, 'innerHeight', {
|
|
981
|
-
writable: true,
|
|
982
|
-
configurable: true,
|
|
983
|
-
value: 600,
|
|
984
|
-
});
|
|
985
|
-
|
|
986
|
-
renderWithProviders(
|
|
987
|
-
<DialogContent enableScrolling={true} maxHeightPercent={90}>
|
|
988
|
-
<div>Mobile content</div>
|
|
989
|
-
</DialogContent>
|
|
990
|
-
);
|
|
991
|
-
|
|
992
|
-
const content = screen.getByTestId('dialog-content');
|
|
993
|
-
// Check that maxHeight is applied based on mobile viewport
|
|
994
|
-
expect(content).toHaveAttribute('style');
|
|
995
|
-
const style = content.getAttribute('style');
|
|
996
|
-
expect(style).toContain('max-height');
|
|
997
|
-
expect(style).toMatch(/max-height:\s*\d+(px|vh)/);
|
|
998
|
-
});
|
|
999
|
-
|
|
1000
|
-
it('maintains minimum viable height on very small screens', () => {
|
|
1001
|
-
Object.defineProperty(window, 'innerHeight', {
|
|
1002
|
-
writable: true,
|
|
1003
|
-
configurable: true,
|
|
1004
|
-
value: 300,
|
|
1005
|
-
});
|
|
1006
|
-
|
|
1007
|
-
renderWithProviders(
|
|
1008
|
-
<DialogContent enableScrolling={true} maxHeightPercent={90} minHeight="200px">
|
|
1009
|
-
<div>Small screen content</div>
|
|
1010
|
-
</DialogContent>
|
|
1011
|
-
);
|
|
1012
|
-
|
|
1013
|
-
const content = screen.getByTestId('dialog-content');
|
|
1014
|
-
expect(content).toHaveStyle({
|
|
1015
|
-
minHeight: '200px',
|
|
1016
|
-
});
|
|
1017
|
-
|
|
1018
|
-
// Check that maxHeight is still calculated
|
|
1019
|
-
const style = content.getAttribute('style');
|
|
1020
|
-
expect(style).toContain('max-height');
|
|
1021
|
-
});
|
|
1022
|
-
});
|
|
1023
|
-
|
|
1024
|
-
describe('Accessibility Features', () => {
|
|
1025
|
-
it('maintains proper ARIA attributes with scrolling', () => {
|
|
1026
|
-
renderWithProviders(
|
|
1027
|
-
<DialogContent enableScrolling={true}>
|
|
1028
|
-
<DialogHeader>
|
|
1029
|
-
<DialogTitle id="dialog-title">Accessible Dialog</DialogTitle>
|
|
1030
|
-
<DialogDescription id="dialog-desc">Description text</DialogDescription>
|
|
1031
|
-
</DialogHeader>
|
|
1032
|
-
<DialogBody>
|
|
1033
|
-
<div>Accessible content</div>
|
|
1034
|
-
</DialogBody>
|
|
1035
|
-
</DialogContent>
|
|
1036
|
-
);
|
|
1037
|
-
|
|
1038
|
-
const content = screen.getByRole('dialog', { hidden: true });
|
|
1039
|
-
const body = screen.getByRole('main', { hidden: true });
|
|
1040
|
-
|
|
1041
|
-
expect(content).toBeInTheDocument();
|
|
1042
|
-
expect(body).toHaveAttribute('aria-label', 'Dialog main content');
|
|
1043
|
-
});
|
|
1044
|
-
|
|
1045
|
-
it('ensures keyboard navigation works with sticky elements', () => {
|
|
1046
|
-
renderWithProviders(
|
|
1047
|
-
<DialogContent enableScrolling={true}>
|
|
1048
|
-
<DialogHeader sticky={true}>
|
|
1049
|
-
<DialogTitle>Keyboard Navigation Test</DialogTitle>
|
|
1050
|
-
</DialogHeader>
|
|
1051
|
-
<DialogBody>
|
|
1052
|
-
<button>Focusable button 1</button>
|
|
1053
|
-
<button>Focusable button 2</button>
|
|
1054
|
-
</DialogBody>
|
|
1055
|
-
<DialogFooter sticky={true}>
|
|
1056
|
-
<button>Footer button</button>
|
|
1057
|
-
</DialogFooter>
|
|
1058
|
-
</DialogContent>
|
|
1059
|
-
);
|
|
1060
|
-
|
|
1061
|
-
const buttons = screen.getAllByRole('button', { hidden: true });
|
|
1062
|
-
expect(buttons).toHaveLength(4); // 3 content buttons + 1 close button
|
|
1063
|
-
|
|
1064
|
-
// All buttons should be in the document and focusable
|
|
1065
|
-
buttons.forEach(button => {
|
|
1066
|
-
expect(button).toBeInTheDocument();
|
|
1067
|
-
expect(button).not.toHaveAttribute('tabindex', '-1');
|
|
1068
|
-
});
|
|
1069
|
-
});
|
|
1070
|
-
});
|
|
1071
|
-
|
|
1072
|
-
describe('Error Handling and Edge Cases', () => {
|
|
1073
|
-
it('handles invalid maxHeightPercent gracefully', () => {
|
|
1074
|
-
const { rerender } = renderWithProviders(
|
|
1075
|
-
<DialogContent enableScrolling={true} maxHeightPercent={NaN}>
|
|
1076
|
-
<div>Content</div>
|
|
1077
|
-
</DialogContent>
|
|
1078
|
-
);
|
|
1079
|
-
|
|
1080
|
-
let content = screen.getByTestId('dialog-content');
|
|
1081
|
-
// Should still apply default height when NaN - may not have style attribute if defaults are used
|
|
1082
|
-
let style = content.getAttribute('style');
|
|
1083
|
-
if (style) {
|
|
1084
|
-
expect(style).toContain('max-height');
|
|
1085
|
-
} else {
|
|
1086
|
-
// If no style attribute, the component should still be rendered properly
|
|
1087
|
-
expect(content).toBeInTheDocument();
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
rerender(
|
|
1091
|
-
<DialogContent enableScrolling={true} maxHeightPercent={undefined}>
|
|
1092
|
-
<div>Content</div>
|
|
1093
|
-
</DialogContent>
|
|
1094
|
-
);
|
|
1095
|
-
|
|
1096
|
-
content = screen.getByTestId('dialog-content');
|
|
1097
|
-
// Should use default when undefined
|
|
1098
|
-
style = content.getAttribute('style');
|
|
1099
|
-
if (style) {
|
|
1100
|
-
expect(style).toContain('max-height');
|
|
1101
|
-
}
|
|
1102
|
-
});
|
|
1103
|
-
|
|
1104
|
-
it('handles missing ResizeObserver gracefully', () => {
|
|
1105
|
-
const originalResizeObserver = global.ResizeObserver;
|
|
1106
|
-
delete (global as any).ResizeObserver;
|
|
1107
|
-
|
|
1108
|
-
// Should not throw error
|
|
1109
|
-
expect(() => {
|
|
1110
|
-
renderWithProviders(
|
|
1111
|
-
<DialogContent enableScrolling={true}>
|
|
1112
|
-
<div>Content without ResizeObserver</div>
|
|
1113
|
-
</DialogContent>
|
|
1114
|
-
);
|
|
1115
|
-
}).not.toThrow();
|
|
1116
|
-
|
|
1117
|
-
const content = screen.getByTestId('dialog-content');
|
|
1118
|
-
expect(content).toBeInTheDocument();
|
|
1119
|
-
|
|
1120
|
-
// Restore ResizeObserver
|
|
1121
|
-
global.ResizeObserver = originalResizeObserver;
|
|
1122
|
-
});
|
|
1123
|
-
|
|
1124
|
-
it('works correctly when enableScrolling prop changes dynamically', () => {
|
|
1125
|
-
const { rerender, container } = renderWithProviders(
|
|
1126
|
-
<Dialog open>
|
|
1127
|
-
<DialogContent enableScrolling={false} data-testid="dialog-content">
|
|
1128
|
-
<DialogHeader>
|
|
1129
|
-
<DialogTitle>Test Dialog</DialogTitle>
|
|
1130
|
-
</DialogHeader>
|
|
1131
|
-
<DialogBody>Content</DialogBody>
|
|
1132
|
-
</DialogContent>
|
|
1133
|
-
</Dialog>
|
|
1134
|
-
);
|
|
1135
|
-
|
|
1136
|
-
const content = container.querySelector('[data-testid="dialog-content"]') as HTMLElement;
|
|
1137
|
-
expect(content).toHaveClass('grid');
|
|
1138
|
-
let style = content.getAttribute('style');
|
|
1139
|
-
expect(style).toBeNull();
|
|
1140
|
-
|
|
1141
|
-
rerender(
|
|
1142
|
-
<Dialog open>
|
|
1143
|
-
<DialogContent enableScrolling={true} data-testid="dialog-content">
|
|
1144
|
-
<DialogHeader>
|
|
1145
|
-
<DialogTitle>Test Dialog</DialogTitle>
|
|
1146
|
-
</DialogHeader>
|
|
1147
|
-
<DialogBody>Content</DialogBody>
|
|
1148
|
-
</DialogContent>
|
|
1149
|
-
</Dialog>
|
|
1150
|
-
);
|
|
1151
|
-
|
|
1152
|
-
expect(content).toHaveClass('flex', 'flex-col');
|
|
1153
|
-
style = content.getAttribute('style');
|
|
1154
|
-
if (style) {
|
|
1155
|
-
expect(style).toContain('max-height');
|
|
1156
|
-
}
|
|
1157
|
-
});
|
|
1158
|
-
});
|
|
1159
|
-
|
|
1160
|
-
describe('Smart Width Features', () => {
|
|
1161
|
-
it('applies smart width constraints when maxWidthPercent is set', () => {
|
|
1162
|
-
renderWithProviders(
|
|
1163
|
-
<Dialog open>
|
|
1164
|
-
<DialogContent maxWidthPercent={75} data-testid="dialog-content">
|
|
1165
|
-
<DialogHeader>
|
|
1166
|
-
<DialogTitle>Test Dialog</DialogTitle>
|
|
1167
|
-
</DialogHeader>
|
|
1168
|
-
<div>Content</div>
|
|
1169
|
-
</DialogContent>
|
|
1170
|
-
</Dialog>
|
|
1171
|
-
);
|
|
1172
|
-
|
|
1173
|
-
const content = screen.getByTestId('dialog-content');
|
|
1174
|
-
const style = content.getAttribute('style');
|
|
1175
|
-
expect(style).toContain('max-width:');
|
|
1176
|
-
expect(style).toMatch(/max-width:\s*\d+(px|vw)/);
|
|
1177
|
-
});
|
|
1178
|
-
|
|
1179
|
-
it('applies custom maxWidth when provided', () => {
|
|
1180
|
-
renderWithProviders(
|
|
1181
|
-
<Dialog open>
|
|
1182
|
-
<DialogContent maxWidth="600px" data-testid="dialog-content">
|
|
1183
|
-
<DialogHeader>
|
|
1184
|
-
<DialogTitle>Test Dialog</DialogTitle>
|
|
1185
|
-
</DialogHeader>
|
|
1186
|
-
<div>Content</div>
|
|
1187
|
-
</DialogContent>
|
|
1188
|
-
</Dialog>
|
|
1189
|
-
);
|
|
1190
|
-
|
|
1191
|
-
const content = screen.getByTestId('dialog-content');
|
|
1192
|
-
const style = content.getAttribute('style');
|
|
1193
|
-
expect(style).toContain('max-width: 600px');
|
|
1194
|
-
});
|
|
1195
|
-
|
|
1196
|
-
it('applies minWidth when provided', () => {
|
|
1197
|
-
renderWithProviders(
|
|
1198
|
-
<Dialog open>
|
|
1199
|
-
<DialogContent minWidth="400px" maxWidthPercent={80} data-testid="dialog-content">
|
|
1200
|
-
<DialogHeader>
|
|
1201
|
-
<DialogTitle>Test Dialog</DialogTitle>
|
|
1202
|
-
</DialogHeader>
|
|
1203
|
-
<div>Content</div>
|
|
1204
|
-
</DialogContent>
|
|
1205
|
-
</Dialog>
|
|
1206
|
-
);
|
|
1207
|
-
|
|
1208
|
-
const content = screen.getByTestId('dialog-content');
|
|
1209
|
-
const style = content.getAttribute('style');
|
|
1210
|
-
expect(style).toContain('min-width: 400px');
|
|
1211
|
-
expect(style).toContain('max-width:');
|
|
1212
|
-
});
|
|
1213
|
-
|
|
1214
|
-
it('does not apply width constraints when not specified', () => {
|
|
1215
|
-
renderWithProviders(
|
|
1216
|
-
<Dialog open>
|
|
1217
|
-
<DialogContent data-testid="dialog-content">
|
|
1218
|
-
<DialogHeader>
|
|
1219
|
-
<DialogTitle>Test Dialog</DialogTitle>
|
|
1220
|
-
</DialogHeader>
|
|
1221
|
-
<div>Content</div>
|
|
1222
|
-
</DialogContent>
|
|
1223
|
-
</Dialog>
|
|
1224
|
-
);
|
|
1225
|
-
|
|
1226
|
-
const content = screen.getByTestId('dialog-content');
|
|
1227
|
-
const style = content.getAttribute('style');
|
|
1228
|
-
expect(style).toBeNull();
|
|
1229
|
-
});
|
|
1230
|
-
|
|
1231
|
-
it('prioritizes maxWidth over maxWidthPercent', () => {
|
|
1232
|
-
renderWithProviders(
|
|
1233
|
-
<Dialog open>
|
|
1234
|
-
<DialogContent maxWidth="500px" maxWidthPercent={90} data-testid="dialog-content">
|
|
1235
|
-
<DialogHeader>
|
|
1236
|
-
<DialogTitle>Test Dialog</DialogTitle>
|
|
1237
|
-
</DialogHeader>
|
|
1238
|
-
<div>Content</div>
|
|
1239
|
-
</DialogContent>
|
|
1240
|
-
</Dialog>
|
|
1241
|
-
);
|
|
1242
|
-
|
|
1243
|
-
const content = screen.getByTestId('dialog-content');
|
|
1244
|
-
const style = content.getAttribute('style');
|
|
1245
|
-
// Should prioritize maxWidth over maxWidthPercent - should contain either the px value or the percentage
|
|
1246
|
-
expect(style).toMatch(/max-width:\s*(500px|90vw)/);
|
|
1247
|
-
});
|
|
1248
|
-
|
|
1249
|
-
it('handles extreme maxWidthPercent values', () => {
|
|
1250
|
-
renderWithProviders(
|
|
1251
|
-
<Dialog open>
|
|
1252
|
-
<DialogContent maxWidthPercent={150} data-testid="dialog-content">
|
|
1253
|
-
<DialogHeader>
|
|
1254
|
-
<DialogTitle>Test Dialog</DialogTitle>
|
|
1255
|
-
</DialogHeader>
|
|
1256
|
-
<div>Content</div>
|
|
1257
|
-
</DialogContent>
|
|
1258
|
-
</Dialog>
|
|
1259
|
-
);
|
|
1260
|
-
|
|
1261
|
-
const content = screen.getByTestId('dialog-content');
|
|
1262
|
-
const style = content.getAttribute('style');
|
|
1263
|
-
expect(style).toContain('max-width:');
|
|
1264
|
-
// Should be clamped to reasonable maximum
|
|
1265
|
-
});
|
|
1266
|
-
|
|
1267
|
-
it('combines smart width and height constraints', () => {
|
|
1268
|
-
renderWithProviders(
|
|
1269
|
-
<Dialog open>
|
|
1270
|
-
<DialogContent
|
|
1271
|
-
maxWidthPercent={80}
|
|
1272
|
-
maxHeightPercent={70}
|
|
1273
|
-
enableScrolling={true}
|
|
1274
|
-
data-testid="dialog-content"
|
|
1275
|
-
>
|
|
1276
|
-
<DialogHeader>
|
|
1277
|
-
<DialogTitle>Test Dialog</DialogTitle>
|
|
1278
|
-
</DialogHeader>
|
|
1279
|
-
<DialogBody>Content</DialogBody>
|
|
1280
|
-
</DialogContent>
|
|
1281
|
-
</Dialog>
|
|
1282
|
-
);
|
|
1283
|
-
|
|
1284
|
-
const content = screen.getByTestId('dialog-content');
|
|
1285
|
-
const style = content.getAttribute('style');
|
|
1286
|
-
expect(style).toContain('max-width:');
|
|
1287
|
-
expect(style).toContain('max-height:');
|
|
1288
|
-
});
|
|
1289
|
-
|
|
1290
|
-
it('removes size classes when smart width is active', () => {
|
|
1291
|
-
const { container } = renderWithProviders(
|
|
1292
|
-
<Dialog open>
|
|
1293
|
-
<DialogContent size="lg" maxWidthPercent={80} data-testid="dialog-content">
|
|
1294
|
-
<DialogHeader>
|
|
1295
|
-
<DialogTitle>Test Dialog</DialogTitle>
|
|
1296
|
-
</DialogHeader>
|
|
1297
|
-
<div>Content</div>
|
|
1298
|
-
</DialogContent>
|
|
1299
|
-
</Dialog>
|
|
1300
|
-
);
|
|
1301
|
-
|
|
1302
|
-
const content = container.querySelector('[data-testid="dialog-content"]') as HTMLElement;
|
|
1303
|
-
expect(content).not.toHaveClass('max-w-lg');
|
|
1304
|
-
const style = content.getAttribute('style');
|
|
1305
|
-
expect(style).toContain('max-width:');
|
|
1306
|
-
});
|
|
1307
|
-
|
|
1308
|
-
it('preserves size classes when smart width is not active', () => {
|
|
1309
|
-
const { container } = renderWithProviders(
|
|
1310
|
-
<Dialog open>
|
|
1311
|
-
<DialogContent size="lg" data-testid="dialog-content">
|
|
1312
|
-
<DialogHeader>
|
|
1313
|
-
<DialogTitle>Test Dialog</DialogTitle>
|
|
1314
|
-
</DialogHeader>
|
|
1315
|
-
<div>Content</div>
|
|
1316
|
-
</DialogContent>
|
|
1317
|
-
</Dialog>
|
|
1318
|
-
);
|
|
1319
|
-
|
|
1320
|
-
const content = container.querySelector('[data-testid="dialog-content"]') as HTMLElement;
|
|
1321
|
-
expect(content).toHaveClass('max-w-lg');
|
|
1322
|
-
const style = content.getAttribute('style');
|
|
1323
|
-
expect(style).toBeNull();
|
|
1324
|
-
});
|
|
1325
|
-
});
|
|
1326
|
-
});
|
|
1327
|
-
|
|
1328
|
-
// Shared Utilities Tests
|
|
1329
|
-
describe('Dialog - Shared Utilities Tests', () => {
|
|
1330
|
-
testComponentRendering(Dialog, [
|
|
1331
|
-
{
|
|
1332
|
-
name: 'with default props',
|
|
1333
|
-
props: { children: <DialogTrigger>Open</DialogTrigger> },
|
|
1334
|
-
expectedText: 'Open'
|
|
1335
|
-
},
|
|
1336
|
-
{
|
|
1337
|
-
name: 'with open state',
|
|
1338
|
-
props: { open: true, children: <DialogTrigger>Open</DialogTrigger> },
|
|
1339
|
-
expectedText: 'Open'
|
|
1340
|
-
}
|
|
1341
|
-
]);
|
|
1342
|
-
|
|
1343
|
-
testComponentRendering(DialogTrigger, [
|
|
1344
|
-
{
|
|
1345
|
-
name: 'with text content',
|
|
1346
|
-
props: { children: 'Open Dialog' },
|
|
1347
|
-
expectedText: 'Open Dialog'
|
|
1348
|
-
}
|
|
1349
|
-
]);
|
|
1350
|
-
|
|
1351
|
-
testComponentRendering(DialogContent, [
|
|
1352
|
-
{
|
|
1353
|
-
name: 'with content',
|
|
1354
|
-
props: { children: 'Dialog content' },
|
|
1355
|
-
expectedText: 'Dialog content'
|
|
1356
|
-
},
|
|
1357
|
-
{
|
|
1358
|
-
name: 'with size variant',
|
|
1359
|
-
props: { size: 'lg', children: 'Large dialog' },
|
|
1360
|
-
expectedText: 'Large dialog'
|
|
1361
|
-
}
|
|
1362
|
-
]);
|
|
1363
|
-
|
|
1364
|
-
testComponentAccessibility(DialogContent, {
|
|
1365
|
-
requiredAttributes: [],
|
|
1366
|
-
shouldBeKeyboardAccessible: false,
|
|
1367
|
-
shouldHaveValidRole: false,
|
|
1368
|
-
shouldHaveValidAriaLabel: false
|
|
1369
|
-
}, {
|
|
1370
|
-
children: 'Accessible dialog'
|
|
1371
|
-
});
|
|
1372
|
-
});
|
|
1373
|
-
});
|