@jmruthers/pace-core 0.5.73 → 0.5.75

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.
Files changed (283) hide show
  1. package/dist/{DataTable-INW5YIFV.js → DataTable-HWZQGASI.js} +8 -8
  2. package/dist/{PublicLoadingSpinner-DLpF5bbs.d.ts → PublicLoadingSpinner-BKNBT6b6.d.ts} +2 -2
  3. package/dist/RBACService-C4udt_Zp.d.ts +528 -0
  4. package/dist/{UnifiedAuthProvider-6SYT5WFN.js → UnifiedAuthProvider-3NKDOSOK.js} +6 -4
  5. package/dist/UnifiedAuthProvider-Bj6YCf7c.d.ts +113 -0
  6. package/dist/{chunk-2PRPDH66.js → chunk-2CHATWBF.js} +5 -7
  7. package/dist/chunk-2CHATWBF.js.map +1 -0
  8. package/dist/{chunk-43C63KLH.js → chunk-2DFZ432F.js} +496 -30
  9. package/dist/chunk-2DFZ432F.js.map +1 -0
  10. package/dist/{chunk-M4UMXYNK.js → chunk-33PHABLB.js} +36 -3
  11. package/dist/chunk-33PHABLB.js.map +1 -0
  12. package/dist/chunk-5F3NDPJV.js +232 -0
  13. package/dist/chunk-5F3NDPJV.js.map +1 -0
  14. package/dist/chunk-A4FUBC7B.js +17 -0
  15. package/dist/chunk-A4FUBC7B.js.map +1 -0
  16. package/dist/{chunk-SMJZMKYN.js → chunk-A6HBIY5P.js} +2 -11
  17. package/dist/{chunk-SMJZMKYN.js.map → chunk-A6HBIY5P.js.map} +1 -1
  18. package/dist/{chunk-GBC5PC3N.js → chunk-CY3AHGO4.js} +6256 -1937
  19. package/dist/chunk-CY3AHGO4.js.map +1 -0
  20. package/dist/{chunk-BYG6OSTC.js → chunk-DAXLNIDY.js} +48 -50
  21. package/dist/chunk-DAXLNIDY.js.map +1 -0
  22. package/dist/{chunk-VKOCWWVY.js → chunk-L3RV2ALE.js} +1 -6
  23. package/dist/{chunk-VKOCWWVY.js.map → chunk-L3RV2ALE.js.map} +1 -1
  24. package/dist/chunk-LW7MMEAQ.js +59 -0
  25. package/dist/chunk-LW7MMEAQ.js.map +1 -0
  26. package/dist/{chunk-LANO5IFV.js → chunk-NTNILOBC.js} +7 -9
  27. package/dist/chunk-NTNILOBC.js.map +1 -0
  28. package/dist/chunk-PYUXFQJ3.js +11 -0
  29. package/dist/chunk-PYUXFQJ3.js.map +1 -0
  30. package/dist/chunk-URUTVZ7N.js +27 -0
  31. package/dist/chunk-URUTVZ7N.js.map +1 -0
  32. package/dist/chunk-WN6XJWOS.js +2468 -0
  33. package/dist/chunk-WN6XJWOS.js.map +1 -0
  34. package/dist/{chunk-3SP4P7NS.js → chunk-XLZ7U46Z.js} +59 -1
  35. package/dist/chunk-XLZ7U46Z.js.map +1 -0
  36. package/dist/{chunk-UC2BWIK7.js → chunk-ZTT2AXMX.js} +9 -14
  37. package/dist/chunk-ZTT2AXMX.js.map +1 -0
  38. package/dist/components.d.ts +4 -5
  39. package/dist/components.js +32 -39
  40. package/dist/components.js.map +1 -1
  41. package/dist/hooks.d.ts +3 -3
  42. package/dist/hooks.js +9 -8
  43. package/dist/hooks.js.map +1 -1
  44. package/dist/index.d.ts +156 -10
  45. package/dist/index.js +188 -93
  46. package/dist/index.js.map +1 -1
  47. package/dist/{organisation-t-vvQC3g.d.ts → organisation-BtshODVF.d.ts} +4 -3
  48. package/dist/providers.d.ts +27 -38
  49. package/dist/providers.js +33 -23
  50. package/dist/rbac/index.d.ts +61 -5
  51. package/dist/rbac/index.js +13 -14
  52. package/dist/styles/index.js +2 -2
  53. package/dist/theming/runtime.js +1 -3
  54. package/dist/types.d.ts +3 -3
  55. package/dist/types.js +1 -1
  56. package/dist/types.js.map +1 -1
  57. package/dist/{unified-CMPjE_fv.d.ts → unified-CM7T0aTK.d.ts} +1 -1
  58. package/dist/useInactivityTracker-MRUU55XI.js +10 -0
  59. package/dist/useInactivityTracker-MRUU55XI.js.map +1 -0
  60. package/dist/{usePublicRouteParams-Ua1Vz-HG.d.ts → usePublicRouteParams-B-CumWRc.d.ts} +3 -3
  61. package/dist/utils.js +7 -9
  62. package/dist/utils.js.map +1 -1
  63. package/dist/validation.d.ts +1 -1
  64. package/docs/api/classes/ColumnFactory.md +1 -1
  65. package/docs/api/classes/ErrorBoundary.md +1 -1
  66. package/docs/api/classes/InvalidScopeError.md +1 -1
  67. package/docs/api/classes/MissingUserContextError.md +1 -1
  68. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  69. package/docs/api/classes/PermissionDeniedError.md +1 -1
  70. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  71. package/docs/api/classes/RBACAuditManager.md +1 -1
  72. package/docs/api/classes/RBACCache.md +1 -1
  73. package/docs/api/classes/RBACEngine.md +1 -1
  74. package/docs/api/classes/RBACError.md +1 -1
  75. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  76. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  77. package/docs/api/classes/StorageUtils.md +1 -1
  78. package/docs/api/enums/FileCategory.md +1 -1
  79. package/docs/api/interfaces/AggregateConfig.md +1 -1
  80. package/docs/api/interfaces/ButtonProps.md +3 -3
  81. package/docs/api/interfaces/CardProps.md +2 -2
  82. package/docs/api/interfaces/ColorPalette.md +1 -1
  83. package/docs/api/interfaces/ColorShade.md +1 -1
  84. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  85. package/docs/api/interfaces/DataTableAction.md +1 -1
  86. package/docs/api/interfaces/DataTableColumn.md +1 -1
  87. package/docs/api/interfaces/DataTableProps.md +1 -1
  88. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  89. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  90. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  91. package/docs/api/interfaces/EventLogoProps.md +2 -2
  92. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  93. package/docs/api/interfaces/FileMetadata.md +1 -1
  94. package/docs/api/interfaces/FileReference.md +1 -1
  95. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  96. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  97. package/docs/api/interfaces/FileUploadProps.md +1 -1
  98. package/docs/api/interfaces/FooterProps.md +1 -1
  99. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  100. package/docs/api/interfaces/InputProps.md +2 -2
  101. package/docs/api/interfaces/LabelProps.md +1 -1
  102. package/docs/api/interfaces/LoginFormProps.md +1 -1
  103. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  104. package/docs/api/interfaces/NavigationContextType.md +1 -1
  105. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  106. package/docs/api/interfaces/NavigationItem.md +1 -1
  107. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  108. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  109. package/docs/api/interfaces/Organisation.md +1 -1
  110. package/docs/api/interfaces/OrganisationContextType.md +28 -17
  111. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  112. package/docs/api/interfaces/OrganisationProviderProps.md +2 -2
  113. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  114. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  115. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  116. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  117. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  118. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  119. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  120. package/docs/api/interfaces/PaletteData.md +1 -1
  121. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  122. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  123. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  124. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +2 -2
  125. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  126. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  127. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  128. package/docs/api/interfaces/RBACConfig.md +1 -1
  129. package/docs/api/interfaces/RBACContextType.md +5 -11
  130. package/docs/api/interfaces/RBACLogger.md +1 -1
  131. package/docs/api/interfaces/RBACProviderProps.md +1 -1
  132. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  133. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  134. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  135. package/docs/api/interfaces/RouteConfig.md +1 -1
  136. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  137. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  138. package/docs/api/interfaces/StorageConfig.md +1 -1
  139. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  140. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  141. package/docs/api/interfaces/StorageListOptions.md +1 -1
  142. package/docs/api/interfaces/StorageListResult.md +1 -1
  143. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  144. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  145. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  146. package/docs/api/interfaces/StyleImport.md +1 -1
  147. package/docs/api/interfaces/SwitchProps.md +1 -1
  148. package/docs/api/interfaces/ToastActionElement.md +1 -1
  149. package/docs/api/interfaces/ToastProps.md +1 -1
  150. package/docs/api/interfaces/UnifiedAuthContextType.md +524 -440
  151. package/docs/api/interfaces/UnifiedAuthProviderProps.md +14 -14
  152. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  153. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  154. package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
  155. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  156. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  157. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  158. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  159. package/docs/api/interfaces/UserEventAccess.md +11 -11
  160. package/docs/api/interfaces/UserMenuProps.md +1 -1
  161. package/docs/api/interfaces/UserProfile.md +1 -1
  162. package/docs/api/modules.md +179 -52
  163. package/docs/architecture/services.md +30 -32
  164. package/docs/breaking-changes.md +2 -5
  165. package/docs/implementation-guides/data-tables.md +82 -1
  166. package/docs/migration/service-architecture.md +121 -260
  167. package/docs/rbac/README-rbac-rls-integration.md +48 -38
  168. package/{src/rbac/examples → examples/RBAC}/CompleteRBACExample.tsx +3 -2
  169. package/{src/rbac/examples → examples/RBAC}/EventBasedApp.tsx +5 -4
  170. package/{src/components/examples → examples/RBAC}/PermissionExample.tsx +7 -6
  171. package/examples/RBAC/__tests__/PermissionExample.test.tsx +150 -0
  172. package/examples/RBAC/index.ts +13 -0
  173. package/examples/README.md +37 -0
  174. package/examples/index.ts +22 -0
  175. package/{src/examples → examples/public-pages}/CorrectPublicPageImplementation.tsx +1 -1
  176. package/{src/examples → examples/public-pages}/PublicEventPage.tsx +1 -1
  177. package/{src/examples → examples/public-pages}/PublicPageApp.tsx +1 -1
  178. package/{src/examples → examples/public-pages}/PublicPageUsageExample.tsx +1 -1
  179. package/examples/public-pages/__tests__/PublicPageUsageExample.test.tsx +159 -0
  180. package/examples/public-pages/index.ts +14 -0
  181. package/package.json +22 -18
  182. package/src/__tests__/TEST_GUIDE_CURSOR.md +650 -9
  183. package/src/__tests__/helpers/README.md +255 -0
  184. package/src/__tests__/helpers/index.ts +62 -0
  185. package/src/__tests__/helpers/supabaseMock.ts +27 -3
  186. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -8
  187. package/src/components/DataTable/components/DataTableCore.tsx +37 -3
  188. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +55 -0
  189. package/src/components/DataTable/core/ColumnManager.ts +10 -0
  190. package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +254 -0
  191. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +193 -0
  192. package/src/components/DataTable/examples/__tests__/HierarchicalExample.test.tsx +45 -0
  193. package/src/components/DataTable/examples/__tests__/PerformanceExample.test.tsx +117 -0
  194. package/src/components/Dialog/Dialog.tsx +2 -2
  195. package/src/components/Dialog/examples/__tests__/HtmlDialogExample.test.tsx +71 -0
  196. package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +122 -0
  197. package/src/components/EventSelector/EventSelector.tsx +1 -1
  198. package/src/components/Header/Header.test.tsx +35 -1
  199. package/src/components/Header/Header.tsx +3 -1
  200. package/src/components/OrganisationSelector/OrganisationSelector.tsx +3 -3
  201. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.rbac.test.tsx +24 -4
  202. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +3 -2
  203. package/src/components/Toast/Toast.test.tsx +1 -1
  204. package/src/components/Toast/Toast.tsx +1 -1
  205. package/src/hooks/__tests__/useFocusManagement.unit.test.ts +220 -0
  206. package/src/hooks/__tests__/useIsMobile.unit.test.ts +117 -0
  207. package/src/hooks/__tests__/useKeyboardShortcuts.unit.test.ts +295 -0
  208. package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +29 -19
  209. package/src/hooks/__tests__/useRBAC.unit.test.ts +7 -3
  210. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +115 -19
  211. package/src/hooks/useEventTheme.test.ts +350 -0
  212. package/src/hooks/useEventTheme.ts +1 -1
  213. package/src/hooks/useEvents.ts +61 -0
  214. package/src/hooks/useOrganisationSecurity.test.ts +4 -4
  215. package/src/hooks/useOrganisationSecurity.ts +2 -2
  216. package/src/hooks/useOrganisations.ts +64 -0
  217. package/src/hooks/useSecureDataAccess.test.ts +9 -5
  218. package/src/hooks/useSecureDataAccess.ts +2 -2
  219. package/src/index.ts +18 -3
  220. package/src/providers/AuthProvider.tsx +8 -292
  221. package/src/providers/EventProvider.tsx +15 -425
  222. package/src/providers/InactivityProvider.tsx +8 -231
  223. package/src/providers/OrganisationProvider.test.simple.tsx +3 -2
  224. package/src/providers/OrganisationProvider.tsx +11 -890
  225. package/src/providers/UnifiedAuthProvider.tsx +8 -320
  226. package/src/providers/__tests__/AuthProvider.test.tsx +18 -17
  227. package/src/providers/__tests__/EventProvider.test.tsx +253 -2
  228. package/src/providers/__tests__/InactivityProvider.test-helper.tsx +65 -0
  229. package/src/providers/__tests__/InactivityProvider.test.tsx +46 -114
  230. package/src/providers/__tests__/OrganisationProvider.test.tsx +313 -3
  231. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +383 -2
  232. package/src/providers/index.ts +8 -7
  233. package/src/providers/services/EventServiceProvider.tsx +3 -0
  234. package/src/providers/services/UnifiedAuthProvider.tsx +3 -0
  235. package/src/rbac/hooks/usePermissions.test.ts +296 -0
  236. package/src/rbac/hooks/useRBAC.test.ts +9 -5
  237. package/src/rbac/hooks/useRBAC.ts +3 -3
  238. package/src/rbac/providers/__tests__/RBACProvider.integration.test.tsx +688 -0
  239. package/src/rbac/providers/__tests__/RBACProvider.test.tsx +507 -0
  240. package/src/services/AuthService.ts +19 -4
  241. package/src/services/__tests__/AuthService.test.ts +288 -0
  242. package/src/styles/core.css +2 -0
  243. package/src/types/__tests__/guards.test.ts +246 -0
  244. package/src/types/guards.ts +1 -0
  245. package/src/types/organisation.ts +3 -2
  246. package/src/validation/__tests__/sanitization.unit.test.ts +250 -0
  247. package/src/validation/__tests__/schemaUtils.unit.test.ts +451 -0
  248. package/src/validation/__tests__/user.unit.test.ts +440 -0
  249. package/dist/RBACProvider-BO4ilsQB.d.ts +0 -63
  250. package/dist/UnifiedAuthProvider-D02AMXgO.d.ts +0 -103
  251. package/dist/chunk-2PRPDH66.js.map +0 -1
  252. package/dist/chunk-3SP4P7NS.js.map +0 -1
  253. package/dist/chunk-43C63KLH.js.map +0 -1
  254. package/dist/chunk-5A4RL4BC.js +0 -5670
  255. package/dist/chunk-5A4RL4BC.js.map +0 -1
  256. package/dist/chunk-BYG6OSTC.js.map +0 -1
  257. package/dist/chunk-CDDYJCYU.js +0 -79
  258. package/dist/chunk-CDDYJCYU.js.map +0 -1
  259. package/dist/chunk-F24P24TZ.js +0 -17
  260. package/dist/chunk-F24P24TZ.js.map +0 -1
  261. package/dist/chunk-GBC5PC3N.js.map +0 -1
  262. package/dist/chunk-LANO5IFV.js.map +0 -1
  263. package/dist/chunk-M4UMXYNK.js.map +0 -1
  264. package/dist/chunk-RJNE764D.js +0 -953
  265. package/dist/chunk-RJNE764D.js.map +0 -1
  266. package/dist/chunk-UC2BWIK7.js.map +0 -1
  267. package/dist/rbac/cli/policy-manager.js +0 -278
  268. package/dist/rbac/cli/policy-manager.js.map +0 -1
  269. package/docs/api/interfaces/EventContextType.md +0 -96
  270. package/docs/api/interfaces/EventProviderProps.md +0 -19
  271. package/src/providers/OrganisationProvider.test.tsx +0 -164
  272. package/src/providers/UnifiedAuthProvider.test.tsx +0 -124
  273. package/src/providers/__tests__/AuthProvider.test.tsx.backup +0 -771
  274. package/src/providers/__tests__/EventProvider.test.tsx.backup +0 -824
  275. package/src/providers/__tests__/OrganisationProvider.test.tsx.backup +0 -820
  276. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx.backup +0 -911
  277. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx.backup2 +0 -166
  278. package/src/rbac/cli/__tests__/policy-manager.test.ts +0 -339
  279. package/src/rbac/cli/policy-manager.ts +0 -443
  280. package/dist/{DataTable-INW5YIFV.js.map → DataTable-HWZQGASI.js.map} +0 -0
  281. package/dist/{UnifiedAuthProvider-6SYT5WFN.js.map → UnifiedAuthProvider-3NKDOSOK.js.map} +0 -0
  282. package/dist/{validation-PM_iOaTI.d.ts → validation-D8VcbTzC.d.ts} +2 -2
  283. /package/src/utils/{appNameResolver.test.ts.backup → appNameResolver.test 2.ts} +0 -0
@@ -0,0 +1,255 @@
1
+ # Test Helpers Directory
2
+
3
+ ## Overview
4
+
5
+ This directory contains all test helper utilities used across the test suite. All helpers are exported through a unified `index.ts` file for convenient imports.
6
+
7
+ ## Quick Start
8
+
9
+ ```typescript
10
+ // Import from the unified index
11
+ import {
12
+ createMockSupabaseClient,
13
+ renderWithProviders,
14
+ testDataGenerators
15
+ } from '@test/helpers';
16
+ ```
17
+
18
+ ## Helper Files
19
+
20
+ ### 📦 `supabaseMock.ts`
21
+ Supabase client and query builder mocking utilities.
22
+
23
+ **Exports**:
24
+ - `createMockSupabaseClient()` - Create a mock Supabase client
25
+ - `createMockQueryBuilder()` - Create a mock query builder with thenable interface
26
+ - `createMockSupabaseAuth()` - Create a mock Supabase auth module
27
+
28
+ **Usage**:
29
+ ```typescript
30
+ import { createMockSupabaseClient } from './supabaseMock';
31
+
32
+ const mockClient = createMockSupabaseClient();
33
+ mockClient.from('users').select().mockResolvedValue({ data: [], error: null });
34
+ ```
35
+
36
+ ### 🔗 `test-providers.tsx`
37
+ React context provider mocking utilities.
38
+
39
+ **Exports**:
40
+ - `TestProviderWrapper` - Wrapper component with all providers
41
+ - `renderWithProviders()` - Render component with providers
42
+ - `useMockUnifiedAuth()` - Mock unified auth context
43
+
44
+ **Usage**:
45
+ ```typescript
46
+ import { renderWithProviders } from './test-providers';
47
+
48
+ const { result } = renderWithProviders(<MyComponent />);
49
+ ```
50
+
51
+ ### 🛠️ `test-utils.tsx`
52
+ General testing utilities and data generators.
53
+
54
+ **Exports**:
55
+ - `renderWithProviders()` - Custom render function with providers
56
+ - `testDataGenerators` - Generate test data
57
+ - `testHelpers` - Common test helper functions
58
+ - `setupTest()` - Setup test environment
59
+ - `createComponentTestStructure()` - Component test patterns
60
+ - `createHookTestStructure()` - Hook test patterns
61
+
62
+ **Usage**:
63
+ ```typescript
64
+ import { testDataGenerators, setupTest } from './test-utils';
65
+
66
+ const mockUser = testDataGenerators.user({ name: 'Test User' });
67
+ ```
68
+
69
+ ### 🧩 `component-test-utils.tsx`
70
+ Specialized utilities for component testing.
71
+
72
+ **Exports**:
73
+ - `componentTestPatterns` - Reusable component test patterns
74
+ - `commonScenarios` - Common test scenarios
75
+ - `createTestData` - Create component test data
76
+
77
+ **Usage**:
78
+ ```typescript
79
+ import { componentTestPatterns } from './component-test-utils';
80
+
81
+ const testRender = componentTestPatterns.testRenders(MyComponent, { prop: 'value' });
82
+ ```
83
+
84
+ ### ⚡ `optimized-test-setup.ts`
85
+ Performance-optimized mock creation and setup.
86
+
87
+ **Exports**:
88
+ - `createFastMock()` - Create fast mock resolvers
89
+ - `createFastErrorMock()` - Create fast mock rejecters
90
+ - `setupOptimizedMocks()` - Setup optimized test environment
91
+ - `cleanupOptimizedMocks()` - Cleanup test environment
92
+
93
+ **Usage**:
94
+ ```typescript
95
+ import { setupOptimizedMocks, createFastMock } from './optimized-test-setup';
96
+
97
+ beforeEach(() => {
98
+ setupOptimizedMocks();
99
+ });
100
+
101
+ const mockFn = createFastMock({ data: 'test' });
102
+ ```
103
+
104
+ ### ⏱️ `timer-utils.ts`
105
+ Timer and async testing utilities.
106
+
107
+ **Exports**:
108
+ - `createMockTimers()` - Create mock timers
109
+ - `waitFor()` - Wait for async operations
110
+ - `sleep()` - Sleep utility
111
+
112
+ **Usage**:
113
+ ```typescript
114
+ import { createMockTimers } from './timer-utils';
115
+
116
+ const timers = createMockTimers();
117
+ await timers.sleep(100);
118
+ ```
119
+
120
+ ## Import Patterns
121
+
122
+ ### ✅ Recommended: Unified Import
123
+
124
+ ```typescript
125
+ // Import everything from index.ts
126
+ import {
127
+ createMockSupabaseClient,
128
+ renderWithProviders,
129
+ testDataGenerators
130
+ } from '@test/helpers';
131
+ ```
132
+
133
+ ### ⚠️ Acceptable: Specific Imports
134
+
135
+ ```typescript
136
+ // Import from specific files if you only need one utility
137
+ import { createMockSupabaseClient } from './helpers/supabaseMock';
138
+ import { renderWithProviders } from './helpers/test-providers';
139
+ ```
140
+
141
+ ### ❌ Avoid: Scattered Imports
142
+
143
+ ```typescript
144
+ // Don't import from multiple places
145
+ import { createMockSupabaseClient } from './helpers/supabaseMock';
146
+ import { testDataGenerators } from './helpers/test-utils';
147
+ import { renderWithProviders } from './helpers/test-providers';
148
+ // Instead, use the unified export
149
+ ```
150
+
151
+ ## Common Patterns
152
+
153
+ ### Testing with Providers
154
+
155
+ ```typescript
156
+ import { renderWithProviders } from '@test/helpers';
157
+
158
+ test('renders component with providers', () => {
159
+ const { result } = renderWithProviders(<MyComponent />);
160
+ expect(result).toBeInTheDocument();
161
+ });
162
+ ```
163
+
164
+ ### Mocking Supabase
165
+
166
+ ```typescript
167
+ import { createMockSupabaseClient } from '@test/helpers';
168
+
169
+ const mockClient = createMockSupabaseClient();
170
+ mockClient.from('users').select().mockResolvedValue({
171
+ data: [{ id: '1' }],
172
+ error: null
173
+ });
174
+ ```
175
+
176
+ ### Generating Test Data
177
+
178
+ ```typescript
179
+ import { testDataGenerators } from '@test/helpers';
180
+
181
+ const mockUser = testDataGenerators.user({
182
+ id: '123',
183
+ email: 'test@example.com'
184
+ });
185
+ ```
186
+
187
+ ## Best Practices
188
+
189
+ 1. **Use Unified Exports**: Import from `index.ts` for consistency
190
+ 2. **Don't Duplicate Helpers**: Add new helpers to appropriate files
191
+ 3. **Keep Helpers Focused**: One helper file = one concern
192
+ 4. **Test Your Helpers**: All helpers have tests in `__tests__/` subdirectory
193
+
194
+ ## Directory Structure
195
+
196
+ ```
197
+ helpers/
198
+ ├── index.ts ✅ Unified exports
199
+ ├── supabaseMock.ts ✅ Supabase mocking
200
+ ├── test-providers.tsx ✅ React provider utilities
201
+ ├── test-utils.tsx ✅ General test utilities
202
+ ├── component-test-utils.tsx ✅ Component-specific utilities
203
+ ├── optimized-test-setup.ts ✅ Performance utilities
204
+ ├── timer-utils.ts ✅ Timer and async utilities
205
+ └── __tests__/ ✅ Tests for each helper file
206
+ ```
207
+
208
+ ## Contributing
209
+
210
+ When adding new test helpers:
211
+
212
+ 1. **Choose the Right File**:
213
+ - Supabase-related → `supabaseMock.ts`
214
+ - React providers → `test-providers.tsx`
215
+ - Component-specific → `component-test-utils.tsx`
216
+ - General utilities → `test-utils.tsx`
217
+
218
+ 2. **Export from Index**:
219
+ - Add exports to `index.ts`
220
+ - Use clear, descriptive names
221
+
222
+ 3. **Add Tests**:
223
+ - Create test file in `__tests__/` subdirectory
224
+ - Cover all exported functions
225
+
226
+ 4. **Update README**:
227
+ - Document the new helper
228
+ - Provide usage examples
229
+
230
+ ## Migration from Individual Imports
231
+
232
+ ### Should I Update Existing Tests?
233
+
234
+ **Short Answer**: No urgent migration needed.
235
+
236
+ **Long Answer**:
237
+ - ✅ Both import patterns work perfectly
238
+ - ✅ Existing tests continue to function
239
+ - ✅ New tests should use unified import
240
+ - ✅ Migrate individual files gradually when you're already touching them
241
+
242
+ ### Migration Example
243
+
244
+ **Old Pattern** (still works):
245
+ ```typescript
246
+ import { createMockSupabaseClient } from '../../__tests__/helpers/test-utils';
247
+ ```
248
+
249
+ **New Pattern** (recommended):
250
+ ```typescript
251
+ import { createMockSupabaseClient } from '../../__tests__/helpers';
252
+ ```
253
+
254
+ Both patterns import from the same underlying functions. The unified import is just cleaner.
255
+
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @file Test Helpers Unified Exports
3
+ * @package @jmruthers/pace-core
4
+ * @module TestHelpers
5
+ * @since 0.4.0
6
+ *
7
+ * Central export file for all test helper utilities.
8
+ * Import test helpers from this file for convenience.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * // Import all test helpers from one place
13
+ * import {
14
+ * createMockSupabaseClient,
15
+ * renderWithProviders,
16
+ * testDataGenerators
17
+ * } from '@core/__tests__/helpers';
18
+ *
19
+ * // Or import specific utilities
20
+ * import { supabaseMock, testUtils } from '@core/__tests__/helpers';
21
+ * ```
22
+ */
23
+
24
+ // Supabase Mock Utilities
25
+ export * from './supabaseMock';
26
+ export { createMockSupabaseClient, createMockQueryBuilder, createMockSupabaseAuth } from './supabaseMock';
27
+
28
+ // Test Provider Utilities
29
+ export * from './test-providers';
30
+ export { TestProviderWrapper, renderWithProviders } from './test-providers';
31
+
32
+ // General Test Utilities
33
+ export * from './test-utils';
34
+ export {
35
+ renderWithProviders as renderWithQueryClient,
36
+ testDataGenerators,
37
+ testHelpers,
38
+ setupTest,
39
+ createComponentTestStructure,
40
+ createHookTestStructure
41
+ } from './test-utils';
42
+
43
+ // Component Test Utilities
44
+ export * from './component-test-utils';
45
+ export {
46
+ componentTestPatterns,
47
+ commonScenarios,
48
+ createTestData
49
+ } from './component-test-utils';
50
+
51
+ // Optimized Test Setup
52
+ export * from './optimized-test-setup';
53
+ export {
54
+ createFastMock,
55
+ createFastErrorMock,
56
+ setupOptimizedMocks,
57
+ cleanupOptimizedMocks
58
+ } from './optimized-test-setup';
59
+
60
+ // Timer Utilities
61
+ export * from './timer-utils';
62
+
@@ -13,6 +13,19 @@ import { vi } from 'vitest';
13
13
  * Creates a proper thenable mock query builder that can be awaited
14
14
  */
15
15
  export const createMockQueryBuilder = (defaultData: any = { data: [], error: null }) => {
16
+ // Helper to get appropriate single/maybeSingle response
17
+ const getSingleResponse = () => {
18
+ // If defaultData is empty array or has empty array data, return null
19
+ if ((Array.isArray(defaultData.data) && defaultData.data.length === 0) ||
20
+ (Array.isArray(defaultData) && defaultData.length === 0)) {
21
+ return { data: null, error: null };
22
+ }
23
+ // Otherwise return the default data
24
+ return typeof defaultData === 'object' && defaultData !== null && !Array.isArray(defaultData)
25
+ ? defaultData
26
+ : { data: defaultData, error: null };
27
+ };
28
+
16
29
  const mockQueryBuilder = {
17
30
  select: vi.fn().mockReturnThis(),
18
31
  insert: vi.fn().mockReturnThis(),
@@ -20,14 +33,25 @@ export const createMockQueryBuilder = (defaultData: any = { data: [], error: nul
20
33
  delete: vi.fn().mockReturnThis(),
21
34
  eq: vi.fn().mockReturnThis(),
22
35
  neq: vi.fn().mockReturnThis(),
36
+ gt: vi.fn().mockReturnThis(),
37
+ gte: vi.fn().mockReturnThis(),
38
+ lt: vi.fn().mockReturnThis(),
39
+ lte: vi.fn().mockReturnThis(),
40
+ like: vi.fn().mockReturnThis(),
41
+ ilike: vi.fn().mockReturnThis(),
23
42
  in: vi.fn().mockReturnThis(),
43
+ not: vi.fn().mockReturnThis(),
24
44
  is: vi.fn().mockReturnThis(),
45
+ or: vi.fn().mockReturnThis(),
46
+ and: vi.fn().mockReturnThis(),
47
+ filter: vi.fn().mockReturnThis(),
48
+ match: vi.fn().mockReturnThis(),
25
49
  order: vi.fn().mockReturnThis(),
26
- limit: vi.fn().mockReturnThis(),
50
+ limit: vi.fn().mockResolvedValue(defaultData),
27
51
  offset: vi.fn().mockReturnThis(),
28
52
  range: vi.fn().mockReturnThis(),
29
- single: vi.fn().mockResolvedValue({ data: null, error: null }),
30
- maybeSingle: vi.fn().mockResolvedValue({ data: null, error: null }),
53
+ single: vi.fn().mockResolvedValue(getSingleResponse()),
54
+ maybeSingle: vi.fn().mockResolvedValue(getSingleResponse()),
31
55
 
32
56
  // Implement thenable interface for await support
33
57
  then: vi.fn().mockImplementation((resolve, reject) => {
@@ -15,11 +15,14 @@ import React from 'react';
15
15
  import { render, screen, waitFor, act } from '@testing-library/react';
16
16
  import { vi } from 'vitest';
17
17
  import { PagePermissionGuard } from '../../rbac/components/PagePermissionGuard';
18
- import { useUnifiedAuth } from '../../providers/UnifiedAuthProvider';
18
+ import { useUnifiedAuth } from '../../providers';
19
19
  import { useCan } from '../../rbac/hooks';
20
20
 
21
21
  // Mock the hooks
22
- vi.mock('../../providers/UnifiedAuthProvider');
22
+ vi.mock('../../providers', () => ({
23
+ useUnifiedAuth: vi.fn(),
24
+ UnifiedAuthProvider: ({ children }: { children: React.ReactNode }) => <>{children}</>,
25
+ }));
23
26
  vi.mock('../../rbac/hooks', () => ({
24
27
  useCan: vi.fn()
25
28
  }));
@@ -28,11 +31,6 @@ vi.mock('../../utils/appNameResolver');
28
31
  const mockUseUnifiedAuth = vi.mocked(useUnifiedAuth);
29
32
  const mockUseCan = vi.mocked(useCan);
30
33
 
31
- // Mock app name resolver
32
- vi.mock('../../utils/appNameResolver', () => ({
33
- getCurrentAppName: () => 'test-app'
34
- }));
35
-
36
34
  describe('PagePermissionGuard', () => {
37
35
  const mockUser = {
38
36
  id: 'user-123',
@@ -50,7 +48,7 @@ describe('PagePermissionGuard', () => {
50
48
  vi.clearAllMocks();
51
49
 
52
50
  // Default mock implementations
53
- mockUseUnifiedAuth.mockReturnValue({
51
+ vi.mocked(useUnifiedAuth).mockReturnValue({
54
52
  user: mockUser,
55
53
  selectedOrganisationId: 'org-123',
56
54
  selectedEventId: 'event-123',
@@ -48,6 +48,7 @@ import { sortHierarchicalData as sortHierarchicalDataWithSorting } from '../util
48
48
  import { ColumnFactory } from '../core/ColumnFactory';
49
49
  import { AccessDeniedPage } from './AccessDeniedPage';
50
50
  import { useCan } from '../../../rbac/hooks';
51
+ import { exportToCSV } from '../utils/exportUtils';
51
52
  import { useUnifiedAuth } from '../../../providers/UnifiedAuthProvider';
52
53
  import { Scope } from '../../../rbac/types';
53
54
  import { getCurrentAppName } from '../../../utils/appNameResolver';
@@ -731,8 +732,21 @@ function DataTableInternal<TData extends DataRecord>({
731
732
  if (!permissions.canUpdate.can) {
732
733
  throw new Error('Insufficient permissions to edit this resource');
733
734
  }
734
- // Get the row ID using the provided getRowId function or fallback to row.id
735
- const rowId = getRowId ? getRowId(row, 0) : (row as any).id || String(0);
735
+ // CRITICAL: Calculate rowId the same way as in DataTableBody
736
+ // Find the index of this row in the data array
737
+ let rowId: string;
738
+ if (getRowId) {
739
+ const rowIndex = data.findIndex(r => r === row);
740
+ rowId = getRowId(row, rowIndex);
741
+ } else {
742
+ rowId = (row as any).id;
743
+ }
744
+
745
+ if (!rowId) {
746
+ console.error('[DataTable] Cannot edit row: no id found. Make sure to provide getRowId or ensure row data has an id property.');
747
+ return;
748
+ }
749
+
736
750
  // Set the row into editing mode with the current row data
737
751
  tableActions.setEditingRow(rowId, { ...row });
738
752
  },
@@ -1010,7 +1024,27 @@ function DataTableInternal<TData extends DataRecord>({
1010
1024
  onCreateRow={secureFeatures.creation && secureHandlers.onCreateRow ? () => tableActions.setCreating(true) : undefined}
1011
1025
  onImportClick={() => setShowImportModal(true)}
1012
1026
  onExport={secureHandlers.onExport || (() => {
1013
- // Export logic here
1027
+ // Automatic export: exports exactly what's shown in the table
1028
+ // Get the current filtered/paginated data (what's actually visible)
1029
+ const currentData = table.getFilteredRowModel().rows.map(row => row.original);
1030
+
1031
+ // Get only visible columns
1032
+ const visibleColumns = columns
1033
+ .filter(col => {
1034
+ const column = table.getColumn(col.accessorKey as string);
1035
+ return column && column.getIsVisible();
1036
+ })
1037
+ .map(col => ({
1038
+ ...col,
1039
+ header: typeof col.header === 'string' ? col.header : col.accessorKey || 'Column',
1040
+ }));
1041
+
1042
+ // Generate filename with timestamp
1043
+ const timestamp = new Date().toISOString().split('T')[0];
1044
+ const filename = title ? `${title.replace(/[^a-z0-9]/gi, '_').toLowerCase()}_${timestamp}.csv` : `data_export_${timestamp}.csv`;
1045
+
1046
+ // Export to CSV
1047
+ exportToCSV(currentData, visibleColumns, filename);
1014
1048
  })}
1015
1049
  rowSelection={rowSelection}
1016
1050
  onDeleteSelected={secureHandlers.onDeleteSelected}
@@ -0,0 +1,55 @@
1
+ # DataTable Subcomponent Testing Strategy
2
+
3
+ ## Summary
4
+
5
+ The DataTable subcomponents (FilterRow, EditableRow, ColumnFilter, GroupHeader, ViewRowModal, etc.) are **intentionally not tested in isolation** because:
6
+
7
+ 1. They are tightly integrated with TanStack React Table
8
+ 2. They are extensively tested through DataTable integration tests
9
+ 3. Isolated unit tests would require extensive mocking that tests implementation, not behavior
10
+
11
+ ## Coverage via Integration Tests
12
+
13
+ The following DataTable integration tests provide comprehensive coverage:
14
+
15
+ ### Workflow Validation (23 tests)
16
+ - ✅ Basic rendering workflows
17
+ - ✅ Editing workflow validation
18
+ - ✅ Deletion workflow validation
19
+ - ✅ Combined features validation
20
+ - ✅ Search workflow validation
21
+ - ✅ Sorting workflow validation
22
+ - ✅ Data integrity validation
23
+ - ✅ Accessibility validation
24
+
25
+ ### Regression Fixes (13 tests)
26
+ - ✅ Save/Cancel action handling
27
+ - ✅ Action button icons and behavior
28
+ - ✅ Handler requirement enforcement
29
+ - ✅ Data integrity prevention
30
+
31
+ ## Subcomponent Coverage Mapping
32
+
33
+ | Subcomponent | Coverage | Testing Method |
34
+ |-------------|----------|---------------|
35
+ | **ColumnFilter** | ✅ | Integration tests validate filter input behavior |
36
+ | **FilterRow** | ✅ | Integration tests validate filtering across columns |
37
+ | **EditableRow** | ✅ | Integration tests validate editing workflows |
38
+ | **GroupHeader** | ✅ | Integration tests validate grouping functionality |
39
+ | **ViewRowModal** | ✅ | Integration tests validate modal display |
40
+ | **DraggableColumnHeader** | ✅ | Integration tests validate column reordering |
41
+ | **ActionButtons** | ✅ | Integration tests validate action buttons |
42
+
43
+ ## Why This Approach Works
44
+
45
+ Following TEST_GUIDE_CURSOR.md principles:
46
+
47
+ 1. **Test Observable Behavior** - Integration tests verify actual user interactions
48
+ 2. **Avoid Implementation Testing** - Don't mock TanStack table internals
49
+ 3. **Focus on User Value** - Users use DataTable, not individual subcomponents
50
+ 4. **Prevent Brittle Tests** - Integration tests are more maintainable
51
+
52
+ ## Conclusion
53
+
54
+ DataTable subcomponents achieve **effective coverage** through integration tests that validate the complete user experience. No additional isolated unit tests are recommended.
55
+
@@ -123,6 +123,16 @@ export class ColumnManagerImpl<TData extends DataRecord> implements ColumnManage
123
123
  return this.columns.filter(column => column.enableGrouping === true);
124
124
  }
125
125
 
126
+ /**
127
+ * Get columns by type
128
+ */
129
+ getColumnsByType(type: string): ColumnDef<TData>[] {
130
+ return this.columns.filter(column => {
131
+ const columnType = column.meta?.type;
132
+ return columnType === type;
133
+ });
134
+ }
135
+
126
136
  /**
127
137
  * Set all columns at once
128
138
  */