@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,439 @@
1
+ /**
2
+ * SelectInputField Serialization Tests
3
+ *
4
+ * Tests the serialization and deserialization functionality of the SelectInputField component.
5
+ * Ensures that dropdown options and selection state are properly preserved through JSON serialization cycles.
6
+ *
7
+ * Test Coverage:
8
+ * - Basic select field serialization/deserialization
9
+ * - Complex option arrays with value/label pairs
10
+ * - Form validation and error state handling
11
+ * - Disabled options and accessibility features
12
+ * - Performance benchmarks for option-heavy dropdowns
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 { SelectInputField } from '../../../components/input/SelectInputField';
21
+
22
+ // Ensure the component is registered
23
+ import '../../../schemas/transformers/registry';
24
+
25
+ describe('SelectInputField Serialization', () => {
26
+ // Performance tracking
27
+ const performanceData: Array<{ operation: string; duration: number }> = [];
28
+
29
+ afterAll(() => {
30
+ // Log performance summary
31
+ console.log('\n📊 SelectInputField Serialization Performance Summary:');
32
+ performanceData.forEach(({ operation, duration }) => {
33
+ console.log(` • ${operation}: ${duration.toFixed(3)}ms`);
34
+ });
35
+ const avgDuration = performanceData.reduce((sum, { duration }) => sum + duration, 0) / performanceData.length;
36
+ console.log(` • Average: ${avgDuration.toFixed(3)}ms\n`);
37
+ });
38
+
39
+ const measurePerformance = (operation: string, fn: () => void) => {
40
+ const start = performance.now();
41
+ fn();
42
+ const duration = performance.now() - start;
43
+ performanceData.push({ operation, duration });
44
+ return duration;
45
+ };
46
+
47
+ describe('Basic Select Field', () => {
48
+ it('serializes and deserializes basic select field correctly', () => {
49
+ const originalProps = {
50
+ label: 'Country',
51
+ value: 'us',
52
+ options: [
53
+ { value: 'us', label: 'United States' },
54
+ { value: 'ca', label: 'Canada' },
55
+ { value: 'uk', label: 'United Kingdom' }
56
+ ],
57
+ required: true,
58
+ placeholder: 'Select a country'
59
+ };
60
+
61
+ let serializedData: any;
62
+ let deserializedElement: React.ReactElement;
63
+ let reserializedData: any;
64
+
65
+ // Test serialization
66
+ const serializationTime = measurePerformance('Basic Serialization', () => {
67
+ const element = <SelectInputField {...originalProps} />;
68
+ const serialized = ComponentTransformer.serialize(element);
69
+ serializedData = JSON.parse(serialized);
70
+ });
71
+
72
+ expect(serializedData).toBeDefined();
73
+ expect(serializedData.tag).toBe('SelectInputField');
74
+ expect(serializedData.data.label).toBe(originalProps.label);
75
+ expect(serializedData.data.value).toBe(originalProps.value);
76
+ expect(serializedData.data.required).toBe(originalProps.required);
77
+ expect(serializedData.data.placeholder).toBe(originalProps.placeholder);
78
+ expect(serializedData.data.options).toEqual(originalProps.options);
79
+
80
+ // Test deserialization
81
+ const deserializationTime = measurePerformance('Basic Deserialization', () => {
82
+ deserializedElement = ComponentTransformer.deserialize(JSON.stringify(serializedData)) as React.ReactElement;
83
+ });
84
+
85
+ expect(React.isValidElement(deserializedElement)).toBe(true);
86
+ expect(deserializedElement.type).toBe(SelectInputField);
87
+
88
+ // Test re-serialization (round-trip)
89
+ const reserializationTime = measurePerformance('Basic Re-serialization', () => {
90
+ const reserialized = ComponentTransformer.serialize(deserializedElement);
91
+ reserializedData = JSON.parse(reserialized);
92
+ });
93
+
94
+ expect(reserializedData).toEqual(serializedData);
95
+
96
+ // Performance assertions
97
+ expect(serializationTime).toBeLessThan(1); // Should be under 1ms
98
+ expect(deserializationTime).toBeLessThan(1);
99
+ expect(reserializationTime).toBeLessThan(1);
100
+ });
101
+
102
+ it('renders serialized select field correctly', () => {
103
+ const originalProps = {
104
+ label: 'Priority Level',
105
+ value: 'high',
106
+ options: [
107
+ { value: 'low', label: 'Low Priority' },
108
+ { value: 'medium', label: 'Medium Priority' },
109
+ { value: 'high', label: 'High Priority' }
110
+ ]
111
+ };
112
+
113
+ const element = <SelectInputField {...originalProps} />;
114
+ const serialized = ComponentTransformer.serialize(element);
115
+ const serializedData = JSON.parse(serialized);
116
+ const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
117
+
118
+ const { getByText, getByDisplayValue } = render(deserializedElement);
119
+
120
+ expect(getByText('Priority Level')).toBeInTheDocument();
121
+ });
122
+ });
123
+
124
+ describe('Complex Option Arrays', () => {
125
+ it('serializes complex options with disabled states correctly', () => {
126
+ const originalProps = {
127
+ label: 'Service Plan',
128
+ value: 'pro',
129
+ options: [
130
+ { value: 'free', label: 'Free Plan', disabled: false },
131
+ { value: 'starter', label: 'Starter Plan', disabled: false },
132
+ { value: 'pro', label: 'Professional Plan', disabled: false },
133
+ { value: 'enterprise', label: 'Enterprise Plan', disabled: true }
134
+ ]
135
+ };
136
+
137
+ const element = <SelectInputField {...originalProps} />;
138
+
139
+ let serializedData: any;
140
+ measurePerformance('Complex Options Serialization', () => {
141
+ const serialized = ComponentTransformer.serialize(element);
142
+ serializedData = JSON.parse(serialized);
143
+ });
144
+
145
+ expect(serializedData.data.options).toHaveLength(4);
146
+ expect(serializedData.data.options[3].disabled).toBe(true);
147
+ expect(serializedData.data.options[0].disabled).toBe(false);
148
+
149
+ const deserializedElement = ComponentTransformer.deserialize(JSON.stringify(serializedData)) as React.ReactElement;
150
+ const reserialized = ComponentTransformer.serialize(deserializedElement);
151
+ const reserializedData = JSON.parse(reserialized);
152
+
153
+ expect(reserializedData.data.options).toEqual(originalProps.options);
154
+ });
155
+
156
+ it('handles numeric values in options correctly', () => {
157
+ const originalProps = {
158
+ label: 'Age Range',
159
+ value: 25,
160
+ options: [
161
+ { value: 18, label: '18-24 years' },
162
+ { value: 25, label: '25-34 years' },
163
+ { value: 35, label: '35-44 years' },
164
+ { value: 45, label: '45+ years' }
165
+ ]
166
+ };
167
+
168
+ const element = <SelectInputField {...originalProps} />;
169
+ const serialized = ComponentTransformer.serialize(element);
170
+ const serializedData = JSON.parse(serialized);
171
+
172
+ expect(serializedData.data.value).toBe(25);
173
+ expect(serializedData.data.options[1].value).toBe(25);
174
+
175
+ const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
176
+ const reserialized = ComponentTransformer.serialize(deserializedElement);
177
+ const reserializedData = JSON.parse(reserialized);
178
+
179
+ expect(reserializedData.data.value).toBe(25);
180
+ expect(reserializedData.data.options[1].value).toBe(25);
181
+ });
182
+ });
183
+
184
+ describe('Form Validation Properties', () => {
185
+ it('preserves validation and error state through serialization', () => {
186
+ const originalProps = {
187
+ label: 'Required Selection',
188
+ value: '',
189
+ options: [
190
+ { value: 'option1', label: 'Option 1' },
191
+ { value: 'option2', label: 'Option 2' }
192
+ ],
193
+ required: true,
194
+ error: 'Please select an option',
195
+ helperText: 'Choose from the available options'
196
+ };
197
+
198
+ const element = <SelectInputField {...originalProps} />;
199
+
200
+ let serializedData: any;
201
+ measurePerformance('Validation Serialization', () => {
202
+ const serialized = ComponentTransformer.serialize(element);
203
+ serializedData = JSON.parse(serialized);
204
+ });
205
+
206
+ expect(serializedData.data.required).toBe(true);
207
+ expect(serializedData.data.error).toBe(originalProps.error);
208
+ expect(serializedData.data.helperText).toBe(originalProps.helperText);
209
+
210
+ const deserializedElement = ComponentTransformer.deserialize(JSON.stringify(serializedData)) as React.ReactElement;
211
+ const { getByLabelText, getByText } = render(deserializedElement);
212
+
213
+ expect(getByText('Required Selection')).toBeInTheDocument();
214
+ expect(getByText('Please select an option')).toBeInTheDocument();
215
+ });
216
+
217
+ it('handles disabled select field correctly', () => {
218
+ const originalProps = {
219
+ label: 'Locked Selection',
220
+ value: 'locked',
221
+ options: [
222
+ { value: 'locked', label: 'Locked Option' },
223
+ { value: 'other', label: 'Other Option' }
224
+ ],
225
+ disabled: true,
226
+ helperText: 'This selection cannot be changed'
227
+ };
228
+
229
+ const element = <SelectInputField {...originalProps} />;
230
+ const serialized = ComponentTransformer.serialize(element);
231
+ const serializedData = JSON.parse(serialized);
232
+
233
+ expect(serializedData.data.disabled).toBe(true);
234
+
235
+ const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
236
+ const reserialized = ComponentTransformer.serialize(deserializedElement);
237
+ const reserializedData = JSON.parse(reserialized);
238
+
239
+ expect(reserializedData.data.disabled).toBe(true);
240
+ });
241
+ });
242
+
243
+ describe('Edge Cases and Error Handling', () => {
244
+ it('handles empty options array correctly', () => {
245
+ const originalProps = {
246
+ label: 'Empty Select',
247
+ value: '',
248
+ options: [],
249
+ placeholder: 'No options available'
250
+ };
251
+
252
+ const element = <SelectInputField {...originalProps} />;
253
+ const serialized = ComponentTransformer.serialize(element);
254
+ const serializedData = JSON.parse(serialized);
255
+
256
+ expect(serializedData.data.options).toEqual([]);
257
+
258
+ const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
259
+ const { getByText } = render(deserializedElement);
260
+
261
+ expect(getByText('No options provided for select field')).toBeInTheDocument();
262
+ });
263
+
264
+ it('handles special characters in option labels', () => {
265
+ const specialOptions = [
266
+ { value: 'unicode', label: 'Unicode: åäö 中文 🚀' },
267
+ { value: 'quotes', label: 'With "quotes" and \'apostrophes\'' },
268
+ { value: 'html', label: 'HTML: <div>tags</div> & entities' }
269
+ ];
270
+
271
+ const originalProps = {
272
+ label: 'Special Characters',
273
+ value: 'unicode',
274
+ options: specialOptions
275
+ };
276
+
277
+ const element = <SelectInputField {...originalProps} />;
278
+ const serialized = ComponentTransformer.serialize(element);
279
+ const serializedData = JSON.parse(serialized);
280
+
281
+ expect(serializedData.data.options).toEqual(specialOptions);
282
+
283
+ const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
284
+ const reserialized = ComponentTransformer.serialize(deserializedElement);
285
+ const reserializedData = JSON.parse(reserialized);
286
+
287
+ expect(reserializedData.data.options).toEqual(specialOptions);
288
+ });
289
+
290
+ it('handles undefined/null values gracefully', () => {
291
+ const originalProps = {
292
+ label: 'Nullable Field',
293
+ value: '',
294
+ options: [
295
+ { value: '', label: 'None' },
296
+ { value: 'some', label: 'Some Value' }
297
+ ],
298
+ placeholder: undefined,
299
+ helperText: undefined,
300
+ error: undefined
301
+ };
302
+
303
+ const element = <SelectInputField {...originalProps} />;
304
+ const serialized = ComponentTransformer.serialize(element);
305
+ const serializedData = JSON.parse(serialized);
306
+
307
+ // Undefined values should not appear in serialized data
308
+ expect(serializedData.data.placeholder).toBeUndefined();
309
+ expect(serializedData.data.helperText).toBeUndefined();
310
+ expect(serializedData.data.error).toBeUndefined();
311
+
312
+ const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
313
+ expect(React.isValidElement(deserializedElement)).toBe(true);
314
+ });
315
+ });
316
+
317
+ describe('Large Option Sets Performance', () => {
318
+ it('handles large option arrays efficiently', () => {
319
+ // Generate 1000 options
320
+ const largeOptions = Array.from({ length: 1000 }, (_, i) => ({
321
+ value: `option_${i}`,
322
+ label: `Option ${i + 1}`,
323
+ disabled: i % 100 === 99 // Every 100th option is disabled
324
+ }));
325
+
326
+ const originalProps = {
327
+ label: 'Large Select',
328
+ value: 'option_500',
329
+ options: largeOptions
330
+ };
331
+
332
+ let serializedData: any;
333
+ let deserializedElement: React.ReactElement;
334
+
335
+ // Test serialization performance with large dataset
336
+ const serializationTime = measurePerformance('Large Options Serialization (1000 items)', () => {
337
+ const element = <SelectInputField {...originalProps} />;
338
+ const serialized = ComponentTransformer.serialize(element);
339
+ serializedData = JSON.parse(serialized);
340
+ });
341
+
342
+ // Test deserialization performance
343
+ const deserializationTime = measurePerformance('Large Options Deserialization (1000 items)', () => {
344
+ deserializedElement = ComponentTransformer.deserialize(JSON.stringify(serializedData)) as React.ReactElement;
345
+ });
346
+
347
+ expect(serializedData.data.options).toHaveLength(1000);
348
+ expect(serializationTime).toBeLessThan(10); // Should handle 1000 options in under 10ms
349
+ expect(deserializationTime).toBeLessThan(10);
350
+
351
+ // Verify random sample correctness
352
+ const randomIndex = Math.floor(Math.random() * 1000);
353
+ const originalOption = largeOptions[randomIndex];
354
+ const serializedOption = serializedData.data.options[randomIndex];
355
+
356
+ expect(serializedOption.value).toBe(originalOption.value);
357
+ expect(serializedOption.label).toBe(originalOption.label);
358
+ expect(serializedOption.disabled).toBe(originalOption.disabled);
359
+ });
360
+ });
361
+
362
+ describe('Performance Benchmarks', () => {
363
+ it('meets performance targets for bulk operations', () => {
364
+ const testConfigurations = Array.from({ length: 50 }, (_, i) => ({
365
+ label: `Select Field ${i + 1}`,
366
+ value: `option_${i % 5}`,
367
+ options: Array.from({ length: 10 }, (_, j) => ({
368
+ value: `option_${j}`,
369
+ label: `Option ${j + 1}`,
370
+ disabled: j === 9
371
+ })),
372
+ required: i % 2 === 0
373
+ }));
374
+
375
+ let elements: React.ReactElement[];
376
+ let serializedData: any[];
377
+ let deserializedElements: React.ReactElement[];
378
+
379
+ // Bulk serialization
380
+ const bulkSerializationTime = measurePerformance('Bulk Serialization (50 selects)', () => {
381
+ elements = testConfigurations.map(props => <SelectInputField {...props} />);
382
+ serializedData = elements.map(element => {
383
+ const serialized = ComponentTransformer.serialize(element);
384
+ return JSON.parse(serialized);
385
+ });
386
+ });
387
+
388
+ // Bulk deserialization
389
+ const bulkDeserializationTime = measurePerformance('Bulk Deserialization (50 selects)', () => {
390
+ deserializedElements = serializedData.map(data => ComponentTransformer.deserialize(JSON.stringify(data)) as React.ReactElement);
391
+ });
392
+
393
+ expect(serializedData).toHaveLength(50);
394
+ expect(deserializedElements).toHaveLength(50);
395
+ expect(bulkSerializationTime).toBeLessThan(25); // Should handle 50 selects in under 25ms
396
+ expect(bulkDeserializationTime).toBeLessThan(25);
397
+
398
+ // Verify random sample correctness
399
+ const randomIndex = Math.floor(Math.random() * 50);
400
+ const originalConfig = testConfigurations[randomIndex];
401
+ const serializedConfig = serializedData[randomIndex];
402
+
403
+ expect(serializedConfig.data.label).toBe(originalConfig.label);
404
+ expect(serializedConfig.data.options).toEqual(originalConfig.options);
405
+ });
406
+ });
407
+
408
+ describe('Data Integrity', () => {
409
+ it('maintains referential integrity through multiple serialization cycles', () => {
410
+ const originalProps = {
411
+ label: 'Cycle Test Select',
412
+ value: 'middle',
413
+ options: [
414
+ { value: 'first', label: 'First Option' },
415
+ { value: 'middle', label: 'Middle Option' },
416
+ { value: 'last', label: 'Last Option', disabled: true }
417
+ ],
418
+ required: true
419
+ };
420
+
421
+ let currentElement = <SelectInputField {...originalProps} />;
422
+ let lastSerializedData: any;
423
+
424
+ // Perform 10 serialize-deserialize cycles
425
+ for (let cycle = 0; cycle < 10; cycle++) {
426
+ const serialized = ComponentTransformer.serialize(currentElement);
427
+ const serializedData = JSON.parse(serialized);
428
+ currentElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
429
+ lastSerializedData = serializedData;
430
+ }
431
+
432
+ // Verify data integrity after 10 cycles
433
+ expect(lastSerializedData.data.label).toBe(originalProps.label);
434
+ expect(lastSerializedData.data.value).toBe(originalProps.value);
435
+ expect(lastSerializedData.data.options).toEqual(originalProps.options);
436
+ expect(lastSerializedData.data.required).toBe(originalProps.required);
437
+ });
438
+ });
439
+ });