@jmruthers/pace-core 0.5.53 → 0.5.55

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 (398) hide show
  1. package/README.md +0 -4
  2. package/dist/{DataTable-7FMFXA7A.js → DataTable-4T627QFJ.js} +11 -11
  3. package/dist/{PublicLoadingSpinner-Bq_-BeK-.d.ts → PublicLoadingSpinner-SL8WaQN7.d.ts} +2 -21
  4. package/dist/{api-H5A3H4IR.js → api-LUNF5O6M.js} +3 -3
  5. package/dist/{appConfig-BVGyuvI7.d.ts → appConfig-DjpeG6P-.d.ts} +9 -1
  6. package/dist/{appNameResolver-7GHF5ED2.js → appNameResolver-UURKN7NF.js} +2 -2
  7. package/dist/{audit-BUW3LMJB.js → audit-6TOCAMKO.js} +2 -2
  8. package/dist/{chunk-MZBUOP4P.js → chunk-5BSLGBYI.js} +4 -3
  9. package/dist/chunk-5BSLGBYI.js.map +1 -0
  10. package/dist/{chunk-I5Z3QH5X.js → chunk-66C4BSAY.js} +2 -2
  11. package/dist/{chunk-I5Z3QH5X.js.map → chunk-66C4BSAY.js.map} +1 -1
  12. package/dist/{chunk-MYP2EGHX.js → chunk-AJ2KMES7.js} +21 -14
  13. package/dist/chunk-AJ2KMES7.js.map +1 -0
  14. package/dist/{chunk-EL2O4IUX.js → chunk-AQFRLC7K.js} +16 -24
  15. package/dist/{chunk-EL2O4IUX.js.map → chunk-AQFRLC7K.js.map} +1 -1
  16. package/dist/{chunk-7BNPOCLL.js → chunk-B2WTCLCV.js} +6 -2
  17. package/dist/chunk-B2WTCLCV.js.map +1 -0
  18. package/dist/{chunk-WJARTBCT.js → chunk-D7ARGIA3.js} +16 -7
  19. package/dist/chunk-D7ARGIA3.js.map +1 -0
  20. package/dist/{chunk-NRK4AIHQ.js → chunk-KBRACSJI.js} +3 -3
  21. package/dist/{chunk-NYUJ4FJR.js → chunk-KJDPSM64.js} +7 -7
  22. package/dist/chunk-KJDPSM64.js.map +1 -0
  23. package/dist/{chunk-GWSBHC4J.js → chunk-KLPVOPRI.js} +261 -38
  24. package/dist/chunk-KLPVOPRI.js.map +1 -0
  25. package/dist/{chunk-TRIZ7IB7.js → chunk-MPQDF75X.js} +148 -288
  26. package/dist/chunk-MPQDF75X.js.map +1 -0
  27. package/dist/{chunk-MSFACPQQ.js → chunk-PAEM3OWN.js} +11 -11
  28. package/dist/{chunk-MSFACPQQ.js.map → chunk-PAEM3OWN.js.map} +1 -1
  29. package/dist/{chunk-GIO7BFE7.js → chunk-RQD3D2CO.js} +66 -169
  30. package/dist/{chunk-GIO7BFE7.js.map → chunk-RQD3D2CO.js.map} +1 -1
  31. package/dist/{chunk-YDJW5XTN.js → chunk-STT7INZR.js} +25 -1
  32. package/dist/chunk-STT7INZR.js.map +1 -0
  33. package/dist/{chunk-6MTY77WU.js → chunk-TNMXZLDR.js} +3 -3
  34. package/dist/{chunk-BC3S53OZ.js → chunk-UQE2Y64H.js} +30 -14
  35. package/dist/chunk-UQE2Y64H.js.map +1 -0
  36. package/dist/{chunk-22KLBHPS.js → chunk-W66AZIOH.js} +2 -2
  37. package/dist/chunk-W66AZIOH.js.map +1 -0
  38. package/dist/{chunk-SS3E6QLB.js → chunk-YNUBMSMV.js} +2 -2
  39. package/dist/chunk-YNUBMSMV.js.map +1 -0
  40. package/dist/{chunk-NZ655MWE.js → chunk-ZOD2ZY6X.js} +5 -4
  41. package/dist/chunk-ZOD2ZY6X.js.map +1 -0
  42. package/dist/{chunk-74C6SNEC.js → chunk-ZPK5656W.js} +3 -3
  43. package/dist/{chunk-74C6SNEC.js.map → chunk-ZPK5656W.js.map} +1 -1
  44. package/dist/components.d.ts +22 -899
  45. package/dist/components.js +436 -3118
  46. package/dist/components.js.map +1 -1
  47. package/dist/file-reference-9xUOnwyt.d.ts +70 -0
  48. package/dist/hooks.d.ts +2 -2
  49. package/dist/hooks.js +10 -10
  50. package/dist/hooks.js.map +1 -1
  51. package/dist/index.d.ts +49 -9
  52. package/dist/index.js +190 -25
  53. package/dist/index.js.map +1 -1
  54. package/dist/{organisation-CO3Sh3_D.d.ts → organisation-t-vvQC3g.d.ts} +1 -8
  55. package/dist/providers.d.ts +2 -2
  56. package/dist/providers.js +5 -5
  57. package/dist/rbac/index.d.ts +65 -46
  58. package/dist/rbac/index.js +10 -12
  59. package/dist/styles/core.css +0 -125
  60. package/dist/types.d.ts +2 -1
  61. package/dist/types.js +3 -1
  62. package/dist/types.js.map +1 -1
  63. package/dist/{usePublicRouteParams-B2OcAsur.d.ts → usePublicRouteParams-CdoFxnJK.d.ts} +1 -1
  64. package/dist/utils.d.ts +3 -4
  65. package/dist/utils.js +44 -13
  66. package/dist/utils.js.map +1 -1
  67. package/docs/FILE_REFERENCE_SYSTEM.md +440 -0
  68. package/docs/INDEX.md +7 -5
  69. package/docs/README.md +0 -1
  70. package/docs/api/README.md +0 -4
  71. package/docs/api/classes/ErrorBoundary.md +1 -1
  72. package/docs/api/classes/InvalidScopeError.md +1 -1
  73. package/docs/api/classes/MissingUserContextError.md +1 -1
  74. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  75. package/docs/api/classes/PermissionDeniedError.md +2 -2
  76. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  77. package/docs/api/classes/RBACAuditManager.md +12 -12
  78. package/docs/api/classes/RBACCache.md +1 -1
  79. package/docs/api/classes/RBACEngine.md +6 -6
  80. package/docs/api/classes/RBACError.md +1 -1
  81. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  82. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  83. package/docs/api/classes/StorageUtils.md +281 -0
  84. package/docs/api/interfaces/AggregateConfig.md +1 -1
  85. package/docs/api/interfaces/ButtonProps.md +1 -1
  86. package/docs/api/interfaces/CardProps.md +1 -1
  87. package/docs/api/interfaces/ColorPalette.md +1 -1
  88. package/docs/api/interfaces/ColorShade.md +1 -1
  89. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  90. package/docs/api/interfaces/DataTableAction.md +1 -1
  91. package/docs/api/interfaces/DataTableColumn.md +1 -1
  92. package/docs/api/interfaces/DataTableProps.md +1 -1
  93. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  94. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  95. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  96. package/docs/api/interfaces/EventContextType.md +1 -1
  97. package/docs/api/interfaces/EventLogoProps.md +1 -1
  98. package/docs/api/interfaces/EventProviderProps.md +1 -1
  99. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  100. package/docs/api/interfaces/FileUploadProps.md +1 -1
  101. package/docs/api/interfaces/FooterProps.md +1 -1
  102. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  103. package/docs/api/interfaces/InputProps.md +1 -1
  104. package/docs/api/interfaces/LabelProps.md +1 -1
  105. package/docs/api/interfaces/LoginFormProps.md +1 -1
  106. package/docs/api/interfaces/NavigationAccessRecord.md +2 -2
  107. package/docs/api/interfaces/NavigationContextType.md +1 -1
  108. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  109. package/docs/api/interfaces/NavigationItem.md +1 -1
  110. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  111. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  112. package/docs/api/interfaces/Organisation.md +1 -1
  113. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  114. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  115. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  116. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  117. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  118. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  119. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  120. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  121. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  122. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  123. package/docs/api/interfaces/PaletteData.md +1 -1
  124. package/docs/api/interfaces/PermissionEnforcerProps.md +4 -4
  125. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  126. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  127. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  128. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  129. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  130. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  131. package/docs/api/interfaces/RBACConfig.md +1 -1
  132. package/docs/api/interfaces/RBACContextType.md +1 -1
  133. package/docs/api/interfaces/RBACLogger.md +1 -1
  134. package/docs/api/interfaces/RBACProviderProps.md +1 -1
  135. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  136. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  137. package/docs/api/interfaces/RouteAccessRecord.md +2 -2
  138. package/docs/api/interfaces/RouteConfig.md +2 -2
  139. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  140. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  141. package/docs/api/interfaces/StorageConfig.md +1 -1
  142. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  143. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  144. package/docs/api/interfaces/StorageListOptions.md +1 -1
  145. package/docs/api/interfaces/StorageListResult.md +1 -1
  146. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  147. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  148. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  149. package/docs/api/interfaces/StyleImport.md +1 -1
  150. package/docs/api/interfaces/ToastActionElement.md +1 -1
  151. package/docs/api/interfaces/ToastProps.md +1 -1
  152. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  153. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  154. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  155. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  156. package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
  157. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  158. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  159. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  160. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  161. package/docs/api/interfaces/UserEventAccess.md +1 -1
  162. package/docs/api/interfaces/UserMenuProps.md +1 -1
  163. package/docs/api/interfaces/UserProfile.md +1 -1
  164. package/docs/api/modules.md +204 -200
  165. package/docs/api-reference/components.md +141 -163
  166. package/docs/api-reference/hooks.md +347 -0
  167. package/docs/core-concepts/rbac-system.md +69 -16
  168. package/docs/getting-started/examples/basic-auth-app.md +0 -1
  169. package/docs/implementation-guides/datatable-rbac-usage.md +12 -11
  170. package/docs/implementation-guides/file-upload-storage.md +733 -0
  171. package/docs/implementation-guides/inactivity-tracking.md +779 -0
  172. package/docs/implementation-guides/organisation-security.md +748 -0
  173. package/docs/implementation-guides/public-pages-advanced.md +1022 -0
  174. package/docs/migration/MIGRATION_GUIDE.md +684 -0
  175. package/docs/migration/README.md +13 -2
  176. package/docs/migration/rbac-migration.md +73 -0
  177. package/docs/rbac/examples/rbac-rls-integration-example.md +11 -13
  178. package/docs/style-guide.md +269 -1
  179. package/package.json +1 -1
  180. package/src/__tests__/TESTING_GUIDELINES.md +331 -18
  181. package/src/__tests__/helpers/supabaseMock.ts +99 -0
  182. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +10 -7
  183. package/src/__tests__/shared.ts +6 -0
  184. package/src/components/DataTable/components/ActionButtons.tsx +2 -2
  185. package/src/components/DataTable/components/DataTableCore.tsx +2 -2
  186. package/src/components/DataTable/components/UnifiedTableBody.tsx +1 -1
  187. package/src/components/DataTable/utils/debugTools.ts +2 -2
  188. package/src/components/Dialog/Dialog.test.tsx +12 -2
  189. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +6 -6
  190. package/src/components/ErrorBoundary/ErrorBoundary.tsx +2 -2
  191. package/src/components/FileDisplay.tsx +233 -0
  192. package/src/components/FileUpload.tsx +176 -0
  193. package/src/components/Footer/Footer.test.tsx +7 -7
  194. package/src/components/NavigationMenu/NavigationMenu.test.tsx +13 -6
  195. package/src/components/OrganisationSelector/OrganisationSelector.test.tsx +30 -3
  196. package/src/components/OrganisationSelector/OrganisationSelector.tsx +1 -1
  197. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.rbac.test.tsx +558 -0
  198. package/src/components/PublicLayout/PublicErrorBoundary.tsx +1 -1
  199. package/src/components/PublicLayout/PublicPageDebugger.tsx +2 -2
  200. package/src/components/PublicLayout/PublicPageDiagnostic.tsx +2 -2
  201. package/src/components/PublicLayout/PublicPageProvider.tsx +2 -2
  202. package/src/components/Select/Select.test.tsx +50 -15
  203. package/src/components/SuperAdminGuard.tsx +2 -2
  204. package/src/components/__tests__/SuperAdminGuard.test.tsx +559 -0
  205. package/src/components/index.ts +0 -183
  206. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +2 -2
  207. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +1 -1
  208. package/src/hooks/__tests__/useRBAC.unit.test.ts +191 -138
  209. package/src/hooks/public/usePublicEvent.ts +2 -2
  210. package/src/hooks/useAppConfig.ts +3 -3
  211. package/src/hooks/useComponentPerformance.ts +1 -1
  212. package/src/hooks/useDataTablePerformance.ts +1 -1
  213. package/src/hooks/useFileReference.ts +232 -0
  214. package/src/hooks/useOrganisationPermissions.test.ts +254 -344
  215. package/src/hooks/useOrganisationPermissions.ts +15 -7
  216. package/src/hooks/useOrganisationSecurity.test.ts +390 -402
  217. package/src/hooks/usePerformanceMonitor.ts +1 -1
  218. package/src/hooks/usePermissionCache.test.ts +264 -395
  219. package/src/hooks/usePermissionCache.ts +34 -4
  220. package/src/hooks/useSecureDataAccess.test.ts +486 -0
  221. package/src/hooks/useSecureDataAccess.ts +4 -1
  222. package/src/providers/InactivityProvider.tsx +2 -2
  223. package/src/providers/OrganisationProvider.test.simple.tsx +168 -0
  224. package/src/providers/OrganisationProvider.test.tsx +168 -0
  225. package/src/providers/OrganisationProvider.tsx +18 -31
  226. package/src/providers/UnifiedAuthProvider.test.simple.tsx +205 -0
  227. package/src/providers/UnifiedAuthProvider.test.tsx +128 -0
  228. package/src/providers/__tests__/InactivityProvider.test.tsx +3 -4
  229. package/src/providers/__tests__/OrganisationProvider.test.tsx +19 -14
  230. package/src/rbac/__tests__/integration.authflow.test.tsx +123 -0
  231. package/src/rbac/__tests__/integration.navigation.test.tsx +72 -0
  232. package/src/rbac/__tests__/integration.securedata.test.tsx +92 -0
  233. package/src/rbac/__tests__/integration.smoke.test.tsx +73 -0
  234. package/src/rbac/__tests__/rbac-core.test.tsx +26 -22
  235. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +411 -0
  236. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +285 -0
  237. package/src/rbac/__tests__/rbac-functions.test.ts +655 -0
  238. package/src/rbac/__tests__/rbac-integration.test.ts +532 -0
  239. package/src/rbac/__tests__/scenarios.user-role.test.tsx +196 -0
  240. package/src/rbac/api.test.ts +6 -6
  241. package/src/rbac/api.ts +2 -2
  242. package/src/rbac/audit.test.ts +485 -0
  243. package/src/rbac/audit.ts +7 -1
  244. package/src/rbac/cache-invalidation.ts +318 -0
  245. package/src/rbac/cache.test.ts +286 -0
  246. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +559 -0
  247. package/src/rbac/components/EnhancedNavigationMenu.tsx +29 -23
  248. package/src/rbac/components/NavigationProvider.test.tsx +449 -0
  249. package/src/rbac/components/PagePermissionGuard.tsx +4 -4
  250. package/src/rbac/components/PagePermissionProvider.test.tsx +479 -0
  251. package/src/rbac/components/SecureDataProvider.test.tsx +511 -0
  252. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +159 -430
  253. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +4 -5
  254. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +112 -118
  255. package/src/rbac/config.test.ts +410 -0
  256. package/src/rbac/engine.test.simple.ts +237 -0
  257. package/src/rbac/engine.test.ts +233 -0
  258. package/src/rbac/engine.ts +37 -41
  259. package/src/rbac/examples/CompleteRBACExample.tsx +3 -3
  260. package/src/rbac/examples/EventBasedApp.tsx +4 -4
  261. package/src/rbac/hooks/useRBAC.simple.test.ts +16 -0
  262. package/src/rbac/hooks/useRBAC.test.ts +207 -455
  263. package/src/rbac/hooks/useRBAC.ts +30 -22
  264. package/src/rbac/permissions.test.ts +128 -0
  265. package/src/rbac/permissions.ts +56 -141
  266. package/src/rbac/providers/RBACProvider.tsx +1 -1
  267. package/src/rbac/secureClient.test.ts +444 -0
  268. package/src/rbac/security.test.ts +390 -0
  269. package/src/rbac/security.ts +1 -1
  270. package/src/rbac/types.test.ts +382 -0
  271. package/src/rbac/types.ts +2 -2
  272. package/src/styles/base.css +208 -0
  273. package/src/styles/core.css +0 -125
  274. package/src/styles/semantic.css +24 -0
  275. package/src/types/file-reference.ts +77 -0
  276. package/src/types/rbac-functions.ts +290 -0
  277. package/src/types/supabase.ts +10 -28
  278. package/src/types/unified.ts +4 -1
  279. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +81 -55
  280. package/src/utils/__tests__/lazyLoad.unit.test.tsx +21 -12
  281. package/src/utils/__tests__/organisationContext.unit.test.ts +13 -7
  282. package/src/utils/__tests__/performanceBudgets.unit.test.ts +3 -3
  283. package/src/utils/__tests__/sessionTracking.unit.test.ts +32 -12
  284. package/src/utils/appConfig.ts +1 -1
  285. package/src/utils/appIdResolver.test.ts +503 -0
  286. package/src/utils/appIdResolver.ts +1 -1
  287. package/src/utils/appNameResolver.test.ts +494 -0
  288. package/src/utils/appNameResolver.ts +3 -2
  289. package/src/utils/bundleAnalysis.ts +3 -3
  290. package/src/utils/debugLogger.ts +1 -1
  291. package/src/utils/file-reference.ts +263 -0
  292. package/src/utils/formatDate.test.ts +2 -2
  293. package/src/utils/organisationContext.test.ts +340 -0
  294. package/src/utils/organisationContext.ts +19 -6
  295. package/src/utils/performanceBudgets.ts +2 -2
  296. package/src/utils/permissionUtils.test.ts +393 -0
  297. package/src/utils/permissionUtils.ts +5 -2
  298. package/src/utils/secureDataAccess.test.ts +715 -0
  299. package/src/utils/secureDataAccess.ts +21 -5
  300. package/src/utils/sessionTracking.ts +34 -4
  301. package/src/utils/storage/__tests__/helpers.unit.test.ts +328 -0
  302. package/src/utils/storage/__tests__/index.unit.test.ts +16 -0
  303. package/src/utils/storage/helpers.ts +20 -25
  304. package/src/utils/storage/index.ts +29 -1
  305. package/src/vite-env.d.ts +17 -0
  306. package/dist/chunk-22KLBHPS.js.map +0 -1
  307. package/dist/chunk-7BNPOCLL.js.map +0 -1
  308. package/dist/chunk-BC3S53OZ.js.map +0 -1
  309. package/dist/chunk-GWSBHC4J.js.map +0 -1
  310. package/dist/chunk-MYP2EGHX.js.map +0 -1
  311. package/dist/chunk-MZBUOP4P.js.map +0 -1
  312. package/dist/chunk-NYUJ4FJR.js.map +0 -1
  313. package/dist/chunk-NZ655MWE.js.map +0 -1
  314. package/dist/chunk-SS3E6QLB.js.map +0 -1
  315. package/dist/chunk-TRIZ7IB7.js.map +0 -1
  316. package/dist/chunk-WJARTBCT.js.map +0 -1
  317. package/dist/chunk-YDJW5XTN.js.map +0 -1
  318. package/docs/print-components/README.md +0 -258
  319. package/docs/print-components/api-reference.md +0 -636
  320. package/docs/print-components/examples/README.md +0 -204
  321. package/docs/print-components/examples/basic-report.tsx +0 -92
  322. package/docs/print-components/examples/card-catalog.tsx +0 -149
  323. package/docs/print-components/examples/cover-page-report.tsx +0 -163
  324. package/docs/print-components/quick-start.md +0 -363
  325. package/src/components/PrintButton/PrintButton.tsx +0 -321
  326. package/src/components/PrintButton/PrintButtonGroup.tsx +0 -84
  327. package/src/components/PrintButton/PrintToolbar.tsx +0 -94
  328. package/src/components/PrintButton/__tests__/PrintButton.test.tsx +0 -271
  329. package/src/components/PrintButton/examples/PrintButtonShowcase.tsx +0 -438
  330. package/src/components/PrintButton/index.ts +0 -33
  331. package/src/components/PrintButton/types.ts +0 -173
  332. package/src/components/PrintCard/PrintCard.tsx +0 -154
  333. package/src/components/PrintCard/PrintCardContent.tsx +0 -57
  334. package/src/components/PrintCard/PrintCardFooter.tsx +0 -60
  335. package/src/components/PrintCard/PrintCardGrid.tsx +0 -91
  336. package/src/components/PrintCard/PrintCardHeader.tsx +0 -78
  337. package/src/components/PrintCard/PrintCardImage.tsx +0 -81
  338. package/src/components/PrintCard/examples/PrintCardShowcase.tsx +0 -239
  339. package/src/components/PrintCard/index.ts +0 -34
  340. package/src/components/PrintCard/types.ts +0 -171
  341. package/src/components/PrintDataTable/PrintDataTable.tsx +0 -215
  342. package/src/components/PrintDataTable/PrintTableGroup.tsx +0 -90
  343. package/src/components/PrintDataTable/PrintTableRow.tsx +0 -76
  344. package/src/components/PrintDataTable/index.ts +0 -25
  345. package/src/components/PrintDataTable/types.ts +0 -67
  346. package/src/components/PrintFooter/PrintFooter.tsx +0 -183
  347. package/src/components/PrintFooter/PrintFooterContent.tsx +0 -71
  348. package/src/components/PrintFooter/PrintFooterInfo.tsx +0 -86
  349. package/src/components/PrintFooter/PrintPageNumber.tsx +0 -90
  350. package/src/components/PrintFooter/examples/PrintFooterShowcase.tsx +0 -390
  351. package/src/components/PrintFooter/index.ts +0 -30
  352. package/src/components/PrintFooter/types.ts +0 -149
  353. package/src/components/PrintGrid/PrintGrid.tsx +0 -180
  354. package/src/components/PrintGrid/PrintGridBreakpoint.tsx +0 -109
  355. package/src/components/PrintGrid/PrintGridContainer.tsx +0 -128
  356. package/src/components/PrintGrid/PrintGridItem.tsx +0 -220
  357. package/src/components/PrintGrid/examples/PrintGridShowcase.tsx +0 -359
  358. package/src/components/PrintGrid/index.ts +0 -31
  359. package/src/components/PrintGrid/types.ts +0 -159
  360. package/src/components/PrintHeader/PrintCoverHeader.tsx +0 -230
  361. package/src/components/PrintHeader/PrintHeader.tsx +0 -150
  362. package/src/components/PrintHeader/index.ts +0 -17
  363. package/src/components/PrintHeader/types.ts +0 -42
  364. package/src/components/PrintLayout/PrintLayout.tsx +0 -122
  365. package/src/components/PrintLayout/PrintLayoutContext.tsx +0 -66
  366. package/src/components/PrintLayout/PrintPageBreak.tsx +0 -52
  367. package/src/components/PrintLayout/examples/PrintShowcase.tsx +0 -230
  368. package/src/components/PrintLayout/index.ts +0 -19
  369. package/src/components/PrintLayout/types.ts +0 -37
  370. package/src/components/PrintPageBreak/PrintPageBreak.tsx +0 -120
  371. package/src/components/PrintPageBreak/PrintPageBreakGroup.tsx +0 -90
  372. package/src/components/PrintPageBreak/PrintPageBreakIndicator.tsx +0 -112
  373. package/src/components/PrintPageBreak/examples/PrintPageBreakShowcase.tsx +0 -279
  374. package/src/components/PrintPageBreak/index.ts +0 -23
  375. package/src/components/PrintPageBreak/types.ts +0 -94
  376. package/src/components/PrintSection/PrintColumn.tsx +0 -104
  377. package/src/components/PrintSection/PrintDivider.tsx +0 -101
  378. package/src/components/PrintSection/PrintSection.tsx +0 -129
  379. package/src/components/PrintSection/PrintSectionContent.tsx +0 -75
  380. package/src/components/PrintSection/PrintSectionHeader.tsx +0 -97
  381. package/src/components/PrintSection/examples/PrintSectionShowcase.tsx +0 -258
  382. package/src/components/PrintSection/index.ts +0 -33
  383. package/src/components/PrintSection/types.ts +0 -155
  384. package/src/components/PrintText/PrintText.tsx +0 -116
  385. package/src/components/PrintText/index.ts +0 -16
  386. package/src/components/PrintText/types.ts +0 -24
  387. package/src/rbac/__tests__/integration.test.tsx +0 -218
  388. package/src/utils/print/PrintDataProcessor.ts +0 -390
  389. package/src/utils/print/examples/PrintUtilitiesShowcase.tsx +0 -397
  390. package/src/utils/print/index.ts +0 -29
  391. package/src/utils/print/types.ts +0 -196
  392. package/src/utils/print/usePrintOptimization.ts +0 -272
  393. /package/dist/{DataTable-7FMFXA7A.js.map → DataTable-4T627QFJ.js.map} +0 -0
  394. /package/dist/{api-H5A3H4IR.js.map → api-LUNF5O6M.js.map} +0 -0
  395. /package/dist/{appNameResolver-7GHF5ED2.js.map → appNameResolver-UURKN7NF.js.map} +0 -0
  396. /package/dist/{audit-BUW3LMJB.js.map → audit-6TOCAMKO.js.map} +0 -0
  397. /package/dist/{chunk-NRK4AIHQ.js.map → chunk-KBRACSJI.js.map} +0 -0
  398. /package/dist/{chunk-6MTY77WU.js.map → chunk-TNMXZLDR.js.map} +0 -0
@@ -32,24 +32,16 @@
32
32
  ## 🏗️ Test Structure
33
33
 
34
34
  ### File Organization
35
- Tests should be colocated with the component, hook, or utility they test (e.g., Button.test.tsx next to Button.tsx).
36
- Use src/__tests__/integration/ only for multi-feature tests that span across modules.
37
-
38
- ```
39
- src/
40
- ├── components/
41
- ├── Button/
42
- │ │ ├── Button.tsx
43
- │ │ └── Button.test.tsx ← colocated unit/component test
44
- ├── hooks/
45
- │ ├── useAuth.ts
46
- │ └── useAuth.test.ts ✅
47
- ├── utils/
48
- │ ├── formatDate.ts
49
- │ └── formatDate.test.ts ✅
50
- ├── __tests__/integration/ ✅ ← multi-module tests, auth flows, user journeys
51
- ├── __tests__/fixtures/ ✅ ← factories, mock data
52
- ├── __tests__/helpers/ ✅ ← shared test utilities
35
+ ```
36
+ src/__tests__/
37
+ ├── components/ # Component tests
38
+ ├── hooks/ # Hook tests
39
+ ├── utils/ # Utility function tests
40
+ ├── integration/ # Integration tests
41
+ ├── unit/ # Unit tests
42
+ ├── fixtures/ # Test data and mocks
43
+ ├── helpers/ # Test utilities
44
+ └── types/ # Test type definitions
53
45
  ```
54
46
 
55
47
  ### Test File Naming
@@ -339,3 +331,324 @@ screen.logTestingPlaygroundURL();
339
331
  - [Vitest Docs](https://vitest.dev/)
340
332
  - [Testing Best Practices](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)
341
333
  - [Jest DOM Matchers](https://github.com/testing-library/jest-dom)
334
+ ---
335
+
336
+ ## 🔖 Test Type Tags
337
+
338
+ Use explicit tags to clarify the type of test being written:
339
+
340
+ - `[unit]` – for isolated logic (e.g. pure functions, hooks)
341
+ - `[component]` – for rendering UI components with interactions
342
+ - `[integration]` – for multi-module tests or user journeys
343
+
344
+ **Example:**
345
+
346
+ ```ts
347
+ describe('[unit] useDebounce', () => {
348
+ it('should delay the update', () => { ... })
349
+ })
350
+ ```
351
+
352
+ ---
353
+
354
+ ## 🚫 Skipped Tests Policy
355
+
356
+ - All `it.skip` or `test.skip` must include a comment explaining why, and reference a JIRA or GitHub issue.
357
+ - Example:
358
+
359
+ ```ts
360
+ it.skip('fails intermittently in CI – see GH#456', () => { ... })
361
+ ```
362
+
363
+ ---
364
+
365
+ ## 🗂 File Placement
366
+
367
+ - ✅ Unit/component tests should be colocated with their source file.
368
+ - ✅ Integration tests go in `src/__tests__/integration/`.
369
+ - ✅ Test utilities, fixtures, and mock setup belong in `src/__tests__/helpers/` or `src/__tests__/fixtures/`.
370
+
371
+ ---
372
+
373
+ ## 🧑‍🎨 Style-Resilient Test Practices
374
+
375
+ Tests should **never assert class names, layout structure, or DOM nesting** unless explicitly testing responsive/UI logic.
376
+ Instead, assert **visible output and interactive behaviour** that users experience (e.g. text content, button states, aria roles, form values).
377
+ This ensures tests remain stable through valid styling and layout changes.
378
+
379
+ ---
380
+
381
+ ## 🚀 Performance Best Practices
382
+
383
+ - Avoid global mocks unless necessary.
384
+ - Prefer `beforeEach` over `beforeAll` to keep tests isolated.
385
+ - Minimise deep setup logic—use lightweight, focused factories.
386
+ - Use `vi.useFakeTimers()` for time-sensitive logic.
387
+ - Monitor heap usage with `--logHeapUsage` flag for memory-intensive tests.
388
+ - Reduce parallelization if encountering memory issues.
389
+
390
+ ---
391
+
392
+ ## 🧹 Memory Leak Prevention
393
+
394
+ ### Common Causes of Memory Leaks
395
+ 1. **Unmounted timers** - setInterval/setTimeout not cleared
396
+ 2. **Event listeners** - Not removed in cleanup
397
+ 3. **Subscriptions** - Not unsubscribed
398
+ 4. **DOM references** - Lingering references to removed elements
399
+ 5. **Global state** - Not reset between tests
400
+ 6. **Mocks** - Not cleared after tests
401
+
402
+ ### Prevention Checklist
403
+ ```typescript
404
+ describe('Component with Resources', () => {
405
+ beforeEach(() => {
406
+ // Setup fake timers if using setTimeout/setInterval
407
+ vi.useFakeTimers();
408
+ });
409
+
410
+ afterEach(() => {
411
+ // Clear all timers
412
+ vi.clearAllTimers();
413
+ vi.useRealTimers();
414
+
415
+ // React Testing Library cleanup (unmount components)
416
+ cleanup();
417
+
418
+ // Clear all mocks
419
+ vi.clearAllMocks();
420
+
421
+ // Clear storage
422
+ localStorage.clear();
423
+ sessionStorage.clear();
424
+ });
425
+
426
+ it('handles async operations', async () => {
427
+ // test implementation
428
+ });
429
+ });
430
+ ```
431
+
432
+ ### Detecting Memory Leaks
433
+ ```bash
434
+ # Run tests with heap logging
435
+ npm test -- --logHeapUsage
436
+
437
+ # Look for tests showing increasing memory usage
438
+ # Baseline: 44-50 MB
439
+ # Warning: 50-55 MB
440
+ # Critical: >55 MB
441
+ ```
442
+
443
+ ---
444
+
445
+ ## ⏱️ Async Testing Best Practices
446
+
447
+ ### Use findBy Over getBy + waitFor
448
+ ```typescript
449
+ // ❌ Bad - Inefficient
450
+ await waitFor(() => {
451
+ expect(screen.getByRole('button')).toBeInTheDocument();
452
+ });
453
+
454
+ // ✅ Good - Built-in waiting
455
+ const button = await screen.findByRole('button');
456
+ expect(button).toBeInTheDocument();
457
+ ```
458
+
459
+ ### Set Appropriate Timeouts
460
+ ```typescript
461
+ // For fast synchronous operations - don't use waitFor
462
+ expect(result.current.value).toBe('test');
463
+
464
+ // For quick async operations
465
+ await waitFor(() => {
466
+ expect(result.current.isLoading).toBe(false);
467
+ }, { timeout: 100, interval: 10 });
468
+
469
+ // For slow operations only
470
+ await waitFor(() => {
471
+ expect(result.current.data).toBeDefined();
472
+ }, { timeout: 5000 });
473
+ ```
474
+
475
+ ### waitFor Usage Guidelines
476
+ - **DON'T** use waitFor for synchronous operations
477
+ - **DO** use findBy queries when waiting for elements
478
+ - **DO** set explicit timeouts based on expected operation speed
479
+ - **DO** add interval to reduce polling frequency for slow operations
480
+ - **DON'T** nest waitFor calls (causes exponential delays)
481
+
482
+ ### Common waitFor Mistakes
483
+ ```typescript
484
+ // ❌ Bad - Waiting for sync operation
485
+ const { result } = renderHook(() => useCounter(0));
486
+ await waitFor(() => {
487
+ expect(result.current.count).toBe(0); // This is synchronous!
488
+ });
489
+
490
+ // ✅ Good - Direct assertion
491
+ const { result } = renderHook(() => useCounter(0));
492
+ expect(result.current.count).toBe(0);
493
+
494
+ // ❌ Bad - Generic timeout without condition
495
+ await waitFor(() => {}, { timeout: 1000 }); // Just waiting
496
+
497
+ // ✅ Good - Wait for specific condition
498
+ await waitFor(() => {
499
+ expect(result.current.isLoading).toBe(false);
500
+ });
501
+ ```
502
+
503
+ ---
504
+
505
+ ## 🔧 Mocking Complex APIs
506
+
507
+ ### Mocking Functions with Multiple Call Signatures
508
+ When testing code that calls a mocked function multiple times with different parameters:
509
+
510
+ ```typescript
511
+ // ❌ Bad - mockResolvedValue returns same data for all calls
512
+ mockSupabase.rpc.mockResolvedValue({ data: [...], error: null });
513
+
514
+ // ✅ Good - mockImplementation handles different calls
515
+ mockSupabase.rpc.mockImplementation((functionName: string, params) => {
516
+ if (functionName === 'get_user') {
517
+ return Promise.resolve({ data: { id: '1' }, error: null });
518
+ }
519
+ if (functionName === 'get_permissions') {
520
+ return Promise.resolve({ data: [...], error: null });
521
+ }
522
+ return Promise.resolve({ data: null, error: null });
523
+ });
524
+ ```
525
+
526
+ ### Example: useRBAC Hook Mocking
527
+ ```typescript
528
+ // useRBAC makes TWO RPC calls - must mock both
529
+ const setupRBACMock = (permissions: any[] = []) => {
530
+ mockSupabase.rpc.mockImplementation((functionName, params) => {
531
+ if (functionName === 'rbac_app_resolve') {
532
+ return Promise.resolve({
533
+ data: [{ app_id: 'test-app-id', has_access: true }],
534
+ error: null
535
+ });
536
+ }
537
+ if (functionName === 'rbac_permissions_get') {
538
+ return Promise.resolve({ data: permissions, error: null });
539
+ }
540
+ return Promise.resolve({ data: null, error: null });
541
+ });
542
+ };
543
+
544
+ // Usage in tests
545
+ it('loads user permissions', async () => {
546
+ setupRBACMock([
547
+ { permission_type: 'all_permissions', role_name: 'super_admin' }
548
+ ]);
549
+
550
+ const { result } = renderHook(() => useRBAC());
551
+ await waitFor(() => {
552
+ expect(result.current.globalRole).toBe('super_admin');
553
+ });
554
+ });
555
+ ```
556
+
557
+ ---
558
+
559
+ ## 🎨 jsdom Configuration
560
+
561
+ ### Enable Visual Testing Features
562
+ To prevent `getComputedStyle` and other visual API errors:
563
+
564
+ ```typescript
565
+ // vitest.config.ts
566
+ export default defineConfig({
567
+ test: {
568
+ environment: 'jsdom',
569
+ environmentOptions: {
570
+ jsdom: {
571
+ pretendToBeVisual: true, // Enables getComputedStyle
572
+ resources: 'usable', // Enables resource loading
573
+ }
574
+ }
575
+ }
576
+ });
577
+ ```
578
+
579
+ ### Benefits
580
+ - ✅ Automatic getComputedStyle support
581
+ - ✅ Proper CSS property access
582
+ - ✅ Window.matchMedia support
583
+ - ✅ Element.getBoundingClientRect support
584
+ - ✅ No manual mocking needed
585
+
586
+ ---
587
+
588
+ ## 🚫 Common Test Anti-Patterns
589
+
590
+ ### 1. Testing with Wrong Mock Approach
591
+ ```typescript
592
+ // ❌ Bad - Single mockResolvedValue for multiple calls
593
+ mockApi.fetch.mockResolvedValue(data);
594
+ // Problem: All calls get same data, even if they should differ
595
+
596
+ // ✅ Good - mockImplementation for different calls
597
+ mockApi.fetch.mockImplementation((endpoint) => {
598
+ if (endpoint === '/users') return Promise.resolve(users);
599
+ if (endpoint === '/posts') return Promise.resolve(posts);
600
+ return Promise.resolve(null);
601
+ });
602
+ ```
603
+
604
+ ### 2. Not Accounting for Multiple API Calls
605
+ ```typescript
606
+ // ❌ Bad - Assumes hook makes one call
607
+ mockApi.getData.mockResolvedValue(testData);
608
+
609
+ // ✅ Good - Account for all calls hook makes
610
+ mockApi.getData.mockImplementation((type) => {
611
+ if (type === 'config') return Promise.resolve(config);
612
+ if (type === 'data') return Promise.resolve(testData);
613
+ return Promise.resolve(null);
614
+ });
615
+ ```
616
+
617
+ ### 3. Insufficient Async Handling
618
+ ```typescript
619
+ // ❌ Bad - Not waiting for async updates
620
+ const { result } = renderHook(() => useAsync());
621
+ expect(result.current.data).toBeDefined(); // May still be loading!
622
+
623
+ // ✅ Good - Wait for async completion
624
+ const { result } = renderHook(() => useAsync());
625
+ await waitFor(() => {
626
+ expect(result.current.isLoading).toBe(false);
627
+ });
628
+ expect(result.current.data).toBeDefined();
629
+ ```
630
+
631
+ ---
632
+
633
+ ## 🎯 Coverage Expectations
634
+
635
+ Minimum thresholds per category:
636
+
637
+ - Core utils/hooks: **≥ 95%**
638
+ - UI components: **≥ 90%**
639
+ - Feature modules: **≥ 85%**
640
+ - Overall project: **≥ 82%** (targeting continuous improvement)
641
+
642
+ ---
643
+
644
+ ## 📚 Additional Resources
645
+
646
+ - [Vitest Mocking Guide](https://vitest.dev/guide/mocking.html)
647
+ - [Testing Library Best Practices](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)
648
+ - [React Hooks Testing](https://react-hooks-testing-library.com/)
649
+ - [jsdom Documentation](https://github.com/jsdom/jsdom)
650
+
651
+ ### Internal Documentation
652
+ - [TEST_FAILURE_ANALYSIS.md](../../../TEST_FAILURE_ANALYSIS.md) - Common test failures and fixes
653
+ - [MEMORY_PERFORMANCE_ANALYSIS.md](../../../MEMORY_PERFORMANCE_ANALYSIS.md) - Performance optimization guide
654
+ - [TEST_SUITE_IMPLEMENTATION_GUIDE.md](../../../TEST_SUITE_IMPLEMENTATION_GUIDE.md) - Step-by-step implementation guide
@@ -0,0 +1,99 @@
1
+ /**
2
+ * @file Supabase Mock Utilities
3
+ * @package @jmruthers/pace-core
4
+ * @module TestHelpers/SupabaseMock
5
+ * @since 0.4.0
6
+ *
7
+ * Proper Supabase mock utilities that implement thenable interface for testing.
8
+ */
9
+
10
+ import { vi } from 'vitest';
11
+
12
+ /**
13
+ * Creates a proper thenable mock query builder that can be awaited
14
+ */
15
+ export const createMockQueryBuilder = (defaultData: any = { data: [], error: null }) => {
16
+ const mockQueryBuilder = {
17
+ select: vi.fn().mockReturnThis(),
18
+ insert: vi.fn().mockReturnThis(),
19
+ update: vi.fn().mockReturnThis(),
20
+ delete: vi.fn().mockReturnThis(),
21
+ eq: vi.fn().mockReturnThis(),
22
+ neq: vi.fn().mockReturnThis(),
23
+ in: vi.fn().mockReturnThis(),
24
+ is: vi.fn().mockReturnThis(),
25
+ order: vi.fn().mockReturnThis(),
26
+ limit: vi.fn().mockReturnThis(),
27
+ offset: vi.fn().mockReturnThis(),
28
+ range: vi.fn().mockReturnThis(),
29
+ single: vi.fn().mockResolvedValue({ data: null, error: null }),
30
+ maybeSingle: vi.fn().mockResolvedValue({ data: null, error: null }),
31
+
32
+ // Implement thenable interface for await support
33
+ then: vi.fn().mockImplementation((resolve, reject) => {
34
+ Promise.resolve(defaultData).then(resolve, reject);
35
+ }),
36
+
37
+ // Implement catch for error handling
38
+ catch: vi.fn().mockImplementation((onRejected) => {
39
+ return Promise.resolve(defaultData).catch(onRejected);
40
+ }),
41
+
42
+ // Implement finally for cleanup
43
+ finally: vi.fn().mockImplementation((onFinally) => {
44
+ return Promise.resolve(defaultData).finally(onFinally);
45
+ })
46
+ };
47
+
48
+ return mockQueryBuilder;
49
+ };
50
+
51
+ /**
52
+ * Creates a complete Supabase client mock
53
+ */
54
+ export const createMockSupabaseClient = (defaultData: any = { data: [], error: null }) => {
55
+ const mockQueryBuilder = createMockQueryBuilder(defaultData);
56
+
57
+ return {
58
+ from: vi.fn().mockReturnValue(mockQueryBuilder),
59
+ rpc: vi.fn().mockResolvedValue({ data: { result: 'success' }, error: null }),
60
+ auth: {
61
+ getUser: vi.fn().mockResolvedValue({ data: { user: null }, error: null }),
62
+ getSession: vi.fn().mockResolvedValue({ data: { session: null }, error: null }),
63
+ signIn: vi.fn().mockResolvedValue({ data: { user: null, session: null }, error: null }),
64
+ signOut: vi.fn().mockResolvedValue({ error: null }),
65
+ onAuthStateChange: vi.fn().mockReturnValue({ data: { subscription: { unsubscribe: vi.fn() } } })
66
+ }
67
+ };
68
+ };
69
+
70
+ /**
71
+ * Creates a mock query builder with specific data for different operations
72
+ */
73
+ export const createMockQueryBuilderWithData = (data: any, error: any = null) => {
74
+ const mockQueryBuilder = createMockQueryBuilder({ data, error });
75
+
76
+ // Override the then method to return the specific data
77
+ mockQueryBuilder.then = vi.fn().mockImplementation((resolve, reject) => {
78
+ if (error) {
79
+ reject(error);
80
+ } else {
81
+ resolve({ data, error });
82
+ }
83
+ });
84
+
85
+ return mockQueryBuilder;
86
+ };
87
+
88
+ /**
89
+ * Creates a mock query builder that rejects with an error
90
+ */
91
+ export const createMockQueryBuilderWithError = (error: any) => {
92
+ const mockQueryBuilder = createMockQueryBuilder();
93
+
94
+ mockQueryBuilder.then = vi.fn().mockImplementation((resolve, reject) => {
95
+ reject(error);
96
+ });
97
+
98
+ return mockQueryBuilder;
99
+ };
@@ -16,11 +16,13 @@ import { render, screen, waitFor, act } from '@testing-library/react';
16
16
  import { vi } from 'vitest';
17
17
  import { PagePermissionGuard } from '../../rbac/components/PagePermissionGuard';
18
18
  import { useUnifiedAuth } from '../../providers/UnifiedAuthProvider';
19
- import { useCan } from '../../rbac/hooks/usePermissions';
19
+ import { useCan } from '../../rbac/hooks';
20
20
 
21
21
  // Mock the hooks
22
22
  vi.mock('../../providers/UnifiedAuthProvider');
23
- vi.mock('../../rbac/hooks/usePermissions');
23
+ vi.mock('../../rbac/hooks', () => ({
24
+ useCan: vi.fn()
25
+ }));
24
26
  vi.mock('../../utils/appNameResolver');
25
27
 
26
28
  const mockUseUnifiedAuth = vi.mocked(useUnifiedAuth);
@@ -77,7 +79,8 @@ describe('PagePermissionGuard', () => {
77
79
  );
78
80
 
79
81
  // Should render something (either loading, content, or fallback)
80
- expect(screen.getByText('Protected Content')).toBeInTheDocument();
82
+ // With default mock (can: false), should show access denied
83
+ expect(screen.getByText('Access Denied')).toBeInTheDocument();
81
84
  });
82
85
 
83
86
  it('should show protected content when permission is granted', async () => {
@@ -136,8 +139,8 @@ describe('PagePermissionGuard', () => {
136
139
  </PagePermissionGuard>
137
140
  );
138
141
 
139
- // Should render something even with errors
140
- expect(screen.getByText('Protected Content')).toBeInTheDocument();
142
+ // Should render access denied when there's an error
143
+ expect(screen.getByText('Access Denied')).toBeInTheDocument();
141
144
  });
142
145
  });
143
146
 
@@ -180,8 +183,8 @@ describe('PagePermissionGuard', () => {
180
183
  </PagePermissionGuard>
181
184
  );
182
185
 
183
- // Should render something
184
- expect(screen.getByText('Protected Content')).toBeInTheDocument();
186
+ // Should render access denied with default mock (can: false)
187
+ expect(screen.getByText('Access Denied')).toBeInTheDocument();
185
188
  });
186
189
  });
187
190
  });
@@ -0,0 +1,6 @@
1
+ // Shared test utilities
2
+ // This file exports common test utilities used across different test files
3
+
4
+ import { testDataGenerators } from './helpers/test-utils';
5
+
6
+ export { testDataGenerators };
@@ -137,7 +137,7 @@ export function ActionButtons({
137
137
  size="sm"
138
138
  onClick={() => {
139
139
  // DEBUG: Log action click
140
- if (process.env.NODE_ENV === 'development') {
140
+ if (import.meta.env.MODE === 'development') {
141
141
  console.log('[ActionButtons] Action clicked:', {
142
142
  actionLabel: action.label,
143
143
  rowOriginal: row.original,
@@ -195,7 +195,7 @@ export function ActionButtons({
195
195
  value={`action-${actionIndex}`}
196
196
  onClick={() => {
197
197
  // DEBUG: Log action click
198
- if (process.env.NODE_ENV === 'development') {
198
+ if (import.meta.env.MODE === 'development') {
199
199
  console.log('[ActionButtons] Dropdown action clicked:', {
200
200
  actionLabel: action.label,
201
201
  rowOriginal: row.original,
@@ -688,7 +688,7 @@ function DataTableInternal<TData extends DataRecord>({
688
688
  const result = [...actions];
689
689
 
690
690
  // DEBUG: Log action configuration
691
- if (process.env.NODE_ENV === 'development') {
691
+ if (import.meta.env.MODE === 'development') {
692
692
  console.log('[DataTable] Action Configuration Debug:', {
693
693
  originalActions: actions.length,
694
694
  secureFeatures: {
@@ -743,7 +743,7 @@ function DataTableInternal<TData extends DataRecord>({
743
743
  }
744
744
 
745
745
  // DEBUG: Log final actions
746
- if (process.env.NODE_ENV === 'development') {
746
+ if (import.meta.env.MODE === 'development') {
747
747
  console.log('[DataTable] Final Actions:', {
748
748
  totalActions: result.length,
749
749
  actionLabels: result.map(a => a.label),
@@ -426,7 +426,7 @@ const MemoizedRow = ({
426
426
  const hasChildren = shouldShowExpansionButton ? hierarchical?.state?.hasChildren(rowId) : false;
427
427
 
428
428
  // Debug logging for expander button conditions (development only)
429
- if (process.env.NODE_ENV === 'development' && isParent && isFirstCell) {
429
+ if (import.meta.env.MODE === 'development' && isParent && isFirstCell) {
430
430
  console.log('🔍 Expander Button Debug:', {
431
431
  rowId,
432
432
  isHierarchical,
@@ -43,7 +43,7 @@ export interface DebugConfig {
43
43
  * Default debug configuration
44
44
  */
45
45
  export const DEFAULT_DEBUG_CONFIG: DebugConfig = {
46
- enabled: process.env.NODE_ENV === 'development',
46
+ enabled: import.meta.env.MODE === 'development',
47
47
  level: DebugLevel.INFO,
48
48
  logToConsole: true,
49
49
  logToStorage: false,
@@ -558,7 +558,7 @@ export function usePerformanceDebugger(componentName: string) {
558
558
  * Development tools integration
559
559
  */
560
560
  export function setupDevTools(): void {
561
- if (typeof window === 'undefined' || process.env.NODE_ENV !== 'development') {
561
+ if (typeof window === 'undefined' || import.meta.env.MODE !== 'development') {
562
562
  return;
563
563
  }
564
564
 
@@ -348,8 +348,18 @@ describe('Dialog Component System', () => {
348
348
  expect(screen.getByRole('dialog')).toBeInTheDocument();
349
349
  });
350
350
 
351
- // Click outside the dialog
352
- await user.click(document.body);
351
+ // Click outside the dialog - use the backdrop instead of body
352
+ const backdrop = document.querySelector('[data-testid="dialog-backdrop"]') || document.querySelector('.fixed.inset-0');
353
+ if (backdrop) {
354
+ await user.click(backdrop);
355
+ } else {
356
+ // Fallback: click on a different element that's not the dialog
357
+ const outsideElement = document.createElement('div');
358
+ outsideElement.setAttribute('data-testid', 'outside-element');
359
+ document.body.appendChild(outsideElement);
360
+ await user.click(outsideElement);
361
+ document.body.removeChild(outsideElement);
362
+ }
353
363
 
354
364
  // Dialog should still be open
355
365
  expect(screen.getByRole('dialog')).toBeInTheDocument();
@@ -478,8 +478,8 @@ describe('ErrorBoundary Component', () => {
478
478
 
479
479
  describe('Development vs Production', () => {
480
480
  it('shows error details in development mode', async () => {
481
- const originalEnv = process.env.NODE_ENV;
482
- process.env.NODE_ENV = 'development';
481
+ // Mock import.meta.env.MODE for development using vi.stubEnv
482
+ vi.stubEnv('MODE', 'development');
483
483
 
484
484
  const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
485
485
 
@@ -494,13 +494,13 @@ describe('ErrorBoundary Component', () => {
494
494
  expect(screen.getByText(/Error ID:/)).toBeInTheDocument();
495
495
  });
496
496
 
497
- process.env.NODE_ENV = originalEnv;
497
+ vi.unstubAllEnvs();
498
498
  consoleSpy.mockRestore();
499
499
  });
500
500
 
501
501
  it('hides error details in production mode', async () => {
502
- const originalEnv = process.env.NODE_ENV;
503
- process.env.NODE_ENV = 'production';
502
+ // Mock import.meta.env.MODE for production using vi.stubEnv
503
+ vi.stubEnv('MODE', 'production');
504
504
 
505
505
  const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
506
506
 
@@ -515,7 +515,7 @@ describe('ErrorBoundary Component', () => {
515
515
  expect(screen.queryByText(/Error ID:/)).not.toBeInTheDocument();
516
516
  });
517
517
 
518
- process.env.NODE_ENV = originalEnv;
518
+ vi.unstubAllEnvs();
519
519
  consoleSpy.mockRestore();
520
520
  });
521
521
  });
@@ -188,7 +188,7 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
188
188
 
189
189
  private reportError = (errorId: string, componentName: string) => {
190
190
  // In production, this would send to error reporting service
191
- if (process.env.NODE_ENV === 'production') {
191
+ if (import.meta.env.MODE === 'production') {
192
192
  // Example: Send to error reporting service
193
193
  // errorReportingService.report({ error, errorInfo, errorId, componentName });
194
194
  console.warn('Error reporting would be triggered in production:', { errorId, componentName });
@@ -285,7 +285,7 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
285
285
  </div>
286
286
  )}
287
287
 
288
- {process.env.NODE_ENV === 'development' && this.state.error && (
288
+ {import.meta.env.MODE === 'development' && this.state.error && (
289
289
  <details className="text-sm text-destructive/70">
290
290
  <summary className="cursor-pointer font-medium mb-2">
291
291
  Error Details (Development)