@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,482 @@
1
+ /**
2
+ * Form Components Serialization Tests
3
+ *
4
+ * Comprehensive serialization tests for HtmlInputField, ChoiceInputField, SwitchInputField, and FormBlock.
5
+ * Ensures all form-specific functionality is preserved through JSON serialization cycles.
6
+ *
7
+ * Test Coverage:
8
+ * - HTML input field with formatting and sanitization
9
+ * - Choice input field with dynamic option management
10
+ * - Switch input field with boolean state handling
11
+ * - FormBlock with nested component serialization
12
+ * - Performance benchmarks and data integrity validation
13
+ *
14
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
15
+ */
16
+
17
+ import React from 'react';
18
+ import { render } from '@testing-library/react';
19
+ import { ComponentTransformer } from '../../../schemas/transformers/ComponentTransformer';
20
+ import { HtmlInputField } from '../../../components/input/HtmlInputField';
21
+ import { ChoiceInputField } from '../../../components/input/ChoiceInputField';
22
+ import { SwitchInputField } from '../../../components/input/SwitchInputField';
23
+ import { FormBlock } from '../../../components/input/../forms/FormBlock';
24
+
25
+ // Ensure components are registered
26
+ import '../../../schemas/transformers/registry';
27
+
28
+ describe('Form Components Serialization', () => {
29
+ // Performance tracking
30
+ const performanceData: Array<{ operation: string; duration: number }> = [];
31
+
32
+ afterAll(() => {
33
+ // Log performance summary
34
+ console.log('\n📊 Form Components Serialization Performance Summary:');
35
+ performanceData.forEach(({ operation, duration }) => {
36
+ console.log(` • ${operation}: ${duration.toFixed(3)}ms`);
37
+ });
38
+ const avgDuration = performanceData.reduce((sum, { duration }) => sum + duration, 0) / performanceData.length;
39
+ console.log(` • Average: ${avgDuration.toFixed(3)}ms\n`);
40
+ });
41
+
42
+ const measurePerformance = (operation: string, fn: () => void) => {
43
+ const start = performance.now();
44
+ fn();
45
+ const duration = performance.now() - start;
46
+ performanceData.push({ operation, duration });
47
+ return duration;
48
+ };
49
+
50
+ describe('HtmlInputField Serialization', () => {
51
+ it('serializes HTML input field with formatting controls correctly', () => {
52
+ const originalProps = {
53
+ label: 'Rich Text Content',
54
+ value: '<b>Bold text</b> and <i>italic text</i> with <code>code</code>',
55
+ multiline: true,
56
+ rows: 6,
57
+ placeholder: 'Enter HTML content...',
58
+ required: true
59
+ };
60
+
61
+ let serializedData: any;
62
+ let deserializedElement: React.ReactElement;
63
+
64
+ // Test serialization
65
+ const serializationTime = measurePerformance('HtmlInputField Serialization', () => {
66
+ const element = <HtmlInputField {...originalProps} />;
67
+ const serialized = ComponentTransformer.serialize(element);
68
+ serializedData = JSON.parse(serialized);
69
+ });
70
+
71
+ expect(serializedData).toBeDefined();
72
+ expect(serializedData.tag).toBe('HtmlInputField');
73
+ expect(serializedData.data.label).toBe(originalProps.label);
74
+ expect(serializedData.data.value).toBe(originalProps.value);
75
+ expect(serializedData.data.multiline).toBe(originalProps.multiline);
76
+ expect(serializedData.data.rows).toBe(originalProps.rows);
77
+
78
+ // Test deserialization
79
+ const deserializationTime = measurePerformance('HtmlInputField Deserialization', () => {
80
+ deserializedElement = ComponentTransformer.deserialize(JSON.stringify(serializedData)) as React.ReactElement;
81
+ });
82
+
83
+ expect(React.isValidElement(deserializedElement)).toBe(true);
84
+ expect(deserializedElement.type).toBe(HtmlInputField);
85
+
86
+ // Performance assertions
87
+ expect(serializationTime).toBeLessThan(1);
88
+ expect(deserializationTime).toBeLessThan(1);
89
+ });
90
+
91
+ it('preserves HTML sanitization settings through serialization', () => {
92
+ const htmlContent = '<script>alert("test")</script><b>Safe content</b>';
93
+ const originalProps = {
94
+ label: 'Sanitized HTML',
95
+ value: htmlContent,
96
+ disabled: false
97
+ };
98
+
99
+ const element = <HtmlInputField {...originalProps} />;
100
+ const serialized = ComponentTransformer.serialize(element);
101
+ const serializedData = JSON.parse(serialized);
102
+ const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
103
+
104
+ // The HTML content should be preserved in serialization
105
+ // Sanitization happens during rendering, not serialization
106
+ expect(serializedData.data.value).toBe(htmlContent);
107
+
108
+ const reserialized = ComponentTransformer.serialize(deserializedElement);
109
+ const reserializedData = JSON.parse(reserialized);
110
+ expect(reserializedData.data.value).toBe(htmlContent);
111
+ });
112
+ });
113
+
114
+ describe('ChoiceInputField Serialization', () => {
115
+ it('serializes dynamic choice options correctly', () => {
116
+ const originalProps = {
117
+ label: 'Survey Questions',
118
+ options: [
119
+ 'What is your favorite color?',
120
+ 'How often do you exercise?',
121
+ 'What type of music do you prefer?'
122
+ ],
123
+ disabled: false,
124
+ placeholder: 'Enter your question...',
125
+ optionLabelPrefix: 'Question',
126
+ rows: 3,
127
+ addButtonText: 'Add Question'
128
+ };
129
+
130
+ let serializedData: any;
131
+ let deserializedElement: React.ReactElement;
132
+
133
+ // Test serialization
134
+ const serializationTime = measurePerformance('ChoiceInputField Serialization', () => {
135
+ const element = <ChoiceInputField {...originalProps} />;
136
+ const serialized = ComponentTransformer.serialize(element);
137
+ serializedData = JSON.parse(serialized);
138
+ });
139
+
140
+ expect(serializedData.tag).toBe('ChoiceInputField');
141
+ expect(serializedData.data.label).toBe(originalProps.label);
142
+ expect(serializedData.data.options).toEqual(originalProps.options);
143
+ expect(serializedData.data.optionLabelPrefix).toBe(originalProps.optionLabelPrefix);
144
+ expect(serializedData.data.rows).toBe(originalProps.rows);
145
+ expect(serializedData.data.addButtonText).toBe(originalProps.addButtonText);
146
+
147
+ // Test deserialization
148
+ const deserializationTime = measurePerformance('ChoiceInputField Deserialization', () => {
149
+ deserializedElement = ComponentTransformer.deserialize(JSON.stringify(serializedData)) as React.ReactElement;
150
+ });
151
+
152
+ expect(React.isValidElement(deserializedElement)).toBe(true);
153
+ expect(deserializedElement.type).toBe(ChoiceInputField);
154
+
155
+ // Test round-trip integrity
156
+ const reserialized = ComponentTransformer.serialize(deserializedElement);
157
+ const reserializedData = JSON.parse(reserialized);
158
+ expect(reserializedData.data.options).toEqual(originalProps.options);
159
+
160
+ // Performance assertions
161
+ expect(serializationTime).toBeLessThan(1);
162
+ expect(deserializationTime).toBeLessThan(1);
163
+ });
164
+
165
+ it('handles empty options array correctly', () => {
166
+ const originalProps = {
167
+ label: 'Empty Choices',
168
+ options: [],
169
+ placeholder: 'No options yet'
170
+ };
171
+
172
+ const element = <ChoiceInputField {...originalProps} />;
173
+ const serialized = ComponentTransformer.serialize(element);
174
+ const serializedData = JSON.parse(serialized);
175
+
176
+ expect(serializedData.data.options).toEqual([]);
177
+
178
+ const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
179
+ const { getByText } = render(deserializedElement);
180
+
181
+ expect(getByText('No options provided')).toBeInTheDocument();
182
+ });
183
+ });
184
+
185
+ describe('SwitchInputField Serialization', () => {
186
+ it('serializes switch state and properties correctly', () => {
187
+ const originalProps = {
188
+ label: 'Enable Notifications',
189
+ checked: true,
190
+ required: false,
191
+ disabled: false,
192
+ helperText: 'Toggle to receive email notifications',
193
+ size: 'medium' as const,
194
+ color: 'primary' as const
195
+ };
196
+
197
+ let serializedData: any;
198
+ let deserializedElement: React.ReactElement;
199
+
200
+ // Test serialization
201
+ const serializationTime = measurePerformance('SwitchInputField Serialization', () => {
202
+ const element = <SwitchInputField {...originalProps} />;
203
+ const serialized = ComponentTransformer.serialize(element);
204
+ serializedData = JSON.parse(serialized);
205
+ });
206
+
207
+ expect(serializedData.tag).toBe('SwitchInputField');
208
+ expect(serializedData.data.label).toBe(originalProps.label);
209
+ expect(serializedData.data.checked).toBe(originalProps.checked);
210
+ expect(serializedData.data.helperText).toBe(originalProps.helperText);
211
+ expect(serializedData.data.size).toBe(originalProps.size);
212
+ expect(serializedData.data.color).toBe(originalProps.color);
213
+
214
+ // Test deserialization
215
+ const deserializationTime = measurePerformance('SwitchInputField Deserialization', () => {
216
+ deserializedElement = ComponentTransformer.deserialize(JSON.stringify(serializedData)) as React.ReactElement;
217
+ });
218
+
219
+ expect(React.isValidElement(deserializedElement)).toBe(true);
220
+ expect(deserializedElement.type).toBe(SwitchInputField);
221
+
222
+ // Performance assertions
223
+ expect(serializationTime).toBeLessThan(1);
224
+ expect(deserializationTime).toBeLessThan(1);
225
+ });
226
+
227
+ it('handles boolean state transitions correctly', () => {
228
+ const testStates = [true, false, undefined];
229
+
230
+ testStates.forEach(checkedState => {
231
+ const originalProps = {
232
+ label: `Switch ${checkedState}`,
233
+ checked: checkedState,
234
+ error: checkedState === false ? 'Required field' : undefined
235
+ };
236
+
237
+ const element = <SwitchInputField {...originalProps} />;
238
+ const serialized = ComponentTransformer.serialize(element);
239
+ const serializedData = JSON.parse(serialized);
240
+
241
+ expect(serializedData.data.checked).toBe(checkedState);
242
+ if (checkedState === false) {
243
+ expect(serializedData.data.error).toBe('Required field');
244
+ }
245
+
246
+ const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
247
+ const reserialized = ComponentTransformer.serialize(deserializedElement);
248
+ const reserializedData = JSON.parse(reserialized);
249
+
250
+ expect(reserializedData.data.checked).toBe(checkedState);
251
+ });
252
+ });
253
+ });
254
+
255
+ describe('FormBlock Serialization', () => {
256
+ it('serializes form block with basic properties correctly', () => {
257
+ const originalProps = {
258
+ title: 'Contact Form',
259
+ description: 'Please fill out all required fields',
260
+ status: 'info' as const,
261
+ message: 'All fields are required',
262
+ maxWidth: 'md' as const,
263
+ background: 'gradient',
264
+ backgroundImage: 'https://example.com/bg.jpg'
265
+ };
266
+
267
+ let serializedData: any;
268
+ let deserializedElement: React.ReactElement;
269
+
270
+ // Test serialization
271
+ const serializationTime = measurePerformance('FormBlock Serialization', () => {
272
+ const element = <FormBlock {...originalProps} />;
273
+ const serialized = ComponentTransformer.serialize(element);
274
+ serializedData = JSON.parse(serialized);
275
+ });
276
+
277
+ expect(serializedData.tag).toBe('FormBlock');
278
+ expect(serializedData.data.title).toBe(originalProps.title);
279
+ expect(serializedData.data.description).toBe(originalProps.description);
280
+ expect(serializedData.data.status).toBe(originalProps.status);
281
+ expect(serializedData.data.message).toBe(originalProps.message);
282
+ expect(serializedData.data.maxWidth).toBe(originalProps.maxWidth);
283
+ expect(serializedData.data.background).toBe(originalProps.background);
284
+ expect(serializedData.data.backgroundImage).toBe(originalProps.backgroundImage);
285
+
286
+ // Test deserialization
287
+ const deserializationTime = measurePerformance('FormBlock Deserialization', () => {
288
+ deserializedElement = ComponentTransformer.deserialize(JSON.stringify(serializedData)) as React.ReactElement;
289
+ });
290
+
291
+ expect(React.isValidElement(deserializedElement)).toBe(true);
292
+ expect(deserializedElement.type).toBe(FormBlock);
293
+
294
+ // Performance assertions
295
+ expect(serializationTime).toBeLessThan(1);
296
+ expect(deserializationTime).toBeLessThan(1);
297
+ });
298
+
299
+ it('handles different status types correctly', () => {
300
+ const statusTypes: Array<'info' | 'success' | 'warning' | 'error'> = ['info', 'success', 'warning', 'error'];
301
+
302
+ statusTypes.forEach(status => {
303
+ const originalProps = {
304
+ title: `${status.charAt(0).toUpperCase() + status.slice(1)} Form`,
305
+ status,
306
+ message: `This is a ${status} message`
307
+ };
308
+
309
+ const element = <FormBlock {...originalProps} />;
310
+ const serialized = ComponentTransformer.serialize(element);
311
+ const serializedData = JSON.parse(serialized);
312
+
313
+ expect(serializedData.data.status).toBe(status);
314
+ expect(serializedData.data.message).toBe(originalProps.message);
315
+
316
+ const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
317
+ const reserialized = ComponentTransformer.serialize(deserializedElement);
318
+ const reserializedData = JSON.parse(reserialized);
319
+
320
+ expect(reserializedData.data.status).toBe(status);
321
+ expect(reserializedData.data.message).toBe(originalProps.message);
322
+ });
323
+ });
324
+
325
+ it('serializes FormBlock with nested form components', () => {
326
+ // This test would be more complex in a real implementation
327
+ // For now, we test the basic structure
328
+ const originalProps = {
329
+ title: 'User Registration',
330
+ children: 'Form content placeholder' // In reality, this would be JSX
331
+ };
332
+
333
+ const element = <FormBlock {...originalProps} />;
334
+ const serialized = ComponentTransformer.serialize(element);
335
+ const serializedData = JSON.parse(serialized);
336
+
337
+ expect(serializedData.data.title).toBe(originalProps.title);
338
+ // Children handling would be tested in integration scenarios
339
+ });
340
+ });
341
+
342
+ describe('Performance Benchmarks', () => {
343
+ it('handles mixed form component serialization efficiently', () => {
344
+ const mixedComponents = [
345
+ <HtmlInputField key="html1" label="Rich Text 1" value="<b>Bold</b> content" />,
346
+ <ChoiceInputField key="choice1" label="Options 1" options={['Option A', 'Option B']} />,
347
+ <SwitchInputField key="switch1" label="Enable Feature" checked={true} />,
348
+ <FormBlock key="form1" title="Sample Form" />,
349
+ <HtmlInputField key="html2" label="Rich Text 2" value="<i>Italic</i> content" multiline rows={4} />,
350
+ <SwitchInputField key="switch2" label="Another Switch" checked={false} />
351
+ ];
352
+
353
+ let serializedData: any[];
354
+ let deserializedElements: React.ReactElement[];
355
+
356
+ // Bulk serialization
357
+ const bulkSerializationTime = measurePerformance('Mixed Components Bulk Serialization', () => {
358
+ serializedData = mixedComponents.map(element => {
359
+ const serialized = ComponentTransformer.serialize(element);
360
+ return JSON.parse(serialized);
361
+ });
362
+ });
363
+
364
+ // Bulk deserialization
365
+ const bulkDeserializationTime = measurePerformance('Mixed Components Bulk Deserialization', () => {
366
+ deserializedElements = serializedData.map(data => ComponentTransformer.deserialize(JSON.stringify(data)) as React.ReactElement);
367
+ });
368
+
369
+ expect(serializedData).toHaveLength(6);
370
+ expect(deserializedElements).toHaveLength(6);
371
+ expect(bulkSerializationTime).toBeLessThan(5); // Should handle 6 mixed components in under 5ms
372
+ expect(bulkDeserializationTime).toBeLessThan(5);
373
+
374
+ // Verify component types are preserved
375
+ expect(deserializedElements[0].type).toBe(HtmlInputField);
376
+ expect(deserializedElements[1].type).toBe(ChoiceInputField);
377
+ expect(deserializedElements[2].type).toBe(SwitchInputField);
378
+ expect(deserializedElements[3].type).toBe(FormBlock);
379
+ });
380
+ });
381
+
382
+ describe('Data Integrity', () => {
383
+ it('maintains data integrity across all form components through multiple cycles', () => {
384
+ const testComponents = [
385
+ {
386
+ type: 'HtmlInputField',
387
+ element: <HtmlInputField label="HTML Test" value="<b>Test</b>" multiline rows={3} />,
388
+ checkProps: ['label', 'value', 'multiline', 'rows']
389
+ },
390
+ {
391
+ type: 'ChoiceInputField',
392
+ element: <ChoiceInputField label="Choice Test" options={['A', 'B', 'C']} rows={2} />,
393
+ checkProps: ['label', 'options', 'rows']
394
+ },
395
+ {
396
+ type: 'SwitchInputField',
397
+ element: <SwitchInputField label="Switch Test" checked={true} size="medium" />,
398
+ checkProps: ['label', 'checked', 'size']
399
+ },
400
+ {
401
+ type: 'FormBlock',
402
+ element: <FormBlock title="Form Test" maxWidth="sm" background="default" />,
403
+ checkProps: ['title', 'maxWidth', 'background']
404
+ }
405
+ ];
406
+
407
+ testComponents.forEach(({ type, element, checkProps }) => {
408
+ let currentElement = element;
409
+ let originalProps: any;
410
+
411
+ // Capture original props from first serialization
412
+ const firstSerialized = ComponentTransformer.serialize(currentElement);
413
+ const firstSerialization = JSON.parse(firstSerialized);
414
+ originalProps = firstSerialization.data;
415
+
416
+ // Perform 5 serialize-deserialize cycles
417
+ for (let cycle = 0; cycle < 5; cycle++) {
418
+ const serialized = ComponentTransformer.serialize(currentElement);
419
+ currentElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
420
+ }
421
+
422
+ // Final verification
423
+ const finalSerialized = ComponentTransformer.serialize(currentElement);
424
+ const finalSerialization = JSON.parse(finalSerialized);
425
+
426
+ // Check all specified properties are preserved
427
+ checkProps.forEach(propName => {
428
+ expect(finalSerialization.data[propName]).toEqual(originalProps[propName]);
429
+ });
430
+ });
431
+ });
432
+ });
433
+
434
+ describe('Error Handling and Edge Cases', () => {
435
+ it('handles malformed data gracefully', () => {
436
+ // Test with minimal props
437
+ const minimalComponents = [
438
+ <HtmlInputField label="Minimal HTML" />,
439
+ <ChoiceInputField label="Minimal Choice" />,
440
+ <SwitchInputField label="Minimal Switch" />,
441
+ <FormBlock title="Minimal Form" />
442
+ ];
443
+
444
+ minimalComponents.forEach(element => {
445
+ const serialized = ComponentTransformer.serialize(element);
446
+ const serializedData = JSON.parse(serialized);
447
+ const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
448
+
449
+ expect(React.isValidElement(deserializedElement)).toBe(true);
450
+
451
+ // Should be able to re-serialize without errors
452
+ const reserialized = ComponentTransformer.serialize(deserializedElement);
453
+ const reserializedData = JSON.parse(reserialized);
454
+ expect(reserializedData.tag).toBe(serializedData.tag);
455
+ });
456
+ });
457
+
458
+ it('preserves complex nested structures', () => {
459
+ const complexChoiceOptions = [
460
+ 'Simple option',
461
+ '<b>HTML</b> option with <i>formatting</i>',
462
+ 'Unicode: 中文 🎉 åäö',
463
+ 'Special chars: "quotes" & <tags>'
464
+ ];
465
+
466
+ const originalProps = {
467
+ label: 'Complex Choice Field',
468
+ options: complexChoiceOptions,
469
+ optionLabelPrefix: 'Complex Question'
470
+ };
471
+
472
+ const element = <ChoiceInputField {...originalProps} />;
473
+ const serialized = ComponentTransformer.serialize(element);
474
+ const serializedData = JSON.parse(serialized);
475
+ const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
476
+ const reserialized = ComponentTransformer.serialize(deserializedElement);
477
+ const reserializedData = JSON.parse(reserialized);
478
+
479
+ expect(reserializedData.data.options).toEqual(complexChoiceOptions);
480
+ });
481
+ });
482
+ });