@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,586 @@
1
+ /**
2
+ * Cross-Browser Compatibility Tests for Component Serialization
3
+ *
4
+ * Tests serialization system behavior across different JavaScript engines,
5
+ * browser environments, and runtime conditions to ensure consistent
6
+ * functionality regardless of platform.
7
+ *
8
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
9
+ */
10
+
11
+ import React, { ReactElement } from 'react';
12
+ import { ComponentTransformer } from '../ComponentTransformer';
13
+ import { Serializable, SerializableConstructor } from '../../types/Serializable';
14
+
15
+ // Mock different browser environments
16
+ interface BrowserEnvironment {
17
+ name: string;
18
+ userAgent: string;
19
+ jsonSupport: {
20
+ parse: typeof JSON.parse;
21
+ stringify: typeof JSON.stringify;
22
+ };
23
+ features: {
24
+ es6: boolean;
25
+ weakMap: boolean;
26
+ symbol: boolean;
27
+ proxy: boolean;
28
+ };
29
+ }
30
+
31
+ // Browser environment simulations
32
+ const browserEnvironments: BrowserEnvironment[] = [
33
+ {
34
+ name: 'Chrome Latest',
35
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
36
+ jsonSupport: { parse: JSON.parse, stringify: JSON.stringify },
37
+ features: { es6: true, weakMap: true, symbol: true, proxy: true }
38
+ },
39
+ {
40
+ name: 'Firefox Latest',
41
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/120.0',
42
+ jsonSupport: { parse: JSON.parse, stringify: JSON.stringify },
43
+ features: { es6: true, weakMap: true, symbol: true, proxy: true }
44
+ },
45
+ {
46
+ name: 'Safari Latest',
47
+ userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Version/17.0 Safari/537.36',
48
+ jsonSupport: { parse: JSON.parse, stringify: JSON.stringify },
49
+ features: { es6: true, weakMap: true, symbol: true, proxy: true }
50
+ },
51
+ {
52
+ name: 'Edge Latest',
53
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0',
54
+ jsonSupport: { parse: JSON.parse, stringify: JSON.stringify },
55
+ features: { es6: true, weakMap: true, symbol: true, proxy: true }
56
+ }
57
+ ];
58
+
59
+ // Test component for cross-browser testing
60
+ class CrossBrowserTestComponent implements Serializable {
61
+ constructor(public props: {
62
+ text?: string;
63
+ number?: number;
64
+ boolean?: boolean;
65
+ array?: any[];
66
+ object?: Record<string, any>;
67
+ date?: string;
68
+ unicode?: string;
69
+ specialChars?: string;
70
+ }) {}
71
+
72
+ static fromJson(jsonData: any): ReactElement {
73
+ return React.createElement('div', {
74
+ 'data-testid': 'cross-browser-test',
75
+ 'data-text': jsonData.text,
76
+ 'data-number': jsonData.number,
77
+ 'data-boolean': jsonData.boolean,
78
+ 'data-array': jsonData.array ? JSON.stringify(jsonData.array) : undefined,
79
+ 'data-object': jsonData.object ? JSON.stringify(jsonData.object) : undefined,
80
+ 'data-date': jsonData.date,
81
+ 'data-unicode': jsonData.unicode,
82
+ 'data-special-chars': jsonData.specialChars
83
+ }, [
84
+ jsonData.text ? React.createElement('span', { key: 'text' }, jsonData.text) : null,
85
+ jsonData.number !== undefined ? React.createElement('span', { key: 'number' }, jsonData.number.toString()) : null,
86
+ jsonData.boolean !== undefined ? React.createElement('span', { key: 'boolean' }, jsonData.boolean.toString()) : null,
87
+ jsonData.unicode ? React.createElement('span', { key: 'unicode' }, jsonData.unicode) : null
88
+ ].filter(Boolean));
89
+ }
90
+
91
+ toJson(): any {
92
+ return {
93
+ text: this.props.text,
94
+ number: this.props.number,
95
+ boolean: this.props.boolean,
96
+ array: this.props.array,
97
+ object: this.props.object,
98
+ date: this.props.date,
99
+ unicode: this.props.unicode,
100
+ specialChars: this.props.specialChars
101
+ };
102
+ }
103
+ }
104
+
105
+ describe('Cross-Browser Compatibility Tests', () => {
106
+ beforeEach(() => {
107
+ ComponentTransformer.clearRegistry();
108
+ ComponentTransformer.registerComponent('CrossBrowserTest', CrossBrowserTestComponent as SerializableConstructor);
109
+ });
110
+
111
+ afterEach(() => {
112
+ ComponentTransformer.clearRegistry();
113
+ });
114
+
115
+ describe('JSON Parsing and Serialization', () => {
116
+ it('should handle JSON parsing consistently across environments', () => {
117
+ const testData = {
118
+ tag: 'CrossBrowserTest',
119
+ version: '1.0.0',
120
+ data: {
121
+ text: 'Hello World',
122
+ number: 42,
123
+ boolean: true,
124
+ array: [1, 2, 3, 'four', true, null],
125
+ object: { nested: 'value', deep: { deeper: 'deepValue' } }
126
+ }
127
+ };
128
+
129
+ browserEnvironments.forEach(env => {
130
+ // Test JSON parsing with each environment's parser
131
+ const jsonString = env.jsonSupport.stringify(testData);
132
+ expect(() => {
133
+ const parsed = env.jsonSupport.parse(jsonString);
134
+ const result = ComponentTransformer.deserialize(parsed);
135
+ expect(React.isValidElement(result)).toBe(true);
136
+ }).not.toThrow();
137
+ });
138
+ });
139
+
140
+ it('should handle special JSON edge cases consistently', () => {
141
+ const edgeCases = [
142
+ { name: 'null', value: null },
143
+ { name: 'empty object', value: {} },
144
+ { name: 'empty array', value: [] },
145
+ { name: 'zero', value: 0 },
146
+ { name: 'false', value: false },
147
+ { name: 'empty string', value: '' },
148
+ { name: 'whitespace string', value: ' \n\t ' },
149
+ ];
150
+
151
+ edgeCases.forEach(({ name, value }) => {
152
+ const testData = {
153
+ tag: 'CrossBrowserTest',
154
+ version: '1.0.0',
155
+ data: { [name.replace(/\s+/g, '_')]: value }
156
+ };
157
+
158
+ browserEnvironments.forEach(env => {
159
+ expect(() => {
160
+ const jsonString = env.jsonSupport.stringify(testData);
161
+ const parsed = env.jsonSupport.parse(jsonString);
162
+ const result = ComponentTransformer.deserialize(parsed);
163
+ expect(React.isValidElement(result)).toBe(true);
164
+ }).not.toThrow(`${name} should work in ${env.name}`);
165
+ });
166
+ });
167
+ });
168
+
169
+ it('should handle large numbers consistently', () => {
170
+ const numberTests = [
171
+ { name: 'small integer', value: 42 },
172
+ { name: 'large integer', value: 9007199254740991 }, // Number.MAX_SAFE_INTEGER
173
+ { name: 'small float', value: 3.14159 },
174
+ { name: 'very small float', value: 0.000000001 },
175
+ { name: 'negative number', value: -123456.789 },
176
+ { name: 'zero', value: 0 },
177
+ { name: 'negative zero', value: -0 }
178
+ ];
179
+
180
+ numberTests.forEach(({ name, value }) => {
181
+ const testData = {
182
+ tag: 'CrossBrowserTest',
183
+ version: '1.0.0',
184
+ data: { number: value }
185
+ };
186
+
187
+ browserEnvironments.forEach(env => {
188
+ const jsonString = env.jsonSupport.stringify(testData);
189
+ const parsed = env.jsonSupport.parse(jsonString);
190
+ const result = ComponentTransformer.deserialize(parsed);
191
+
192
+ expect(React.isValidElement(result)).toBe(true);
193
+
194
+ const element = result as ReactElement;
195
+ const numberValue = parseFloat(element.props['data-number']);
196
+
197
+ if (name === 'negative zero') {
198
+ // Negative zero becomes positive zero in JSON
199
+ expect(numberValue).toBe(0);
200
+ } else {
201
+ expect(numberValue).toBeCloseTo(value, 10);
202
+ }
203
+ });
204
+ });
205
+ });
206
+ });
207
+
208
+ describe('Unicode and Character Encoding', () => {
209
+ it('should handle Unicode characters consistently', () => {
210
+ const unicodeTests = [
211
+ { name: 'emoji', text: '🚀🎉💻🌟⭐' },
212
+ { name: 'chinese', text: '你好世界' },
213
+ { name: 'arabic', text: 'مرحبا بالعالم' },
214
+ { name: 'russian', text: 'Привет мир' },
215
+ { name: 'greek', text: 'Γεια σου κόσμε' },
216
+ { name: 'mathematical', text: '∑∏∆√∞≈≠±×÷' },
217
+ { name: 'currency', text: '$€£¥₹₿' },
218
+ { name: 'mixed', text: 'Hello 世界 🌍 مرحبا Привет!' }
219
+ ];
220
+
221
+ unicodeTests.forEach(({ name, text }) => {
222
+ const testData = {
223
+ tag: 'CrossBrowserTest',
224
+ version: '1.0.0',
225
+ data: { unicode: text }
226
+ };
227
+
228
+ browserEnvironments.forEach(env => {
229
+ const jsonString = env.jsonSupport.stringify(testData);
230
+ const parsed = env.jsonSupport.parse(jsonString);
231
+ const result = ComponentTransformer.deserialize(parsed);
232
+
233
+ expect(React.isValidElement(result)).toBe(true);
234
+
235
+ const element = result as ReactElement;
236
+ expect(element.props['data-unicode']).toBe(text);
237
+ });
238
+ });
239
+ });
240
+
241
+ it('should handle special characters and escaping', () => {
242
+ const specialCharTests = [
243
+ { name: 'quotes', text: 'He said "Hello \'World\'"' },
244
+ { name: 'backslashes', text: 'C:\\Users\\Name\\File.txt' },
245
+ { name: 'control chars', text: 'Line 1\nLine 2\tTabbed\rCarriage Return' },
246
+ { name: 'html entities', text: '<script>alert("xss")</script>&lt;&gt;&amp;' },
247
+ { name: 'json-like', text: '{"fake": "json", "array": [1,2,3]}' },
248
+ { name: 'regex special', text: '^$.*+?()[]{}|\\' }
249
+ ];
250
+
251
+ specialCharTests.forEach(({ name, text }) => {
252
+ const testData = {
253
+ tag: 'CrossBrowserTest',
254
+ version: '1.0.0',
255
+ data: { specialChars: text }
256
+ };
257
+
258
+ browserEnvironments.forEach(env => {
259
+ expect(() => {
260
+ const jsonString = env.jsonSupport.stringify(testData);
261
+ const parsed = env.jsonSupport.parse(jsonString);
262
+ const result = ComponentTransformer.deserialize(parsed);
263
+
264
+ expect(React.isValidElement(result)).toBe(true);
265
+
266
+ const element = result as ReactElement;
267
+ expect(element.props['data-special-chars']).toBe(text);
268
+ }).not.toThrow(`${name} should work in ${env.name}`);
269
+ });
270
+ });
271
+ });
272
+ });
273
+
274
+ describe('Date and Time Handling', () => {
275
+ it('should handle date strings consistently', () => {
276
+ const dateTests = [
277
+ { name: 'ISO string', date: '2025-01-01T12:00:00.000Z' },
278
+ { name: 'ISO with timezone', date: '2025-01-01T12:00:00+05:30' },
279
+ { name: 'short date', date: '2025-01-01' },
280
+ { name: 'human readable', date: 'January 1, 2025' },
281
+ { name: 'timestamp string', date: '1735732800000' }
282
+ ];
283
+
284
+ dateTests.forEach(({ name, date }) => {
285
+ const testData = {
286
+ tag: 'CrossBrowserTest',
287
+ version: '1.0.0',
288
+ data: { date }
289
+ };
290
+
291
+ browserEnvironments.forEach(env => {
292
+ expect(() => {
293
+ const jsonString = env.jsonSupport.stringify(testData);
294
+ const parsed = env.jsonSupport.parse(jsonString);
295
+ const result = ComponentTransformer.deserialize(parsed);
296
+
297
+ expect(React.isValidElement(result)).toBe(true);
298
+
299
+ const element = result as ReactElement;
300
+ expect(element.props['data-date']).toBe(date);
301
+ }).not.toThrow(`${name} should work in ${env.name}`);
302
+ });
303
+ });
304
+ });
305
+ });
306
+
307
+ describe('Array and Object Handling', () => {
308
+ it('should handle complex nested structures consistently', () => {
309
+ const nestedTests = [
310
+ {
311
+ name: 'deeply nested object',
312
+ data: {
313
+ level1: {
314
+ level2: {
315
+ level3: {
316
+ level4: {
317
+ value: 'deep value'
318
+ }
319
+ }
320
+ }
321
+ }
322
+ }
323
+ },
324
+ {
325
+ name: 'mixed array types',
326
+ data: {
327
+ array: [
328
+ 'string',
329
+ 42,
330
+ true,
331
+ null,
332
+ { nested: 'object' },
333
+ ['nested', 'array'],
334
+ undefined // Will be converted to null in JSON
335
+ ]
336
+ }
337
+ },
338
+ {
339
+ name: 'sparse array',
340
+ data: {
341
+ sparse: [1, , , 4, , 6] // Sparse array with holes
342
+ }
343
+ }
344
+ ];
345
+
346
+ nestedTests.forEach(({ name, data }) => {
347
+ const testData = {
348
+ tag: 'CrossBrowserTest',
349
+ version: '1.0.0',
350
+ data
351
+ };
352
+
353
+ browserEnvironments.forEach(env => {
354
+ expect(() => {
355
+ const jsonString = env.jsonSupport.stringify(testData);
356
+ const parsed = env.jsonSupport.parse(jsonString);
357
+ const result = ComponentTransformer.deserialize(parsed);
358
+
359
+ expect(React.isValidElement(result)).toBe(true);
360
+ }).not.toThrow(`${name} should work in ${env.name}`);
361
+ });
362
+ });
363
+ });
364
+
365
+ it('should handle object property order consistently', () => {
366
+ const testData = {
367
+ tag: 'CrossBrowserTest',
368
+ version: '1.0.0',
369
+ data: {
370
+ z_property: 'last',
371
+ a_property: 'first',
372
+ m_property: 'middle'
373
+ }
374
+ };
375
+
376
+ browserEnvironments.forEach(env => {
377
+ const jsonString = env.jsonSupport.stringify(testData);
378
+ const parsed = env.jsonSupport.parse(jsonString);
379
+ const result = ComponentTransformer.deserialize(parsed);
380
+
381
+ expect(React.isValidElement(result)).toBe(true);
382
+
383
+ // Property order might differ, but values should be preserved
384
+ const element = result as ReactElement;
385
+ const objectData = JSON.parse(element.props['data-object'] || '{}');
386
+ expect(objectData.z_property).toBe('last');
387
+ expect(objectData.a_property).toBe('first');
388
+ expect(objectData.m_property).toBe('middle');
389
+ });
390
+ });
391
+ });
392
+
393
+ describe('Error Handling Consistency', () => {
394
+ it('should handle malformed JSON consistently', () => {
395
+ const malformedJsonTests = [
396
+ '{"unclosed": object',
397
+ '{key: "missing quotes"}',
398
+ '[1, 2, 3,]', // Trailing comma
399
+ '{"duplicate": "key1", "duplicate": "key2"}' // Actually valid JSON
400
+ ];
401
+
402
+ malformedJsonTests.forEach((malformedJson, index) => {
403
+ if (index === 3) return; // Skip the valid JSON case
404
+
405
+ browserEnvironments.forEach(env => {
406
+ expect(() => {
407
+ env.jsonSupport.parse(malformedJson);
408
+ }).toThrow();
409
+
410
+ expect(() => {
411
+ ComponentTransformer.deserialize(malformedJson);
412
+ }).toThrow(/Invalid JSON input/);
413
+ });
414
+ });
415
+ });
416
+
417
+ it('should handle component errors consistently', () => {
418
+ const invalidComponent = {
419
+ tag: 'NonExistentComponent',
420
+ version: '1.0.0',
421
+ data: {}
422
+ };
423
+
424
+ browserEnvironments.forEach(env => {
425
+ expect(() => {
426
+ const jsonString = env.jsonSupport.stringify(invalidComponent);
427
+ const parsed = env.jsonSupport.parse(jsonString);
428
+ ComponentTransformer.deserialize(parsed);
429
+ }).toThrow('Unknown component: NonExistentComponent');
430
+ });
431
+ });
432
+ });
433
+
434
+ describe('Performance Consistency', () => {
435
+ it('should maintain consistent performance across browsers', () => {
436
+ const largeTestData = {
437
+ tag: 'CrossBrowserTest',
438
+ version: '1.0.0',
439
+ data: {
440
+ array: Array.from({ length: 1000 }, (_, i) => ({
441
+ id: i,
442
+ text: `Item ${i}`,
443
+ nested: { value: i * 2 }
444
+ }))
445
+ }
446
+ };
447
+
448
+ const performanceResults: { [browser: string]: number } = {};
449
+
450
+ browserEnvironments.forEach(env => {
451
+ const startTime = performance.now();
452
+
453
+ const jsonString = env.jsonSupport.stringify(largeTestData);
454
+ const parsed = env.jsonSupport.parse(jsonString);
455
+ const result = ComponentTransformer.deserialize(parsed);
456
+
457
+ const endTime = performance.now();
458
+ performanceResults[env.name] = endTime - startTime;
459
+
460
+ expect(React.isValidElement(result)).toBe(true);
461
+ });
462
+
463
+ // Verify that performance is within reasonable bounds
464
+ const times = Object.values(performanceResults);
465
+ const avgTime = times.reduce((a, b) => a + b, 0) / times.length;
466
+ const maxTime = Math.max(...times);
467
+ const minTime = Math.min(...times);
468
+
469
+ console.log('Cross-browser performance:', performanceResults);
470
+
471
+ // No browser should be more than 3x slower than the fastest
472
+ expect(maxTime / minTime).toBeLessThan(3);
473
+
474
+ // Average time should be reasonable (< 100ms for this test)
475
+ expect(avgTime).toBeLessThan(100);
476
+ });
477
+ });
478
+
479
+ describe('Memory Usage Consistency', () => {
480
+ it('should handle memory usage consistently', () => {
481
+ const memoryTestData = Array.from({ length: 100 }, (_, i) => ({
482
+ tag: 'CrossBrowserTest',
483
+ version: '1.0.0',
484
+ data: {
485
+ text: `Memory test item ${i}`,
486
+ array: Array.from({ length: 100 }, (_, j) => `item-${i}-${j}`)
487
+ }
488
+ }));
489
+
490
+ browserEnvironments.forEach(env => {
491
+ const initialMemory = process.memoryUsage().heapUsed;
492
+
493
+ // Process the data multiple times
494
+ for (let iteration = 0; iteration < 10; iteration++) {
495
+ memoryTestData.forEach(testItem => {
496
+ const jsonString = env.jsonSupport.stringify(testItem);
497
+ const parsed = env.jsonSupport.parse(jsonString);
498
+ const result = ComponentTransformer.deserialize(parsed);
499
+
500
+ expect(React.isValidElement(result)).toBe(true);
501
+ });
502
+ }
503
+
504
+ const finalMemory = process.memoryUsage().heapUsed;
505
+ const memoryGrowth = (finalMemory - initialMemory) / (1024 * 1024); // MB
506
+
507
+ // Memory growth should be reasonable (< 50MB for this test)
508
+ expect(memoryGrowth).toBeLessThan(50);
509
+
510
+ console.log(`${env.name} memory growth: ${memoryGrowth.toFixed(2)}MB`);
511
+ });
512
+ });
513
+ });
514
+
515
+ describe('Edge Case Compatibility', () => {
516
+ it('should handle boundary values consistently', () => {
517
+ const boundaryTests = [
518
+ { name: 'max safe integer', value: Number.MAX_SAFE_INTEGER },
519
+ { name: 'min safe integer', value: Number.MIN_SAFE_INTEGER },
520
+ { name: 'max value', value: Number.MAX_VALUE },
521
+ { name: 'min value', value: Number.MIN_VALUE },
522
+ { name: 'positive infinity', value: Number.POSITIVE_INFINITY },
523
+ { name: 'negative infinity', value: Number.NEGATIVE_INFINITY },
524
+ { name: 'NaN', value: Number.NaN }
525
+ ];
526
+
527
+ boundaryTests.forEach(({ name, value }) => {
528
+ const testData = {
529
+ tag: 'CrossBrowserTest',
530
+ version: '1.0.0',
531
+ data: { number: value }
532
+ };
533
+
534
+ browserEnvironments.forEach(env => {
535
+ if (name.includes('infinity') || name === 'NaN') {
536
+ // JSON doesn't support these values - they become null
537
+ expect(() => {
538
+ const jsonString = env.jsonSupport.stringify(testData);
539
+ expect(jsonString).toContain('null');
540
+ }).not.toThrow();
541
+ } else {
542
+ expect(() => {
543
+ const jsonString = env.jsonSupport.stringify(testData);
544
+ const parsed = env.jsonSupport.parse(jsonString);
545
+ const result = ComponentTransformer.deserialize(parsed);
546
+
547
+ expect(React.isValidElement(result)).toBe(true);
548
+ }).not.toThrow(`${name} should work in ${env.name}`);
549
+ }
550
+ });
551
+ });
552
+ });
553
+
554
+ it('should handle string length limits consistently', () => {
555
+ const lengthTests = [
556
+ { name: 'empty string', length: 0 },
557
+ { name: 'short string', length: 10 },
558
+ { name: 'medium string', length: 1000 },
559
+ { name: 'long string', length: 10000 },
560
+ { name: 'very long string', length: 100000 }
561
+ ];
562
+
563
+ lengthTests.forEach(({ name, length }) => {
564
+ const longString = 'x'.repeat(length);
565
+ const testData = {
566
+ tag: 'CrossBrowserTest',
567
+ version: '1.0.0',
568
+ data: { text: longString }
569
+ };
570
+
571
+ browserEnvironments.forEach(env => {
572
+ expect(() => {
573
+ const jsonString = env.jsonSupport.stringify(testData);
574
+ const parsed = env.jsonSupport.parse(jsonString);
575
+ const result = ComponentTransformer.deserialize(parsed);
576
+
577
+ expect(React.isValidElement(result)).toBe(true);
578
+
579
+ const element = result as ReactElement;
580
+ expect(element.props['data-text']).toBe(longString);
581
+ }).not.toThrow(`${name} should work in ${env.name}`);
582
+ });
583
+ });
584
+ });
585
+ });
586
+ });
@@ -0,0 +1,103 @@
1
+ /**
2
+ * MockSerializableComponent - Test helper component implementing new SerializableConstructor interface
3
+ *
4
+ * NOTE: This is not a test file - it's a helper module for testing.
5
+ * Jest should not run this as a test suite.
6
+ *
7
+ * Demonstrates component self-declaration pattern with static tagName and version properties
8
+ * Used for testing the updated ComponentTransformer architecture
9
+ *
10
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
11
+ */
12
+
13
+ import React, { ReactElement } from 'react';
14
+ import { Serializable, SerializableConstructor } from '../../../schemas';
15
+
16
+ /**
17
+ * Mock component implementing the new Serializable interface with self-declaration
18
+ */
19
+ export class MockSerializableComponent implements Serializable {
20
+ static readonly tagName = 'MockComponent';
21
+ static readonly version = '1.0.0';
22
+
23
+ constructor(public props: {
24
+ title?: string;
25
+ content?: string;
26
+ variant?: string;
27
+ children?: React.ReactNode;
28
+ }) {}
29
+
30
+ static fromJson(jsonData: any): ReactElement {
31
+ return React.createElement('div', {
32
+ className: `mock-component ${jsonData.variant || 'default'}`,
33
+ 'data-testid': 'mock-component'
34
+ }, [
35
+ jsonData.title && React.createElement('h3', { key: 'title' }, jsonData.title),
36
+ jsonData.content && React.createElement('p', { key: 'content' }, jsonData.content),
37
+ jsonData.children
38
+ ].filter(Boolean));
39
+ }
40
+
41
+ toJson(): any {
42
+ return {
43
+ title: this.props.title,
44
+ content: this.props.content,
45
+ variant: this.props.variant,
46
+ children: this.props.children
47
+ };
48
+ }
49
+ }
50
+
51
+ // Type assertion to ensure it meets the interface requirements
52
+ export const MockSerializableComponentClass = MockSerializableComponent as unknown as SerializableConstructor;
53
+
54
+ /**
55
+ * Alternative mock component with different tagName and version for testing conflicts
56
+ */
57
+ export class AlternativeMockComponent implements Serializable {
58
+ static readonly tagName = 'AlternativeComponent';
59
+ static readonly version = '2.1.0';
60
+
61
+ constructor(public props: {
62
+ label?: string;
63
+ type?: string;
64
+ active?: boolean;
65
+ }) {}
66
+
67
+ static fromJson(jsonData: any): ReactElement {
68
+ return React.createElement('button', {
69
+ className: `alt-mock ${jsonData.type || 'default'}`,
70
+ 'data-active': jsonData.active,
71
+ 'data-testid': 'alternative-mock'
72
+ }, jsonData.label || 'Alternative Component');
73
+ }
74
+
75
+ toJson(): any {
76
+ return {
77
+ label: this.props.label,
78
+ type: this.props.type,
79
+ active: this.props.active
80
+ };
81
+ }
82
+ }
83
+
84
+ export const AlternativeMockComponentClass = AlternativeMockComponent as unknown as SerializableConstructor;
85
+
86
+ /**
87
+ * Mock component missing required static properties (for error testing)
88
+ */
89
+ export class InvalidMockComponent implements Serializable {
90
+ // Missing static tagName and version properties intentionally
91
+
92
+ constructor(public props: any) {}
93
+
94
+ static fromJson(jsonData: any): ReactElement {
95
+ return React.createElement('div', {}, 'Invalid Component');
96
+ }
97
+
98
+ toJson(): any {
99
+ return {};
100
+ }
101
+ }
102
+
103
+ export const InvalidMockComponentClass = InvalidMockComponent as any; // Intentionally not typed as SerializableConstructor