@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,414 @@
1
+ /**
2
+ * HeroBlock Serialization Performance Tests
3
+ *
4
+ * Comprehensive test suite for HeroBlock component serialization functionality,
5
+ * including performance benchmarks and nested component serialization.
6
+ *
7
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
8
+ */
9
+
10
+ import React from 'react';
11
+ import { render } from '@testing-library/react';
12
+ import '@testing-library/jest-dom';
13
+ import HeroBlock from '../../../components/blocks/HeroBlock';
14
+ import { ComponentTransformer } from '../../../schemas/transformers/ComponentTransformer';
15
+ import '../../../schemas/transformers/registry';
16
+
17
+ describe('HeroBlock Serialization', () => {
18
+ describe('Performance Benchmarks', () => {
19
+ it('serializes basic HeroBlock in under 1ms', () => {
20
+ const heroComponent = (
21
+ <HeroBlock
22
+ title="Performance Test Hero"
23
+ subtitle="Testing serialization speed"
24
+ backgroundColor="primary"
25
+ textAlign="center"
26
+ blockHeight="medium"
27
+ />
28
+ );
29
+
30
+ const startTime = performance.now();
31
+ const serializedData = ComponentTransformer.serialize(heroComponent);
32
+ const endTime = performance.now();
33
+
34
+ const serializationTime = endTime - startTime;
35
+
36
+ expect(serializedData).toBeDefined();
37
+ expect(serializationTime).toBeLessThan(1); // Less than 1ms target
38
+
39
+ const parsedData = JSON.parse(serializedData);
40
+ expect(parsedData.tag).toBe('HeroBlock');
41
+ expect(parsedData.data.title).toBe('Performance Test Hero');
42
+ });
43
+
44
+ it('serializes complex HeroBlock with multiple actions in under 2ms', () => {
45
+ const complexHero = (
46
+ <HeroBlock
47
+ title="Complex Performance Test"
48
+ subtitle="Hero with multiple actions and configurations"
49
+ backgroundGradient="linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
50
+ backgroundImage="https://example.com/hero-bg.jpg"
51
+ overlayOpacity={0.7}
52
+ textAlign="center"
53
+ blockHeight="large"
54
+ actions={[
55
+ { label: 'Primary Action', variant: 'primary', buttonSize: 'large', href: '/test' },
56
+ { label: 'Secondary Action', variant: 'secondary', buttonSize: 'medium', target: '_blank' },
57
+ { label: 'Outlined Action', variant: 'outlined', buttonSize: 'small' },
58
+ { label: 'Text Action', variant: 'text', disabled: true },
59
+ { label: 'Loading Action', variant: 'contained', loading: true }
60
+ ]}
61
+ />
62
+ );
63
+
64
+ const startTime = performance.now();
65
+ const serializedData = ComponentTransformer.serialize(complexHero);
66
+ const endTime = performance.now();
67
+
68
+ const serializationTime = endTime - startTime;
69
+
70
+ expect(serializedData).toBeDefined();
71
+ expect(serializationTime).toBeLessThan(2); // Less than 2ms target for complex components
72
+
73
+ const parsedData = JSON.parse(serializedData);
74
+ expect(parsedData.tag).toBe('HeroBlock');
75
+ expect(parsedData.data.actions).toHaveLength(5);
76
+ });
77
+
78
+ it('deserializes HeroBlock in under 1ms', () => {
79
+ const heroComponent = (
80
+ <HeroBlock
81
+ title="Deserialization Test"
82
+ subtitle="Testing deserialization speed"
83
+ backgroundColor="secondary"
84
+ actions={[
85
+ { label: 'Test Action', variant: 'primary', buttonSize: 'large' }
86
+ ]}
87
+ />
88
+ );
89
+
90
+ const serializedData = ComponentTransformer.serialize(heroComponent);
91
+
92
+ const startTime = performance.now();
93
+ const deserializedComponent = ComponentTransformer.deserialize(serializedData);
94
+ const endTime = performance.now();
95
+
96
+ const deserializationTime = endTime - startTime;
97
+
98
+ expect(deserializedComponent).toBeDefined();
99
+ expect(React.isValidElement(deserializedComponent)).toBe(true);
100
+ expect(deserializationTime).toBeLessThan(1); // Less than 1ms target
101
+ });
102
+
103
+ it('performs round-trip serialization 100 times in under 100ms', () => {
104
+ const heroComponent = (
105
+ <HeroBlock
106
+ title="Batch Test Hero"
107
+ subtitle="Testing batch serialization performance"
108
+ backgroundColor="primary"
109
+ actions={[
110
+ { label: 'Batch Action', variant: 'primary', buttonSize: 'medium' }
111
+ ]}
112
+ />
113
+ );
114
+
115
+ const startTime = performance.now();
116
+
117
+ for (let i = 0; i < 100; i++) {
118
+ const serialized = ComponentTransformer.serialize(heroComponent);
119
+ const deserialized = ComponentTransformer.deserialize(serialized);
120
+ expect(React.isValidElement(deserialized)).toBe(true);
121
+ }
122
+
123
+ const endTime = performance.now();
124
+ const totalTime = endTime - startTime;
125
+
126
+ expect(totalTime).toBeLessThan(100); // 100 round-trips in under 100ms (1ms per operation)
127
+
128
+ // Average time per operation should be under 1ms
129
+ const averageTime = totalTime / 100;
130
+ expect(averageTime).toBeLessThan(1);
131
+ });
132
+ });
133
+
134
+ describe('Nested Component Serialization', () => {
135
+ it('properly serializes HeroBlock with Button actions', () => {
136
+ const heroWithActions = (
137
+ <HeroBlock
138
+ title="Hero with Nested Actions"
139
+ subtitle="Testing nested Button component serialization"
140
+ backgroundGradient="linear-gradient(45deg, #2196F3, #21CBF3)"
141
+ textAlign="center"
142
+ blockHeight="medium"
143
+ actions={[
144
+ {
145
+ label: 'Primary Button',
146
+ variant: 'primary',
147
+ buttonSize: 'large',
148
+ href: '/primary-action'
149
+ },
150
+ {
151
+ label: 'Secondary Button',
152
+ variant: 'secondary',
153
+ buttonSize: 'medium',
154
+ disabled: false,
155
+ loading: false
156
+ }
157
+ ]}
158
+ />
159
+ );
160
+
161
+ const serializedData = ComponentTransformer.serialize(heroWithActions);
162
+ const parsedData = JSON.parse(serializedData);
163
+
164
+ // Verify HeroBlock serialization
165
+ expect(parsedData.tag).toBe('HeroBlock');
166
+ expect(parsedData.version).toBe('1.0.0');
167
+ expect(parsedData.data.title).toBe('Hero with Nested Actions');
168
+
169
+ // Verify nested actions serialization
170
+ expect(parsedData.data.actions).toHaveLength(2);
171
+ expect(parsedData.data.actions[0].label).toBe('Primary Button');
172
+ expect(parsedData.data.actions[0].variant).toBe('primary');
173
+ expect(parsedData.data.actions[0].buttonSize).toBe('large');
174
+ expect(parsedData.data.actions[0].href).toBe('/primary-action');
175
+
176
+ expect(parsedData.data.actions[1].label).toBe('Secondary Button');
177
+ expect(parsedData.data.actions[1].variant).toBe('secondary');
178
+ expect(parsedData.data.actions[1].buttonSize).toBe('medium');
179
+
180
+ // Verify deserialization works
181
+ const deserializedComponent = ComponentTransformer.deserialize(serializedData);
182
+ expect(React.isValidElement(deserializedComponent)).toBe(true);
183
+ });
184
+
185
+ it('handles complex action configurations with custom properties', () => {
186
+ const complexActionsHero = (
187
+ <HeroBlock
188
+ title="Complex Actions Test"
189
+ actions={[
190
+ {
191
+ label: 'Navigate Action',
192
+ variant: 'primary',
193
+ buttonSize: 'large',
194
+ action: { type: 'navigate', url: '/dashboard', target: '_self' }
195
+ },
196
+ {
197
+ label: 'External Action',
198
+ variant: 'outlined',
199
+ buttonSize: 'medium',
200
+ action: { type: 'external', url: 'https://example.com', target: '_blank' }
201
+ },
202
+ {
203
+ label: 'Custom Handler',
204
+ variant: 'text',
205
+ buttonSize: 'small',
206
+ action: { type: 'custom', customHandler: 'handleCustomClick' }
207
+ }
208
+ ]}
209
+ />
210
+ );
211
+
212
+ const serializedData = ComponentTransformer.serialize(complexActionsHero);
213
+ const parsedData = JSON.parse(serializedData);
214
+
215
+ expect(parsedData.data.actions).toHaveLength(3);
216
+
217
+ // Verify complex action structures are preserved
218
+ expect(parsedData.data.actions[0].action.type).toBe('navigate');
219
+ expect(parsedData.data.actions[0].action.url).toBe('/dashboard');
220
+ expect(parsedData.data.actions[0].action.target).toBe('_self');
221
+
222
+ expect(parsedData.data.actions[1].action.type).toBe('external');
223
+ expect(parsedData.data.actions[1].action.url).toBe('https://example.com');
224
+
225
+ expect(parsedData.data.actions[2].action.type).toBe('custom');
226
+ expect(parsedData.data.actions[2].action.customHandler).toBe('handleCustomClick');
227
+
228
+ // Verify deserialization maintains complex structures
229
+ const deserializedComponent = ComponentTransformer.deserialize(serializedData);
230
+ expect(React.isValidElement(deserializedComponent)).toBe(true);
231
+ });
232
+
233
+ it('preserves all background configuration options', () => {
234
+ const backgroundConfigHero = (
235
+ <HeroBlock
236
+ title="Background Config Test"
237
+ subtitle="Testing all background options"
238
+ backgroundImage="https://example.com/hero-bg.jpg"
239
+ backgroundGradient="linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
240
+ backgroundColor="primary"
241
+ overlayOpacity={0.8}
242
+ textAlign="right"
243
+ blockHeight="viewport"
244
+ />
245
+ );
246
+
247
+ const serializedData = ComponentTransformer.serialize(backgroundConfigHero);
248
+ const parsedData = JSON.parse(serializedData);
249
+
250
+ expect(parsedData.data.backgroundImage).toBe('https://example.com/hero-bg.jpg');
251
+ expect(parsedData.data.backgroundGradient).toBe('linear-gradient(135deg, #667eea 0%, #764ba2 100%)');
252
+ expect(parsedData.data.backgroundColor).toBe('primary');
253
+ expect(parsedData.data.overlayOpacity).toBe(0.8);
254
+ expect(parsedData.data.textAlign).toBe('right');
255
+ expect(parsedData.data.blockHeight).toBe('viewport');
256
+
257
+ const deserializedComponent = ComponentTransformer.deserialize(serializedData);
258
+ expect(React.isValidElement(deserializedComponent)).toBe(true);
259
+ });
260
+
261
+ it('handles data binding configuration preservation', () => {
262
+ const dataBindingHero = (
263
+ <HeroBlock
264
+ dataSource="heroes.main"
265
+ bindingOptions={{ cache: true, cacheTTL: 300000, strict: false }}
266
+ title="Fallback Title"
267
+ subtitle="Fallback Subtitle"
268
+ />
269
+ );
270
+
271
+ const serializedData = ComponentTransformer.serialize(dataBindingHero);
272
+ const parsedData = JSON.parse(serializedData);
273
+
274
+ // Verify data binding properties are preserved
275
+ expect(parsedData.data.dataSource).toBe('heroes.main');
276
+ expect(parsedData.data.bindingOptions.cache).toBe(true);
277
+ expect(parsedData.data.bindingOptions.cacheTTL).toBe(300000);
278
+ expect(parsedData.data.bindingOptions.strict).toBe(false);
279
+
280
+ // Verify fallback props are preserved
281
+ expect(parsedData.data.title).toBe('Fallback Title');
282
+ expect(parsedData.data.subtitle).toBe('Fallback Subtitle');
283
+
284
+ const deserializedComponent = ComponentTransformer.deserialize(serializedData);
285
+ expect(React.isValidElement(deserializedComponent)).toBe(true);
286
+ });
287
+
288
+ it('handles edge cases with empty and undefined values', () => {
289
+ const edgeCaseHero = (
290
+ <HeroBlock
291
+ title=""
292
+ subtitle={undefined}
293
+ actions={[]}
294
+ backgroundImage={undefined}
295
+ overlayOpacity={0}
296
+ className=""
297
+ />
298
+ );
299
+
300
+ const serializedData = ComponentTransformer.serialize(edgeCaseHero);
301
+ const parsedData = JSON.parse(serializedData);
302
+
303
+ expect(parsedData.data.title).toBe('');
304
+ expect(parsedData.data.actions).toEqual([]);
305
+ expect(parsedData.data.overlayOpacity).toBe(0);
306
+
307
+ const deserializedComponent = ComponentTransformer.deserialize(serializedData);
308
+ expect(React.isValidElement(deserializedComponent)).toBe(true);
309
+ });
310
+ });
311
+
312
+ describe('Data Integrity', () => {
313
+ it('maintains complete data integrity through multiple serialization cycles', () => {
314
+ const originalHero = (
315
+ <HeroBlock
316
+ title="Data Integrity Test"
317
+ subtitle="Testing multiple serialization cycles"
318
+ backgroundGradient="linear-gradient(45deg, #FF6B6B, #4ECDC4)"
319
+ backgroundColor="secondary"
320
+ textAlign="center"
321
+ blockHeight="large"
322
+ overlayOpacity={0.6}
323
+ actions={[
324
+ {
325
+ label: 'Complex Action',
326
+ variant: 'primary',
327
+ buttonSize: 'large',
328
+ href: '/test-url',
329
+ target: '_blank',
330
+ disabled: false,
331
+ loading: false,
332
+ fullWidth: false,
333
+ action: {
334
+ type: 'navigate',
335
+ url: '/complex-url',
336
+ target: '_self'
337
+ }
338
+ }
339
+ ]}
340
+ />
341
+ );
342
+
343
+ // First serialization cycle
344
+ const serialized1 = ComponentTransformer.serialize(originalHero);
345
+ const deserialized1 = ComponentTransformer.deserialize(serialized1);
346
+
347
+ // Second serialization cycle
348
+ const serialized2 = ComponentTransformer.serialize(deserialized1 as React.ReactElement);
349
+ const deserialized2 = ComponentTransformer.deserialize(serialized2);
350
+
351
+ // Third serialization cycle
352
+ const serialized3 = ComponentTransformer.serialize(deserialized2 as React.ReactElement);
353
+ const parsedData3 = JSON.parse(serialized3);
354
+
355
+ // Verify data integrity is maintained across multiple cycles
356
+ expect(parsedData3.tag).toBe('HeroBlock');
357
+ expect(parsedData3.version).toBe('1.0.0');
358
+ expect(parsedData3.data.title).toBe('Data Integrity Test');
359
+ expect(parsedData3.data.subtitle).toBe('Testing multiple serialization cycles');
360
+ expect(parsedData3.data.backgroundGradient).toBe('linear-gradient(45deg, #FF6B6B, #4ECDC4)');
361
+ expect(parsedData3.data.backgroundColor).toBe('secondary');
362
+ expect(parsedData3.data.textAlign).toBe('center');
363
+ expect(parsedData3.data.blockHeight).toBe('large');
364
+ expect(parsedData3.data.overlayOpacity).toBe(0.6);
365
+
366
+ expect(parsedData3.data.actions).toHaveLength(1);
367
+ expect(parsedData3.data.actions[0].label).toBe('Complex Action');
368
+ expect(parsedData3.data.actions[0].variant).toBe('primary');
369
+ expect(parsedData3.data.actions[0].href).toBe('/test-url');
370
+ expect(parsedData3.data.actions[0].target).toBe('_blank');
371
+ expect(parsedData3.data.actions[0].action.type).toBe('navigate');
372
+ expect(parsedData3.data.actions[0].action.url).toBe('/complex-url');
373
+
374
+ const finalDeserialized = ComponentTransformer.deserialize(serialized3);
375
+ expect(React.isValidElement(finalDeserialized)).toBe(true);
376
+ });
377
+
378
+ it('preserves component hierarchy and structure', () => {
379
+ const structuralHero = (
380
+ <HeroBlock
381
+ title="Structural Test"
382
+ subtitle="Testing component structure preservation"
383
+ backgroundColor="primary"
384
+ actions={[
385
+ { label: 'Action 1', variant: 'primary' },
386
+ { label: 'Action 2', variant: 'secondary' },
387
+ { label: 'Action 3', variant: 'outlined' }
388
+ ]}
389
+ />
390
+ );
391
+
392
+ const serializedData = ComponentTransformer.serialize(structuralHero);
393
+ const parsedData = JSON.parse(serializedData);
394
+
395
+ // Verify component structure
396
+ expect(parsedData).toHaveProperty('tag');
397
+ expect(parsedData).toHaveProperty('version');
398
+ expect(parsedData).toHaveProperty('data');
399
+
400
+ // Verify nested structure (actions array)
401
+ expect(parsedData.data.actions).toBeInstanceOf(Array);
402
+ expect(parsedData.data.actions).toHaveLength(3);
403
+
404
+ parsedData.data.actions.forEach((action: any, index: number) => {
405
+ expect(action).toHaveProperty('label');
406
+ expect(action).toHaveProperty('variant');
407
+ expect(action.label).toBe(`Action ${index + 1}`);
408
+ });
409
+
410
+ const deserializedComponent = ComponentTransformer.deserialize(serializedData);
411
+ expect(React.isValidElement(deserializedComponent)).toBe(true);
412
+ });
413
+ });
414
+ });
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Image Component Serialization Tests
3
+ *
4
+ * Tests for the Image component's ModelView implementation and
5
+ * serialization capabilities using ComponentTransformer.
6
+ *
7
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
8
+ */
9
+
10
+ import React from 'react';
11
+ import { render, screen } from '@testing-library/react';
12
+ import '@testing-library/jest-dom';
13
+ import { ComponentTransformer } from '../../../schemas/transformers/ComponentTransformer';
14
+ import { Image } from '../../../components/blocks/Image';
15
+
16
+ describe('Image Serialization', () => {
17
+ beforeEach(() => {
18
+ // Clear component registry for clean tests
19
+ ComponentTransformer.clearRegistry();
20
+
21
+ // Register Image component
22
+ ComponentTransformer.registerComponent(Image as any);
23
+ });
24
+
25
+ afterEach(() => {
26
+ ComponentTransformer.clearRegistry();
27
+ });
28
+
29
+ describe('Basic Serialization', () => {
30
+ it('should serialize and deserialize basic image component', () => {
31
+ // Create original component
32
+ const originalComponent = (
33
+ <Image
34
+ src="https://example.com/image.jpg"
35
+ alt="Test image"
36
+ width={400}
37
+ height={300}
38
+ />
39
+ );
40
+
41
+ // Serialize
42
+ const serialized = ComponentTransformer.serialize(originalComponent);
43
+ expect(serialized).toBeTruthy();
44
+ expect(typeof serialized).toBe('string');
45
+
46
+ // Parse to check structure
47
+ const parsed = JSON.parse(serialized);
48
+ expect(parsed.tag).toBe('Image');
49
+ expect(parsed.version).toBe('1.0.0');
50
+ expect(parsed.data.src).toBe('https://example.com/image.jpg');
51
+ expect(parsed.data.alt).toBe('Test image');
52
+ expect(parsed.data.width).toBe(400);
53
+ expect(parsed.data.height).toBe(300);
54
+
55
+ // Deserialize
56
+ const deserialized = ComponentTransformer.deserialize(serialized);
57
+ expect(React.isValidElement(deserialized)).toBe(true);
58
+ });
59
+
60
+ it('should preserve all image properties through serialization', () => {
61
+ const originalComponent = (
62
+ <Image
63
+ src="https://example.com/image.jpg"
64
+ alt="Comprehensive test image"
65
+ width={600}
66
+ height={400}
67
+ objectFit="cover"
68
+ objectPosition="center"
69
+ loading="lazy"
70
+ title="Test image title"
71
+ draggable={false}
72
+ borderRadius="12px"
73
+ showLoading={true}
74
+ showError={true}
75
+ fallbackSrc="https://example.com/fallback.jpg"
76
+ />
77
+ );
78
+
79
+ const serialized = ComponentTransformer.serialize(originalComponent);
80
+ const parsed = JSON.parse(serialized);
81
+ const data = parsed.data;
82
+
83
+ expect(data.src).toBe('https://example.com/image.jpg');
84
+ expect(data.alt).toBe('Comprehensive test image');
85
+ expect(data.width).toBe(600);
86
+ expect(data.height).toBe(400);
87
+ expect(data.objectFit).toBe('cover');
88
+ expect(data.objectPosition).toBe('center');
89
+ expect(data.loading).toBe('lazy');
90
+ expect(data.title).toBe('Test image title');
91
+ expect(data.draggable).toBe(false);
92
+ expect(data.borderRadius).toBe('12px');
93
+ expect(data.showLoading).toBe(true);
94
+ expect(data.showError).toBe(true);
95
+ expect(data.fallbackSrc).toBe('https://example.com/fallback.jpg');
96
+
97
+ const deserialized = ComponentTransformer.deserialize(serialized);
98
+ expect(React.isValidElement(deserialized)).toBe(true);
99
+ });
100
+
101
+ it('should handle responsive image properties', () => {
102
+ const originalComponent = (
103
+ <Image
104
+ src="https://example.com/image.jpg"
105
+ alt="Responsive image"
106
+ sizes="(max-width: 768px) 100vw, 50vw"
107
+ srcSet="https://example.com/image-400.jpg 400w, https://example.com/image-800.jpg 800w"
108
+ />
109
+ );
110
+
111
+ const serialized = ComponentTransformer.serialize(originalComponent);
112
+ const parsed = JSON.parse(serialized);
113
+
114
+ expect(parsed.data.sizes).toBe('(max-width: 768px) 100vw, 50vw');
115
+ expect(parsed.data.srcSet).toBe('https://example.com/image-400.jpg 400w, https://example.com/image-800.jpg 800w');
116
+
117
+ const deserialized = ComponentTransformer.deserialize(serialized);
118
+ expect(React.isValidElement(deserialized)).toBe(true);
119
+ });
120
+ });
121
+
122
+ describe('ModelView Integration', () => {
123
+ it('should have correct static properties', () => {
124
+ expect((Image as any).tagName).toBe('Image');
125
+ expect((Image as any).version).toBe('1.0.0');
126
+ expect(typeof (Image as any).fromJson).toBe('function');
127
+ });
128
+
129
+ it('should create instance with toJson method', () => {
130
+ const imageInstance = new Image({
131
+ src: 'https://example.com/test.jpg',
132
+ alt: 'Test image'
133
+ });
134
+
135
+ expect(typeof imageInstance.toJson).toBe('function');
136
+
137
+ const serialized = imageInstance.toJson();
138
+ expect(serialized.src).toBe('https://example.com/test.jpg');
139
+ expect(serialized.alt).toBe('Test image');
140
+ });
141
+
142
+ it('should handle fromJson static method', () => {
143
+ const jsonData = {
144
+ src: 'https://example.com/test.jpg',
145
+ alt: 'From JSON test',
146
+ width: 300,
147
+ height: 200
148
+ };
149
+
150
+ const component = (Image as any).fromJson(jsonData);
151
+ expect(React.isValidElement(component)).toBe(true);
152
+ });
153
+ });
154
+
155
+ describe('Data Binding Serialization', () => {
156
+ it('should preserve dataSource and bindingOptions', () => {
157
+ const originalComponent = (
158
+ <Image
159
+ src="https://example.com/image.jpg"
160
+ alt="Data bound image"
161
+ dataSource="images.hero"
162
+ bindingOptions={{
163
+ cache: true,
164
+ cacheTTL: 300000,
165
+ strict: false
166
+ }}
167
+ />
168
+ );
169
+
170
+ const serialized = ComponentTransformer.serialize(originalComponent);
171
+ const parsed = JSON.parse(serialized);
172
+
173
+ expect(parsed.data.dataSource).toBe('images.hero');
174
+ expect(parsed.data.bindingOptions).toEqual({
175
+ cache: true,
176
+ cacheTTL: 300000,
177
+ strict: false
178
+ });
179
+
180
+ const deserialized = ComponentTransformer.deserialize(serialized);
181
+ expect(React.isValidElement(deserialized)).toBe(true);
182
+ });
183
+ });
184
+
185
+ describe('Error Handling', () => {
186
+ it('should handle serialization of image without required props', () => {
187
+ // Image without src should still serialize (though it may not render)
188
+ const originalComponent = <Image alt="Image without src" />;
189
+
190
+ const serialized = ComponentTransformer.serialize(originalComponent);
191
+ expect(serialized).toBeTruthy();
192
+
193
+ const parsed = JSON.parse(serialized);
194
+ expect(parsed.tag).toBe('Image');
195
+ expect(parsed.data.alt).toBe('Image without src');
196
+ expect(parsed.data.src).toBeUndefined();
197
+
198
+ const deserialized = ComponentTransformer.deserialize(serialized);
199
+ expect(React.isValidElement(deserialized)).toBe(true);
200
+ });
201
+
202
+ it('should handle empty/null values gracefully', () => {
203
+ const originalComponent = (
204
+ <Image
205
+ src=""
206
+ alt=""
207
+ width={undefined}
208
+ height={undefined}
209
+ />
210
+ );
211
+
212
+ const serialized = ComponentTransformer.serialize(originalComponent);
213
+ const parsed = JSON.parse(serialized);
214
+
215
+ expect(parsed.data.src).toBe('');
216
+ expect(parsed.data.alt).toBe('');
217
+
218
+ const deserialized = ComponentTransformer.deserialize(serialized);
219
+ expect(React.isValidElement(deserialized)).toBe(true);
220
+ });
221
+ });
222
+
223
+ describe('Component Registry', () => {
224
+ it('should be registered in ComponentTransformer', () => {
225
+ const registeredComponents = ComponentTransformer.getRegisteredComponents();
226
+ expect(registeredComponents).toContain('Image');
227
+ });
228
+
229
+ it('should support round-trip serialization consistency', () => {
230
+ const originalComponent = (
231
+ <Image
232
+ src="https://example.com/consistency-test.jpg"
233
+ alt="Consistency test image"
234
+ width={500}
235
+ height={300}
236
+ objectFit="contain"
237
+ borderRadius="8px"
238
+ showLoading={true}
239
+ />
240
+ );
241
+
242
+ // First round-trip
243
+ const serialized1 = ComponentTransformer.serialize(originalComponent);
244
+ const deserialized1 = ComponentTransformer.deserialize(serialized1);
245
+
246
+ // Second round-trip
247
+ const serialized2 = ComponentTransformer.serialize(deserialized1);
248
+ const parsed1 = JSON.parse(serialized1);
249
+ const parsed2 = JSON.parse(serialized2);
250
+
251
+ // Should be identical
252
+ expect(parsed1.tag).toBe(parsed2.tag);
253
+ expect(parsed1.version).toBe(parsed2.version);
254
+ expect(parsed1.data).toEqual(parsed2.data);
255
+ });
256
+ });
257
+ });