@qwickapps/react-framework 1.3.5 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (320) hide show
  1. package/README.md +1691 -2
  2. package/dist/__tests__/schemas/transformers/MockSerializableComponent.d.ts +66 -0
  3. package/dist/__tests__/schemas/transformers/MockSerializableComponent.d.ts.map +1 -0
  4. package/dist/components/ErrorBoundary.d.ts +7 -0
  5. package/dist/components/ErrorBoundary.d.ts.map +1 -1
  6. package/dist/components/Html.d.ts +28 -18
  7. package/dist/components/Html.d.ts.map +1 -1
  8. package/dist/components/Logo.d.ts +12 -35
  9. package/dist/components/Logo.d.ts.map +1 -1
  10. package/dist/components/Markdown.d.ts +18 -13
  11. package/dist/components/Markdown.d.ts.map +1 -1
  12. package/dist/components/QwickApp.d.ts +16 -3
  13. package/dist/components/QwickApp.d.ts.map +1 -1
  14. package/dist/components/QwickIcon.d.ts +23 -0
  15. package/dist/components/QwickIcon.d.ts.map +1 -0
  16. package/dist/components/SafeSpan.d.ts +12 -5
  17. package/dist/components/SafeSpan.d.ts.map +1 -1
  18. package/dist/components/Scaffold.d.ts.map +1 -1
  19. package/dist/components/base/ModelView.d.ts +101 -0
  20. package/dist/components/base/ModelView.d.ts.map +1 -0
  21. package/dist/components/base/index.d.ts +11 -0
  22. package/dist/components/base/index.d.ts.map +1 -0
  23. package/dist/components/blocks/Article.d.ts +12 -2
  24. package/dist/components/blocks/Article.d.ts.map +1 -1
  25. package/dist/components/blocks/Code.d.ts +13 -2
  26. package/dist/components/blocks/Code.d.ts.map +1 -1
  27. package/dist/components/blocks/CoverImageHeader.d.ts.map +1 -1
  28. package/dist/components/blocks/FeatureCard.d.ts.map +1 -1
  29. package/dist/components/blocks/FeatureGrid.d.ts.map +1 -1
  30. package/dist/components/blocks/Footer.d.ts.map +1 -1
  31. package/dist/components/blocks/HeroBlock.d.ts +27 -13
  32. package/dist/components/blocks/HeroBlock.d.ts.map +1 -1
  33. package/dist/components/blocks/Image.d.ts +41 -0
  34. package/dist/components/blocks/Image.d.ts.map +1 -0
  35. package/dist/components/blocks/PageBannerHeader.d.ts.map +1 -1
  36. package/dist/components/blocks/Section.d.ts +16 -2
  37. package/dist/components/blocks/Section.d.ts.map +1 -1
  38. package/dist/components/blocks/Text.d.ts +41 -0
  39. package/dist/components/blocks/Text.d.ts.map +1 -0
  40. package/dist/components/blocks/index.d.ts +4 -0
  41. package/dist/components/blocks/index.d.ts.map +1 -1
  42. package/dist/components/buttons/Button.d.ts +23 -7
  43. package/dist/components/buttons/Button.d.ts.map +1 -1
  44. package/dist/components/forms/FormBlock.d.ts +19 -13
  45. package/dist/components/forms/FormBlock.d.ts.map +1 -1
  46. package/dist/components/index.d.ts +4 -0
  47. package/dist/components/index.d.ts.map +1 -1
  48. package/dist/components/input/ChoiceInputField.d.ts +17 -11
  49. package/dist/components/input/ChoiceInputField.d.ts.map +1 -1
  50. package/dist/components/input/HtmlInputField.d.ts +17 -11
  51. package/dist/components/input/HtmlInputField.d.ts.map +1 -1
  52. package/dist/components/input/SelectInputField.d.ts +16 -10
  53. package/dist/components/input/SelectInputField.d.ts.map +1 -1
  54. package/dist/components/input/SwitchInputField.d.ts +16 -10
  55. package/dist/components/input/SwitchInputField.d.ts.map +1 -1
  56. package/dist/components/input/TextField.d.ts.map +1 -1
  57. package/dist/components/input/TextInputField.d.ts +16 -11
  58. package/dist/components/input/TextInputField.d.ts.map +1 -1
  59. package/dist/components/layout/GridCell.d.ts +23 -6
  60. package/dist/components/layout/GridCell.d.ts.map +1 -1
  61. package/dist/components/layout/GridLayout.d.ts +24 -23
  62. package/dist/components/layout/GridLayout.d.ts.map +1 -1
  63. package/dist/components/pages/FormPage.d.ts.map +1 -1
  64. package/dist/components/pages/Page.d.ts +49 -87
  65. package/dist/components/pages/Page.d.ts.map +1 -1
  66. package/dist/components/pages/index.d.ts +2 -2
  67. package/dist/components/pages/index.d.ts.map +1 -1
  68. package/dist/config/AppConfig.d.ts +49 -0
  69. package/dist/config/AppConfig.d.ts.map +1 -0
  70. package/dist/config/AppConfigBuilder.d.ts +75 -0
  71. package/dist/config/AppConfigBuilder.d.ts.map +1 -0
  72. package/dist/config/index.d.ts +13 -0
  73. package/dist/config/index.d.ts.map +1 -0
  74. package/dist/config/types.d.ts +130 -0
  75. package/dist/config/types.d.ts.map +1 -0
  76. package/dist/config.d.ts +15 -0
  77. package/dist/config.d.ts.map +1 -0
  78. package/dist/config.esm.js +451 -0
  79. package/dist/config.js +455 -0
  80. package/dist/contexts/PrintModeContext.d.ts +27 -0
  81. package/dist/contexts/PrintModeContext.d.ts.map +1 -0
  82. package/dist/contexts/QwickAppContext.d.ts +2 -2
  83. package/dist/contexts/QwickAppContext.d.ts.map +1 -1
  84. package/dist/contexts/index.d.ts +2 -0
  85. package/dist/contexts/index.d.ts.map +1 -1
  86. package/dist/hooks/index.d.ts +2 -0
  87. package/dist/hooks/index.d.ts.map +1 -1
  88. package/dist/hooks/usePrintMode.d.ts +39 -0
  89. package/dist/hooks/usePrintMode.d.ts.map +1 -0
  90. package/dist/index.css +1 -1
  91. package/dist/index.d.ts +1 -0
  92. package/dist/index.d.ts.map +1 -1
  93. package/dist/index.esm.css +1 -1
  94. package/dist/index.esm.js +10951 -6238
  95. package/dist/index.js +11014 -6287
  96. package/dist/schemas/CodeSchema.d.ts +2 -1
  97. package/dist/schemas/CodeSchema.d.ts.map +1 -1
  98. package/dist/schemas/CollapsibleLayoutSchema.d.ts +2 -1
  99. package/dist/schemas/CollapsibleLayoutSchema.d.ts.map +1 -1
  100. package/dist/schemas/ContentSchema.d.ts +2 -1
  101. package/dist/schemas/ContentSchema.d.ts.map +1 -1
  102. package/dist/schemas/GridCellSchema.d.ts +25 -0
  103. package/dist/schemas/GridCellSchema.d.ts.map +1 -0
  104. package/dist/schemas/GridLayoutSchema.d.ts +23 -0
  105. package/dist/schemas/GridLayoutSchema.d.ts.map +1 -0
  106. package/dist/schemas/HtmlSchema.d.ts +14 -0
  107. package/dist/schemas/HtmlSchema.d.ts.map +1 -0
  108. package/dist/schemas/ImageSchema.d.ts +32 -0
  109. package/dist/schemas/ImageSchema.d.ts.map +1 -0
  110. package/dist/schemas/LogoSchema.d.ts +35 -0
  111. package/dist/schemas/LogoSchema.d.ts.map +1 -0
  112. package/dist/schemas/MarkdownSchema.d.ts +14 -0
  113. package/dist/schemas/MarkdownSchema.d.ts.map +1 -0
  114. package/dist/schemas/PageTemplateSchema.d.ts +31 -0
  115. package/dist/schemas/PageTemplateSchema.d.ts.map +1 -0
  116. package/dist/schemas/PrintConfigSchema.d.ts +31 -0
  117. package/dist/schemas/PrintConfigSchema.d.ts.map +1 -0
  118. package/dist/schemas/SectionSchema.d.ts +2 -1
  119. package/dist/schemas/SectionSchema.d.ts.map +1 -1
  120. package/dist/schemas/TextSchema.d.ts +37 -0
  121. package/dist/schemas/TextSchema.d.ts.map +1 -0
  122. package/dist/schemas/ViewModelSchema.d.ts +23 -0
  123. package/dist/schemas/ViewModelSchema.d.ts.map +1 -0
  124. package/dist/schemas/index.d.ts +15 -1
  125. package/dist/schemas/index.d.ts.map +1 -1
  126. package/dist/schemas/transformers/ComponentTransformer.d.ts +116 -0
  127. package/dist/schemas/transformers/ComponentTransformer.d.ts.map +1 -0
  128. package/dist/schemas/transformers/ReactNodeTransformer.d.ts +53 -0
  129. package/dist/schemas/transformers/ReactNodeTransformer.d.ts.map +1 -0
  130. package/dist/schemas/transformers/__tests__/MockSerializableComponent.d.ts +66 -0
  131. package/dist/schemas/transformers/__tests__/MockSerializableComponent.d.ts.map +1 -0
  132. package/dist/schemas/transformers/registry.d.ts +15 -0
  133. package/dist/schemas/transformers/registry.d.ts.map +1 -0
  134. package/dist/schemas/types/Serializable.d.ts +46 -0
  135. package/dist/schemas/types/Serializable.d.ts.map +1 -0
  136. package/dist/utils/htmlTransform.d.ts.map +1 -1
  137. package/dist/utils/reactUtils.d.ts +12 -3
  138. package/dist/utils/reactUtils.d.ts.map +1 -1
  139. package/package.json +17 -3
  140. package/src/{components/__tests__ → __tests__/components}/AccessibilityProvider.test.tsx +1 -1
  141. package/src/{components/__tests__ → __tests__/components}/Article.test.tsx +1 -1
  142. package/src/{components/__tests__ → __tests__/components}/Breadcrumbs.test.tsx +1 -1
  143. package/src/{components/__tests__ → __tests__/components}/Button.test.tsx +1 -1
  144. package/src/{components/__tests__ → __tests__/components}/CardListGrid.test.tsx +2 -2
  145. package/src/{components/__tests__ → __tests__/components}/ChoiceInputField.test.tsx +1 -1
  146. package/src/{components/__tests__ → __tests__/components}/Code.test.tsx +1 -1
  147. package/src/{components/__tests__ → __tests__/components}/Content.integration.test.tsx +1 -1
  148. package/src/{components/__tests__ → __tests__/components}/Content.test.tsx +1 -1
  149. package/src/{components/__tests__ → __tests__/components}/CoverImageHeader.test.tsx +2 -2
  150. package/src/{components/__tests__ → __tests__/components}/ErrorBoundary.test.tsx +1 -1
  151. package/src/{components/__tests__ → __tests__/components}/FeatureCard.integration.test.tsx +2 -2
  152. package/src/{components/__tests__ → __tests__/components}/FeatureGrid.integration.test.tsx +2 -2
  153. package/src/{components/__tests__ → __tests__/components}/FeatureGrid.test.tsx +2 -2
  154. package/src/{components/__tests__ → __tests__/components}/Footer.test.tsx +4 -4
  155. package/src/{components/__tests__ → __tests__/components}/FormBlock.test.tsx +1 -1
  156. package/src/{components/__tests__ → __tests__/components}/HeroBlock.integration.test.tsx +2 -2
  157. package/src/{components/__tests__ → __tests__/components}/HeroBlock.test.tsx +233 -7
  158. package/src/{components/__tests__ → __tests__/components}/Html.test.tsx +11 -2
  159. package/src/{components/__tests__ → __tests__/components}/HtmlInputField.test.tsx +3 -3
  160. package/src/__tests__/components/Logo.test.js +3 -3
  161. package/src/{components/__tests__ → __tests__/components}/Markdown.test.tsx +1 -1
  162. package/src/{components/__tests__ → __tests__/components}/PageBannerHeader.test.tsx +3 -3
  163. package/src/{components/__tests__ → __tests__/components}/PaletteSwitcher.test.tsx +3 -3
  164. package/src/{components/__tests__ → __tests__/components}/ProductCard.test.tsx +4 -4
  165. package/src/{components/__tests__ → __tests__/components}/SafeSpan.integration.test.tsx +2 -2
  166. package/src/{components/__tests__ → __tests__/components}/SafeSpan.simple.test.tsx +1 -1
  167. package/src/{components/__tests__ → __tests__/components}/SafeSpan.test.tsx +1 -1
  168. package/src/{components/__tests__ → __tests__/components}/Section.integration.test.tsx +1 -1
  169. package/src/{components/__tests__ → __tests__/components}/Section.test.tsx +1 -1
  170. package/src/{components/__tests__ → __tests__/components}/SelectInputField.test.tsx +1 -1
  171. package/src/{components/__tests__ → __tests__/components}/TextInputField.test.tsx +3 -3
  172. package/src/{components/__tests__ → __tests__/components}/ThemeSwitcher.test.tsx +3 -3
  173. package/src/__tests__/components/base/ModelView.test.tsx +220 -0
  174. package/src/__tests__/components/blocks/Code.performance.test.tsx +625 -0
  175. package/src/__tests__/components/blocks/Code.serialization.test.tsx +507 -0
  176. package/src/__tests__/components/blocks/HeroBlock.serialization.test.tsx +414 -0
  177. package/src/__tests__/components/blocks/Image.serialization.test.tsx +257 -0
  178. package/src/__tests__/components/blocks/Section.serialization.test.tsx +553 -0
  179. package/src/__tests__/components/blocks/Text.performance.test.tsx +442 -0
  180. package/src/__tests__/components/blocks/Text.serialization.test.tsx +491 -0
  181. package/src/__tests__/components/buttons/Button.serialization.test.tsx +443 -0
  182. package/src/__tests__/components/input/FormComponents.serialization.test.tsx +482 -0
  183. package/src/__tests__/components/input/SelectInputField.serialization.test.tsx +439 -0
  184. package/src/__tests__/components/input/TextInputField.serialization.test.tsx +359 -0
  185. package/src/{components/layout/CollapsibleLayout/__tests__ → __tests__/components/layout}/CollapsibleLayout.test.tsx +4 -4
  186. package/src/__tests__/components/layout/GridCell.serialization.test.tsx +403 -0
  187. package/src/__tests__/components/layout/GridLayout.serialization.test.tsx +311 -0
  188. package/src/__tests__/hooks/usePrintMode.test.ts +89 -0
  189. package/src/__tests__/schemas/PageTemplateSchema.test.ts +161 -0
  190. package/src/__tests__/schemas/PrintConfigSchema.test.ts +127 -0
  191. package/src/__tests__/schemas/ViewModelSchema.test.ts +80 -0
  192. package/src/__tests__/schemas/transformers/ComponentSerializationPatterns.test.tsx +602 -0
  193. package/src/__tests__/schemas/transformers/ComponentTransformer.htmlPatterns.test.ts +301 -0
  194. package/src/__tests__/schemas/transformers/ComponentTransformer.test.ts +521 -0
  195. package/src/__tests__/schemas/transformers/CrossBrowserCompatibility.test.ts +586 -0
  196. package/src/__tests__/schemas/transformers/MockSerializableComponent.ts +103 -0
  197. package/src/__tests__/schemas/transformers/RealWorldScenarios.test.tsx +1165 -0
  198. package/src/__tests__/schemas/transformers/SerializationErrorHandling.test.ts +602 -0
  199. package/src/__tests__/schemas/transformers/SerializationIntegration.test.tsx +691 -0
  200. package/src/__tests__/schemas/transformers/SerializationPerformance.test.ts +460 -0
  201. package/src/__tests__/schemas/transformers/TestAutomation.test.ts +597 -0
  202. package/src/{utils/__tests__ → __tests__/utils}/nested-dom-fix.test.tsx +1 -1
  203. package/src/components/ErrorBoundary.tsx +8 -8
  204. package/src/components/Html.tsx +147 -44
  205. package/src/components/Logo.tsx +198 -100
  206. package/src/components/Markdown.tsx +125 -16
  207. package/src/components/QwickApp.tsx +64 -31
  208. package/src/components/QwickIcon.tsx +59 -0
  209. package/src/components/SafeSpan.tsx +65 -10
  210. package/src/components/Scaffold.tsx +2 -8
  211. package/src/components/base/ModelView.tsx +199 -0
  212. package/src/components/base/index.ts +11 -0
  213. package/src/components/blocks/Article.tsx +57 -18
  214. package/src/components/blocks/Code.md +529 -0
  215. package/src/components/blocks/Code.tsx +102 -15
  216. package/src/components/blocks/CoverImageHeader.tsx +9 -4
  217. package/src/components/blocks/FeatureCard.tsx +1 -2
  218. package/src/components/blocks/FeatureGrid.tsx +19 -1
  219. package/src/components/blocks/Footer.tsx +13 -1
  220. package/src/components/blocks/HeroBlock.tsx +87 -20
  221. package/src/components/blocks/Image.tsx +395 -0
  222. package/src/components/blocks/PageBannerHeader.tsx +14 -12
  223. package/src/components/blocks/ProductCard.tsx +1 -1
  224. package/src/components/blocks/Section.tsx +113 -8
  225. package/src/components/blocks/Text.tsx +285 -0
  226. package/src/components/blocks/index.ts +4 -0
  227. package/src/components/buttons/Button.tsx +184 -15
  228. package/src/components/forms/FormBlock.tsx +70 -17
  229. package/src/components/index.ts +5 -0
  230. package/src/components/input/ChoiceInputField.tsx +48 -18
  231. package/src/components/input/HtmlInputField.tsx +48 -18
  232. package/src/components/input/SelectInputField.tsx +48 -16
  233. package/src/components/input/SwitchInputField.tsx +48 -17
  234. package/src/components/input/TextField.tsx +41 -1
  235. package/src/components/input/TextInputField.tsx +52 -18
  236. package/src/components/layout/GridCell.tsx +118 -9
  237. package/src/components/layout/GridLayout.tsx +125 -24
  238. package/src/components/pages/FormPage.tsx +0 -1
  239. package/src/components/pages/Page.css +304 -332
  240. package/src/components/pages/Page.tsx +307 -255
  241. package/src/components/pages/index.ts +2 -2
  242. package/src/config/AppConfig.ts +133 -0
  243. package/src/config/AppConfigBuilder.ts +421 -0
  244. package/src/config/__tests__/AppConfig.test.ts +385 -0
  245. package/src/config/__tests__/AppConfigBuilder.test.ts +432 -0
  246. package/src/config/index.ts +24 -0
  247. package/src/config/types.ts +170 -0
  248. package/src/config.ts +25 -0
  249. package/src/contexts/PrintModeContext.tsx +332 -0
  250. package/src/contexts/QwickAppContext.tsx +2 -2
  251. package/src/contexts/index.ts +2 -0
  252. package/src/hooks/index.ts +5 -1
  253. package/src/hooks/usePrintMode.ts +73 -0
  254. package/src/index.ts +3 -0
  255. package/src/schemas/CodeSchema.ts +3 -3
  256. package/src/schemas/CollapsibleLayoutSchema.ts +2 -1
  257. package/src/schemas/ContentSchema.ts +2 -1
  258. package/src/schemas/GridCellSchema.ts +164 -0
  259. package/src/schemas/GridLayoutSchema.ts +133 -0
  260. package/src/schemas/HtmlSchema.ts +47 -0
  261. package/src/schemas/ImageSchema.ts +235 -0
  262. package/src/schemas/LogoSchema.ts +241 -0
  263. package/src/schemas/MarkdownSchema.ts +47 -0
  264. package/src/schemas/PageTemplateSchema.ts +186 -0
  265. package/src/schemas/PrintConfigSchema.ts +207 -0
  266. package/src/schemas/README.md +661 -0
  267. package/src/schemas/SectionSchema.ts +2 -1
  268. package/src/schemas/TextSchema.ts +329 -0
  269. package/src/schemas/ViewModelSchema.ts +115 -0
  270. package/src/schemas/index.ts +21 -2
  271. package/src/schemas/transformers/ComponentTransformer.ts +403 -0
  272. package/src/schemas/transformers/ReactNodeTransformer.ts +236 -0
  273. package/src/schemas/transformers/registry.ts +72 -0
  274. package/src/schemas/types/Serializable.ts +51 -0
  275. package/src/stories/AccessibilityProvider.stories.tsx +253 -253
  276. package/src/stories/Article.stories.tsx +433 -433
  277. package/src/stories/Button.stories.tsx +1 -1
  278. package/src/stories/CardListGrid.stories.tsx +451 -451
  279. package/src/stories/ChoiceInputField.stories.tsx +503 -503
  280. package/src/stories/Code.stories.tsx +1 -1
  281. package/src/stories/CollapsibleLayout.stories.tsx +1414 -1414
  282. package/src/stories/Content.stories.tsx +393 -393
  283. package/src/stories/CoverImageHeader.stories.tsx +701 -701
  284. package/src/stories/DataBinding.advanced.stories.tsx +432 -432
  285. package/src/stories/DataProvider.stories.tsx +1192 -1192
  286. package/src/stories/FeatureCard.stories.tsx +557 -557
  287. package/src/stories/FeatureGrid.stories.tsx +594 -594
  288. package/src/stories/Footer.stories.tsx +640 -640
  289. package/src/stories/FormBlock.stories.tsx +760 -760
  290. package/src/stories/FormComponents.stories.tsx +349 -541
  291. package/src/stories/GridCell.stories.tsx +417 -0
  292. package/src/stories/GridLayout.stories.tsx +353 -0
  293. package/src/stories/HeroBlock.stories.tsx +862 -373
  294. package/src/stories/HtmlInputField.stories.tsx +474 -474
  295. package/src/stories/Image.stories.tsx +819 -0
  296. package/src/stories/Introduction.stories.tsx +667 -667
  297. package/src/stories/LayoutBlocks.stories.tsx +324 -324
  298. package/src/stories/Logo.stories.tsx +165 -6
  299. package/src/stories/Markdown.stories.tsx +137 -137
  300. package/src/stories/ModelView.stories.tsx +477 -0
  301. package/src/stories/Page.stories.tsx +688 -688
  302. package/src/stories/PageBannerHeader.stories.tsx +864 -864
  303. package/src/stories/PaletteSwitcher.stories.tsx +119 -119
  304. package/src/stories/ProductCard.stories.tsx +424 -424
  305. package/src/stories/QwickApp.stories.tsx +368 -368
  306. package/src/stories/ResponsiveMenu.stories.tsx +249 -249
  307. package/src/stories/SafeSpan.stories.tsx +531 -531
  308. package/src/stories/Section.stories.tsx +90 -2
  309. package/src/stories/SelectInputField.stories.tsx +524 -524
  310. package/src/stories/Text.stories.tsx +560 -0
  311. package/src/stories/TextInputField.stories.tsx +443 -443
  312. package/src/stories/ThemeSwitcher.stories.tsx +123 -123
  313. package/src/utils/htmlTransform.tsx +74 -53
  314. package/src/utils/reactUtils.tsx +57 -6
  315. package/dist/index.bundled.css +0 -12
  316. /package/src/{hooks/__tests__ → __tests__/hooks}/useDataBinding.test.tsx.disabled +0 -0
  317. /package/src/{schemas/__tests__ → __tests__/schemas}/builders.test.ts +0 -0
  318. /package/src/{utils/__tests__ → __tests__/utils}/createDataDrivenComponent.test.tsx.disabled +0 -0
  319. /package/src/{utils/__tests__ → __tests__/utils}/htmlTransform.test.tsx +0 -0
  320. /package/src/{utils/__tests__ → __tests__/utils}/optional-logging.test.ts +0 -0
@@ -0,0 +1,443 @@
1
+ /**
2
+ * Button Serialization Tests
3
+ *
4
+ * Comprehensive test suite for Button component serialization functionality.
5
+ * Tests the Serializable interface implementation and action handling.
6
+ *
7
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
8
+ */
9
+
10
+ import React from 'react';
11
+ import { render, screen, fireEvent } from '@testing-library/react';
12
+ import '@testing-library/jest-dom';
13
+ import Button, { ButtonAction } from '../../../components/buttons/Button';
14
+ import { ComponentTransformer } from '../../../schemas/transformers/ComponentTransformer';
15
+ // Import registry to ensure component registration happens
16
+ import '../../../schemas/transformers/registry';
17
+
18
+ // Mock React Router for navigation tests
19
+ const mockNavigate = jest.fn();
20
+ jest.mock('react-router-dom', () => ({
21
+ useNavigate: () => mockNavigate,
22
+ }));
23
+
24
+ describe('Button Serialization', () => {
25
+ beforeEach(() => {
26
+ jest.clearAllMocks();
27
+ // Clear any global handlers
28
+ (global as any).testHandler = undefined;
29
+ });
30
+
31
+ describe('Basic Serialization', () => {
32
+ test('should serialize basic button with label', () => {
33
+ const button = new Button({ label: 'Click me', variant: 'primary' });
34
+ const json = button.toJson();
35
+
36
+ expect(json).toEqual({
37
+ children: '', // extractTextFromReactNode returns empty string for undefined
38
+ label: 'Click me',
39
+ variant: 'primary',
40
+ buttonSize: undefined,
41
+ href: undefined,
42
+ target: undefined,
43
+ disabled: undefined,
44
+ loading: undefined,
45
+ fullWidth: undefined,
46
+ action: undefined,
47
+ dataSource: undefined,
48
+ bindingOptions: undefined
49
+ });
50
+ });
51
+
52
+ test('should serialize button with children text', () => {
53
+ const button = new Button({ children: 'Button text' });
54
+ const json = button.toJson();
55
+
56
+ expect(json.children).toBe('Button text');
57
+ });
58
+
59
+ test('should serialize button with children ReactNode', () => {
60
+ const children = <span>Complex <strong>content</strong></span>;
61
+ const button = new Button({ children });
62
+ const json = button.toJson();
63
+
64
+ expect(json.children).toBe('Complex content');
65
+ });
66
+
67
+ test('should serialize all button properties', () => {
68
+ const button = new Button({
69
+ label: 'Submit',
70
+ variant: 'contained',
71
+ buttonSize: 'large',
72
+ href: 'https://example.com',
73
+ target: '_blank',
74
+ disabled: true,
75
+ loading: false,
76
+ fullWidth: true
77
+ });
78
+ const json = button.toJson();
79
+
80
+ expect(json).toMatchObject({
81
+ label: 'Submit',
82
+ variant: 'contained',
83
+ buttonSize: 'large',
84
+ href: 'https://example.com',
85
+ target: '_blank',
86
+ disabled: true,
87
+ loading: false,
88
+ fullWidth: true
89
+ });
90
+ });
91
+ });
92
+
93
+ describe('Action Serialization', () => {
94
+ test('should serialize navigation action', () => {
95
+ const action: ButtonAction = {
96
+ type: 'navigate',
97
+ url: '/dashboard',
98
+ target: '_self'
99
+ };
100
+ const button = new Button({ label: 'Go to Dashboard', action });
101
+ const json = button.toJson();
102
+
103
+ expect(json.action).toEqual(action);
104
+ });
105
+
106
+ test('should serialize form submit action', () => {
107
+ const action: ButtonAction = {
108
+ type: 'submit',
109
+ form: 'contact-form'
110
+ };
111
+ const button = new Button({ label: 'Submit Form', action });
112
+ const json = button.toJson();
113
+
114
+ expect(json.action).toEqual(action);
115
+ });
116
+
117
+ test('should serialize external link action', () => {
118
+ const action: ButtonAction = {
119
+ type: 'external',
120
+ url: 'https://external.com',
121
+ target: '_blank'
122
+ };
123
+ const button = new Button({ label: 'External Link', action });
124
+ const json = button.toJson();
125
+
126
+ expect(json.action).toEqual(action);
127
+ });
128
+
129
+ test('should serialize custom action', () => {
130
+ const action: ButtonAction = {
131
+ type: 'custom',
132
+ customHandler: 'handleCustomAction'
133
+ };
134
+ const button = new Button({ label: 'Custom Action', action });
135
+ const json = button.toJson();
136
+
137
+ expect(json.action).toEqual(action);
138
+ });
139
+ });
140
+
141
+ describe('Data Binding Serialization', () => {
142
+ test('should serialize data binding properties', () => {
143
+ const dataSource = { endpoint: '/api/buttons/1' };
144
+ const bindingOptions = { cache: true, cacheTTL: 5000 };
145
+
146
+ const button = new Button({
147
+ label: 'Dynamic Button',
148
+ dataSource,
149
+ bindingOptions
150
+ });
151
+ const json = button.toJson();
152
+
153
+ expect(json.dataSource).toEqual(dataSource);
154
+ expect(json.bindingOptions).toEqual(bindingOptions);
155
+ });
156
+ });
157
+
158
+ describe('Deserialization', () => {
159
+ test('should deserialize basic button from JSON', () => {
160
+ const json = {
161
+ label: 'Click me',
162
+ variant: 'primary',
163
+ buttonSize: 'medium'
164
+ };
165
+
166
+ const element = Button.fromJson(json);
167
+ expect(React.isValidElement(element)).toBe(true);
168
+ expect(element.type).toBe(Button);
169
+ expect(element.props).toMatchObject(json);
170
+ });
171
+
172
+ test('should deserialize button with action', () => {
173
+ const json = {
174
+ label: 'Navigate',
175
+ action: {
176
+ type: 'navigate',
177
+ url: '/page'
178
+ }
179
+ };
180
+
181
+ const element = Button.fromJson(json);
182
+ expect(element.props.action).toEqual(json.action);
183
+ });
184
+
185
+ test('should deserialize button with children', () => {
186
+ const json = {
187
+ children: 'Button content',
188
+ variant: 'outlined'
189
+ };
190
+
191
+ const element = Button.fromJson(json);
192
+ expect(element.props.children).toBe('Button content');
193
+ });
194
+ });
195
+
196
+ describe('Round-trip Serialization', () => {
197
+ test('should maintain data integrity through serialize-deserialize cycle', () => {
198
+ const originalProps = {
199
+ label: 'Test Button',
200
+ variant: 'contained' as const,
201
+ buttonSize: 'large' as const,
202
+ disabled: false,
203
+ fullWidth: true,
204
+ action: {
205
+ type: 'navigate' as const,
206
+ url: '/test-page'
207
+ }
208
+ };
209
+
210
+ const button = new Button(originalProps);
211
+ const json = button.toJson();
212
+ const deserializedElement = Button.fromJson(json);
213
+ const newButton = new Button(deserializedElement.props);
214
+ const finalJson = newButton.toJson();
215
+
216
+ expect(finalJson.label).toBe(originalProps.label);
217
+ expect(finalJson.variant).toBe(originalProps.variant);
218
+ expect(finalJson.buttonSize).toBe(originalProps.buttonSize);
219
+ expect(finalJson.disabled).toBe(originalProps.disabled);
220
+ expect(finalJson.fullWidth).toBe(originalProps.fullWidth);
221
+ expect(finalJson.action).toEqual(originalProps.action);
222
+ });
223
+
224
+ test('should handle complex children content in round-trip', () => {
225
+ const originalProps = {
226
+ children: 'Multi-word button text',
227
+ variant: 'text' as const
228
+ };
229
+
230
+ const button = new Button(originalProps);
231
+ const json = button.toJson();
232
+ const deserializedElement = Button.fromJson(json);
233
+
234
+ expect(deserializedElement.props.children).toBe('Multi-word button text');
235
+ });
236
+ });
237
+
238
+ describe('Component Registration', () => {
239
+ test('should be registered with ComponentTransformer', () => {
240
+ const registeredComponents = ComponentTransformer.getRegisteredComponents();
241
+ expect(registeredComponents).toContain('Button');
242
+ });
243
+
244
+ test('should have correct tagName and version', () => {
245
+ expect(Button.tagName).toBe('Button');
246
+ expect(Button.version).toBe('1.0.0');
247
+ });
248
+ });
249
+
250
+ describe('Action Handling', () => {
251
+ // Mock window.open for external action tests
252
+ const mockWindowOpen = jest.fn();
253
+ const originalOpen = window.open;
254
+
255
+ beforeAll(() => {
256
+ window.open = mockWindowOpen;
257
+ });
258
+
259
+ afterAll(() => {
260
+ window.open = originalOpen;
261
+ });
262
+
263
+ beforeEach(() => {
264
+ mockWindowOpen.mockClear();
265
+ mockNavigate.mockClear();
266
+ });
267
+
268
+ test('should handle navigation action click', () => {
269
+ const action: ButtonAction = {
270
+ type: 'navigate',
271
+ url: '/dashboard'
272
+ };
273
+
274
+ render(<Button label="Navigate" action={action} />);
275
+ const button = screen.getByRole('button');
276
+
277
+ fireEvent.click(button);
278
+
279
+ // Note: In test environment, the navigate hook might not work as expected
280
+ // This test verifies the click handler is called without error
281
+ expect(button).toBeInTheDocument();
282
+ });
283
+
284
+ test('should handle external action click', () => {
285
+ const action: ButtonAction = {
286
+ type: 'external',
287
+ url: 'https://external.com',
288
+ target: '_blank'
289
+ };
290
+
291
+ render(<Button label="External" action={action} />);
292
+ const button = screen.getByRole('button');
293
+
294
+ fireEvent.click(button);
295
+
296
+ expect(mockWindowOpen).toHaveBeenCalledWith(
297
+ 'https://external.com',
298
+ '_blank',
299
+ 'noopener,noreferrer'
300
+ );
301
+ });
302
+
303
+ test('should handle form submit action', () => {
304
+ // Create a mock form element
305
+ const form = document.createElement('form');
306
+ form.id = 'test-form';
307
+ form.requestSubmit = jest.fn();
308
+ document.body.appendChild(form);
309
+
310
+ const action: ButtonAction = {
311
+ type: 'submit',
312
+ form: 'test-form'
313
+ };
314
+
315
+ render(<Button label="Submit" action={action} />);
316
+ const button = screen.getByRole('button');
317
+
318
+ fireEvent.click(button);
319
+
320
+ expect(form.requestSubmit).toHaveBeenCalled();
321
+
322
+ // Cleanup
323
+ document.body.removeChild(form);
324
+ });
325
+
326
+ test('should handle custom action with global handler', () => {
327
+ const customHandler = jest.fn();
328
+ (global as any).testHandler = customHandler;
329
+
330
+ const action: ButtonAction = {
331
+ type: 'custom',
332
+ customHandler: 'testHandler'
333
+ };
334
+
335
+ render(<Button label="Custom" action={action} />);
336
+ const button = screen.getByRole('button');
337
+
338
+ fireEvent.click(button);
339
+
340
+ expect(customHandler).toHaveBeenCalled();
341
+ });
342
+
343
+ test('should not execute action when disabled', () => {
344
+ const action: ButtonAction = {
345
+ type: 'external',
346
+ url: 'https://external.com'
347
+ };
348
+
349
+ render(<Button label="Disabled" action={action} disabled />);
350
+ const button = screen.getByRole('button');
351
+
352
+ fireEvent.click(button);
353
+
354
+ expect(mockWindowOpen).not.toHaveBeenCalled();
355
+ });
356
+
357
+ test('should not execute action when loading', () => {
358
+ const action: ButtonAction = {
359
+ type: 'external',
360
+ url: 'https://external.com'
361
+ };
362
+
363
+ render(<Button label="Loading" action={action} loading />);
364
+ const button = screen.getByRole('button');
365
+
366
+ fireEvent.click(button);
367
+
368
+ expect(mockWindowOpen).not.toHaveBeenCalled();
369
+ });
370
+ });
371
+
372
+ describe('Error Handling', () => {
373
+ test('should handle missing action properties gracefully', () => {
374
+ const action: ButtonAction = {
375
+ type: 'navigate'
376
+ // Missing url property
377
+ };
378
+
379
+ render(<Button label="Invalid" action={action} />);
380
+ const button = screen.getByRole('button');
381
+
382
+ // Should not throw error when clicking
383
+ expect(() => fireEvent.click(button)).not.toThrow();
384
+ });
385
+
386
+ test('should handle non-existent form ID gracefully', () => {
387
+ const action: ButtonAction = {
388
+ type: 'submit',
389
+ form: 'non-existent-form'
390
+ };
391
+
392
+ render(<Button label="Submit" action={action} />);
393
+ const button = screen.getByRole('button');
394
+
395
+ // Should not throw error when clicking
396
+ expect(() => fireEvent.click(button)).not.toThrow();
397
+ });
398
+
399
+ test('should handle non-existent custom handler gracefully', () => {
400
+ const action: ButtonAction = {
401
+ type: 'custom',
402
+ customHandler: 'nonExistentHandler'
403
+ };
404
+
405
+ render(<Button label="Custom" action={action} />);
406
+ const button = screen.getByRole('button');
407
+
408
+ // Should not throw error when clicking
409
+ expect(() => fireEvent.click(button)).not.toThrow();
410
+ });
411
+ });
412
+
413
+ describe('Integration with Original onClick', () => {
414
+ test('should call both action and original onClick', () => {
415
+ const originalClick = jest.fn();
416
+ const action: ButtonAction = {
417
+ type: 'custom',
418
+ customHandler: 'testHandler'
419
+ };
420
+
421
+ (global as any).testHandler = jest.fn();
422
+
423
+ render(<Button label="Both" action={action} onClick={originalClick} />);
424
+ const button = screen.getByRole('button');
425
+
426
+ fireEvent.click(button);
427
+
428
+ expect((global as any).testHandler).toHaveBeenCalled();
429
+ expect(originalClick).toHaveBeenCalled();
430
+ });
431
+
432
+ test('should work with only onClick (no action)', () => {
433
+ const onClick = jest.fn();
434
+
435
+ render(<Button label="Click Only" onClick={onClick} />);
436
+ const button = screen.getByRole('button');
437
+
438
+ fireEvent.click(button);
439
+
440
+ expect(onClick).toHaveBeenCalled();
441
+ });
442
+ });
443
+ });