@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.
- package/README.md +1691 -2
- package/dist/__tests__/schemas/transformers/MockSerializableComponent.d.ts +66 -0
- package/dist/__tests__/schemas/transformers/MockSerializableComponent.d.ts.map +1 -0
- package/dist/components/ErrorBoundary.d.ts +7 -0
- package/dist/components/ErrorBoundary.d.ts.map +1 -1
- package/dist/components/Html.d.ts +28 -18
- package/dist/components/Html.d.ts.map +1 -1
- package/dist/components/Logo.d.ts +12 -35
- package/dist/components/Logo.d.ts.map +1 -1
- package/dist/components/Markdown.d.ts +18 -13
- package/dist/components/Markdown.d.ts.map +1 -1
- package/dist/components/QwickApp.d.ts +16 -3
- package/dist/components/QwickApp.d.ts.map +1 -1
- package/dist/components/QwickIcon.d.ts +23 -0
- package/dist/components/QwickIcon.d.ts.map +1 -0
- package/dist/components/SafeSpan.d.ts +12 -5
- package/dist/components/SafeSpan.d.ts.map +1 -1
- package/dist/components/Scaffold.d.ts.map +1 -1
- package/dist/components/base/ModelView.d.ts +101 -0
- package/dist/components/base/ModelView.d.ts.map +1 -0
- package/dist/components/base/index.d.ts +11 -0
- package/dist/components/base/index.d.ts.map +1 -0
- package/dist/components/blocks/Article.d.ts +12 -2
- package/dist/components/blocks/Article.d.ts.map +1 -1
- package/dist/components/blocks/Code.d.ts +13 -2
- package/dist/components/blocks/Code.d.ts.map +1 -1
- package/dist/components/blocks/CoverImageHeader.d.ts.map +1 -1
- package/dist/components/blocks/FeatureCard.d.ts.map +1 -1
- package/dist/components/blocks/FeatureGrid.d.ts.map +1 -1
- package/dist/components/blocks/Footer.d.ts.map +1 -1
- package/dist/components/blocks/HeroBlock.d.ts +27 -13
- package/dist/components/blocks/HeroBlock.d.ts.map +1 -1
- package/dist/components/blocks/Image.d.ts +41 -0
- package/dist/components/blocks/Image.d.ts.map +1 -0
- package/dist/components/blocks/PageBannerHeader.d.ts.map +1 -1
- package/dist/components/blocks/Section.d.ts +16 -2
- package/dist/components/blocks/Section.d.ts.map +1 -1
- package/dist/components/blocks/Text.d.ts +41 -0
- package/dist/components/blocks/Text.d.ts.map +1 -0
- package/dist/components/blocks/index.d.ts +4 -0
- package/dist/components/blocks/index.d.ts.map +1 -1
- package/dist/components/buttons/Button.d.ts +23 -7
- package/dist/components/buttons/Button.d.ts.map +1 -1
- package/dist/components/forms/FormBlock.d.ts +19 -13
- package/dist/components/forms/FormBlock.d.ts.map +1 -1
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/input/ChoiceInputField.d.ts +17 -11
- package/dist/components/input/ChoiceInputField.d.ts.map +1 -1
- package/dist/components/input/HtmlInputField.d.ts +17 -11
- package/dist/components/input/HtmlInputField.d.ts.map +1 -1
- package/dist/components/input/SelectInputField.d.ts +16 -10
- package/dist/components/input/SelectInputField.d.ts.map +1 -1
- package/dist/components/input/SwitchInputField.d.ts +16 -10
- package/dist/components/input/SwitchInputField.d.ts.map +1 -1
- package/dist/components/input/TextField.d.ts.map +1 -1
- package/dist/components/input/TextInputField.d.ts +16 -11
- package/dist/components/input/TextInputField.d.ts.map +1 -1
- package/dist/components/layout/GridCell.d.ts +23 -6
- package/dist/components/layout/GridCell.d.ts.map +1 -1
- package/dist/components/layout/GridLayout.d.ts +24 -23
- package/dist/components/layout/GridLayout.d.ts.map +1 -1
- package/dist/components/pages/FormPage.d.ts.map +1 -1
- package/dist/components/pages/Page.d.ts +49 -87
- package/dist/components/pages/Page.d.ts.map +1 -1
- package/dist/components/pages/index.d.ts +2 -2
- package/dist/components/pages/index.d.ts.map +1 -1
- package/dist/config/AppConfig.d.ts +49 -0
- package/dist/config/AppConfig.d.ts.map +1 -0
- package/dist/config/AppConfigBuilder.d.ts +75 -0
- package/dist/config/AppConfigBuilder.d.ts.map +1 -0
- package/dist/config/index.d.ts +13 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/types.d.ts +130 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.esm.js +451 -0
- package/dist/config.js +455 -0
- package/dist/contexts/PrintModeContext.d.ts +27 -0
- package/dist/contexts/PrintModeContext.d.ts.map +1 -0
- package/dist/contexts/QwickAppContext.d.ts +2 -2
- package/dist/contexts/QwickAppContext.d.ts.map +1 -1
- package/dist/contexts/index.d.ts +2 -0
- package/dist/contexts/index.d.ts.map +1 -1
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/usePrintMode.d.ts +39 -0
- package/dist/hooks/usePrintMode.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.js +10951 -6238
- package/dist/index.js +11014 -6287
- package/dist/schemas/CodeSchema.d.ts +2 -1
- package/dist/schemas/CodeSchema.d.ts.map +1 -1
- package/dist/schemas/CollapsibleLayoutSchema.d.ts +2 -1
- package/dist/schemas/CollapsibleLayoutSchema.d.ts.map +1 -1
- package/dist/schemas/ContentSchema.d.ts +2 -1
- package/dist/schemas/ContentSchema.d.ts.map +1 -1
- package/dist/schemas/GridCellSchema.d.ts +25 -0
- package/dist/schemas/GridCellSchema.d.ts.map +1 -0
- package/dist/schemas/GridLayoutSchema.d.ts +23 -0
- package/dist/schemas/GridLayoutSchema.d.ts.map +1 -0
- package/dist/schemas/HtmlSchema.d.ts +14 -0
- package/dist/schemas/HtmlSchema.d.ts.map +1 -0
- package/dist/schemas/ImageSchema.d.ts +32 -0
- package/dist/schemas/ImageSchema.d.ts.map +1 -0
- package/dist/schemas/LogoSchema.d.ts +35 -0
- package/dist/schemas/LogoSchema.d.ts.map +1 -0
- package/dist/schemas/MarkdownSchema.d.ts +14 -0
- package/dist/schemas/MarkdownSchema.d.ts.map +1 -0
- package/dist/schemas/PageTemplateSchema.d.ts +31 -0
- package/dist/schemas/PageTemplateSchema.d.ts.map +1 -0
- package/dist/schemas/PrintConfigSchema.d.ts +31 -0
- package/dist/schemas/PrintConfigSchema.d.ts.map +1 -0
- package/dist/schemas/SectionSchema.d.ts +2 -1
- package/dist/schemas/SectionSchema.d.ts.map +1 -1
- package/dist/schemas/TextSchema.d.ts +37 -0
- package/dist/schemas/TextSchema.d.ts.map +1 -0
- package/dist/schemas/ViewModelSchema.d.ts +23 -0
- package/dist/schemas/ViewModelSchema.d.ts.map +1 -0
- package/dist/schemas/index.d.ts +15 -1
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/transformers/ComponentTransformer.d.ts +116 -0
- package/dist/schemas/transformers/ComponentTransformer.d.ts.map +1 -0
- package/dist/schemas/transformers/ReactNodeTransformer.d.ts +53 -0
- package/dist/schemas/transformers/ReactNodeTransformer.d.ts.map +1 -0
- package/dist/schemas/transformers/__tests__/MockSerializableComponent.d.ts +66 -0
- package/dist/schemas/transformers/__tests__/MockSerializableComponent.d.ts.map +1 -0
- package/dist/schemas/transformers/registry.d.ts +15 -0
- package/dist/schemas/transformers/registry.d.ts.map +1 -0
- package/dist/schemas/types/Serializable.d.ts +46 -0
- package/dist/schemas/types/Serializable.d.ts.map +1 -0
- package/dist/utils/htmlTransform.d.ts.map +1 -1
- package/dist/utils/reactUtils.d.ts +12 -3
- package/dist/utils/reactUtils.d.ts.map +1 -1
- package/package.json +17 -3
- package/src/{components/__tests__ → __tests__/components}/AccessibilityProvider.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Article.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Breadcrumbs.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Button.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/CardListGrid.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/ChoiceInputField.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Code.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Content.integration.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Content.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/CoverImageHeader.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/ErrorBoundary.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/FeatureCard.integration.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/FeatureGrid.integration.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/FeatureGrid.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/Footer.test.tsx +4 -4
- package/src/{components/__tests__ → __tests__/components}/FormBlock.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/HeroBlock.integration.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/HeroBlock.test.tsx +233 -7
- package/src/{components/__tests__ → __tests__/components}/Html.test.tsx +11 -2
- package/src/{components/__tests__ → __tests__/components}/HtmlInputField.test.tsx +3 -3
- package/src/__tests__/components/Logo.test.js +3 -3
- package/src/{components/__tests__ → __tests__/components}/Markdown.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/PageBannerHeader.test.tsx +3 -3
- package/src/{components/__tests__ → __tests__/components}/PaletteSwitcher.test.tsx +3 -3
- package/src/{components/__tests__ → __tests__/components}/ProductCard.test.tsx +4 -4
- package/src/{components/__tests__ → __tests__/components}/SafeSpan.integration.test.tsx +2 -2
- package/src/{components/__tests__ → __tests__/components}/SafeSpan.simple.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/SafeSpan.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Section.integration.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/Section.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/SelectInputField.test.tsx +1 -1
- package/src/{components/__tests__ → __tests__/components}/TextInputField.test.tsx +3 -3
- package/src/{components/__tests__ → __tests__/components}/ThemeSwitcher.test.tsx +3 -3
- package/src/__tests__/components/base/ModelView.test.tsx +220 -0
- package/src/__tests__/components/blocks/Code.performance.test.tsx +625 -0
- package/src/__tests__/components/blocks/Code.serialization.test.tsx +507 -0
- package/src/__tests__/components/blocks/HeroBlock.serialization.test.tsx +414 -0
- package/src/__tests__/components/blocks/Image.serialization.test.tsx +257 -0
- package/src/__tests__/components/blocks/Section.serialization.test.tsx +553 -0
- package/src/__tests__/components/blocks/Text.performance.test.tsx +442 -0
- package/src/__tests__/components/blocks/Text.serialization.test.tsx +491 -0
- package/src/__tests__/components/buttons/Button.serialization.test.tsx +443 -0
- package/src/__tests__/components/input/FormComponents.serialization.test.tsx +482 -0
- package/src/__tests__/components/input/SelectInputField.serialization.test.tsx +439 -0
- package/src/__tests__/components/input/TextInputField.serialization.test.tsx +359 -0
- package/src/{components/layout/CollapsibleLayout/__tests__ → __tests__/components/layout}/CollapsibleLayout.test.tsx +4 -4
- package/src/__tests__/components/layout/GridCell.serialization.test.tsx +403 -0
- package/src/__tests__/components/layout/GridLayout.serialization.test.tsx +311 -0
- package/src/__tests__/hooks/usePrintMode.test.ts +89 -0
- package/src/__tests__/schemas/PageTemplateSchema.test.ts +161 -0
- package/src/__tests__/schemas/PrintConfigSchema.test.ts +127 -0
- package/src/__tests__/schemas/ViewModelSchema.test.ts +80 -0
- package/src/__tests__/schemas/transformers/ComponentSerializationPatterns.test.tsx +602 -0
- package/src/__tests__/schemas/transformers/ComponentTransformer.htmlPatterns.test.ts +301 -0
- package/src/__tests__/schemas/transformers/ComponentTransformer.test.ts +521 -0
- package/src/__tests__/schemas/transformers/CrossBrowserCompatibility.test.ts +586 -0
- package/src/__tests__/schemas/transformers/MockSerializableComponent.ts +103 -0
- package/src/__tests__/schemas/transformers/RealWorldScenarios.test.tsx +1165 -0
- package/src/__tests__/schemas/transformers/SerializationErrorHandling.test.ts +602 -0
- package/src/__tests__/schemas/transformers/SerializationIntegration.test.tsx +691 -0
- package/src/__tests__/schemas/transformers/SerializationPerformance.test.ts +460 -0
- package/src/__tests__/schemas/transformers/TestAutomation.test.ts +597 -0
- package/src/{utils/__tests__ → __tests__/utils}/nested-dom-fix.test.tsx +1 -1
- package/src/components/ErrorBoundary.tsx +8 -8
- package/src/components/Html.tsx +147 -44
- package/src/components/Logo.tsx +198 -100
- package/src/components/Markdown.tsx +125 -16
- package/src/components/QwickApp.tsx +64 -31
- package/src/components/QwickIcon.tsx +59 -0
- package/src/components/SafeSpan.tsx +65 -10
- package/src/components/Scaffold.tsx +2 -8
- package/src/components/base/ModelView.tsx +199 -0
- package/src/components/base/index.ts +11 -0
- package/src/components/blocks/Article.tsx +57 -18
- package/src/components/blocks/Code.md +529 -0
- package/src/components/blocks/Code.tsx +102 -15
- package/src/components/blocks/CoverImageHeader.tsx +9 -4
- package/src/components/blocks/FeatureCard.tsx +1 -2
- package/src/components/blocks/FeatureGrid.tsx +19 -1
- package/src/components/blocks/Footer.tsx +13 -1
- package/src/components/blocks/HeroBlock.tsx +87 -20
- package/src/components/blocks/Image.tsx +395 -0
- package/src/components/blocks/PageBannerHeader.tsx +14 -12
- package/src/components/blocks/ProductCard.tsx +1 -1
- package/src/components/blocks/Section.tsx +113 -8
- package/src/components/blocks/Text.tsx +285 -0
- package/src/components/blocks/index.ts +4 -0
- package/src/components/buttons/Button.tsx +184 -15
- package/src/components/forms/FormBlock.tsx +70 -17
- package/src/components/index.ts +5 -0
- package/src/components/input/ChoiceInputField.tsx +48 -18
- package/src/components/input/HtmlInputField.tsx +48 -18
- package/src/components/input/SelectInputField.tsx +48 -16
- package/src/components/input/SwitchInputField.tsx +48 -17
- package/src/components/input/TextField.tsx +41 -1
- package/src/components/input/TextInputField.tsx +52 -18
- package/src/components/layout/GridCell.tsx +118 -9
- package/src/components/layout/GridLayout.tsx +125 -24
- package/src/components/pages/FormPage.tsx +0 -1
- package/src/components/pages/Page.css +304 -332
- package/src/components/pages/Page.tsx +307 -255
- package/src/components/pages/index.ts +2 -2
- package/src/config/AppConfig.ts +133 -0
- package/src/config/AppConfigBuilder.ts +421 -0
- package/src/config/__tests__/AppConfig.test.ts +385 -0
- package/src/config/__tests__/AppConfigBuilder.test.ts +432 -0
- package/src/config/index.ts +24 -0
- package/src/config/types.ts +170 -0
- package/src/config.ts +25 -0
- package/src/contexts/PrintModeContext.tsx +332 -0
- package/src/contexts/QwickAppContext.tsx +2 -2
- package/src/contexts/index.ts +2 -0
- package/src/hooks/index.ts +5 -1
- package/src/hooks/usePrintMode.ts +73 -0
- package/src/index.ts +3 -0
- package/src/schemas/CodeSchema.ts +3 -3
- package/src/schemas/CollapsibleLayoutSchema.ts +2 -1
- package/src/schemas/ContentSchema.ts +2 -1
- package/src/schemas/GridCellSchema.ts +164 -0
- package/src/schemas/GridLayoutSchema.ts +133 -0
- package/src/schemas/HtmlSchema.ts +47 -0
- package/src/schemas/ImageSchema.ts +235 -0
- package/src/schemas/LogoSchema.ts +241 -0
- package/src/schemas/MarkdownSchema.ts +47 -0
- package/src/schemas/PageTemplateSchema.ts +186 -0
- package/src/schemas/PrintConfigSchema.ts +207 -0
- package/src/schemas/README.md +661 -0
- package/src/schemas/SectionSchema.ts +2 -1
- package/src/schemas/TextSchema.ts +329 -0
- package/src/schemas/ViewModelSchema.ts +115 -0
- package/src/schemas/index.ts +21 -2
- package/src/schemas/transformers/ComponentTransformer.ts +403 -0
- package/src/schemas/transformers/ReactNodeTransformer.ts +236 -0
- package/src/schemas/transformers/registry.ts +72 -0
- package/src/schemas/types/Serializable.ts +51 -0
- package/src/stories/AccessibilityProvider.stories.tsx +253 -253
- package/src/stories/Article.stories.tsx +433 -433
- package/src/stories/Button.stories.tsx +1 -1
- package/src/stories/CardListGrid.stories.tsx +451 -451
- package/src/stories/ChoiceInputField.stories.tsx +503 -503
- package/src/stories/Code.stories.tsx +1 -1
- package/src/stories/CollapsibleLayout.stories.tsx +1414 -1414
- package/src/stories/Content.stories.tsx +393 -393
- package/src/stories/CoverImageHeader.stories.tsx +701 -701
- package/src/stories/DataBinding.advanced.stories.tsx +432 -432
- package/src/stories/DataProvider.stories.tsx +1192 -1192
- package/src/stories/FeatureCard.stories.tsx +557 -557
- package/src/stories/FeatureGrid.stories.tsx +594 -594
- package/src/stories/Footer.stories.tsx +640 -640
- package/src/stories/FormBlock.stories.tsx +760 -760
- package/src/stories/FormComponents.stories.tsx +349 -541
- package/src/stories/GridCell.stories.tsx +417 -0
- package/src/stories/GridLayout.stories.tsx +353 -0
- package/src/stories/HeroBlock.stories.tsx +862 -373
- package/src/stories/HtmlInputField.stories.tsx +474 -474
- package/src/stories/Image.stories.tsx +819 -0
- package/src/stories/Introduction.stories.tsx +667 -667
- package/src/stories/LayoutBlocks.stories.tsx +324 -324
- package/src/stories/Logo.stories.tsx +165 -6
- package/src/stories/Markdown.stories.tsx +137 -137
- package/src/stories/ModelView.stories.tsx +477 -0
- package/src/stories/Page.stories.tsx +688 -688
- package/src/stories/PageBannerHeader.stories.tsx +864 -864
- package/src/stories/PaletteSwitcher.stories.tsx +119 -119
- package/src/stories/ProductCard.stories.tsx +424 -424
- package/src/stories/QwickApp.stories.tsx +368 -368
- package/src/stories/ResponsiveMenu.stories.tsx +249 -249
- package/src/stories/SafeSpan.stories.tsx +531 -531
- package/src/stories/Section.stories.tsx +90 -2
- package/src/stories/SelectInputField.stories.tsx +524 -524
- package/src/stories/Text.stories.tsx +560 -0
- package/src/stories/TextInputField.stories.tsx +443 -443
- package/src/stories/ThemeSwitcher.stories.tsx +123 -123
- package/src/utils/htmlTransform.tsx +74 -53
- package/src/utils/reactUtils.tsx +57 -6
- package/dist/index.bundled.css +0 -12
- /package/src/{hooks/__tests__ → __tests__/hooks}/useDataBinding.test.tsx.disabled +0 -0
- /package/src/{schemas/__tests__ → __tests__/schemas}/builders.test.ts +0 -0
- /package/src/{utils/__tests__ → __tests__/utils}/createDataDrivenComponent.test.tsx.disabled +0 -0
- /package/src/{utils/__tests__ → __tests__/utils}/htmlTransform.test.tsx +0 -0
- /package/src/{utils/__tests__ → __tests__/utils}/optional-logging.test.ts +0 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TextInputField Serialization Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests the serialization and deserialization functionality of the TextInputField component.
|
|
5
|
+
* Ensures that all component properties are properly preserved through JSON serialization cycles.
|
|
6
|
+
*
|
|
7
|
+
* Test Coverage:
|
|
8
|
+
* - Basic text input serialization/deserialization
|
|
9
|
+
* - Multiline textarea field handling
|
|
10
|
+
* - Form validation properties (required, error, helperText)
|
|
11
|
+
* - Input type variations (text, email, password, etc.)
|
|
12
|
+
* - Performance benchmarks for serialization operations
|
|
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 '@testing-library/jest-dom';
|
|
20
|
+
import { ComponentTransformer } from '../../../schemas/transformers/ComponentTransformer';
|
|
21
|
+
import { TextInputField } from '../../../components/input/TextInputField';
|
|
22
|
+
|
|
23
|
+
// Ensure the component is registered
|
|
24
|
+
import '../../../schemas/transformers/registry';
|
|
25
|
+
|
|
26
|
+
describe('TextInputField Serialization', () => {
|
|
27
|
+
// Performance tracking
|
|
28
|
+
const performanceData: Array<{ operation: string; duration: number }> = [];
|
|
29
|
+
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
// Clear component registry for clean tests
|
|
32
|
+
ComponentTransformer.clearRegistry();
|
|
33
|
+
|
|
34
|
+
// Register TextInputField component
|
|
35
|
+
ComponentTransformer.registerComponent(TextInputField as any);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
afterEach(() => {
|
|
39
|
+
ComponentTransformer.clearRegistry();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
afterAll(() => {
|
|
43
|
+
// Log performance summary
|
|
44
|
+
console.log('\n📊 TextInputField Serialization Performance Summary:');
|
|
45
|
+
performanceData.forEach(({ operation, duration }) => {
|
|
46
|
+
console.log(` • ${operation}: ${duration.toFixed(3)}ms`);
|
|
47
|
+
});
|
|
48
|
+
const avgDuration = performanceData.reduce((sum, { duration }) => sum + duration, 0) / performanceData.length;
|
|
49
|
+
console.log(` • Average: ${avgDuration.toFixed(3)}ms\n`);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const measurePerformance = (operation: string, fn: () => void) => {
|
|
53
|
+
const start = performance.now();
|
|
54
|
+
fn();
|
|
55
|
+
const duration = performance.now() - start;
|
|
56
|
+
performanceData.push({ operation, duration });
|
|
57
|
+
return duration;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
describe('Basic Text Input Field', () => {
|
|
61
|
+
it('serializes and deserializes basic text input correctly', () => {
|
|
62
|
+
const originalProps = {
|
|
63
|
+
label: 'Full Name',
|
|
64
|
+
value: 'John Doe',
|
|
65
|
+
placeholder: 'Enter your full name',
|
|
66
|
+
required: true,
|
|
67
|
+
disabled: false,
|
|
68
|
+
type: 'text'
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
let serializedData: any;
|
|
72
|
+
let deserializedElement: React.ReactElement;
|
|
73
|
+
let reserializedData: any;
|
|
74
|
+
|
|
75
|
+
// Test serialization
|
|
76
|
+
const serializationTime = measurePerformance('Basic Serialization', () => {
|
|
77
|
+
const element = <TextInputField {...originalProps} />;
|
|
78
|
+
const serialized = ComponentTransformer.serialize(element);
|
|
79
|
+
serializedData = JSON.parse(serialized);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
expect(serializedData).toBeDefined();
|
|
83
|
+
expect(serializedData.tag).toBe('TextInputField');
|
|
84
|
+
expect(serializedData.data.label).toBe(originalProps.label);
|
|
85
|
+
expect(serializedData.data.value).toBe(originalProps.value);
|
|
86
|
+
expect(serializedData.data.placeholder).toBe(originalProps.placeholder);
|
|
87
|
+
expect(serializedData.data.required).toBe(originalProps.required);
|
|
88
|
+
expect(serializedData.data.disabled).toBe(originalProps.disabled);
|
|
89
|
+
expect(serializedData.data.type).toBe(originalProps.type);
|
|
90
|
+
|
|
91
|
+
// Test deserialization
|
|
92
|
+
const deserializationTime = measurePerformance('Basic Deserialization', () => {
|
|
93
|
+
deserializedElement = ComponentTransformer.deserialize(JSON.stringify(serializedData)) as React.ReactElement;
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
expect(React.isValidElement(deserializedElement)).toBe(true);
|
|
97
|
+
expect(deserializedElement.type).toBe(TextInputField);
|
|
98
|
+
|
|
99
|
+
// Test re-serialization (round-trip)
|
|
100
|
+
const reserializationTime = measurePerformance('Basic Re-serialization', () => {
|
|
101
|
+
const reserialized = ComponentTransformer.serialize(deserializedElement);
|
|
102
|
+
reserializedData = JSON.parse(reserialized);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
expect(reserializedData.data).toEqual(serializedData.data);
|
|
106
|
+
|
|
107
|
+
// Performance assertions
|
|
108
|
+
expect(serializationTime).toBeLessThan(1); // Should be under 1ms
|
|
109
|
+
expect(deserializationTime).toBeLessThan(1);
|
|
110
|
+
expect(reserializationTime).toBeLessThan(1);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('renders serialized component correctly', () => {
|
|
114
|
+
const originalProps = {
|
|
115
|
+
label: 'Email Address',
|
|
116
|
+
value: 'user@example.com',
|
|
117
|
+
type: 'email',
|
|
118
|
+
required: true
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const element = <TextInputField {...originalProps} />;
|
|
122
|
+
const serialized = ComponentTransformer.serialize(element);
|
|
123
|
+
const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
|
|
124
|
+
|
|
125
|
+
const { getByDisplayValue, getByLabelText } = render(deserializedElement);
|
|
126
|
+
|
|
127
|
+
expect(getByLabelText('Email Address *')).toBeInTheDocument();
|
|
128
|
+
expect(getByDisplayValue('user@example.com')).toBeInTheDocument();
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe('Multiline Textarea Field', () => {
|
|
133
|
+
it('serializes multiline textarea properties correctly', () => {
|
|
134
|
+
const originalProps = {
|
|
135
|
+
label: 'Description',
|
|
136
|
+
value: 'This is a multi-line\ndescription with\nline breaks.',
|
|
137
|
+
multiline: true,
|
|
138
|
+
rows: 4,
|
|
139
|
+
maxRows: 8,
|
|
140
|
+
placeholder: 'Enter your description...'
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const element = <TextInputField {...originalProps} />;
|
|
144
|
+
|
|
145
|
+
let serializedData: any;
|
|
146
|
+
measurePerformance('Multiline Serialization', () => {
|
|
147
|
+
const serialized = ComponentTransformer.serialize(element);
|
|
148
|
+
serializedData = JSON.parse(serialized);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
expect(serializedData.data.multiline).toBe(true);
|
|
152
|
+
expect(serializedData.data.rows).toBe(4);
|
|
153
|
+
expect(serializedData.data.maxRows).toBe(8);
|
|
154
|
+
expect(serializedData.data.value).toBe(originalProps.value);
|
|
155
|
+
|
|
156
|
+
const deserializedElement = ComponentTransformer.deserialize(JSON.stringify(serializedData)) as React.ReactElement;
|
|
157
|
+
const reserializedString = ComponentTransformer.serialize(deserializedElement);
|
|
158
|
+
const reserializedData = JSON.parse(reserializedString);
|
|
159
|
+
|
|
160
|
+
expect(reserializedData.data.multiline).toBe(true);
|
|
161
|
+
expect(reserializedData.data.rows).toBe(4);
|
|
162
|
+
expect(reserializedData.data.maxRows).toBe(8);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe('Form Validation Properties', () => {
|
|
167
|
+
it('preserves validation and error state through serialization', () => {
|
|
168
|
+
const originalProps = {
|
|
169
|
+
label: 'Username',
|
|
170
|
+
value: 'invalid-username!',
|
|
171
|
+
required: true,
|
|
172
|
+
error: 'Username can only contain letters and numbers',
|
|
173
|
+
helperText: 'Choose a unique username'
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const element = <TextInputField {...originalProps} />;
|
|
177
|
+
|
|
178
|
+
let serializedData: any;
|
|
179
|
+
measurePerformance('Validation Serialization', () => {
|
|
180
|
+
const serialized = ComponentTransformer.serialize(element);
|
|
181
|
+
serializedData = JSON.parse(serialized);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
expect(serializedData.data.required).toBe(true);
|
|
185
|
+
expect(serializedData.data.error).toBe(originalProps.error);
|
|
186
|
+
expect(serializedData.data.helperText).toBe(originalProps.helperText);
|
|
187
|
+
|
|
188
|
+
const deserializedElement = ComponentTransformer.deserialize(JSON.stringify(serializedData)) as React.ReactElement;
|
|
189
|
+
const { getByLabelText, getByText } = render(deserializedElement);
|
|
190
|
+
|
|
191
|
+
expect(getByLabelText('Username *')).toBeInTheDocument();
|
|
192
|
+
expect(getByText('Username can only contain letters and numbers')).toBeInTheDocument();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('handles disabled state correctly', () => {
|
|
196
|
+
const originalProps = {
|
|
197
|
+
label: 'Locked Field',
|
|
198
|
+
value: 'Cannot be changed',
|
|
199
|
+
disabled: true,
|
|
200
|
+
helperText: 'This field is read-only'
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const element = <TextInputField {...originalProps} />;
|
|
204
|
+
const serialized = ComponentTransformer.serialize(element);
|
|
205
|
+
const serializedData = JSON.parse(serialized);
|
|
206
|
+
|
|
207
|
+
expect(serializedData.data.disabled).toBe(true);
|
|
208
|
+
|
|
209
|
+
const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
|
|
210
|
+
const { getByDisplayValue } = render(deserializedElement);
|
|
211
|
+
|
|
212
|
+
const inputElement = getByDisplayValue('Cannot be changed') as HTMLInputElement;
|
|
213
|
+
expect(inputElement.disabled).toBe(true);
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
describe('Input Type Variations', () => {
|
|
218
|
+
const inputTypes = ['text', 'email', 'password', 'number', 'tel', 'url'];
|
|
219
|
+
|
|
220
|
+
inputTypes.forEach(inputType => {
|
|
221
|
+
it(`serializes ${inputType} input type correctly`, () => {
|
|
222
|
+
const originalProps = {
|
|
223
|
+
label: `${inputType.charAt(0).toUpperCase() + inputType.slice(1)} Field`,
|
|
224
|
+
value: inputType === 'number' ? '42' : `sample-${inputType}`,
|
|
225
|
+
type: inputType,
|
|
226
|
+
placeholder: `Enter ${inputType}`
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const element = <TextInputField {...originalProps} />;
|
|
230
|
+
const serialized = ComponentTransformer.serialize(element);
|
|
231
|
+
const serializedData = JSON.parse(serialized);
|
|
232
|
+
|
|
233
|
+
expect(serializedData.data.type).toBe(inputType);
|
|
234
|
+
|
|
235
|
+
const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
|
|
236
|
+
const reserializedString = ComponentTransformer.serialize(deserializedElement);
|
|
237
|
+
const reserializedData = JSON.parse(reserializedString);
|
|
238
|
+
|
|
239
|
+
expect(reserializedData.data.type).toBe(inputType);
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
describe('Edge Cases and Error Handling', () => {
|
|
245
|
+
it('handles empty/undefined values correctly', () => {
|
|
246
|
+
const originalProps = {
|
|
247
|
+
label: 'Optional Field',
|
|
248
|
+
value: '',
|
|
249
|
+
placeholder: undefined,
|
|
250
|
+
helperText: undefined,
|
|
251
|
+
error: undefined
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
const element = <TextInputField {...originalProps} />;
|
|
255
|
+
const serialized = ComponentTransformer.serialize(element);
|
|
256
|
+
const serializedData = JSON.parse(serialized);
|
|
257
|
+
|
|
258
|
+
expect(serializedData.data.value).toBe('');
|
|
259
|
+
// Undefined values should not appear in serialized data
|
|
260
|
+
expect(serializedData.data.placeholder).toBeUndefined();
|
|
261
|
+
expect(serializedData.data.helperText).toBeUndefined();
|
|
262
|
+
expect(serializedData.data.error).toBeUndefined();
|
|
263
|
+
|
|
264
|
+
const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
|
|
265
|
+
expect(React.isValidElement(deserializedElement)).toBe(true);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('handles special characters in text values', () => {
|
|
269
|
+
const specialText = 'Special chars: åäö 中文 🚀 "quotes" <tags> & symbols!';
|
|
270
|
+
const originalProps = {
|
|
271
|
+
label: 'Unicode Test',
|
|
272
|
+
value: specialText,
|
|
273
|
+
placeholder: 'Special chars: åäö 中文 🚀'
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const element = <TextInputField {...originalProps} />;
|
|
277
|
+
const serialized = ComponentTransformer.serialize(element);
|
|
278
|
+
const serializedData = JSON.parse(serialized);
|
|
279
|
+
|
|
280
|
+
expect(serializedData.data.value).toBe(specialText);
|
|
281
|
+
|
|
282
|
+
const deserializedElement = ComponentTransformer.deserialize(serialized) as React.ReactElement;
|
|
283
|
+
const { getByDisplayValue } = render(deserializedElement);
|
|
284
|
+
|
|
285
|
+
expect(getByDisplayValue(specialText)).toBeInTheDocument();
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
describe('Performance Benchmarks', () => {
|
|
290
|
+
it('meets performance targets for bulk operations', () => {
|
|
291
|
+
const testConfigurations = Array.from({ length: 100 }, (_, i) => ({
|
|
292
|
+
label: `Field ${i + 1}`,
|
|
293
|
+
value: `Value ${i + 1}`,
|
|
294
|
+
type: ['text', 'email', 'password'][i % 3],
|
|
295
|
+
required: i % 2 === 0,
|
|
296
|
+
multiline: i % 5 === 0,
|
|
297
|
+
rows: i % 5 === 0 ? 3 : undefined
|
|
298
|
+
}));
|
|
299
|
+
|
|
300
|
+
let elements: React.ReactElement[];
|
|
301
|
+
let serializedData: any[];
|
|
302
|
+
let deserializedElements: React.ReactElement[];
|
|
303
|
+
|
|
304
|
+
// Bulk serialization
|
|
305
|
+
const bulkSerializationTime = measurePerformance('Bulk Serialization (100 items)', () => {
|
|
306
|
+
elements = testConfigurations.map(props => <TextInputField {...props} />);
|
|
307
|
+
serializedData = elements.map(element => JSON.parse(ComponentTransformer.serialize(element)));
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// Bulk deserialization
|
|
311
|
+
const bulkDeserializationTime = measurePerformance('Bulk Deserialization (100 items)', () => {
|
|
312
|
+
deserializedElements = serializedData.map(data => ComponentTransformer.deserialize(JSON.stringify(data)) as React.ReactElement);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
expect(serializedData).toHaveLength(100);
|
|
316
|
+
expect(deserializedElements).toHaveLength(100);
|
|
317
|
+
expect(bulkSerializationTime).toBeLessThan(50); // Should handle 100 items in under 50ms
|
|
318
|
+
expect(bulkDeserializationTime).toBeLessThan(50);
|
|
319
|
+
|
|
320
|
+
// Verify random sample correctness
|
|
321
|
+
const randomIndex = Math.floor(Math.random() * 100);
|
|
322
|
+
const originalConfig = testConfigurations[randomIndex];
|
|
323
|
+
const serializedConfig = serializedData[randomIndex];
|
|
324
|
+
|
|
325
|
+
expect(serializedConfig.data.label).toBe(originalConfig.label);
|
|
326
|
+
expect(serializedConfig.data.value).toBe(originalConfig.value);
|
|
327
|
+
expect(serializedConfig.data.type).toBe(originalConfig.type);
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
describe('Data Integrity', () => {
|
|
332
|
+
it('maintains referential integrity through multiple serialization cycles', () => {
|
|
333
|
+
const originalProps = {
|
|
334
|
+
label: 'Cycle Test Field',
|
|
335
|
+
value: 'Original Value',
|
|
336
|
+
required: true,
|
|
337
|
+
multiline: true,
|
|
338
|
+
rows: 5
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
let currentElement = <TextInputField {...originalProps} />;
|
|
342
|
+
let lastSerializedData: any;
|
|
343
|
+
|
|
344
|
+
// Perform 10 serialize-deserialize cycles
|
|
345
|
+
for (let cycle = 0; cycle < 10; cycle++) {
|
|
346
|
+
const serializedString = ComponentTransformer.serialize(currentElement);
|
|
347
|
+
lastSerializedData = JSON.parse(serializedString);
|
|
348
|
+
currentElement = ComponentTransformer.deserialize(serializedString) as React.ReactElement;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Verify data integrity after 10 cycles
|
|
352
|
+
expect(lastSerializedData.data.label).toBe(originalProps.label);
|
|
353
|
+
expect(lastSerializedData.data.value).toBe(originalProps.value);
|
|
354
|
+
expect(lastSerializedData.data.required).toBe(originalProps.required);
|
|
355
|
+
expect(lastSerializedData.data.multiline).toBe(originalProps.multiline);
|
|
356
|
+
expect(lastSerializedData.data.rows).toBe(originalProps.rows);
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
});
|
|
@@ -19,11 +19,11 @@ import React from 'react';
|
|
|
19
19
|
import { render, screen, fireEvent, waitFor, act } from '@testing-library/react';
|
|
20
20
|
import userEvent from '@testing-library/user-event';
|
|
21
21
|
import '@testing-library/jest-dom';
|
|
22
|
-
import CollapsibleLayout, { CollapsibleLayoutView, useCollapsibleState } from '
|
|
23
|
-
import { DataProvider } from '
|
|
22
|
+
import CollapsibleLayout, { CollapsibleLayoutView, useCollapsibleState } from '../../../components/layout/CollapsibleLayout';
|
|
23
|
+
import { DataProvider } from '../../../contexts/DataContext';
|
|
24
24
|
import { JsonDataProvider } from '@qwickapps/schema';
|
|
25
|
-
import { ThemeProvider, PaletteProvider } from '
|
|
26
|
-
import { CollapsibleLayoutProps } from '
|
|
25
|
+
import { ThemeProvider, PaletteProvider } from '../../../contexts';
|
|
26
|
+
import { CollapsibleLayoutProps } from '../../../types/CollapsibleLayout';
|
|
27
27
|
|
|
28
28
|
// Test data for data binding
|
|
29
29
|
const sampleCmsData = {
|