@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,311 @@
1
+ /**
2
+ * GridLayout Component Serialization Tests
3
+ *
4
+ * Tests for the GridLayout 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 { GridLayout } from '../../../components/layout/GridLayout';
15
+ import { GridCell } from '../../../components/layout/GridCell';
16
+ import { Text } from '../../../components/layout/../blocks/Text';
17
+ import { Button } from '../../../components/layout/../buttons/Button';
18
+
19
+ describe('GridLayout Serialization', () => {
20
+ beforeEach(() => {
21
+ // Clear component registry for clean tests
22
+ ComponentTransformer.clearRegistry();
23
+
24
+ // Register all necessary components
25
+ ComponentTransformer.registerComponent(GridLayout as any);
26
+ ComponentTransformer.registerComponent(GridCell as any);
27
+ ComponentTransformer.registerComponent(Text as any);
28
+ ComponentTransformer.registerComponent(Button as any);
29
+ });
30
+
31
+ afterEach(() => {
32
+ ComponentTransformer.clearRegistry();
33
+ });
34
+
35
+ describe('Basic Serialization', () => {
36
+ it('should serialize and deserialize basic grid layout', () => {
37
+ // Create original component
38
+ const originalComponent = (
39
+ <GridLayout
40
+ columns={3}
41
+ spacing="medium"
42
+ equalHeight={true}
43
+ >
44
+ <div>Column 1</div>
45
+ <div>Column 2</div>
46
+ <div>Column 3</div>
47
+ </GridLayout>
48
+ );
49
+
50
+ // Serialize
51
+ const serialized = ComponentTransformer.serialize(originalComponent);
52
+ expect(serialized).toBeTruthy();
53
+ expect(typeof serialized).toBe('string');
54
+
55
+ // Parse to check structure
56
+ const parsed = JSON.parse(serialized);
57
+ expect(parsed.tag).toBe('GridLayout');
58
+ expect(parsed.version).toBe('1.0.0');
59
+ expect(parsed.data.columns).toBe(3);
60
+ expect(parsed.data.spacing).toBe('medium');
61
+ expect(parsed.data.equalHeight).toBe(true);
62
+
63
+ // Children should be serialized as JSON string
64
+ expect(typeof parsed.data.children).toBe('string');
65
+ const children = JSON.parse(parsed.data.children);
66
+ expect(Array.isArray(children)).toBe(true);
67
+ expect(children).toHaveLength(3);
68
+ });
69
+
70
+ it('should serialize empty grid layout', () => {
71
+ const originalComponent = (
72
+ <GridLayout columns={2} />
73
+ );
74
+
75
+ const serialized = ComponentTransformer.serialize(originalComponent);
76
+ const parsed = JSON.parse(serialized);
77
+
78
+ expect(parsed.tag).toBe('GridLayout');
79
+ expect(parsed.data.columns).toBe(2);
80
+ expect(parsed.data.children).toBeUndefined();
81
+ });
82
+
83
+ it('should serialize grid layout with dimension props', () => {
84
+ const originalComponent = (
85
+ <GridLayout
86
+ columns={2}
87
+ height="400px"
88
+ width="100%"
89
+ maxWidth="800px"
90
+ className="custom-grid"
91
+ >
92
+ <div>Content</div>
93
+ </GridLayout>
94
+ );
95
+
96
+ const serialized = ComponentTransformer.serialize(originalComponent);
97
+ const parsed = JSON.parse(serialized);
98
+
99
+ expect(parsed.data.height).toBe('400px');
100
+ expect(parsed.data.width).toBe('100%');
101
+ expect(parsed.data.maxWidth).toBe('800px');
102
+ expect(parsed.data.className).toBe('custom-grid');
103
+ });
104
+ });
105
+
106
+ describe('Nested Component Serialization', () => {
107
+ it('should serialize grid with nested GridCell components', () => {
108
+ const originalComponent = (
109
+ <GridLayout columns={2} spacing="large">
110
+ <GridCell span={6}>
111
+ <Text content="First Cell" variant="h3" />
112
+ </GridCell>
113
+ <GridCell span={6}>
114
+ <Text content="Second Cell" variant="body1" />
115
+ </GridCell>
116
+ </GridLayout>
117
+ );
118
+
119
+ const serialized = ComponentTransformer.serialize(originalComponent);
120
+ const parsed = JSON.parse(serialized);
121
+
122
+ expect(parsed.tag).toBe('GridLayout');
123
+
124
+ // Children should be serialized as JSON string
125
+ expect(typeof parsed.data.children).toBe('string');
126
+ const children = JSON.parse(parsed.data.children);
127
+ expect(Array.isArray(children)).toBe(true);
128
+ expect(children).toHaveLength(2);
129
+
130
+ // Check that nested GridCell components are serialized
131
+ const firstChild = children[0];
132
+ expect(typeof firstChild).toBe('object');
133
+ expect(firstChild.tag).toBe('GridCell');
134
+ expect(firstChild.data.span).toBe(6);
135
+
136
+ // Check that Text components inside GridCell are serialized
137
+ expect(typeof firstChild.data.children).toBe('string');
138
+ const nestedText = JSON.parse(firstChild.data.children);
139
+ expect(nestedText.tag).toBe('Text');
140
+ expect(nestedText.data.content).toBe('First Cell');
141
+ });
142
+
143
+ it('should serialize grid with mixed nested components', () => {
144
+ const originalComponent = (
145
+ <GridLayout columns={3} spacing="medium">
146
+ <GridCell xs={12} sm={4}>
147
+ <Text content="Column 1" variant="h4" />
148
+ </GridCell>
149
+ <div>Regular div content</div>
150
+ <GridCell xs={12} sm={8}>
151
+ <Button label="Action Button" variant="primary" />
152
+ </GridCell>
153
+ </GridLayout>
154
+ );
155
+
156
+ const serialized = ComponentTransformer.serialize(originalComponent);
157
+ const parsed = JSON.parse(serialized);
158
+
159
+ // Children should be serialized as JSON string
160
+ expect(typeof parsed.data.children).toBe('string');
161
+ const children = JSON.parse(parsed.data.children);
162
+ expect(Array.isArray(children)).toBe(true);
163
+ expect(children).toHaveLength(3);
164
+
165
+ // First child is GridCell with Text
166
+ expect(children[0].tag).toBe('GridCell');
167
+ expect(children[0].data.xs).toBe(12);
168
+ expect(children[0].data.sm).toBe(4);
169
+
170
+ // Second child is regular div (serialized as react node)
171
+ expect(typeof children[1]).toBe('object');
172
+ expect(children[1].tag).toBe('__react_node__');
173
+
174
+ // Third child is GridCell with Button
175
+ expect(children[2].tag).toBe('GridCell');
176
+ const buttonChild = JSON.parse(children[2].data.children);
177
+ expect(buttonChild.tag).toBe('Button');
178
+ expect(buttonChild.data.label).toBe('Action Button');
179
+ });
180
+ });
181
+
182
+ describe('Deserialization', () => {
183
+ it('should deserialize back to working component', () => {
184
+ const originalComponent = (
185
+ <GridLayout columns={2} spacing="small" equalHeight={true}>
186
+ <GridCell span={8}>
187
+ <Text content="Main Content" />
188
+ </GridCell>
189
+ <GridCell span={4}>
190
+ <Text content="Sidebar" />
191
+ </GridCell>
192
+ </GridLayout>
193
+ );
194
+
195
+ // Serialize and deserialize
196
+ const serialized = ComponentTransformer.serialize(originalComponent);
197
+ const deserialized = ComponentTransformer.deserialize(serialized);
198
+
199
+ // Render both to compare
200
+ const { container: originalContainer } = render(originalComponent);
201
+ const { container: deserializedContainer } = render(deserialized);
202
+
203
+ // Check that both render successfully
204
+ expect(originalContainer.firstChild).toBeTruthy();
205
+ expect(deserializedContainer.firstChild).toBeTruthy();
206
+
207
+ // Both should have grid container classes
208
+ const originalGrid = originalContainer.querySelector('.MuiGrid-container');
209
+ const deserializedGrid = deserializedContainer.querySelector('.MuiGrid-container');
210
+ expect(originalGrid).toBeTruthy();
211
+ expect(deserializedGrid).toBeTruthy();
212
+ });
213
+
214
+ it('should preserve all layout properties after round-trip serialization', () => {
215
+ const originalComponent = (
216
+ <GridLayout
217
+ columns={4}
218
+ spacing="huge"
219
+ equalHeight={false}
220
+ height="300px"
221
+ minHeight="200px"
222
+ maxWidth="1200px"
223
+ className="test-grid"
224
+ >
225
+ <div>Test content</div>
226
+ </GridLayout>
227
+ );
228
+
229
+ // Double serialization to test round-trip
230
+ const serialized1 = ComponentTransformer.serialize(originalComponent);
231
+ const deserialized1 = ComponentTransformer.deserialize(serialized1);
232
+ const serialized2 = ComponentTransformer.serialize(deserialized1);
233
+ const parsed2 = JSON.parse(serialized2);
234
+
235
+ // Properties should be preserved
236
+ expect(parsed2.data.columns).toBe(4);
237
+ expect(parsed2.data.spacing).toBe('huge');
238
+ expect(parsed2.data.equalHeight).toBe(false);
239
+ expect(parsed2.data.height).toBe('300px');
240
+ expect(parsed2.data.minHeight).toBe('200px');
241
+ expect(parsed2.data.maxWidth).toBe('1200px');
242
+ expect(parsed2.data.className).toBe('test-grid');
243
+ });
244
+ });
245
+
246
+ describe('Performance', () => {
247
+ it('should serialize large grid efficiently', () => {
248
+ const gridItems = Array.from({ length: 50 }, (_, i) => (
249
+ <GridCell key={i} xs={12} sm={6} md={4} lg={3}>
250
+ <Text content={`Item ${i + 1}`} />
251
+ </GridCell>
252
+ ));
253
+
254
+ const largeGrid = (
255
+ <GridLayout columns={4} spacing="medium">
256
+ {gridItems}
257
+ </GridLayout>
258
+ );
259
+
260
+ const startTime = performance.now();
261
+ const serialized = ComponentTransformer.serialize(largeGrid);
262
+ const endTime = performance.now();
263
+
264
+ expect(serialized).toBeTruthy();
265
+ expect(endTime - startTime).toBeLessThan(100); // Should complete within 100ms
266
+
267
+ const parsed = JSON.parse(serialized);
268
+ const children = JSON.parse(parsed.data.children);
269
+ expect(children).toHaveLength(50);
270
+ });
271
+ });
272
+
273
+ describe('Error Handling', () => {
274
+ it('should handle grid with invalid children gracefully', () => {
275
+ const gridWithNullChild = (
276
+ <GridLayout columns={2}>
277
+ <div>Valid content</div>
278
+ {null}
279
+ <div>More valid content</div>
280
+ </GridLayout>
281
+ );
282
+
283
+ expect(() => {
284
+ const serialized = ComponentTransformer.serialize(gridWithNullChild);
285
+ const parsed = JSON.parse(serialized);
286
+ const children = JSON.parse(parsed.data.children);
287
+ expect(children).toHaveLength(3); // null becomes a child
288
+ }).not.toThrow();
289
+ });
290
+
291
+ it('should handle grid with complex nested structures', () => {
292
+ const complexGrid = (
293
+ <GridLayout columns={1}>
294
+ <GridCell>
295
+ <div>
296
+ <span>Complex</span>
297
+ <strong>Nested</strong>
298
+ <em>Structure</em>
299
+ </div>
300
+ </GridCell>
301
+ </GridLayout>
302
+ );
303
+
304
+ expect(() => {
305
+ const serialized = ComponentTransformer.serialize(complexGrid);
306
+ const deserialized = ComponentTransformer.deserialize(serialized);
307
+ render(deserialized);
308
+ }).not.toThrow();
309
+ });
310
+ });
311
+ });
@@ -0,0 +1,89 @@
1
+ /**
2
+ * usePrintMode Hook Tests
3
+ *
4
+ * Tests for print mode detection and management
5
+ */
6
+
7
+ import { PrintConfigSchema } from '../../schemas/PrintConfigSchema';
8
+
9
+ // Mock QwickApp context
10
+ const mockUpdateConfig = jest.fn();
11
+ jest.mock('../../contexts/QwickAppContext', () => ({
12
+ useQwickApp: () => ({
13
+ updateConfig: mockUpdateConfig,
14
+ }),
15
+ }));
16
+
17
+ describe('PrintConfig Integration', () => {
18
+ beforeEach(() => {
19
+ jest.clearAllMocks();
20
+ });
21
+
22
+ it('should merge print configurations correctly', () => {
23
+ const baseConfig = PrintConfigSchema.createWithDefaults();
24
+ const overrideConfig = {
25
+ theme: 'dark' as const,
26
+ printTitle: 'Custom Title'
27
+ };
28
+
29
+ const merged = { ...baseConfig, ...overrideConfig };
30
+
31
+ expect(merged.theme).toBe('dark');
32
+ expect(merged.palette).toBe('default'); // Should retain base value
33
+ expect(merged.hideScaffolding).toBe(true); // Should retain base value
34
+ expect(merged.printTitle).toBe('Custom Title');
35
+ });
36
+
37
+ it('should validate print config properties', async () => {
38
+ const config = {
39
+ theme: 'light' as const,
40
+ palette: 'cosmic',
41
+ hideScaffolding: true,
42
+ optimizeForMonochrome: false,
43
+ printTitle: 'Test Document'
44
+ };
45
+
46
+ const result = await PrintConfigSchema.validate(config);
47
+ expect(result.isValid).toBe(true);
48
+ expect(result.errors).toHaveLength(0);
49
+ });
50
+
51
+ it('should create proper default print configuration', () => {
52
+ const config = PrintConfigSchema.createWithDefaults();
53
+
54
+ expect(config.theme).toBe('light');
55
+ expect(config.palette).toBe('default');
56
+ expect(config.hideScaffolding).toBe(true);
57
+ expect(config.hideInteractiveElements).toBe(false);
58
+ expect(config.optimizeForMonochrome).toBe(false);
59
+ expect(config.showPrintDate).toBe(true);
60
+ });
61
+
62
+ it('should support custom print configuration values', () => {
63
+ const customConfig = {
64
+ theme: 'dark' as const,
65
+ palette: 'ocean',
66
+ hideScaffolding: false,
67
+ optimizeForMonochrome: true,
68
+ printTitle: 'Custom Print Title',
69
+ printHeader: 'Custom Header',
70
+ printFooter: 'Custom Footer'
71
+ };
72
+
73
+ const config = PrintConfigSchema.createWithDefaults(customConfig);
74
+
75
+ expect(config.theme).toBe('dark');
76
+ expect(config.palette).toBe('ocean');
77
+ expect(config.hideScaffolding).toBe(false);
78
+ expect(config.optimizeForMonochrome).toBe(true);
79
+ expect(config.printTitle).toBe('Custom Print Title');
80
+ expect(config.printHeader).toBe('Custom Header');
81
+ expect(config.printFooter).toBe('Custom Footer');
82
+ });
83
+
84
+ it('should export PrintModeState interface from usePrintMode', () => {
85
+ // This test ensures the types are properly exported
86
+ const { usePrintMode } = require('../../hooks/usePrintMode');
87
+ expect(typeof usePrintMode).toBe('function');
88
+ });
89
+ });
@@ -0,0 +1,161 @@
1
+ /**
2
+ * PageTemplate Schema Tests
3
+ *
4
+ * Tests for PageTemplateSchema functionality and validation
5
+ */
6
+
7
+ import { PageTemplateSchema } from '../../schemas/PageTemplateSchema';
8
+ import { PrintConfigSchema } from '../../schemas/PrintConfigSchema';
9
+
10
+ describe('PageTemplateSchema', () => {
11
+ it('should create a valid PageTemplateSchema instance', () => {
12
+ const pageTemplate = new PageTemplateSchema();
13
+ expect(pageTemplate).toBeInstanceOf(PageTemplateSchema);
14
+ });
15
+
16
+ it('should have correct schema metadata', () => {
17
+ const schema = PageTemplateSchema.getSchema();
18
+ expect(schema.name).toBe('PageTemplate');
19
+ expect(schema.version).toBe('1.0.0');
20
+ });
21
+
22
+ it('should inherit from ViewModel properties', async () => {
23
+ const data = {
24
+ className: 'page-template',
25
+ id: 'test-page',
26
+ 'aria-label': 'Test Page Template'
27
+ };
28
+
29
+ const result = await PageTemplateSchema.validate(data);
30
+ expect(result.isValid).toBe(true);
31
+
32
+ const pageTemplate = PageTemplateSchema.createWithDefaults(data);
33
+ expect(pageTemplate.className).toBe('page-template');
34
+ expect(pageTemplate.id).toBe('test-page');
35
+ expect(pageTemplate['aria-label']).toBe('Test Page Template');
36
+ });
37
+
38
+ it('should validate page-specific properties correctly', async () => {
39
+ const data = {
40
+ slug: 'about-us',
41
+ name: 'About Us',
42
+ description: 'Learn more about our company',
43
+ title: 'About Us | Company Name',
44
+ metaKeywords: 'about, company, information',
45
+ metaAuthor: 'Web Team',
46
+ canonicalUrl: 'https://example.com/about-us',
47
+ children: '<div>Page content here</div>',
48
+ layout: 'default',
49
+ icon: 'info',
50
+ requiresAuth: false,
51
+ requiredRoles: 'user',
52
+ showInNavigation: true,
53
+ navigationPriority: 1,
54
+ indexable: true
55
+ };
56
+
57
+ const result = await PageTemplateSchema.validate(data);
58
+ expect(result.isValid).toBe(true);
59
+ expect(result.errors).toHaveLength(0);
60
+ });
61
+
62
+ it('should create instance with page data correctly', () => {
63
+ const data = {
64
+ slug: 'contact',
65
+ name: 'Contact Us',
66
+ description: 'Get in touch with us',
67
+ title: 'Contact | Company',
68
+ layout: 'fullwidth',
69
+ showInNavigation: true,
70
+ navigationPriority: 5
71
+ };
72
+
73
+ const pageTemplate = PageTemplateSchema.createWithDefaults(data);
74
+ expect(pageTemplate.slug).toBe('contact');
75
+ expect(pageTemplate.name).toBe('Contact Us');
76
+ expect(pageTemplate.description).toBe('Get in touch with us');
77
+ expect(pageTemplate.title).toBe('Contact | Company');
78
+ expect(pageTemplate.layout).toBe('fullwidth');
79
+ expect(pageTemplate.showInNavigation).toBe(true);
80
+ expect(pageTemplate.navigationPriority).toBe(5);
81
+ });
82
+
83
+ it('should handle print configuration integration', () => {
84
+ const printConfig = PrintConfigSchema.createWithDefaults({
85
+ theme: 'dark',
86
+ palette: 'ocean',
87
+ hideScaffolding: false,
88
+ printTitle: 'Page Print Title'
89
+ });
90
+
91
+ const pageData = {
92
+ name: 'Test Page',
93
+ slug: 'test-page',
94
+ printConfig: printConfig
95
+ };
96
+
97
+ const pageTemplate = PageTemplateSchema.createWithDefaults(pageData);
98
+ expect(pageTemplate.name).toBe('Test Page');
99
+ expect(pageTemplate.slug).toBe('test-page');
100
+ expect(pageTemplate.printConfig).toBeDefined();
101
+ expect(pageTemplate.printConfig?.theme).toBe('dark');
102
+ expect(pageTemplate.printConfig?.palette).toBe('ocean');
103
+ expect(pageTemplate.printConfig?.hideScaffolding).toBe(false);
104
+ expect(pageTemplate.printConfig?.printTitle).toBe('Page Print Title');
105
+ });
106
+
107
+ it('should handle boolean default values correctly', () => {
108
+ const pageTemplate = PageTemplateSchema.createWithDefaults();
109
+
110
+ // These are the default values as specified in the schema
111
+ expect(pageTemplate.requiresAuth).toBe(false); // @Field({ defaultValue: false })
112
+ expect(pageTemplate.showInNavigation).toBe(true); // @Field({ defaultValue: true })
113
+ expect(pageTemplate.navigationPriority).toBe(0); // @Field({ defaultValue: 0 })
114
+ expect(pageTemplate.indexable).toBe(true); // @Field({ defaultValue: true })
115
+ });
116
+
117
+ it('should support comprehensive page metadata', async () => {
118
+ const comprehensiveData = {
119
+ slug: 'comprehensive-page',
120
+ name: 'Comprehensive Test Page',
121
+ description: 'A page with all possible metadata',
122
+ title: 'Complete Page | Site',
123
+ metaKeywords: 'test, comprehensive, page, metadata',
124
+ metaAuthor: 'Test Author',
125
+ canonicalUrl: 'https://example.com/comprehensive',
126
+ children: '<h1>Welcome</h1><p>This is a comprehensive test page.</p>',
127
+ layout: 'sidebar',
128
+ icon: 'star',
129
+ requiresAuth: true,
130
+ requiredRoles: 'admin,moderator',
131
+ showInNavigation: false,
132
+ navigationPriority: 10,
133
+ indexable: false,
134
+ className: 'comprehensive-page',
135
+ id: 'comp-page',
136
+ hidden: false
137
+ };
138
+
139
+ const result = await PageTemplateSchema.validate(comprehensiveData);
140
+ expect(result.isValid).toBe(true);
141
+
142
+ const pageTemplate = PageTemplateSchema.createWithDefaults(comprehensiveData);
143
+ expect(pageTemplate.slug).toBe('comprehensive-page');
144
+ expect(pageTemplate.name).toBe('Comprehensive Test Page');
145
+ expect(pageTemplate.description).toBe('A page with all possible metadata');
146
+ expect(pageTemplate.title).toBe('Complete Page | Site');
147
+ expect(pageTemplate.metaKeywords).toBe('test, comprehensive, page, metadata');
148
+ expect(pageTemplate.metaAuthor).toBe('Test Author');
149
+ expect(pageTemplate.canonicalUrl).toBe('https://example.com/comprehensive');
150
+ expect(pageTemplate.layout).toBe('sidebar');
151
+ expect(pageTemplate.icon).toBe('star');
152
+ expect(pageTemplate.requiresAuth).toBe(true);
153
+ expect(pageTemplate.requiredRoles).toBe('admin,moderator');
154
+ expect(pageTemplate.showInNavigation).toBe(false);
155
+ expect(pageTemplate.navigationPriority).toBe(10);
156
+ expect(pageTemplate.indexable).toBe(false);
157
+ expect(pageTemplate.className).toBe('comprehensive-page');
158
+ expect(pageTemplate.id).toBe('comp-page');
159
+ expect(pageTemplate.hidden).toBe(false);
160
+ });
161
+ });
@@ -0,0 +1,127 @@
1
+ /**
2
+ * PrintConfig Schema Tests
3
+ *
4
+ * Tests for PrintConfigSchema functionality and validation
5
+ */
6
+
7
+ import { PrintConfigSchema } from '../../schemas/PrintConfigSchema';
8
+
9
+ describe('PrintConfigSchema', () => {
10
+ it('should create a valid PrintConfigSchema instance', () => {
11
+ const printConfig = new PrintConfigSchema();
12
+ expect(printConfig).toBeInstanceOf(PrintConfigSchema);
13
+ });
14
+
15
+ it('should have correct schema metadata', () => {
16
+ const schema = PrintConfigSchema.getSchema();
17
+ expect(schema.name).toBe('PrintConfig');
18
+ expect(schema.version).toBe('1.0.0');
19
+ });
20
+
21
+ it('should have proper default values', () => {
22
+ const printConfig = PrintConfigSchema.createWithDefaults();
23
+ expect(printConfig.theme).toBe('light');
24
+ expect(printConfig.palette).toBe('default');
25
+ expect(printConfig.hideScaffolding).toBe(true);
26
+ expect(printConfig.hideInteractiveElements).toBe(false);
27
+ expect(printConfig.optimizeForMonochrome).toBe(false);
28
+ expect(printConfig.showPrintDate).toBe(true);
29
+ });
30
+
31
+ it('should validate theme values correctly', async () => {
32
+ const lightData = { theme: 'light' as const };
33
+ const darkData = { theme: 'dark' as const };
34
+
35
+ const lightResult = await PrintConfigSchema.validate(lightData);
36
+ const darkResult = await PrintConfigSchema.validate(darkData);
37
+
38
+ expect(lightResult.isValid).toBe(true);
39
+ expect(darkResult.isValid).toBe(true);
40
+ });
41
+
42
+ it('should validate boolean properties correctly', async () => {
43
+ const data = {
44
+ hideScaffolding: false,
45
+ hideInteractiveElements: true,
46
+ optimizeForMonochrome: true,
47
+ showPrintDate: false
48
+ };
49
+
50
+ const result = await PrintConfigSchema.validate(data);
51
+ expect(result.isValid).toBe(true);
52
+
53
+ const printConfig = PrintConfigSchema.createWithDefaults(data);
54
+ expect(printConfig.hideScaffolding).toBe(false);
55
+ expect(printConfig.hideInteractiveElements).toBe(true);
56
+ expect(printConfig.optimizeForMonochrome).toBe(true);
57
+ expect(printConfig.showPrintDate).toBe(false);
58
+ });
59
+
60
+ it('should handle optional string properties', async () => {
61
+ const data = {
62
+ printTitle: 'Custom Print Title',
63
+ printHeader: 'Custom Header',
64
+ printFooter: 'Custom Footer',
65
+ palette: 'ocean'
66
+ };
67
+
68
+ const result = await PrintConfigSchema.validate(data);
69
+ expect(result.isValid).toBe(true);
70
+
71
+ const printConfig = PrintConfigSchema.createWithDefaults(data);
72
+ expect(printConfig.printTitle).toBe('Custom Print Title');
73
+ expect(printConfig.printHeader).toBe('Custom Header');
74
+ expect(printConfig.printFooter).toBe('Custom Footer');
75
+ expect(printConfig.palette).toBe('ocean');
76
+ });
77
+
78
+ it('should create instance with data correctly', () => {
79
+ const data = {
80
+ theme: 'dark' as const,
81
+ palette: 'cosmic',
82
+ printTitle: 'Test Document',
83
+ hideScaffolding: false
84
+ };
85
+
86
+ const printConfig = PrintConfigSchema.createWithDefaults(data);
87
+ expect(printConfig.theme).toBe('dark');
88
+ expect(printConfig.palette).toBe('cosmic');
89
+ expect(printConfig.printTitle).toBe('Test Document');
90
+ expect(printConfig.hideScaffolding).toBe(false);
91
+ });
92
+
93
+ it('should restore from JSON correctly', () => {
94
+ const jsonData = {
95
+ theme: 'dark' as const,
96
+ palette: 'winter',
97
+ hideScaffolding: false,
98
+ optimizeForMonochrome: true,
99
+ printTitle: 'Restored Document',
100
+ printHeader: 'Restored Header'
101
+ };
102
+
103
+ const printConfig = PrintConfigSchema.createWithDefaults(jsonData);
104
+ expect(printConfig.theme).toBe('dark');
105
+ expect(printConfig.palette).toBe('winter');
106
+ expect(printConfig.hideScaffolding).toBe(false);
107
+ expect(printConfig.optimizeForMonochrome).toBe(true);
108
+ expect(printConfig.printTitle).toBe('Restored Document');
109
+ expect(printConfig.printHeader).toBe('Restored Header');
110
+ });
111
+
112
+ it('should merge configurations correctly', () => {
113
+ const baseConfig = new PrintConfigSchema();
114
+ baseConfig.theme = 'light';
115
+ baseConfig.palette = 'default';
116
+
117
+ const overrideData = {
118
+ theme: 'dark',
119
+ printTitle: 'Override Title'
120
+ };
121
+
122
+ const merged = { ...baseConfig, ...overrideData };
123
+ expect(merged.theme).toBe('dark');
124
+ expect(merged.palette).toBe('default'); // Should retain base value
125
+ expect(merged.printTitle).toBe('Override Title');
126
+ });
127
+ });