@qwickapps/react-framework 1.3.4 → 1.4.0

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 (325) hide show
  1. package/README.md +1688 -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/Content.d.ts.map +1 -1
  28. package/dist/components/blocks/CoverImageHeader.d.ts.map +1 -1
  29. package/dist/components/blocks/FeatureCard.d.ts.map +1 -1
  30. package/dist/components/blocks/FeatureGrid.d.ts.map +1 -1
  31. package/dist/components/blocks/Footer.d.ts.map +1 -1
  32. package/dist/components/blocks/HeroBlock.d.ts +27 -13
  33. package/dist/components/blocks/HeroBlock.d.ts.map +1 -1
  34. package/dist/components/blocks/Image.d.ts +41 -0
  35. package/dist/components/blocks/Image.d.ts.map +1 -0
  36. package/dist/components/blocks/PageBannerHeader.d.ts.map +1 -1
  37. package/dist/components/blocks/ProductCard.d.ts.map +1 -1
  38. package/dist/components/blocks/Section.d.ts +16 -2
  39. package/dist/components/blocks/Section.d.ts.map +1 -1
  40. package/dist/components/blocks/Text.d.ts +41 -0
  41. package/dist/components/blocks/Text.d.ts.map +1 -0
  42. package/dist/components/blocks/index.d.ts +4 -0
  43. package/dist/components/blocks/index.d.ts.map +1 -1
  44. package/dist/components/buttons/Button.d.ts +23 -7
  45. package/dist/components/buttons/Button.d.ts.map +1 -1
  46. package/dist/components/forms/FormBlock.d.ts +19 -13
  47. package/dist/components/forms/FormBlock.d.ts.map +1 -1
  48. package/dist/components/index.d.ts +4 -0
  49. package/dist/components/index.d.ts.map +1 -1
  50. package/dist/components/input/ChoiceInputField.d.ts +17 -11
  51. package/dist/components/input/ChoiceInputField.d.ts.map +1 -1
  52. package/dist/components/input/HtmlInputField.d.ts +17 -11
  53. package/dist/components/input/HtmlInputField.d.ts.map +1 -1
  54. package/dist/components/input/SelectInputField.d.ts +16 -10
  55. package/dist/components/input/SelectInputField.d.ts.map +1 -1
  56. package/dist/components/input/SwitchInputField.d.ts +16 -10
  57. package/dist/components/input/SwitchInputField.d.ts.map +1 -1
  58. package/dist/components/input/TextField.d.ts.map +1 -1
  59. package/dist/components/input/TextInputField.d.ts +16 -11
  60. package/dist/components/input/TextInputField.d.ts.map +1 -1
  61. package/dist/components/layout/GridCell.d.ts +23 -6
  62. package/dist/components/layout/GridCell.d.ts.map +1 -1
  63. package/dist/components/layout/GridLayout.d.ts +24 -23
  64. package/dist/components/layout/GridLayout.d.ts.map +1 -1
  65. package/dist/components/pages/FormPage.d.ts.map +1 -1
  66. package/dist/components/pages/Page.d.ts +49 -87
  67. package/dist/components/pages/Page.d.ts.map +1 -1
  68. package/dist/components/pages/index.d.ts +2 -2
  69. package/dist/components/pages/index.d.ts.map +1 -1
  70. package/dist/config/AppConfig.d.ts +49 -0
  71. package/dist/config/AppConfig.d.ts.map +1 -0
  72. package/dist/config/AppConfigBuilder.d.ts +75 -0
  73. package/dist/config/AppConfigBuilder.d.ts.map +1 -0
  74. package/dist/config/index.d.ts +13 -0
  75. package/dist/config/index.d.ts.map +1 -0
  76. package/dist/config/types.d.ts +130 -0
  77. package/dist/config/types.d.ts.map +1 -0
  78. package/dist/config.d.ts +15 -0
  79. package/dist/config.d.ts.map +1 -0
  80. package/dist/config.esm.js +451 -0
  81. package/dist/config.js +455 -0
  82. package/dist/contexts/PrintModeContext.d.ts +27 -0
  83. package/dist/contexts/PrintModeContext.d.ts.map +1 -0
  84. package/dist/contexts/QwickAppContext.d.ts +2 -2
  85. package/dist/contexts/QwickAppContext.d.ts.map +1 -1
  86. package/dist/contexts/ThemeContext.d.ts.map +1 -1
  87. package/dist/contexts/index.d.ts +2 -0
  88. package/dist/contexts/index.d.ts.map +1 -1
  89. package/dist/hooks/index.d.ts +2 -0
  90. package/dist/hooks/index.d.ts.map +1 -1
  91. package/dist/hooks/usePrintMode.d.ts +39 -0
  92. package/dist/hooks/usePrintMode.d.ts.map +1 -0
  93. package/dist/index.css +1 -1
  94. package/dist/index.d.ts +1 -0
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.esm.css +1 -1
  97. package/dist/index.esm.js +20722 -16021
  98. package/dist/index.js +20725 -16010
  99. package/dist/schemas/CodeSchema.d.ts +2 -1
  100. package/dist/schemas/CodeSchema.d.ts.map +1 -1
  101. package/dist/schemas/CollapsibleLayoutSchema.d.ts +2 -1
  102. package/dist/schemas/CollapsibleLayoutSchema.d.ts.map +1 -1
  103. package/dist/schemas/ContentSchema.d.ts +2 -1
  104. package/dist/schemas/ContentSchema.d.ts.map +1 -1
  105. package/dist/schemas/GridCellSchema.d.ts +25 -0
  106. package/dist/schemas/GridCellSchema.d.ts.map +1 -0
  107. package/dist/schemas/GridLayoutSchema.d.ts +23 -0
  108. package/dist/schemas/GridLayoutSchema.d.ts.map +1 -0
  109. package/dist/schemas/HtmlSchema.d.ts +14 -0
  110. package/dist/schemas/HtmlSchema.d.ts.map +1 -0
  111. package/dist/schemas/ImageSchema.d.ts +32 -0
  112. package/dist/schemas/ImageSchema.d.ts.map +1 -0
  113. package/dist/schemas/LogoSchema.d.ts +35 -0
  114. package/dist/schemas/LogoSchema.d.ts.map +1 -0
  115. package/dist/schemas/MarkdownSchema.d.ts +14 -0
  116. package/dist/schemas/MarkdownSchema.d.ts.map +1 -0
  117. package/dist/schemas/PageTemplateSchema.d.ts +31 -0
  118. package/dist/schemas/PageTemplateSchema.d.ts.map +1 -0
  119. package/dist/schemas/PrintConfigSchema.d.ts +31 -0
  120. package/dist/schemas/PrintConfigSchema.d.ts.map +1 -0
  121. package/dist/schemas/SectionSchema.d.ts +2 -1
  122. package/dist/schemas/SectionSchema.d.ts.map +1 -1
  123. package/dist/schemas/TextSchema.d.ts +37 -0
  124. package/dist/schemas/TextSchema.d.ts.map +1 -0
  125. package/dist/schemas/ViewModelSchema.d.ts +23 -0
  126. package/dist/schemas/ViewModelSchema.d.ts.map +1 -0
  127. package/dist/schemas/index.d.ts +15 -1
  128. package/dist/schemas/index.d.ts.map +1 -1
  129. package/dist/schemas/transformers/ComponentTransformer.d.ts +116 -0
  130. package/dist/schemas/transformers/ComponentTransformer.d.ts.map +1 -0
  131. package/dist/schemas/transformers/ReactNodeTransformer.d.ts +53 -0
  132. package/dist/schemas/transformers/ReactNodeTransformer.d.ts.map +1 -0
  133. package/dist/schemas/transformers/__tests__/MockSerializableComponent.d.ts +66 -0
  134. package/dist/schemas/transformers/__tests__/MockSerializableComponent.d.ts.map +1 -0
  135. package/dist/schemas/transformers/registry.d.ts +15 -0
  136. package/dist/schemas/transformers/registry.d.ts.map +1 -0
  137. package/dist/schemas/types/Serializable.d.ts +46 -0
  138. package/dist/schemas/types/Serializable.d.ts.map +1 -0
  139. package/dist/utils/htmlTransform.d.ts.map +1 -1
  140. package/dist/utils/reactUtils.d.ts +12 -3
  141. package/dist/utils/reactUtils.d.ts.map +1 -1
  142. package/package.json +17 -3
  143. package/src/{components/__tests__ → __tests__/components}/AccessibilityProvider.test.tsx +1 -1
  144. package/src/{components/__tests__ → __tests__/components}/Article.test.tsx +1 -1
  145. package/src/{components/__tests__ → __tests__/components}/Breadcrumbs.test.tsx +1 -1
  146. package/src/{components/__tests__ → __tests__/components}/Button.test.tsx +1 -1
  147. package/src/{components/__tests__ → __tests__/components}/CardListGrid.test.tsx +2 -2
  148. package/src/{components/__tests__ → __tests__/components}/ChoiceInputField.test.tsx +1 -1
  149. package/src/{components/__tests__ → __tests__/components}/Code.test.tsx +1 -1
  150. package/src/{components/__tests__ → __tests__/components}/Content.integration.test.tsx +1 -1
  151. package/src/{components/__tests__ → __tests__/components}/Content.test.tsx +1 -1
  152. package/src/{components/__tests__ → __tests__/components}/CoverImageHeader.test.tsx +2 -2
  153. package/src/{components/__tests__ → __tests__/components}/ErrorBoundary.test.tsx +1 -1
  154. package/src/{components/__tests__ → __tests__/components}/FeatureCard.integration.test.tsx +2 -2
  155. package/src/{components/__tests__ → __tests__/components}/FeatureGrid.integration.test.tsx +2 -2
  156. package/src/{components/__tests__ → __tests__/components}/FeatureGrid.test.tsx +2 -2
  157. package/src/{components/__tests__ → __tests__/components}/Footer.test.tsx +4 -4
  158. package/src/{components/__tests__ → __tests__/components}/FormBlock.test.tsx +1 -1
  159. package/src/{components/__tests__ → __tests__/components}/HeroBlock.integration.test.tsx +2 -2
  160. package/src/{components/__tests__ → __tests__/components}/HeroBlock.test.tsx +233 -7
  161. package/src/{components/__tests__ → __tests__/components}/Html.test.tsx +11 -2
  162. package/src/{components/__tests__ → __tests__/components}/HtmlInputField.test.tsx +3 -3
  163. package/src/__tests__/components/Logo.test.js +3 -3
  164. package/src/{components/__tests__ → __tests__/components}/Markdown.test.tsx +1 -1
  165. package/src/{components/__tests__ → __tests__/components}/PageBannerHeader.test.tsx +3 -3
  166. package/src/{components/__tests__ → __tests__/components}/PaletteSwitcher.test.tsx +3 -3
  167. package/src/{components/__tests__ → __tests__/components}/ProductCard.test.tsx +4 -4
  168. package/src/{components/__tests__ → __tests__/components}/SafeSpan.integration.test.tsx +2 -2
  169. package/src/{components/__tests__ → __tests__/components}/SafeSpan.simple.test.tsx +1 -1
  170. package/src/{components/__tests__ → __tests__/components}/SafeSpan.test.tsx +1 -1
  171. package/src/{components/__tests__ → __tests__/components}/Section.integration.test.tsx +1 -1
  172. package/src/{components/__tests__ → __tests__/components}/Section.test.tsx +1 -1
  173. package/src/{components/__tests__ → __tests__/components}/SelectInputField.test.tsx +1 -1
  174. package/src/{components/__tests__ → __tests__/components}/TextInputField.test.tsx +3 -3
  175. package/src/{components/__tests__ → __tests__/components}/ThemeSwitcher.test.tsx +3 -3
  176. package/src/__tests__/components/base/ModelView.test.tsx +220 -0
  177. package/src/__tests__/components/blocks/Code.performance.test.tsx +625 -0
  178. package/src/__tests__/components/blocks/Code.serialization.test.tsx +507 -0
  179. package/src/__tests__/components/blocks/HeroBlock.serialization.test.tsx +414 -0
  180. package/src/__tests__/components/blocks/Image.serialization.test.tsx +257 -0
  181. package/src/__tests__/components/blocks/Section.serialization.test.tsx +553 -0
  182. package/src/__tests__/components/blocks/Text.performance.test.tsx +442 -0
  183. package/src/__tests__/components/blocks/Text.serialization.test.tsx +491 -0
  184. package/src/__tests__/components/buttons/Button.serialization.test.tsx +443 -0
  185. package/src/__tests__/components/input/FormComponents.serialization.test.tsx +482 -0
  186. package/src/__tests__/components/input/SelectInputField.serialization.test.tsx +439 -0
  187. package/src/__tests__/components/input/TextInputField.serialization.test.tsx +359 -0
  188. package/src/{components/layout/CollapsibleLayout/__tests__ → __tests__/components/layout}/CollapsibleLayout.test.tsx +4 -4
  189. package/src/__tests__/components/layout/GridCell.serialization.test.tsx +403 -0
  190. package/src/__tests__/components/layout/GridLayout.serialization.test.tsx +311 -0
  191. package/src/__tests__/hooks/usePrintMode.test.ts +89 -0
  192. package/src/__tests__/schemas/PageTemplateSchema.test.ts +161 -0
  193. package/src/__tests__/schemas/PrintConfigSchema.test.ts +127 -0
  194. package/src/__tests__/schemas/ViewModelSchema.test.ts +80 -0
  195. package/src/__tests__/schemas/transformers/ComponentSerializationPatterns.test.tsx +602 -0
  196. package/src/__tests__/schemas/transformers/ComponentTransformer.htmlPatterns.test.ts +301 -0
  197. package/src/__tests__/schemas/transformers/ComponentTransformer.test.ts +521 -0
  198. package/src/__tests__/schemas/transformers/CrossBrowserCompatibility.test.ts +586 -0
  199. package/src/__tests__/schemas/transformers/MockSerializableComponent.ts +103 -0
  200. package/src/__tests__/schemas/transformers/RealWorldScenarios.test.tsx +1165 -0
  201. package/src/__tests__/schemas/transformers/SerializationErrorHandling.test.ts +602 -0
  202. package/src/__tests__/schemas/transformers/SerializationIntegration.test.tsx +691 -0
  203. package/src/__tests__/schemas/transformers/SerializationPerformance.test.ts +460 -0
  204. package/src/__tests__/schemas/transformers/TestAutomation.test.ts +597 -0
  205. package/src/{utils/__tests__ → __tests__/utils}/nested-dom-fix.test.tsx +1 -1
  206. package/src/components/ErrorBoundary.tsx +8 -8
  207. package/src/components/Html.tsx +147 -44
  208. package/src/components/Logo.tsx +198 -100
  209. package/src/components/Markdown.tsx +125 -16
  210. package/src/components/QwickApp.tsx +64 -31
  211. package/src/components/QwickIcon.tsx +59 -0
  212. package/src/components/SafeSpan.tsx +65 -10
  213. package/src/components/Scaffold.tsx +2 -8
  214. package/src/components/base/ModelView.tsx +199 -0
  215. package/src/components/base/index.ts +11 -0
  216. package/src/components/blocks/Article.tsx +57 -18
  217. package/src/components/blocks/Code.md +529 -0
  218. package/src/components/blocks/Code.tsx +102 -15
  219. package/src/components/blocks/Content.tsx +25 -77
  220. package/src/components/blocks/CoverImageHeader.tsx +9 -4
  221. package/src/components/blocks/FeatureCard.tsx +1 -2
  222. package/src/components/blocks/FeatureGrid.tsx +19 -1
  223. package/src/components/blocks/Footer.tsx +13 -1
  224. package/src/components/blocks/HeroBlock.tsx +87 -20
  225. package/src/components/blocks/Image.tsx +395 -0
  226. package/src/components/blocks/PageBannerHeader.tsx +14 -12
  227. package/src/components/blocks/ProductCard.tsx +51 -52
  228. package/src/components/blocks/Section.tsx +113 -8
  229. package/src/components/blocks/Text.tsx +285 -0
  230. package/src/components/blocks/index.ts +4 -0
  231. package/src/components/buttons/Button.tsx +184 -15
  232. package/src/components/forms/FormBlock.tsx +70 -17
  233. package/src/components/index.ts +5 -0
  234. package/src/components/input/ChoiceInputField.tsx +48 -18
  235. package/src/components/input/HtmlInputField.tsx +48 -18
  236. package/src/components/input/SelectInputField.tsx +48 -16
  237. package/src/components/input/SwitchInputField.tsx +48 -17
  238. package/src/components/input/TextField.tsx +41 -1
  239. package/src/components/input/TextInputField.tsx +52 -18
  240. package/src/components/layout/GridCell.tsx +118 -9
  241. package/src/components/layout/GridLayout.tsx +125 -24
  242. package/src/components/pages/FormPage.tsx +0 -1
  243. package/src/components/pages/Page.css +304 -332
  244. package/src/components/pages/Page.tsx +307 -255
  245. package/src/components/pages/index.ts +2 -2
  246. package/src/config/AppConfig.ts +133 -0
  247. package/src/config/AppConfigBuilder.ts +421 -0
  248. package/src/config/__tests__/AppConfig.test.ts +385 -0
  249. package/src/config/__tests__/AppConfigBuilder.test.ts +432 -0
  250. package/src/config/index.ts +24 -0
  251. package/src/config/types.ts +170 -0
  252. package/src/config.ts +25 -0
  253. package/src/contexts/PrintModeContext.tsx +332 -0
  254. package/src/contexts/QwickAppContext.tsx +2 -2
  255. package/src/contexts/ThemeContext.tsx +1 -2
  256. package/src/contexts/index.ts +2 -0
  257. package/src/hooks/index.ts +5 -1
  258. package/src/hooks/usePrintMode.ts +73 -0
  259. package/src/index.ts +3 -0
  260. package/src/schemas/CodeSchema.ts +3 -3
  261. package/src/schemas/CollapsibleLayoutSchema.ts +2 -1
  262. package/src/schemas/ContentSchema.ts +2 -1
  263. package/src/schemas/GridCellSchema.ts +164 -0
  264. package/src/schemas/GridLayoutSchema.ts +133 -0
  265. package/src/schemas/HtmlSchema.ts +47 -0
  266. package/src/schemas/ImageSchema.ts +235 -0
  267. package/src/schemas/LogoSchema.ts +241 -0
  268. package/src/schemas/MarkdownSchema.ts +47 -0
  269. package/src/schemas/PageTemplateSchema.ts +186 -0
  270. package/src/schemas/PrintConfigSchema.ts +207 -0
  271. package/src/schemas/README.md +661 -0
  272. package/src/schemas/SectionSchema.ts +2 -1
  273. package/src/schemas/TextSchema.ts +329 -0
  274. package/src/schemas/ViewModelSchema.ts +115 -0
  275. package/src/schemas/index.ts +21 -2
  276. package/src/schemas/transformers/ComponentTransformer.ts +403 -0
  277. package/src/schemas/transformers/ReactNodeTransformer.ts +236 -0
  278. package/src/schemas/transformers/registry.ts +72 -0
  279. package/src/schemas/types/Serializable.ts +51 -0
  280. package/src/stories/AccessibilityProvider.stories.tsx +253 -253
  281. package/src/stories/Article.stories.tsx +433 -433
  282. package/src/stories/Button.stories.tsx +1 -1
  283. package/src/stories/CardListGrid.stories.tsx +451 -451
  284. package/src/stories/ChoiceInputField.stories.tsx +503 -503
  285. package/src/stories/Code.stories.tsx +1 -1
  286. package/src/stories/CollapsibleLayout.stories.tsx +1414 -1414
  287. package/src/stories/Content.stories.tsx +393 -393
  288. package/src/stories/CoverImageHeader.stories.tsx +701 -701
  289. package/src/stories/DataBinding.advanced.stories.tsx +432 -432
  290. package/src/stories/DataProvider.stories.tsx +1192 -1192
  291. package/src/stories/FeatureCard.stories.tsx +557 -557
  292. package/src/stories/FeatureGrid.stories.tsx +594 -594
  293. package/src/stories/Footer.stories.tsx +640 -640
  294. package/src/stories/FormBlock.stories.tsx +760 -760
  295. package/src/stories/FormComponents.stories.tsx +349 -541
  296. package/src/stories/GridCell.stories.tsx +417 -0
  297. package/src/stories/GridLayout.stories.tsx +353 -0
  298. package/src/stories/HeroBlock.stories.tsx +862 -373
  299. package/src/stories/HtmlInputField.stories.tsx +474 -474
  300. package/src/stories/Image.stories.tsx +819 -0
  301. package/src/stories/Introduction.stories.tsx +667 -667
  302. package/src/stories/LayoutBlocks.stories.tsx +324 -324
  303. package/src/stories/Logo.stories.tsx +165 -6
  304. package/src/stories/Markdown.stories.tsx +137 -137
  305. package/src/stories/ModelView.stories.tsx +477 -0
  306. package/src/stories/Page.stories.tsx +688 -688
  307. package/src/stories/PageBannerHeader.stories.tsx +864 -864
  308. package/src/stories/PaletteSwitcher.stories.tsx +119 -119
  309. package/src/stories/ProductCard.stories.tsx +424 -424
  310. package/src/stories/QwickApp.stories.tsx +368 -368
  311. package/src/stories/ResponsiveMenu.stories.tsx +249 -249
  312. package/src/stories/SafeSpan.stories.tsx +531 -531
  313. package/src/stories/Section.stories.tsx +90 -2
  314. package/src/stories/SelectInputField.stories.tsx +524 -524
  315. package/src/stories/Text.stories.tsx +560 -0
  316. package/src/stories/TextInputField.stories.tsx +443 -443
  317. package/src/stories/ThemeSwitcher.stories.tsx +123 -123
  318. package/src/utils/htmlTransform.tsx +74 -53
  319. package/src/utils/reactUtils.tsx +57 -6
  320. package/dist/index.bundled.css +0 -12
  321. /package/src/{hooks/__tests__ → __tests__/hooks}/useDataBinding.test.tsx.disabled +0 -0
  322. /package/src/{schemas/__tests__ → __tests__/schemas}/builders.test.ts +0 -0
  323. /package/src/{utils/__tests__ → __tests__/utils}/createDataDrivenComponent.test.tsx.disabled +0 -0
  324. /package/src/{utils/__tests__ → __tests__/utils}/htmlTransform.test.tsx +0 -0
  325. /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
+ });