@jmruthers/pace-core 0.6.4 → 0.6.6

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 (387) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +5 -403
  3. package/core-usage-manifest.json +93 -0
  4. package/cursor-rules/00-pace-core-compliance.mdc +128 -26
  5. package/cursor-rules/01-standards-compliance.mdc +49 -8
  6. package/cursor-rules/02-project-structure.mdc +6 -0
  7. package/cursor-rules/03-solid-principles.mdc +2 -0
  8. package/cursor-rules/04-testing-standards.mdc +2 -0
  9. package/cursor-rules/05-bug-reports-and-features.mdc +2 -0
  10. package/cursor-rules/06-code-quality.mdc +2 -0
  11. package/cursor-rules/07-tech-stack-compliance.mdc +2 -0
  12. package/cursor-rules/08-markup-quality.mdc +52 -27
  13. package/cursor-rules/09-rbac-compliance.mdc +462 -0
  14. package/cursor-rules/10-error-handling-patterns.mdc +179 -0
  15. package/cursor-rules/11-performance-optimization.mdc +169 -0
  16. package/cursor-rules/12-ci-cd-integration.mdc +150 -0
  17. package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
  18. package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-2N_tqbfq.d.ts} +1 -1
  19. package/dist/DataTable-LRJL4IRV.js +15 -0
  20. package/dist/{PublicPageProvider-DEMpysFR.d.ts → PublicPageProvider-BBH6Vqg7.d.ts} +72 -139
  21. package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
  22. package/dist/api-Y4MQWOFW.js +4 -0
  23. package/dist/audit-MYQXYZFU.js +3 -0
  24. package/dist/{chunk-J36DSWQK.js → chunk-2HGJFNAH.js} +8 -28
  25. package/dist/{chunk-OEWDTMG7.js → chunk-3O3WHILE.js} +38 -121
  26. package/dist/{chunk-M43Y4SSO.js → chunk-3QC3KRHK.js} +1 -14
  27. package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
  28. package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
  29. package/dist/chunk-4T7OBVTU.js +62 -0
  30. package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
  31. package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
  32. package/dist/{chunk-NN6WWZ5U.js → chunk-7TYHROIV.js} +579 -563
  33. package/dist/{chunk-M7MPQISP.js → chunk-A55DK444.js} +9 -16
  34. package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
  35. package/dist/{chunk-L4OXEN46.js → chunk-BVP2BCJF.js} +2 -16
  36. package/dist/chunk-C7NSAPTL.js +1 -0
  37. package/dist/{chunk-YKRAFF5K.js → chunk-FENMYN2U.js} +73 -149
  38. package/dist/{chunk-AVMLPIM7.js → chunk-FTCRZOG2.js} +284 -432
  39. package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
  40. package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
  41. package/dist/{chunk-I6DAQMWX.js → chunk-LAZMKTTF.js} +930 -891
  42. package/dist/{chunk-5EC5MEWX.js → chunk-MAGBIDNS.js} +77 -222
  43. package/dist/chunk-MBADTM7L.js +64 -0
  44. package/dist/chunk-OHIK3MIO.js +994 -0
  45. package/dist/{chunk-6SOIHG6Z.js → chunk-S7DKJPLT.js} +115 -44
  46. package/dist/{chunk-FMUCXFII.js → chunk-SD6WQY43.js} +1 -5
  47. package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
  48. package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
  49. package/dist/{chunk-FFQEQTNW.js → chunk-UIYSCEV7.js} +134 -45
  50. package/dist/{chunk-3LPHPB62.js → chunk-ZFYPMX46.js} +271 -87
  51. package/dist/{chunk-7JPAB3T5.js → chunk-ZS5VO5JB.js} +1989 -1283
  52. package/dist/components.d.ts +6 -6
  53. package/dist/components.js +57 -267
  54. package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
  55. package/dist/eslint-rules/index.cjs +22 -0
  56. package/dist/eslint-rules/rules/compliance.cjs +348 -0
  57. package/dist/eslint-rules/rules/components.cjs +113 -0
  58. package/dist/eslint-rules/rules/imports.cjs +102 -0
  59. package/dist/eslint-rules/rules/rbac.cjs +790 -0
  60. package/dist/eslint-rules/utils/helpers.cjs +42 -0
  61. package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
  62. package/dist/hooks.d.ts +5 -5
  63. package/dist/hooks.js +62 -270
  64. package/dist/icons/index.d.ts +1 -0
  65. package/dist/icons/index.js +1 -0
  66. package/dist/index.d.ts +36 -26
  67. package/dist/index.js +87 -690
  68. package/dist/providers.d.ts +2 -2
  69. package/dist/providers.js +8 -35
  70. package/dist/rbac/eslint-rules.d.ts +46 -44
  71. package/dist/rbac/eslint-rules.js +7 -4
  72. package/dist/rbac/index.d.ts +124 -594
  73. package/dist/rbac/index.js +14 -207
  74. package/dist/styles/index.js +2 -12
  75. package/dist/theming/runtime.js +3 -19
  76. package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
  77. package/dist/{types-CkbwOr4Y.d.ts → types-B-K_5VnO.d.ts} +4 -0
  78. package/dist/types-t9H8qKRw.d.ts +55 -0
  79. package/dist/types.d.ts +1 -1
  80. package/dist/types.js +7 -94
  81. package/dist/{usePublicRouteParams-i3qtoBgg.d.ts → usePublicRouteParams-COZ28Mvq.d.ts} +9 -9
  82. package/dist/utils.d.ts +24 -117
  83. package/dist/utils.js +54 -392
  84. package/docs/README.md +16 -6
  85. package/docs/api/README.md +4 -402
  86. package/docs/api/modules.md +454 -930
  87. package/docs/api-reference/components.md +3 -1
  88. package/docs/api-reference/deprecated.md +31 -6
  89. package/docs/api-reference/rpc-functions.md +78 -3
  90. package/docs/best-practices/accessibility.md +6 -3
  91. package/docs/getting-started/cursor-rules.md +3 -23
  92. package/docs/getting-started/dependencies.md +650 -0
  93. package/docs/getting-started/installation-guide.md +20 -7
  94. package/docs/getting-started/quick-start.md +23 -12
  95. package/docs/implementation-guides/permission-enforcement.md +4 -0
  96. package/docs/rbac/MIGRATION_GUIDE.md +819 -0
  97. package/docs/rbac/RBAC_CONTRACT.md +724 -0
  98. package/docs/rbac/README.md +12 -3
  99. package/docs/rbac/edge-functions-guide.md +376 -0
  100. package/docs/rbac/secure-client-protection.md +0 -34
  101. package/docs/standards/00-pace-core-compliance.md +967 -0
  102. package/docs/standards/01-standards-compliance.md +188 -0
  103. package/docs/standards/02-project-structure.md +985 -0
  104. package/docs/standards/03-solid-principles.md +39 -0
  105. package/docs/standards/04-testing-standards.md +36 -0
  106. package/docs/standards/05-bug-reports-and-features.md +27 -0
  107. package/docs/standards/{04-code-style-standard.md → 06-code-quality.md} +2 -0
  108. package/docs/standards/07-tech-stack-compliance.md +30 -0
  109. package/docs/standards/08-markup-quality.md +345 -0
  110. package/docs/standards/{07-rbac-and-rls-standard.md → 09-rbac-compliance.md} +149 -54
  111. package/docs/standards/10-error-handling-patterns.md +401 -0
  112. package/docs/standards/11-performance-optimization.md +348 -0
  113. package/docs/standards/12-ci-cd-integration.md +370 -0
  114. package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +192 -0
  115. package/docs/standards/README.md +62 -33
  116. package/docs/troubleshooting/organisation-context-setup.md +42 -19
  117. package/eslint-config-pace-core.cjs +20 -4
  118. package/package.json +31 -21
  119. package/scripts/audit/audit-compliance.cjs +1295 -0
  120. package/scripts/audit/audit-components.cjs +260 -0
  121. package/scripts/audit/audit-dependencies.cjs +395 -0
  122. package/scripts/audit/audit-rbac.cjs +954 -0
  123. package/scripts/audit/audit-standards.cjs +1268 -0
  124. package/scripts/audit/index.cjs +1898 -194
  125. package/scripts/install-cursor-rules.cjs +259 -8
  126. package/scripts/validate-master.js +1 -1
  127. package/src/__tests__/fixtures/supabase.ts +1 -1
  128. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +1 -1
  129. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
  130. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
  131. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +3 -3
  132. package/src/__tests__/helpers/component-test-utils.tsx +1 -1
  133. package/src/__tests__/helpers/supabaseMock.ts +2 -2
  134. package/src/__tests__/public-recipe-view.test.ts +38 -9
  135. package/src/components/Button/Button.tsx +5 -1
  136. package/src/components/ContextSelector/ContextSelector.tsx +42 -39
  137. package/src/components/DataTable/__tests__/keyboard.test.tsx +15 -2
  138. package/src/components/DataTable/components/DataTableBody.tsx +55 -31
  139. package/src/components/DataTable/components/DataTableCore.tsx +186 -13
  140. package/src/components/DataTable/components/DataTableLayout.tsx +30 -5
  141. package/src/components/DataTable/components/EditFields.tsx +23 -3
  142. package/src/components/DataTable/components/EditableRow.tsx +7 -2
  143. package/src/components/DataTable/components/ImportModal.tsx +4 -6
  144. package/src/components/DataTable/components/RowComponent.tsx +12 -0
  145. package/src/components/DataTable/components/ViewRowModal.tsx +4 -4
  146. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +455 -96
  147. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +122 -58
  148. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
  149. package/src/components/DataTable/core/DataTableContext.tsx +1 -1
  150. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
  151. package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
  152. package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
  153. package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
  154. package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
  155. package/src/components/DataTable/types.ts +5 -0
  156. package/src/components/DateTimeField/DateTimeField.tsx +20 -20
  157. package/src/components/DateTimeField/README.md +5 -2
  158. package/src/components/Dialog/Dialog.test.tsx +361 -318
  159. package/src/components/Dialog/Dialog.tsx +1154 -323
  160. package/src/components/Dialog/index.ts +3 -3
  161. package/src/components/FileDisplay/FileDisplay.test.tsx +45 -2
  162. package/src/components/FileDisplay/FileDisplay.tsx +28 -22
  163. package/src/components/Form/Form.test.tsx +9 -10
  164. package/src/components/Form/Form.tsx +369 -9
  165. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +28 -28
  166. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +40 -54
  167. package/src/components/LoginForm/LoginForm.tsx +2 -2
  168. package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
  169. package/src/components/NavigationMenu/NavigationMenu.tsx +2 -2
  170. package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
  171. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
  172. package/src/components/PaceAppLayout/PaceAppLayout.tsx +30 -41
  173. package/src/components/PaceAppLayout/README.md +10 -9
  174. package/src/components/PaceAppLayout/test-setup.tsx +40 -31
  175. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
  176. package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
  177. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +61 -0
  178. package/src/components/PasswordChange/PasswordChangeForm.tsx +20 -13
  179. package/src/components/PublicLayout/PublicLayout.test.tsx +7 -3
  180. package/src/components/PublicLayout/PublicPageLayout.tsx +5 -8
  181. package/src/components/Select/Select.tsx +23 -21
  182. package/src/components/Select/types.ts +1 -1
  183. package/src/components/UserMenu/UserMenu.test.tsx +38 -6
  184. package/src/components/UserMenu/UserMenu.tsx +39 -34
  185. package/src/components/index.ts +3 -4
  186. package/src/eslint-rules/index.cjs +22 -0
  187. package/src/eslint-rules/rules/compliance.cjs +348 -0
  188. package/src/eslint-rules/rules/components.cjs +113 -0
  189. package/src/eslint-rules/rules/imports.cjs +102 -0
  190. package/src/eslint-rules/rules/rbac.cjs +790 -0
  191. package/src/eslint-rules/utils/helpers.cjs +42 -0
  192. package/src/eslint-rules/utils/manifest-loader.cjs +75 -0
  193. package/src/hooks/__tests__/hooks.integration.test.tsx +6 -8
  194. package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
  195. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
  196. package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
  197. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
  198. package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
  199. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
  200. package/src/hooks/public/usePublicEvent.ts +62 -190
  201. package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
  202. package/src/hooks/public/usePublicEventLogo.ts +19 -9
  203. package/src/hooks/useAppConfig.ts +26 -24
  204. package/src/hooks/useEventTheme.test.ts +211 -233
  205. package/src/hooks/useEventTheme.ts +19 -28
  206. package/src/hooks/useEvents.ts +11 -7
  207. package/src/hooks/useKeyboardShortcuts.ts +1 -1
  208. package/src/hooks/useOrganisationPermissions.ts +9 -11
  209. package/src/hooks/useOrganisations.ts +13 -7
  210. package/src/hooks/useQueryCache.ts +0 -1
  211. package/src/hooks/useSessionDraft.ts +380 -0
  212. package/src/hooks/useSessionRestoration.ts +3 -1
  213. package/src/icons/index.ts +27 -0
  214. package/src/index.ts +16 -1
  215. package/src/providers/OrganisationProvider.tsx +23 -14
  216. package/src/providers/services/EventServiceProvider.tsx +1 -24
  217. package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
  218. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +3 -0
  219. package/src/rbac/README.md +20 -20
  220. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
  221. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
  222. package/src/rbac/adapters.tsx +7 -295
  223. package/src/rbac/api.test.ts +44 -56
  224. package/src/rbac/api.ts +10 -17
  225. package/src/rbac/cache-invalidation.ts +0 -1
  226. package/src/rbac/compliance/index.ts +10 -0
  227. package/src/rbac/compliance/pattern-detector.ts +553 -0
  228. package/src/rbac/compliance/runtime-compliance.ts +22 -0
  229. package/src/rbac/components/AccessDenied.tsx +150 -0
  230. package/src/rbac/components/NavigationGuard.tsx +12 -20
  231. package/src/rbac/components/PagePermissionGuard.tsx +4 -24
  232. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
  233. package/src/rbac/components/index.ts +3 -41
  234. package/src/rbac/eslint-rules.js +1 -1
  235. package/src/rbac/hooks/index.ts +0 -3
  236. package/src/rbac/hooks/permissions/index.ts +0 -3
  237. package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
  238. package/src/rbac/hooks/usePermissions.ts +0 -3
  239. package/src/rbac/hooks/useRBAC.test.ts +21 -3
  240. package/src/rbac/hooks/useRBAC.ts +4 -3
  241. package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
  242. package/src/rbac/hooks/useResolvedScope.ts +58 -140
  243. package/src/rbac/hooks/useResourcePermissions.test.ts +241 -60
  244. package/src/rbac/hooks/useResourcePermissions.ts +182 -63
  245. package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
  246. package/src/rbac/hooks/useRoleManagement.ts +147 -19
  247. package/src/rbac/hooks/useSecureSupabase.ts +4 -8
  248. package/src/rbac/index.ts +7 -9
  249. package/src/rbac/permissions.ts +17 -17
  250. package/src/rbac/utils/contextValidator.ts +45 -7
  251. package/src/services/AuthService.ts +132 -23
  252. package/src/services/EventService.ts +4 -97
  253. package/src/services/InactivityService.ts +155 -58
  254. package/src/services/OrganisationService.ts +7 -44
  255. package/src/services/__tests__/OrganisationService.test.ts +26 -8
  256. package/src/services/base/BaseService.ts +0 -3
  257. package/src/styles/core.css +4 -0
  258. package/src/types/database.generated.ts +4733 -3809
  259. package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
  260. package/src/utils/context/organisationContext.test.ts +13 -28
  261. package/src/utils/context/organisationContext.ts +21 -52
  262. package/src/utils/dynamic/dynamicUtils.ts +1 -1
  263. package/src/utils/file-reference/index.ts +39 -15
  264. package/src/utils/formatting/formatDateTime.test.ts +3 -2
  265. package/src/utils/formatting/formatTime.test.ts +3 -2
  266. package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
  267. package/src/utils/index.ts +4 -1
  268. package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
  269. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
  270. package/src/utils/persistence/keyDerivation.ts +304 -0
  271. package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
  272. package/src/utils/security/secureStorage.ts +5 -5
  273. package/src/utils/storage/helpers.ts +3 -3
  274. package/src/utils/supabase/createBaseClient.ts +147 -0
  275. package/src/utils/timezone/timezone.test.ts +1 -2
  276. package/src/utils/timezone/timezone.ts +1 -1
  277. package/src/utils/validation/csrf.ts +4 -4
  278. package/cursor-rules/CHANGELOG.md +0 -119
  279. package/cursor-rules/README.md +0 -192
  280. package/dist/DataTable-E7YQZD7D.js +0 -175
  281. package/dist/DataTable-E7YQZD7D.js.map +0 -1
  282. package/dist/UnifiedAuthProvider-QPXO24B4.js +0 -18
  283. package/dist/UnifiedAuthProvider-QPXO24B4.js.map +0 -1
  284. package/dist/api-6LVZTHDS.js +0 -52
  285. package/dist/api-6LVZTHDS.js.map +0 -1
  286. package/dist/audit-V53FV5AG.js +0 -17
  287. package/dist/audit-V53FV5AG.js.map +0 -1
  288. package/dist/chunk-36LVWXB2.js +0 -227
  289. package/dist/chunk-36LVWXB2.js.map +0 -1
  290. package/dist/chunk-3LPHPB62.js.map +0 -1
  291. package/dist/chunk-5DRSZLL2.js.map +0 -1
  292. package/dist/chunk-5EC5MEWX.js.map +0 -1
  293. package/dist/chunk-63FOKYGO.js.map +0 -1
  294. package/dist/chunk-6SOIHG6Z.js.map +0 -1
  295. package/dist/chunk-7JPAB3T5.js.map +0 -1
  296. package/dist/chunk-ATKZM7RX.js +0 -2053
  297. package/dist/chunk-ATKZM7RX.js.map +0 -1
  298. package/dist/chunk-AVMLPIM7.js.map +0 -1
  299. package/dist/chunk-DGUM43GV.js.map +0 -1
  300. package/dist/chunk-E66EQZE6.js.map +0 -1
  301. package/dist/chunk-FFQEQTNW.js.map +0 -1
  302. package/dist/chunk-FMUCXFII.js.map +0 -1
  303. package/dist/chunk-G37KK66H.js.map +0 -1
  304. package/dist/chunk-I6DAQMWX.js.map +0 -1
  305. package/dist/chunk-J36DSWQK.js.map +0 -1
  306. package/dist/chunk-KQCRWDSA.js +0 -1
  307. package/dist/chunk-KQCRWDSA.js.map +0 -1
  308. package/dist/chunk-L4OXEN46.js.map +0 -1
  309. package/dist/chunk-LMC26NLJ.js +0 -84
  310. package/dist/chunk-LMC26NLJ.js.map +0 -1
  311. package/dist/chunk-M43Y4SSO.js.map +0 -1
  312. package/dist/chunk-M7MPQISP.js.map +0 -1
  313. package/dist/chunk-NN6WWZ5U.js.map +0 -1
  314. package/dist/chunk-OEWDTMG7.js.map +0 -1
  315. package/dist/chunk-PWLANIRT.js.map +0 -1
  316. package/dist/chunk-QXHPKYJV.js.map +0 -1
  317. package/dist/chunk-VBXEHIUJ.js.map +0 -1
  318. package/dist/chunk-YKRAFF5K.js.map +0 -1
  319. package/dist/chunk-ZSAAAMVR.js.map +0 -1
  320. package/dist/components.js.map +0 -1
  321. package/dist/contextValidator-OOPCLPZW.js +0 -9
  322. package/dist/contextValidator-OOPCLPZW.js.map +0 -1
  323. package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
  324. package/dist/hooks.js.map +0 -1
  325. package/dist/index.js.map +0 -1
  326. package/dist/providers.js.map +0 -1
  327. package/dist/rbac/eslint-rules.js.map +0 -1
  328. package/dist/rbac/index.js.map +0 -1
  329. package/dist/styles/index.js.map +0 -1
  330. package/dist/theming/runtime.js.map +0 -1
  331. package/dist/types.js.map +0 -1
  332. package/dist/utils.js.map +0 -1
  333. package/docs/standards/01-architecture-standard.md +0 -44
  334. package/docs/standards/02-api-and-rpc-standard.md +0 -39
  335. package/docs/standards/03-component-standard.md +0 -32
  336. package/docs/standards/05-security-standard.md +0 -44
  337. package/docs/standards/06-testing-and-docs-standard.md +0 -29
  338. package/docs/standards/pace-core-compliance.md +0 -432
  339. package/scripts/audit/core/checks/accessibility.cjs +0 -197
  340. package/scripts/audit/core/checks/api-usage.cjs +0 -191
  341. package/scripts/audit/core/checks/bundle.cjs +0 -142
  342. package/scripts/audit/core/checks/compliance.cjs +0 -2706
  343. package/scripts/audit/core/checks/config.cjs +0 -54
  344. package/scripts/audit/core/checks/coverage.cjs +0 -84
  345. package/scripts/audit/core/checks/dependencies.cjs +0 -994
  346. package/scripts/audit/core/checks/documentation.cjs +0 -268
  347. package/scripts/audit/core/checks/environment.cjs +0 -116
  348. package/scripts/audit/core/checks/error-handling.cjs +0 -340
  349. package/scripts/audit/core/checks/forms.cjs +0 -172
  350. package/scripts/audit/core/checks/heuristics.cjs +0 -68
  351. package/scripts/audit/core/checks/hooks.cjs +0 -334
  352. package/scripts/audit/core/checks/imports.cjs +0 -244
  353. package/scripts/audit/core/checks/performance.cjs +0 -325
  354. package/scripts/audit/core/checks/routes.cjs +0 -117
  355. package/scripts/audit/core/checks/state.cjs +0 -130
  356. package/scripts/audit/core/checks/structure.cjs +0 -65
  357. package/scripts/audit/core/checks/style.cjs +0 -584
  358. package/scripts/audit/core/checks/testing.cjs +0 -122
  359. package/scripts/audit/core/checks/typescript.cjs +0 -61
  360. package/scripts/audit/core/scanner.cjs +0 -199
  361. package/scripts/audit/core/utils.cjs +0 -137
  362. package/scripts/audit/reporters/console.cjs +0 -151
  363. package/scripts/audit/reporters/json.cjs +0 -54
  364. package/scripts/audit/reporters/markdown.cjs +0 -124
  365. package/scripts/audit-consuming-app.cjs +0 -86
  366. package/src/eslint-rules/pace-core-compliance.cjs +0 -510
  367. package/src/eslint-rules/pace-core-compliance.js +0 -638
  368. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
  369. package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
  370. package/src/rbac/components/NavigationProvider.test.tsx +0 -481
  371. package/src/rbac/components/NavigationProvider.tsx +0 -345
  372. package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
  373. package/src/rbac/components/PagePermissionProvider.tsx +0 -279
  374. package/src/rbac/components/PermissionEnforcer.tsx +0 -312
  375. package/src/rbac/components/RoleBasedRouter.tsx +0 -440
  376. package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
  377. package/src/rbac/components/SecureDataProvider.tsx +0 -339
  378. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
  379. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
  380. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
  381. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
  382. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
  383. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
  384. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
  385. package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
  386. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
  387. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
@@ -1,659 +0,0 @@
1
- /**
2
- * @file Secure Data Provider Component Tests (Fixed)
3
- * @package @jmruthers/pace-core
4
- * @module RBAC/Components/SecureDataProvider
5
- * @since 2.0.0
6
- *
7
- * Comprehensive test suite for the SecureDataProvider component.
8
- * Tests cover all functionality including data access control, audit logging,
9
- * strict mode enforcement, context management, and error scenarios.
10
- */
11
-
12
- import React from 'react';
13
- import { render, screen, waitFor, act } from '@testing-library/react';
14
- import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
15
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
16
- import { renderWithProviders } from '../../../__tests__/helpers';
17
-
18
- // Mock the RBAC logger - define inside factory to avoid hoisting issues
19
- const mockLogger = {
20
- debug: vi.fn(),
21
- error: vi.fn(),
22
- warn: vi.fn(),
23
- info: vi.fn(),
24
- };
25
-
26
- vi.mock('../../config', () => ({
27
- getRBACLogger: vi.fn(() => mockLogger),
28
- getRBACConfig: vi.fn(() => ({
29
- debug: true,
30
- logLevel: 'debug',
31
- developmentMode: true,
32
- audit: {
33
- enabled: true,
34
- logLevel: 'debug'
35
- }
36
- })),
37
- isDebugMode: vi.fn(() => true),
38
- isDevelopmentMode: vi.fn(() => true),
39
- }));
40
-
41
- import {
42
- SecureDataProvider,
43
- SecureDataProviderProps,
44
- useSecureData,
45
- DataAccessRecord
46
- } from '../SecureDataProvider';
47
- import { useUnifiedAuth } from '../../../providers/services/UnifiedAuthProvider';
48
-
49
- // Mock the UnifiedAuthProvider
50
- const mockUseUnifiedAuthFn = vi.fn();
51
- vi.mock('../../../providers/services/UnifiedAuthProvider', () => ({
52
- useUnifiedAuth: () => mockUseUnifiedAuthFn(),
53
- UnifiedAuthProvider: ({ children }: { children: React.ReactNode }) => <div data-testid="unified-auth-provider">{children}</div>
54
- }));
55
-
56
- // useSecureDataAccess has been removed - SecureDataProvider now uses useSecureSupabase internally
57
- // No mock needed as SecureDataProvider handles validation internally
58
-
59
- // Mock useResolvedScope
60
- const mockUseResolvedScopeFn = vi.fn();
61
- vi.mock('../../hooks/useResolvedScope', () => ({
62
- useResolvedScope: () => mockUseResolvedScopeFn(),
63
- }));
64
-
65
- // Mock useOrganisations to prevent provider requirement
66
- vi.mock('../../../hooks/useOrganisations', () => ({
67
- useOrganisations: vi.fn(() => ({
68
- organisations: [],
69
- isLoading: false,
70
- error: null,
71
- refetch: vi.fn(),
72
- selectedOrganisation: {
73
- id: 'org-456',
74
- name: 'Test Org',
75
- display_name: 'Test Organisation',
76
- description: 'Test',
77
- subscription_tier: 'basic',
78
- settings: {},
79
- is_active: true,
80
- created_at: '2023-01-01T00:00:00Z',
81
- updated_at: '2023-01-01T00:00:00Z'
82
- }
83
- }))
84
- }));
85
-
86
- // Mock useEvents
87
- vi.mock('../../../hooks/useEvents', () => ({
88
- useEvents: vi.fn(() => ({
89
- events: [],
90
- isLoading: false,
91
- error: null,
92
- refetch: vi.fn(),
93
- selectedEvent: {
94
- id: 'event-789',
95
- event_id: 'event-789',
96
- event_name: 'Test Event',
97
- event_date: '2023-01-01T00:00:00Z',
98
- event_venue: 'Test Venue',
99
- event_participants: 100,
100
- event_colours: '#FF0000',
101
- event_logo: '',
102
- organisation_id: 'org-456' as any,
103
- is_visible: true,
104
- created_at: '2023-01-01T00:00:00Z',
105
- updated_at: '2023-01-01T00:00:00Z'
106
- },
107
- eventLoading: false
108
- }))
109
- }));
110
-
111
- // Mock useOrganisationSecurity
112
- vi.mock('../../../hooks/useOrganisationSecurity', () => ({
113
- useOrganisationSecurity: vi.fn(() => ({
114
- superAdminContext: {
115
- isSuperAdmin: false,
116
- isLoading: false
117
- },
118
- organisationSecurity: {
119
- canAccessOrganisation: vi.fn(() => true),
120
- canAccessEvent: vi.fn(() => true)
121
- }
122
- }))
123
- }));
124
-
125
- // Mock supabase client
126
- const mockSupabase = {
127
- from: vi.fn(() => ({
128
- select: vi.fn().mockReturnThis(),
129
- insert: vi.fn().mockReturnThis(),
130
- update: vi.fn().mockReturnThis(),
131
- delete: vi.fn().mockReturnThis(),
132
- eq: vi.fn().mockReturnThis(),
133
- then: vi.fn((resolve) => resolve({ data: [], error: null }))
134
- }))
135
- } as any;
136
-
137
- // Test data
138
- const mockUser = {
139
- user: {
140
- id: 'user-123',
141
- email: 'test@example.com',
142
- },
143
- supabase: mockSupabase,
144
- selectedOrganisation: {
145
- id: 'org-456',
146
- name: 'Test Org',
147
- display_name: 'Test Organisation',
148
- description: 'Test',
149
- subscription_tier: 'basic',
150
- settings: {},
151
- is_active: true,
152
- created_at: '2023-01-01T00:00:00Z',
153
- updated_at: '2023-01-01T00:00:00Z'
154
- },
155
- selectedEvent: {
156
- id: 'event-789',
157
- event_id: 'event-789',
158
- event_name: 'Test Event',
159
- event_date: '2023-01-01T00:00:00Z',
160
- event_venue: 'Test Venue',
161
- event_participants: 100,
162
- event_colours: '#FF0000',
163
- event_logo: '',
164
- organisation_id: 'org-456' as any,
165
- is_visible: true,
166
- created_at: '2023-01-01T00:00:00Z',
167
- updated_at: '2023-01-01T00:00:00Z'
168
- }
169
- };
170
-
171
- const mockScope = {
172
- organisationId: 'org-456',
173
- eventId: 'event-789',
174
- appId: undefined
175
- };
176
-
177
- // Test component that uses the context
178
- const TestComponent: React.FC<{ testId?: string }> = ({ testId = 'test-component' }) => {
179
- const context = useSecureData();
180
-
181
- return (
182
- <div data-testid={testId}>
183
- <div data-testid="is-enabled">{context.isEnabled.toString()}</div>
184
- <div data-testid="is-strict-mode">{context.isStrictMode.toString()}</div>
185
- <div data-testid="is-audit-log-enabled">{context.isAuditLogEnabled.toString()}</div>
186
- <div data-testid="data-access-allowed">
187
- {context.isDataAccessAllowed('test_table', 'read').toString()}
188
- </div>
189
- <div data-testid="permissions">
190
- {JSON.stringify(context.getDataAccessPermissions())}
191
- </div>
192
- <div data-testid="history-length">
193
- {context.getDataAccessHistory().length}
194
- </div>
195
- </div>
196
- );
197
- };
198
-
199
- // Test wrapper component
200
- const TestWrapper: React.FC<{
201
- children: React.ReactNode;
202
- providerProps?: Partial<SecureDataProviderProps>
203
- }> = ({ children, providerProps = {} }) => {
204
- const queryClient = new QueryClient({
205
- defaultOptions: {
206
- queries: { retry: false },
207
- mutations: { retry: false }
208
- }
209
- });
210
-
211
- return (
212
- <QueryClientProvider client={queryClient}>
213
- <SecureDataProvider {...providerProps}>
214
- {children}
215
- </SecureDataProvider>
216
- </QueryClientProvider>
217
- );
218
- };
219
-
220
- describe('SecureDataProvider', () => {
221
- beforeEach(() => {
222
- vi.clearAllMocks();
223
-
224
- mockUseUnifiedAuthFn.mockReturnValue({
225
- ...mockUser,
226
- supabase: {} as any,
227
- });
228
-
229
- // Mock useResolvedScope to return resolved scope
230
- mockUseResolvedScopeFn.mockReturnValue({
231
- resolvedScope: mockScope,
232
- isLoading: false,
233
- error: null,
234
- });
235
-
236
- // mockValidateContext removed - SecureDataProvider handles validation internally
237
- });
238
-
239
- afterEach(() => {
240
- vi.clearAllMocks();
241
- });
242
-
243
- describe('Basic Functionality', () => {
244
- it('should render children correctly', () => {
245
- renderWithProviders(
246
- <TestWrapper>
247
- <div data-testid="simple-test">Test Content</div>
248
- </TestWrapper>
249
- );
250
-
251
- expect(screen.getByTestId('simple-test')).toBeInTheDocument();
252
- });
253
-
254
- it('should provide context values with defaults', () => {
255
- renderWithProviders(
256
- <TestWrapper>
257
- <TestComponent />
258
- </TestWrapper>
259
- );
260
-
261
- expect(screen.getByTestId('is-enabled')).toHaveTextContent('true');
262
- expect(screen.getByTestId('is-strict-mode')).toHaveTextContent('true');
263
- expect(screen.getByTestId('is-audit-log-enabled')).toHaveTextContent('true');
264
- });
265
-
266
- it('should allow data access when enabled', () => {
267
- renderWithProviders(
268
- <TestWrapper>
269
- <TestComponent />
270
- </TestWrapper>
271
- );
272
-
273
- // When enabled with valid user and scope, isDataAccessAllowed returns true
274
- expect(screen.getByTestId('data-access-allowed')).toHaveTextContent('true');
275
- });
276
-
277
- it('should return empty permissions initially', () => {
278
- renderWithProviders(
279
- <TestWrapper>
280
- <TestComponent />
281
- </TestWrapper>
282
- );
283
-
284
- expect(screen.getByTestId('permissions')).toHaveTextContent('{}');
285
- });
286
-
287
- it('should return empty history initially', () => {
288
- renderWithProviders(
289
- <TestWrapper>
290
- <TestComponent />
291
- </TestWrapper>
292
- );
293
-
294
- expect(screen.getByTestId('history-length')).toHaveTextContent('0');
295
- });
296
- });
297
-
298
- describe('Configuration Options', () => {
299
- it('should respect strictMode prop', () => {
300
- renderWithProviders(
301
- <TestWrapper providerProps={{ strictMode: true }}>
302
- <TestComponent />
303
- </TestWrapper>
304
- );
305
-
306
- expect(screen.getByTestId('is-strict-mode')).toHaveTextContent('true');
307
- });
308
-
309
- it('should respect auditLog prop', () => {
310
- renderWithProviders(
311
- <TestWrapper providerProps={{ auditLog: true }}>
312
- <TestComponent />
313
- </TestWrapper>
314
- );
315
-
316
- expect(screen.getByTestId('is-audit-log-enabled')).toHaveTextContent('true');
317
- });
318
-
319
- it('should respect maxHistorySize prop', () => {
320
- const onDataAccess = vi.fn();
321
-
322
- renderWithProviders(
323
- <TestWrapper providerProps={{ maxHistorySize: 50, onDataAccess }}>
324
- <TestComponent />
325
- </TestWrapper>
326
- );
327
-
328
- expect(screen.getByTestId('test-component')).toBeInTheDocument();
329
- });
330
-
331
- it('should respect enforceRLS prop', () => {
332
- renderWithProviders(
333
- <TestWrapper providerProps={{ enforceRLS: true }}>
334
- <TestComponent />
335
- </TestWrapper>
336
- );
337
-
338
- expect(screen.getByTestId('test-component')).toBeInTheDocument();
339
- });
340
- });
341
-
342
- describe('Data Access Control', () => {
343
- it('should allow data access when user is authenticated', () => {
344
- renderWithProviders(
345
- <TestWrapper>
346
- <TestComponent />
347
- </TestWrapper>
348
- );
349
-
350
- // When user is authenticated with valid scope, isDataAccessAllowed returns true
351
- expect(screen.getByTestId('data-access-allowed')).toHaveTextContent('true');
352
- });
353
-
354
- it('should deny data access when user is not authenticated', () => {
355
- mockUseUnifiedAuthFn.mockReturnValue({ ...mockUser, user: null });
356
-
357
- renderWithProviders(
358
- <TestWrapper>
359
- <TestComponent />
360
- </TestWrapper>
361
- );
362
-
363
- expect(screen.getByTestId('data-access-allowed')).toHaveTextContent('false');
364
- });
365
-
366
- it('should deny data access when organisation context is missing (org-required app)', () => {
367
- // For org-required apps, selectedOrganisation is required
368
- // For event-required apps, selectedOrganisation is null and org is derived from event
369
- mockUseUnifiedAuthFn.mockReturnValue({
370
- ...mockUser,
371
- selectedOrganisation: null,
372
- selectedEvent: null, // No event either, so no context available
373
- supabase: {} as any,
374
- });
375
-
376
- // Mock useResolvedScope to return null scope when no context available
377
- mockUseResolvedScopeFn.mockReturnValue({
378
- resolvedScope: null,
379
- isLoading: false,
380
- error: null,
381
- });
382
-
383
- renderWithProviders(
384
- <TestWrapper>
385
- <TestComponent />
386
- </TestWrapper>
387
- );
388
-
389
- expect(screen.getByTestId('data-access-allowed')).toHaveTextContent('false');
390
- });
391
-
392
- it('should allow data access when disabled', () => {
393
- renderWithProviders(
394
- <TestWrapper providerProps={{ isEnabled: false }}>
395
- <TestComponent />
396
- </TestWrapper>
397
- );
398
-
399
- // When disabled, isDataAccessAllowed returns true (allows all access)
400
- expect(screen.getByTestId('data-access-allowed')).toHaveTextContent('true');
401
- });
402
- });
403
-
404
- describe('Context Validation', () => {
405
- it('should validate context successfully', () => {
406
- renderWithProviders(
407
- <TestWrapper>
408
- <TestComponent />
409
- </TestWrapper>
410
- );
411
-
412
- // The component should render without errors
413
- expect(screen.getByTestId('test-component')).toBeInTheDocument();
414
- });
415
-
416
- it('should handle context validation errors', () => {
417
- // Context validation is handled internally by SecureDataProvider
418
- // We can't directly mock it anymore, so we'll test the error through the component behavior
419
- // For now, this test verifies the component renders without crashing
420
- renderWithProviders(
421
- <TestWrapper>
422
- <TestComponent />
423
- </TestWrapper>
424
- );
425
-
426
- // The component should render without errors
427
- expect(screen.getByTestId('test-component')).toBeInTheDocument();
428
- });
429
- });
430
-
431
- describe('Audit Logging', () => {
432
- it('should log strict mode status when enabled', async () => {
433
- renderWithProviders(
434
- <TestWrapper providerProps={{ strictMode: true, auditLog: true }}>
435
- <TestComponent />
436
- </TestWrapper>
437
- );
438
-
439
- await waitFor(() => {
440
- expect(mockLogger.debug).toHaveBeenCalledWith(
441
- 'Strict mode enabled - all data access attempts will be logged and enforced'
442
- );
443
- });
444
- });
445
-
446
- it('should log RLS enforcement when enabled', async () => {
447
- renderWithProviders(
448
- <TestWrapper providerProps={{ enforceRLS: true, auditLog: true }}>
449
- <TestComponent />
450
- </TestWrapper>
451
- );
452
-
453
- await waitFor(() => {
454
- expect(mockLogger.debug).toHaveBeenCalledWith(
455
- 'Strict mode enabled - all data access attempts will be logged and enforced'
456
- );
457
- });
458
- });
459
-
460
- it('should not log when audit logging is disabled', async () => {
461
- renderWithProviders(
462
- <TestWrapper providerProps={{ strictMode: true, auditLog: false }}>
463
- <TestComponent />
464
- </TestWrapper>
465
- );
466
-
467
- await waitFor(() => {
468
- expect(mockLogger.debug).not.toHaveBeenCalledWith(
469
- 'Strict mode enabled - all data access attempts will be logged and enforced'
470
- );
471
- });
472
- });
473
- });
474
-
475
- describe('History Management', () => {
476
- it('should clear data access history', () => {
477
- renderWithProviders(
478
- <TestWrapper>
479
- <TestComponent />
480
- </TestWrapper>
481
- );
482
-
483
- expect(screen.getByTestId('history-length')).toHaveTextContent('0');
484
- });
485
-
486
- it('should maintain history within maxHistorySize limit', () => {
487
- renderWithProviders(
488
- <TestWrapper providerProps={{ maxHistorySize: 5 }}>
489
- <TestComponent />
490
- </TestWrapper>
491
- );
492
-
493
- expect(screen.getByTestId('history-length')).toHaveTextContent('0');
494
- });
495
- });
496
-
497
- describe('Error Handling', () => {
498
- it('should handle missing user gracefully', () => {
499
- mockUseUnifiedAuthFn.mockReturnValue({ user: null, selectedOrganisation: null, selectedEvent: null });
500
-
501
- renderWithProviders(
502
- <TestWrapper>
503
- <TestComponent />
504
- </TestWrapper>
505
- );
506
-
507
- expect(screen.getByTestId('data-access-allowed')).toHaveTextContent('false');
508
- });
509
-
510
- it('should handle missing organisation context gracefully', () => {
511
- mockUseUnifiedAuthFn.mockReturnValue({
512
- ...mockUser,
513
- selectedOrganisation: null,
514
- selectedEvent: null, // No event either
515
- supabase: {} as any,
516
- });
517
-
518
- // Mock useResolvedScope to return null scope when no context available
519
- mockUseResolvedScopeFn.mockReturnValue({
520
- resolvedScope: null,
521
- isLoading: false,
522
- error: null,
523
- });
524
-
525
- renderWithProviders(
526
- <TestWrapper>
527
- <TestComponent />
528
- </TestWrapper>
529
- );
530
-
531
- expect(screen.getByTestId('data-access-allowed')).toHaveTextContent('false');
532
- });
533
- });
534
-
535
- describe('useSecureData Hook', () => {
536
- it('should throw error when used outside provider', () => {
537
- // Suppress console.error for this test
538
- const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
539
-
540
- expect(() => {
541
- renderWithProviders(<TestComponent />);
542
- }).toThrow('useSecureData must be used within a SecureDataProvider');
543
-
544
- consoleSpy.mockRestore();
545
- });
546
-
547
- it('should return context when used within provider', () => {
548
- renderWithProviders(
549
- <TestWrapper>
550
- <TestComponent />
551
- </TestWrapper>
552
- );
553
-
554
- expect(screen.getByTestId('test-component')).toBeInTheDocument();
555
- });
556
- });
557
-
558
- describe('Callback Functions', () => {
559
- it('should call onDataAccess callback when provided', () => {
560
- const onDataAccess = vi.fn();
561
-
562
- renderWithProviders(
563
- <TestWrapper providerProps={{ onDataAccess }}>
564
- <TestComponent />
565
- </TestWrapper>
566
- );
567
-
568
- expect(screen.getByTestId('test-component')).toBeInTheDocument();
569
- });
570
-
571
- it('should call onStrictModeViolation callback when provided', () => {
572
- const onStrictModeViolation = vi.fn();
573
-
574
- renderWithProviders(
575
- <TestWrapper providerProps={{ onStrictModeViolation }}>
576
- <TestComponent />
577
- </TestWrapper>
578
- );
579
-
580
- expect(screen.getByTestId('test-component')).toBeInTheDocument();
581
- });
582
- });
583
-
584
- describe('Scope Management', () => {
585
- it('should create scope with organisation and event IDs', () => {
586
- renderWithProviders(
587
- <TestWrapper>
588
- <TestComponent />
589
- </TestWrapper>
590
- );
591
-
592
- expect(screen.getByTestId('test-component')).toBeInTheDocument();
593
- });
594
-
595
- it('should handle missing event ID in scope', () => {
596
- mockUseUnifiedAuthFn.mockReturnValue({ ...mockUser, selectedEvent: null });
597
-
598
- renderWithProviders(
599
- <TestWrapper>
600
- <TestComponent />
601
- </TestWrapper>
602
- );
603
-
604
- expect(screen.getByTestId('test-component')).toBeInTheDocument();
605
- });
606
- });
607
-
608
- describe('Performance', () => {
609
- it('should memoize context value', () => {
610
- const { rerender } = renderWithProviders(
611
- <TestWrapper>
612
- <TestComponent />
613
- </TestWrapper>
614
- );
615
-
616
- const initialHistoryLength = screen.getByTestId('history-length').textContent;
617
-
618
- rerender(
619
- <TestWrapper>
620
- <TestComponent />
621
- </TestWrapper>
622
- );
623
-
624
- expect(screen.getByTestId('history-length')).toHaveTextContent(initialHistoryLength!);
625
- });
626
- });
627
-
628
- describe('Integration', () => {
629
- it('should work with multiple consumers', () => {
630
- renderWithProviders(
631
- <TestWrapper>
632
- <TestComponent testId="component-1" />
633
- <TestComponent testId="component-2" />
634
- </TestWrapper>
635
- );
636
-
637
- expect(screen.getByTestId('component-1')).toBeInTheDocument();
638
- expect(screen.getByTestId('component-2')).toBeInTheDocument();
639
- });
640
-
641
- it('should maintain state across re-renders', () => {
642
- const { rerender } = renderWithProviders(
643
- <TestWrapper>
644
- <TestComponent />
645
- </TestWrapper>
646
- );
647
-
648
- expect(screen.getByTestId('test-component')).toBeInTheDocument();
649
-
650
- rerender(
651
- <TestWrapper>
652
- <TestComponent />
653
- </TestWrapper>
654
- );
655
-
656
- expect(screen.getByTestId('test-component')).toBeInTheDocument();
657
- });
658
- });
659
- });