@jmruthers/pace-core 0.5.115 → 0.5.117
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/{AuthService-CVgsgtaZ.d.ts → AuthService-D4646R4b.d.ts} +9 -4
- package/dist/{DataTable-H5KJCAIS.js → DataTable-ZOAKQ3SU.js} +10 -9
- package/dist/{UnifiedAuthProvider-KZZUO27W.js → UnifiedAuthProvider-YFN7YGVN.js} +4 -3
- package/dist/{api-PKU4PUBO.js → api-TNIBJWLM.js} +3 -3
- package/dist/{audit-H4YJJF7R.js → audit-T36HM7IM.js} +2 -2
- package/dist/{chunk-SYXOZQ4P.js → chunk-2GJ5GL77.js} +1 -1
- package/dist/chunk-2GJ5GL77.js.map +1 -0
- package/dist/{chunk-XYRZV7R5.js → chunk-2LM4QQGH.js} +30 -34
- package/dist/chunk-2LM4QQGH.js.map +1 -0
- package/dist/{chunk-3OGQLOJM.js → chunk-3DBFLLLU.js} +30 -1
- package/dist/chunk-3DBFLLLU.js.map +1 -0
- package/dist/{chunk-KTHLNIMA.js → chunk-ECOVPXYS.js} +13 -62
- package/dist/chunk-ECOVPXYS.js.map +1 -0
- package/dist/{chunk-HKWQN44G.js → chunk-IZXS7RZK.js} +15 -15
- package/dist/{chunk-OO3V7W4H.js → chunk-KA3PSVNV.js} +87 -40
- package/dist/chunk-KA3PSVNV.js.map +1 -0
- package/dist/{chunk-L36JW4KV.js → chunk-LFS45U62.js} +2 -2
- package/dist/{chunk-BUN7NMV7.js → chunk-O3FTRYEU.js} +2 -2
- package/dist/{chunk-F6QB26OS.js → chunk-P3PUOL6B.js} +80 -8
- package/dist/chunk-P3PUOL6B.js.map +1 -0
- package/dist/{chunk-ZPXWJA4H.js → chunk-PHDAXDHB.js} +131 -5
- package/dist/chunk-PHDAXDHB.js.map +1 -0
- package/dist/chunk-UJI6WSMD.js +201 -0
- package/dist/{chunk-5CDJCTOO.js.map → chunk-UJI6WSMD.js.map} +1 -1
- package/dist/{chunk-OUU3SP6I.js → chunk-UKZWNQMB.js} +50 -7
- package/dist/{chunk-OUU3SP6I.js.map → chunk-UKZWNQMB.js.map} +1 -1
- package/dist/{chunk-7H75SHXZ.js → chunk-VN3OOE35.js} +2 -2
- package/dist/{chunk-QKIVSZ2O.js → chunk-WP5I5GLN.js} +2 -2
- package/dist/{chunk-NEONKMTU.js → chunk-XN2LYHDI.js} +47 -6
- package/dist/chunk-XN2LYHDI.js.map +1 -0
- package/dist/components.d.ts +1 -1
- package/dist/components.js +12 -11
- package/dist/components.js.map +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +10 -9
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +19 -16
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +3 -2
- package/dist/rbac/index.d.ts +82 -1
- package/dist/rbac/index.js +13 -10
- package/dist/{useToast-DVT4dMtf.d.ts → useToast-Cs_g32bg.d.ts} +1 -1
- package/dist/utils.js +6 -4
- package/dist/utils.js.map +1 -1
- package/dist/validation.js +3 -1
- package/dist/validation.js.map +1 -1
- package/docs/README.md +4 -0
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +35 -12
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +1 -1
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +1 -1
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventAppRoleData.md +71 -0
- package/docs/api/interfaces/FileDisplayProps.md +1 -1
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/GrantEventAppRoleParams.md +122 -0
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +27 -27
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProtectedRouteProps.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/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +100 -0
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RoleManagementResult.md +52 -0
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeReturn.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 +41 -14
- package/docs/architecture/rpc-function-standards.md +193 -0
- package/package.json +1 -1
- package/src/__tests__/TEST_STANDARD.md +244 -2
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +46 -16
- package/src/components/DataTable/__tests__/keyboard.test.tsx +276 -217
- package/src/components/DataTable/components/DataTableCore.tsx +29 -2
- package/src/components/DataTable/components/DataTableToolbar.tsx +3 -2
- package/src/components/DataTable/components/EditableRow.tsx +18 -1
- package/src/components/DataTable/components/ViewRowModal.tsx +1 -1
- package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +735 -0
- package/src/components/DataTable/components/__tests__/BulkOperationsDropdown.test.tsx +572 -0
- package/src/components/DataTable/components/__tests__/ColumnVisibilityDropdown.test.tsx +708 -0
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +451 -0
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +456 -0
- package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +454 -0
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +462 -0
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +423 -0
- package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +393 -0
- package/src/components/DataTable/components/__tests__/GroupingDropdown.test.tsx +617 -0
- package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +734 -0
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +412 -0
- package/src/components/DataTable/hooks/useTableHandlers.ts +4 -0
- package/src/components/EventSelector/EventSelector.tsx +5 -25
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +12 -7
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +4 -0
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +7 -2
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +13 -8
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +109 -100
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +18 -13
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +17 -12
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +2 -0
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +11 -1
- package/src/components/PasswordReset/PasswordChangeForm.test.tsx +2 -2
- package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +648 -0
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +10 -7
- package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +4 -12
- package/src/components/Select/Select.tsx +8 -0
- package/src/components/Toast/Toast.tsx +1 -1
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +367 -3
- package/src/hooks/__tests__/usePublicFileDisplay.test.ts +916 -0
- package/src/hooks/useEventTheme.ts +49 -18
- package/src/hooks/usePermissionCache.ts +5 -3
- package/src/hooks/useSecureDataAccess.ts +56 -3
- package/src/hooks/useToast.ts +1 -1
- package/src/providers/services/EventServiceProvider.tsx +15 -8
- package/src/rbac/__tests__/cache-invalidation.test.ts +385 -0
- package/src/rbac/audit.test.ts +206 -0
- package/src/rbac/audit.ts +37 -2
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +26 -23
- package/src/rbac/errors.test.ts +340 -0
- package/src/rbac/hooks/index.ts +9 -0
- package/src/rbac/hooks/useResolvedScope.test.ts +1063 -0
- package/src/rbac/hooks/useRoleManagement.test.ts +908 -0
- package/src/rbac/hooks/useRoleManagement.ts +255 -0
- package/src/services/AuthService.ts +10 -0
- package/src/services/EventService.ts +111 -50
- package/src/services/__tests__/AuthService.test.ts +1 -1
- package/src/services/__tests__/EventService.test.ts +60 -45
- package/src/services/interfaces/IEventService.ts +1 -1
- package/src/utils/__tests__/deviceFingerprint.unit.test.ts +320 -0
- package/src/utils/__tests__/logger.unit.test.ts +398 -0
- package/src/utils/__tests__/validation.unit.test.ts +225 -1
- package/src/utils/file-reference.test.ts +214 -0
- package/dist/chunk-3OGQLOJM.js.map +0 -1
- package/dist/chunk-5CDJCTOO.js +0 -190
- package/dist/chunk-F6QB26OS.js.map +0 -1
- package/dist/chunk-KTHLNIMA.js.map +0 -1
- package/dist/chunk-NEONKMTU.js.map +0 -1
- package/dist/chunk-OO3V7W4H.js.map +0 -1
- package/dist/chunk-SYXOZQ4P.js.map +0 -1
- package/dist/chunk-XYRZV7R5.js.map +0 -1
- package/dist/chunk-ZPXWJA4H.js.map +0 -1
- package/src/rbac/audit-enhanced.ts +0 -351
- /package/dist/{DataTable-H5KJCAIS.js.map → DataTable-ZOAKQ3SU.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-KZZUO27W.js.map → UnifiedAuthProvider-YFN7YGVN.js.map} +0 -0
- /package/dist/{api-PKU4PUBO.js.map → api-TNIBJWLM.js.map} +0 -0
- /package/dist/{audit-H4YJJF7R.js.map → audit-T36HM7IM.js.map} +0 -0
- /package/dist/{chunk-HKWQN44G.js.map → chunk-IZXS7RZK.js.map} +0 -0
- /package/dist/{chunk-L36JW4KV.js.map → chunk-LFS45U62.js.map} +0 -0
- /package/dist/{chunk-BUN7NMV7.js.map → chunk-O3FTRYEU.js.map} +0 -0
- /package/dist/{chunk-7H75SHXZ.js.map → chunk-VN3OOE35.js.map} +0 -0
- /package/dist/{chunk-QKIVSZ2O.js.map → chunk-WP5I5GLN.js.map} +0 -0
|
@@ -0,0 +1,708 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file ColumnVisibilityDropdown Component Tests
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Components/DataTable/Components/__tests__
|
|
5
|
+
* @since 0.4.0
|
|
6
|
+
*
|
|
7
|
+
* Comprehensive test suite for ColumnVisibilityDropdown component following testing guidelines.
|
|
8
|
+
* Tests cover all major functionality, edge cases, and user interactions.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import React from 'react';
|
|
12
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
13
|
+
import userEvent from '@testing-library/user-event';
|
|
14
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
15
|
+
import { ColumnVisibilityDropdown } from '../ColumnVisibilityDropdown';
|
|
16
|
+
import type { Column } from '@tanstack/react-table';
|
|
17
|
+
|
|
18
|
+
// Mock lucide-react icons - use importActual to include ChevronDown for Select
|
|
19
|
+
vi.mock('lucide-react', async () => {
|
|
20
|
+
const actual = await vi.importActual('lucide-react');
|
|
21
|
+
return {
|
|
22
|
+
...actual,
|
|
23
|
+
Settings2: ({ className }: { className?: string }) => (
|
|
24
|
+
<div data-testid="settings-2-icon" className={className}>Settings</div>
|
|
25
|
+
),
|
|
26
|
+
Eye: ({ className }: { className?: string }) => (
|
|
27
|
+
<div data-testid="eye-icon" className={className}>Eye</div>
|
|
28
|
+
),
|
|
29
|
+
EyeOff: ({ className }: { className?: string }) => (
|
|
30
|
+
<div data-testid="eye-off-icon" className={className}>EyeOff</div>
|
|
31
|
+
),
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Mock Button component
|
|
36
|
+
vi.mock('../../Button/Button', () => ({
|
|
37
|
+
Button: ({ children, onClick, variant, size, className, ...props }: any) => (
|
|
38
|
+
<button
|
|
39
|
+
onClick={onClick}
|
|
40
|
+
data-variant={variant}
|
|
41
|
+
data-size={size}
|
|
42
|
+
className={className}
|
|
43
|
+
{...props}
|
|
44
|
+
>
|
|
45
|
+
{children}
|
|
46
|
+
</button>
|
|
47
|
+
),
|
|
48
|
+
}));
|
|
49
|
+
|
|
50
|
+
// Mock Checkbox component
|
|
51
|
+
vi.mock('../../Checkbox/Checkbox', () => ({
|
|
52
|
+
Checkbox: ({ id, checked, onCheckedChange, ...props }: any) => (
|
|
53
|
+
<input
|
|
54
|
+
type="checkbox"
|
|
55
|
+
id={id}
|
|
56
|
+
checked={checked}
|
|
57
|
+
onChange={(e) => onCheckedChange && onCheckedChange(e.target.checked)}
|
|
58
|
+
{...props}
|
|
59
|
+
/>
|
|
60
|
+
),
|
|
61
|
+
}));
|
|
62
|
+
|
|
63
|
+
// Mock Select components - use importActual to avoid missing ChevronDown
|
|
64
|
+
vi.mock('../../Select/Select', async () => {
|
|
65
|
+
const actual = await vi.importActual('../../Select/Select');
|
|
66
|
+
return {
|
|
67
|
+
...actual,
|
|
68
|
+
Select: ({ children, className }: any) => (
|
|
69
|
+
<form data-testid="select-root" className={className}>
|
|
70
|
+
{children}
|
|
71
|
+
</form>
|
|
72
|
+
),
|
|
73
|
+
SelectTrigger: ({ children, asChild, className }: any) =>
|
|
74
|
+
asChild ? children : <button data-testid="select-trigger" role="combobox" className={className}>{children}</button>,
|
|
75
|
+
SelectContent: ({ children }: any) => (
|
|
76
|
+
<ul data-testid="select-content" role="listbox">{children}</ul>
|
|
77
|
+
),
|
|
78
|
+
SelectItem: ({ children, onClick, value, className, ...props }: any) => (
|
|
79
|
+
<li
|
|
80
|
+
data-testid="select-item"
|
|
81
|
+
data-value={value}
|
|
82
|
+
onClick={onClick}
|
|
83
|
+
role="option"
|
|
84
|
+
className={className}
|
|
85
|
+
{...props}
|
|
86
|
+
>
|
|
87
|
+
{children}
|
|
88
|
+
</li>
|
|
89
|
+
),
|
|
90
|
+
SelectSeparator: () => <div data-testid="select-separator" />,
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const createMockColumn = (overrides: Partial<Column<any, unknown>> = {}): Column<any, unknown> => ({
|
|
95
|
+
id: 'test-column',
|
|
96
|
+
getCanHide: vi.fn(() => true),
|
|
97
|
+
getIsVisible: vi.fn(() => true),
|
|
98
|
+
columnDef: {
|
|
99
|
+
header: 'Test Column',
|
|
100
|
+
},
|
|
101
|
+
...overrides,
|
|
102
|
+
} as unknown as Column<any, unknown>);
|
|
103
|
+
|
|
104
|
+
describe('[component] ColumnVisibilityDropdown', () => {
|
|
105
|
+
let mockColumns: Column<any, unknown>[];
|
|
106
|
+
let handleVisibilityChange: ReturnType<typeof vi.fn>;
|
|
107
|
+
|
|
108
|
+
beforeEach(() => {
|
|
109
|
+
vi.clearAllMocks();
|
|
110
|
+
handleVisibilityChange = vi.fn();
|
|
111
|
+
|
|
112
|
+
mockColumns = [
|
|
113
|
+
createMockColumn({ id: 'col1', columnDef: { header: 'Column 1' } }),
|
|
114
|
+
createMockColumn({ id: 'col2', columnDef: { header: 'Column 2' } }),
|
|
115
|
+
createMockColumn({ id: 'col3', columnDef: { header: 'Column 3' } }),
|
|
116
|
+
];
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
afterEach(() => {
|
|
120
|
+
vi.clearAllMocks();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe('Rendering', () => {
|
|
124
|
+
it('renders dropdown with trigger button', () => {
|
|
125
|
+
render(
|
|
126
|
+
<ColumnVisibilityDropdown
|
|
127
|
+
columns={mockColumns}
|
|
128
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
129
|
+
/>
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
expect(screen.getByTestId('select-root')).toBeInTheDocument();
|
|
133
|
+
expect(screen.getByTestId('select-trigger')).toBeInTheDocument();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('renders Settings2 icon', () => {
|
|
137
|
+
render(
|
|
138
|
+
<ColumnVisibilityDropdown
|
|
139
|
+
columns={mockColumns}
|
|
140
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
141
|
+
/>
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
expect(screen.getByTestId('settings-2-icon')).toBeInTheDocument();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('renders "Columns" text in trigger', () => {
|
|
148
|
+
render(
|
|
149
|
+
<ColumnVisibilityDropdown
|
|
150
|
+
columns={mockColumns}
|
|
151
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
152
|
+
/>
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
expect(screen.getByText('Columns')).toBeInTheDocument();
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('renders Show All and Hide All buttons', async () => {
|
|
159
|
+
const user = userEvent.setup();
|
|
160
|
+
render(
|
|
161
|
+
<ColumnVisibilityDropdown
|
|
162
|
+
columns={mockColumns}
|
|
163
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
164
|
+
/>
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
168
|
+
await user.click(trigger);
|
|
169
|
+
|
|
170
|
+
await waitFor(() => {
|
|
171
|
+
expect(screen.getByText('Show All')).toBeInTheDocument();
|
|
172
|
+
expect(screen.getByText('Hide All')).toBeInTheDocument();
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('renders Eye icon in Show All button', async () => {
|
|
177
|
+
const user = userEvent.setup();
|
|
178
|
+
render(
|
|
179
|
+
<ColumnVisibilityDropdown
|
|
180
|
+
columns={mockColumns}
|
|
181
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
182
|
+
/>
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
186
|
+
await user.click(trigger);
|
|
187
|
+
|
|
188
|
+
await waitFor(() => {
|
|
189
|
+
expect(screen.getByTestId('eye-icon')).toBeInTheDocument();
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('renders EyeOff icon in Hide All button', async () => {
|
|
194
|
+
const user = userEvent.setup();
|
|
195
|
+
render(
|
|
196
|
+
<ColumnVisibilityDropdown
|
|
197
|
+
columns={mockColumns}
|
|
198
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
199
|
+
/>
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
203
|
+
await user.click(trigger);
|
|
204
|
+
|
|
205
|
+
await waitFor(() => {
|
|
206
|
+
expect(screen.getByTestId('eye-off-icon')).toBeInTheDocument();
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('renders separator between buttons and columns', async () => {
|
|
211
|
+
const user = userEvent.setup();
|
|
212
|
+
render(
|
|
213
|
+
<ColumnVisibilityDropdown
|
|
214
|
+
columns={mockColumns}
|
|
215
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
216
|
+
/>
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
220
|
+
await user.click(trigger);
|
|
221
|
+
|
|
222
|
+
await waitFor(() => {
|
|
223
|
+
expect(screen.getByTestId('select-separator')).toBeInTheDocument();
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
describe('Column List', () => {
|
|
229
|
+
it('renders all toggleable columns', async () => {
|
|
230
|
+
const user = userEvent.setup();
|
|
231
|
+
render(
|
|
232
|
+
<ColumnVisibilityDropdown
|
|
233
|
+
columns={mockColumns}
|
|
234
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
235
|
+
/>
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
239
|
+
await user.click(trigger);
|
|
240
|
+
|
|
241
|
+
await waitFor(() => {
|
|
242
|
+
expect(screen.getByText('Column 1')).toBeInTheDocument();
|
|
243
|
+
expect(screen.getByText('Column 2')).toBeInTheDocument();
|
|
244
|
+
expect(screen.getByText('Column 3')).toBeInTheDocument();
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('filters out non-hideable columns', async () => {
|
|
249
|
+
const user = userEvent.setup();
|
|
250
|
+
const columnsWithNonHideable = [
|
|
251
|
+
...mockColumns,
|
|
252
|
+
createMockColumn({
|
|
253
|
+
id: 'actions',
|
|
254
|
+
getCanHide: vi.fn(() => false),
|
|
255
|
+
columnDef: { header: 'Actions' },
|
|
256
|
+
}),
|
|
257
|
+
];
|
|
258
|
+
|
|
259
|
+
render(
|
|
260
|
+
<ColumnVisibilityDropdown
|
|
261
|
+
columns={columnsWithNonHideable}
|
|
262
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
263
|
+
/>
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
267
|
+
await user.click(trigger);
|
|
268
|
+
|
|
269
|
+
await waitFor(() => {
|
|
270
|
+
expect(screen.queryByText('Actions')).not.toBeInTheDocument();
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('filters out actions column', async () => {
|
|
275
|
+
const user = userEvent.setup();
|
|
276
|
+
const columnsWithActions = [
|
|
277
|
+
...mockColumns,
|
|
278
|
+
createMockColumn({
|
|
279
|
+
id: 'actions',
|
|
280
|
+
getCanHide: vi.fn(() => true),
|
|
281
|
+
columnDef: { header: 'Actions' },
|
|
282
|
+
}),
|
|
283
|
+
];
|
|
284
|
+
|
|
285
|
+
render(
|
|
286
|
+
<ColumnVisibilityDropdown
|
|
287
|
+
columns={columnsWithActions}
|
|
288
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
289
|
+
/>
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
293
|
+
await user.click(trigger);
|
|
294
|
+
|
|
295
|
+
await waitFor(() => {
|
|
296
|
+
expect(screen.queryByText('Actions')).not.toBeInTheDocument();
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('uses column header as label when available', async () => {
|
|
301
|
+
const user = userEvent.setup();
|
|
302
|
+
render(
|
|
303
|
+
<ColumnVisibilityDropdown
|
|
304
|
+
columns={mockColumns}
|
|
305
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
306
|
+
/>
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
310
|
+
await user.click(trigger);
|
|
311
|
+
|
|
312
|
+
await waitFor(() => {
|
|
313
|
+
expect(screen.getByText('Column 1')).toBeInTheDocument();
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it('uses column id as label when header is not a string', async () => {
|
|
318
|
+
const user = userEvent.setup();
|
|
319
|
+
const columnsWithComplexHeader = [
|
|
320
|
+
createMockColumn({
|
|
321
|
+
id: 'col-complex',
|
|
322
|
+
columnDef: { header: () => <span>Complex Header</span> },
|
|
323
|
+
}),
|
|
324
|
+
];
|
|
325
|
+
|
|
326
|
+
render(
|
|
327
|
+
<ColumnVisibilityDropdown
|
|
328
|
+
columns={columnsWithComplexHeader}
|
|
329
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
330
|
+
/>
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
334
|
+
await user.click(trigger);
|
|
335
|
+
|
|
336
|
+
await waitFor(() => {
|
|
337
|
+
expect(screen.getByText('col-complex')).toBeInTheDocument();
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
describe('Checkbox States', () => {
|
|
343
|
+
it('renders checked checkbox for visible columns', async () => {
|
|
344
|
+
const user = userEvent.setup();
|
|
345
|
+
const visibleColumn = createMockColumn({
|
|
346
|
+
id: 'visible-col',
|
|
347
|
+
getIsVisible: vi.fn(() => true),
|
|
348
|
+
columnDef: { header: 'Visible Column' },
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
render(
|
|
352
|
+
<ColumnVisibilityDropdown
|
|
353
|
+
columns={[visibleColumn]}
|
|
354
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
355
|
+
/>
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
359
|
+
await user.click(trigger);
|
|
360
|
+
|
|
361
|
+
await waitFor(() => {
|
|
362
|
+
const checkbox = screen.getByRole('checkbox', { name: /Visible Column/i });
|
|
363
|
+
expect(checkbox).toBeChecked();
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it('renders unchecked checkbox for hidden columns', async () => {
|
|
368
|
+
const user = userEvent.setup();
|
|
369
|
+
const hiddenColumn = createMockColumn({
|
|
370
|
+
id: 'hidden-col',
|
|
371
|
+
getIsVisible: vi.fn(() => false),
|
|
372
|
+
columnDef: { header: 'Hidden Column' },
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
render(
|
|
376
|
+
<ColumnVisibilityDropdown
|
|
377
|
+
columns={[hiddenColumn]}
|
|
378
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
379
|
+
/>
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
383
|
+
await user.click(trigger);
|
|
384
|
+
|
|
385
|
+
await waitFor(() => {
|
|
386
|
+
const checkbox = screen.getByRole('checkbox', { name: /Hidden Column/i });
|
|
387
|
+
expect(checkbox).not.toBeChecked();
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
describe('User Interactions', () => {
|
|
393
|
+
it('calls onColumnVisibilityChange when checkbox is toggled', async () => {
|
|
394
|
+
const user = userEvent.setup();
|
|
395
|
+
const column = createMockColumn({
|
|
396
|
+
id: 'toggle-col',
|
|
397
|
+
getIsVisible: vi.fn(() => true),
|
|
398
|
+
columnDef: { header: 'Toggle Column' },
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
render(
|
|
402
|
+
<ColumnVisibilityDropdown
|
|
403
|
+
columns={[column]}
|
|
404
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
405
|
+
/>
|
|
406
|
+
);
|
|
407
|
+
|
|
408
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
409
|
+
await user.click(trigger);
|
|
410
|
+
|
|
411
|
+
await waitFor(() => {
|
|
412
|
+
const checkbox = screen.getByRole('checkbox', { name: /Toggle Column/i });
|
|
413
|
+
expect(checkbox).toBeInTheDocument();
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
const checkbox = screen.getByRole('checkbox', { name: /Toggle Column/i });
|
|
417
|
+
await user.click(checkbox);
|
|
418
|
+
|
|
419
|
+
expect(handleVisibilityChange).toHaveBeenCalledTimes(1);
|
|
420
|
+
expect(handleVisibilityChange).toHaveBeenCalledWith('toggle-col', false);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
it('calls onColumnVisibilityChange with true when hidden column is checked', async () => {
|
|
424
|
+
const user = userEvent.setup();
|
|
425
|
+
const column = createMockColumn({
|
|
426
|
+
id: 'hidden-col',
|
|
427
|
+
getIsVisible: vi.fn(() => false),
|
|
428
|
+
columnDef: { header: 'Hidden Column' },
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
render(
|
|
432
|
+
<ColumnVisibilityDropdown
|
|
433
|
+
columns={[column]}
|
|
434
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
435
|
+
/>
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
439
|
+
await user.click(trigger);
|
|
440
|
+
|
|
441
|
+
await waitFor(() => {
|
|
442
|
+
const checkbox = screen.getByRole('checkbox', { name: /Hidden Column/i });
|
|
443
|
+
expect(checkbox).toBeInTheDocument();
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
const checkbox = screen.getByRole('checkbox', { name: /Hidden Column/i });
|
|
447
|
+
await user.click(checkbox);
|
|
448
|
+
|
|
449
|
+
expect(handleVisibilityChange).toHaveBeenCalledWith('hidden-col', true);
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
it('calls onColumnVisibilityChange for all hidden columns when Show All is clicked', async () => {
|
|
453
|
+
const user = userEvent.setup();
|
|
454
|
+
const columns = [
|
|
455
|
+
createMockColumn({
|
|
456
|
+
id: 'col1',
|
|
457
|
+
getIsVisible: vi.fn(() => false),
|
|
458
|
+
columnDef: { header: 'Column 1' },
|
|
459
|
+
}),
|
|
460
|
+
createMockColumn({
|
|
461
|
+
id: 'col2',
|
|
462
|
+
getIsVisible: vi.fn(() => false),
|
|
463
|
+
columnDef: { header: 'Column 2' },
|
|
464
|
+
}),
|
|
465
|
+
];
|
|
466
|
+
|
|
467
|
+
render(
|
|
468
|
+
<ColumnVisibilityDropdown
|
|
469
|
+
columns={columns}
|
|
470
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
471
|
+
/>
|
|
472
|
+
);
|
|
473
|
+
|
|
474
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
475
|
+
await user.click(trigger);
|
|
476
|
+
|
|
477
|
+
await waitFor(() => {
|
|
478
|
+
const showAllButton = screen.getByText('Show All');
|
|
479
|
+
expect(showAllButton).toBeInTheDocument();
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
const showAllButton = screen.getByText('Show All');
|
|
483
|
+
await user.click(showAllButton);
|
|
484
|
+
|
|
485
|
+
expect(handleVisibilityChange).toHaveBeenCalledTimes(2);
|
|
486
|
+
expect(handleVisibilityChange).toHaveBeenCalledWith('col1', true);
|
|
487
|
+
expect(handleVisibilityChange).toHaveBeenCalledWith('col2', true);
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
it('calls onColumnVisibilityChange for all visible columns when Hide All is clicked', async () => {
|
|
491
|
+
const user = userEvent.setup();
|
|
492
|
+
const columns = [
|
|
493
|
+
createMockColumn({
|
|
494
|
+
id: 'col1',
|
|
495
|
+
getIsVisible: vi.fn(() => true),
|
|
496
|
+
columnDef: { header: 'Column 1' },
|
|
497
|
+
}),
|
|
498
|
+
createMockColumn({
|
|
499
|
+
id: 'col2',
|
|
500
|
+
getIsVisible: vi.fn(() => true),
|
|
501
|
+
columnDef: { header: 'Column 2' },
|
|
502
|
+
}),
|
|
503
|
+
];
|
|
504
|
+
|
|
505
|
+
render(
|
|
506
|
+
<ColumnVisibilityDropdown
|
|
507
|
+
columns={columns}
|
|
508
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
509
|
+
/>
|
|
510
|
+
);
|
|
511
|
+
|
|
512
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
513
|
+
await user.click(trigger);
|
|
514
|
+
|
|
515
|
+
await waitFor(() => {
|
|
516
|
+
const hideAllButton = screen.getByText('Hide All');
|
|
517
|
+
expect(hideAllButton).toBeInTheDocument();
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
const hideAllButton = screen.getByText('Hide All');
|
|
521
|
+
await user.click(hideAllButton);
|
|
522
|
+
|
|
523
|
+
expect(handleVisibilityChange).toHaveBeenCalledTimes(2);
|
|
524
|
+
expect(handleVisibilityChange).toHaveBeenCalledWith('col1', false);
|
|
525
|
+
expect(handleVisibilityChange).toHaveBeenCalledWith('col2', false);
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
it('only shows visible columns when Show All is clicked', async () => {
|
|
529
|
+
const user = userEvent.setup();
|
|
530
|
+
const columns = [
|
|
531
|
+
createMockColumn({
|
|
532
|
+
id: 'visible-col',
|
|
533
|
+
getIsVisible: vi.fn(() => true),
|
|
534
|
+
columnDef: { header: 'Visible Column' },
|
|
535
|
+
}),
|
|
536
|
+
createMockColumn({
|
|
537
|
+
id: 'hidden-col',
|
|
538
|
+
getIsVisible: vi.fn(() => false),
|
|
539
|
+
columnDef: { header: 'Hidden Column' },
|
|
540
|
+
}),
|
|
541
|
+
];
|
|
542
|
+
|
|
543
|
+
render(
|
|
544
|
+
<ColumnVisibilityDropdown
|
|
545
|
+
columns={columns}
|
|
546
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
547
|
+
/>
|
|
548
|
+
);
|
|
549
|
+
|
|
550
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
551
|
+
await user.click(trigger);
|
|
552
|
+
|
|
553
|
+
await waitFor(() => {
|
|
554
|
+
const showAllButton = screen.getByText('Show All');
|
|
555
|
+
expect(showAllButton).toBeInTheDocument();
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
const showAllButton = screen.getByText('Show All');
|
|
559
|
+
await user.click(showAllButton);
|
|
560
|
+
|
|
561
|
+
// Only hidden column should be shown
|
|
562
|
+
expect(handleVisibilityChange).toHaveBeenCalledTimes(1);
|
|
563
|
+
expect(handleVisibilityChange).toHaveBeenCalledWith('hidden-col', true);
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
it('only hides visible columns when Hide All is clicked', async () => {
|
|
567
|
+
const user = userEvent.setup();
|
|
568
|
+
const columns = [
|
|
569
|
+
createMockColumn({
|
|
570
|
+
id: 'visible-col',
|
|
571
|
+
getIsVisible: vi.fn(() => true),
|
|
572
|
+
columnDef: { header: 'Visible Column' },
|
|
573
|
+
}),
|
|
574
|
+
createMockColumn({
|
|
575
|
+
id: 'hidden-col',
|
|
576
|
+
getIsVisible: vi.fn(() => false),
|
|
577
|
+
columnDef: { header: 'Hidden Column' },
|
|
578
|
+
}),
|
|
579
|
+
];
|
|
580
|
+
|
|
581
|
+
render(
|
|
582
|
+
<ColumnVisibilityDropdown
|
|
583
|
+
columns={columns}
|
|
584
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
585
|
+
/>
|
|
586
|
+
);
|
|
587
|
+
|
|
588
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
589
|
+
await user.click(trigger);
|
|
590
|
+
|
|
591
|
+
await waitFor(() => {
|
|
592
|
+
const hideAllButton = screen.getByText('Hide All');
|
|
593
|
+
expect(hideAllButton).toBeInTheDocument();
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
const hideAllButton = screen.getByText('Hide All');
|
|
597
|
+
await user.click(hideAllButton);
|
|
598
|
+
|
|
599
|
+
// Only visible column should be hidden
|
|
600
|
+
expect(handleVisibilityChange).toHaveBeenCalledTimes(1);
|
|
601
|
+
expect(handleVisibilityChange).toHaveBeenCalledWith('visible-col', false);
|
|
602
|
+
});
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
describe('Edge Cases', () => {
|
|
606
|
+
it('handles empty columns array', () => {
|
|
607
|
+
render(
|
|
608
|
+
<ColumnVisibilityDropdown
|
|
609
|
+
columns={[]}
|
|
610
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
611
|
+
/>
|
|
612
|
+
);
|
|
613
|
+
|
|
614
|
+
expect(screen.getByTestId('select-root')).toBeInTheDocument();
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
it('handles columns with no toggleable columns', async () => {
|
|
618
|
+
const user = userEvent.setup();
|
|
619
|
+
const nonToggleableColumns = [
|
|
620
|
+
createMockColumn({
|
|
621
|
+
id: 'col1',
|
|
622
|
+
getCanHide: vi.fn(() => false),
|
|
623
|
+
columnDef: { header: 'Column 1' },
|
|
624
|
+
}),
|
|
625
|
+
];
|
|
626
|
+
|
|
627
|
+
render(
|
|
628
|
+
<ColumnVisibilityDropdown
|
|
629
|
+
columns={nonToggleableColumns}
|
|
630
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
631
|
+
/>
|
|
632
|
+
);
|
|
633
|
+
|
|
634
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
635
|
+
await user.click(trigger);
|
|
636
|
+
|
|
637
|
+
await waitFor(() => {
|
|
638
|
+
expect(screen.queryByText('Column 1')).not.toBeInTheDocument();
|
|
639
|
+
});
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
it('handles columns with undefined header', async () => {
|
|
643
|
+
const user = userEvent.setup();
|
|
644
|
+
const columnWithUndefinedHeader = createMockColumn({
|
|
645
|
+
id: 'col-undefined',
|
|
646
|
+
columnDef: { header: undefined },
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
render(
|
|
650
|
+
<ColumnVisibilityDropdown
|
|
651
|
+
columns={[columnWithUndefinedHeader]}
|
|
652
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
653
|
+
/>
|
|
654
|
+
);
|
|
655
|
+
|
|
656
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
657
|
+
await user.click(trigger);
|
|
658
|
+
|
|
659
|
+
await waitFor(() => {
|
|
660
|
+
expect(screen.getByText('col-undefined')).toBeInTheDocument();
|
|
661
|
+
});
|
|
662
|
+
});
|
|
663
|
+
});
|
|
664
|
+
|
|
665
|
+
describe('Accessibility', () => {
|
|
666
|
+
it('provides checkbox labels for screen readers', async () => {
|
|
667
|
+
const user = userEvent.setup();
|
|
668
|
+
render(
|
|
669
|
+
<ColumnVisibilityDropdown
|
|
670
|
+
columns={mockColumns}
|
|
671
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
672
|
+
/>
|
|
673
|
+
);
|
|
674
|
+
|
|
675
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
676
|
+
await user.click(trigger);
|
|
677
|
+
|
|
678
|
+
await waitFor(() => {
|
|
679
|
+
const checkboxes = screen.getAllByRole('checkbox');
|
|
680
|
+
expect(checkboxes.length).toBeGreaterThan(0);
|
|
681
|
+
});
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
it('associates labels with checkboxes', async () => {
|
|
685
|
+
const user = userEvent.setup();
|
|
686
|
+
const column = createMockColumn({
|
|
687
|
+
id: 'test-col',
|
|
688
|
+
columnDef: { header: 'Test Column' },
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
render(
|
|
692
|
+
<ColumnVisibilityDropdown
|
|
693
|
+
columns={[column]}
|
|
694
|
+
onColumnVisibilityChange={handleVisibilityChange}
|
|
695
|
+
/>
|
|
696
|
+
);
|
|
697
|
+
|
|
698
|
+
const trigger = screen.getByTestId('select-trigger');
|
|
699
|
+
await user.click(trigger);
|
|
700
|
+
|
|
701
|
+
await waitFor(() => {
|
|
702
|
+
const checkbox = screen.getByRole('checkbox', { name: /Test Column/i });
|
|
703
|
+
expect(checkbox).toBeInTheDocument();
|
|
704
|
+
});
|
|
705
|
+
});
|
|
706
|
+
});
|
|
707
|
+
});
|
|
708
|
+
|