@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.
- package/README.md +1688 -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/Content.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/ProductCard.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/ThemeContext.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 +20722 -16021
- package/dist/index.js +20725 -16010
- 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/Content.tsx +25 -77
- 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 +51 -52
- 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/ThemeContext.tsx +1 -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,460 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component Serialization Performance Tests
|
|
3
|
+
*
|
|
4
|
+
* Performance benchmarking and validation for the serialization system
|
|
5
|
+
* covering memory usage, speed, and scalability under various loads.
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import React, { ReactElement } from 'react';
|
|
11
|
+
import { ComponentTransformer } from '../ComponentTransformer';
|
|
12
|
+
import { Serializable, SerializableConstructor } from '../../types/Serializable';
|
|
13
|
+
|
|
14
|
+
// Performance-focused mock components
|
|
15
|
+
class PerfMockButton implements Serializable {
|
|
16
|
+
static readonly tagName = 'Button';
|
|
17
|
+
static readonly version = '1.0.0';
|
|
18
|
+
|
|
19
|
+
constructor(public props: { id?: string; label?: string; metadata?: any }) {}
|
|
20
|
+
|
|
21
|
+
static fromJson(jsonData: any): ReactElement {
|
|
22
|
+
return React.createElement('button', {
|
|
23
|
+
id: jsonData.id,
|
|
24
|
+
'data-label': jsonData.label,
|
|
25
|
+
'data-metadata': JSON.stringify(jsonData.metadata || {})
|
|
26
|
+
}, jsonData.label || 'Button');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
toJson(): any {
|
|
30
|
+
return {
|
|
31
|
+
id: this.props.id,
|
|
32
|
+
label: this.props.label,
|
|
33
|
+
metadata: this.props.metadata
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
class PerfMockSection implements Serializable {
|
|
39
|
+
static readonly tagName = 'Section';
|
|
40
|
+
static readonly version = '1.0.0';
|
|
41
|
+
|
|
42
|
+
constructor(public props: { id?: string; children?: any }) {}
|
|
43
|
+
|
|
44
|
+
static fromJson(jsonData: any): ReactElement {
|
|
45
|
+
const children = jsonData.children ? ComponentTransformer.deserialize(jsonData.children) : null;
|
|
46
|
+
return React.createElement('section', {
|
|
47
|
+
id: jsonData.id,
|
|
48
|
+
'data-testid': 'perf-section'
|
|
49
|
+
}, children);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
toJson(): any {
|
|
53
|
+
return {
|
|
54
|
+
id: this.props.id,
|
|
55
|
+
children: this.props.children ? ComponentTransformer.serialize(this.props.children) : null
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Performance measurement utilities
|
|
61
|
+
interface PerformanceMetrics {
|
|
62
|
+
duration: number;
|
|
63
|
+
memoryUsed?: number;
|
|
64
|
+
operations: number;
|
|
65
|
+
opsPerSecond: number;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function measurePerformance<T>(
|
|
69
|
+
operation: () => T,
|
|
70
|
+
operationCount: number = 1
|
|
71
|
+
): { result: T; metrics: PerformanceMetrics } {
|
|
72
|
+
// Force garbage collection if available (for more accurate memory measurements)
|
|
73
|
+
if ((global as any).gc) {
|
|
74
|
+
(global as any).gc();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const startMemory = process.memoryUsage().heapUsed;
|
|
78
|
+
const startTime = performance.now();
|
|
79
|
+
|
|
80
|
+
let result: T;
|
|
81
|
+
for (let i = 0; i < operationCount; i++) {
|
|
82
|
+
result = operation();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const endTime = performance.now();
|
|
86
|
+
const endMemory = process.memoryUsage().heapUsed;
|
|
87
|
+
|
|
88
|
+
const duration = endTime - startTime;
|
|
89
|
+
const memoryUsed = endMemory - startMemory;
|
|
90
|
+
const opsPerSecond = operationCount > 1 ? (operationCount / duration) * 1000 : 1000 / duration;
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
result: result!,
|
|
94
|
+
metrics: {
|
|
95
|
+
duration,
|
|
96
|
+
memoryUsed,
|
|
97
|
+
operations: operationCount,
|
|
98
|
+
opsPerSecond
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
describe('Component Serialization Performance Tests', () => {
|
|
104
|
+
beforeEach(() => {
|
|
105
|
+
ComponentTransformer.clearRegistry();
|
|
106
|
+
ComponentTransformer.registerComponent(PerfMockButton as SerializableConstructor);
|
|
107
|
+
ComponentTransformer.registerComponent(PerfMockSection as SerializableConstructor);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
afterEach(() => {
|
|
111
|
+
ComponentTransformer.clearRegistry();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe('Serialization Speed Benchmarks', () => {
|
|
115
|
+
it('should serialize 1000 simple components within performance budget', () => {
|
|
116
|
+
const components = Array.from({ length: 1000 }, (_, i) => ({
|
|
117
|
+
tag: 'Button',
|
|
118
|
+
version: '1.0.0',
|
|
119
|
+
data: {
|
|
120
|
+
id: `btn-${i}`,
|
|
121
|
+
label: `Button ${i}`,
|
|
122
|
+
metadata: { index: i, category: i % 10 }
|
|
123
|
+
}
|
|
124
|
+
}));
|
|
125
|
+
|
|
126
|
+
const { metrics } = measurePerformance(() => {
|
|
127
|
+
return ComponentTransformer.deserialize(components);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Performance budget: should complete within 50ms for 1000 components
|
|
131
|
+
expect(metrics.duration).toBeLessThan(50);
|
|
132
|
+
expect(metrics.opsPerSecond).toBeGreaterThan(20000); // At least 20k ops/sec
|
|
133
|
+
|
|
134
|
+
console.log(`Serialized 1000 components in ${metrics.duration.toFixed(2)}ms (${metrics.opsPerSecond.toFixed(0)} ops/sec)`);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('should deserialize complex nested structures efficiently', () => {
|
|
138
|
+
// Create nested structure with 10 sections, each containing 50 buttons
|
|
139
|
+
const nestedStructure = Array.from({ length: 10 }, (_, sectionIndex) => ({
|
|
140
|
+
tag: 'Section',
|
|
141
|
+
version: '1.0.0',
|
|
142
|
+
data: {
|
|
143
|
+
id: `section-${sectionIndex}`,
|
|
144
|
+
children: Array.from({ length: 50 }, (_, buttonIndex) => ({
|
|
145
|
+
tag: 'Button',
|
|
146
|
+
version: '1.0.0',
|
|
147
|
+
data: {
|
|
148
|
+
id: `btn-${sectionIndex}-${buttonIndex}`,
|
|
149
|
+
label: `Button ${buttonIndex}`,
|
|
150
|
+
metadata: { section: sectionIndex, button: buttonIndex }
|
|
151
|
+
}
|
|
152
|
+
}))
|
|
153
|
+
}
|
|
154
|
+
}));
|
|
155
|
+
|
|
156
|
+
const { result, metrics } = measurePerformance(() => {
|
|
157
|
+
return ComponentTransformer.deserialize(nestedStructure);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Performance budget: 500 nested components should complete within 100ms
|
|
161
|
+
expect(metrics.duration).toBeLessThan(100);
|
|
162
|
+
expect(Array.isArray(result)).toBe(true);
|
|
163
|
+
expect(result).toHaveLength(10);
|
|
164
|
+
|
|
165
|
+
console.log(`Deserialized 500 nested components in ${metrics.duration.toFixed(2)}ms`);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('should handle roundtrip serialization efficiently', () => {
|
|
169
|
+
const testData = Array.from({ length: 100 }, (_, i) => ({
|
|
170
|
+
tag: 'Section',
|
|
171
|
+
version: '1.0.0',
|
|
172
|
+
data: {
|
|
173
|
+
id: `section-${i}`,
|
|
174
|
+
children: [{
|
|
175
|
+
tag: 'Button',
|
|
176
|
+
version: '1.0.0',
|
|
177
|
+
data: { id: `btn-${i}`, label: `Button ${i}` }
|
|
178
|
+
}]
|
|
179
|
+
}
|
|
180
|
+
}));
|
|
181
|
+
|
|
182
|
+
const { metrics: deserializeMetrics } = measurePerformance(() => {
|
|
183
|
+
return ComponentTransformer.deserialize(testData);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const reactElements = ComponentTransformer.deserialize(testData);
|
|
187
|
+
|
|
188
|
+
const { metrics: serializeMetrics } = measurePerformance(() => {
|
|
189
|
+
return ComponentTransformer.serialize(reactElements);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Both operations should be fast
|
|
193
|
+
expect(deserializeMetrics.duration).toBeLessThan(20);
|
|
194
|
+
expect(serializeMetrics.duration).toBeLessThan(20);
|
|
195
|
+
|
|
196
|
+
console.log(`Roundtrip: Deserialize ${deserializeMetrics.duration.toFixed(2)}ms, Serialize ${serializeMetrics.duration.toFixed(2)}ms`);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
describe('Memory Usage Validation', () => {
|
|
201
|
+
it('should not create excessive memory overhead for large component trees', () => {
|
|
202
|
+
const largeComponentTree = Array.from({ length: 5000 }, (_, i) => ({
|
|
203
|
+
tag: 'Button',
|
|
204
|
+
version: '1.0.0',
|
|
205
|
+
data: {
|
|
206
|
+
id: `large-btn-${i}`,
|
|
207
|
+
label: `Large Button ${i}`,
|
|
208
|
+
metadata: {
|
|
209
|
+
index: i,
|
|
210
|
+
timestamp: Date.now(),
|
|
211
|
+
category: `category-${i % 20}`,
|
|
212
|
+
tags: [`tag-${i % 10}`, `tag-${(i + 1) % 10}`]
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}));
|
|
216
|
+
|
|
217
|
+
const { result, metrics } = measurePerformance(() => {
|
|
218
|
+
return ComponentTransformer.deserialize(largeComponentTree);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
expect(Array.isArray(result)).toBe(true);
|
|
222
|
+
expect(result).toHaveLength(5000);
|
|
223
|
+
|
|
224
|
+
// Memory budget: Should not use more than 50MB for 5000 components
|
|
225
|
+
if (metrics.memoryUsed) {
|
|
226
|
+
const memoryMB = metrics.memoryUsed / (1024 * 1024);
|
|
227
|
+
expect(memoryMB).toBeLessThan(50);
|
|
228
|
+
console.log(`Memory used for 5000 components: ${memoryMB.toFixed(2)}MB`);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('should release memory properly after deserialization', async () => {
|
|
233
|
+
const initialMemory = process.memoryUsage().heapUsed;
|
|
234
|
+
|
|
235
|
+
// Create and process large data
|
|
236
|
+
for (let batch = 0; batch < 10; batch++) {
|
|
237
|
+
const batchData = Array.from({ length: 1000 }, (_, i) => ({
|
|
238
|
+
tag: 'Button',
|
|
239
|
+
version: '1.0.0',
|
|
240
|
+
data: { id: `batch-${batch}-btn-${i}`, label: `Button ${i}` }
|
|
241
|
+
}));
|
|
242
|
+
|
|
243
|
+
const result = ComponentTransformer.deserialize(batchData);
|
|
244
|
+
expect(Array.isArray(result)).toBe(true);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Force garbage collection
|
|
248
|
+
if ((global as any).gc) {
|
|
249
|
+
(global as any).gc();
|
|
250
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const finalMemory = process.memoryUsage().heapUsed;
|
|
254
|
+
const memoryGrowth = (finalMemory - initialMemory) / (1024 * 1024);
|
|
255
|
+
|
|
256
|
+
// Memory should not grow by more than 20MB after processing 10k components
|
|
257
|
+
expect(memoryGrowth).toBeLessThan(20);
|
|
258
|
+
console.log(`Memory growth after 10 batches: ${memoryGrowth.toFixed(2)}MB`);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
describe('Scalability Testing', () => {
|
|
263
|
+
it('should scale linearly with component count', () => {
|
|
264
|
+
const componentCounts = [100, 500, 1000, 2000];
|
|
265
|
+
const results: { count: number; duration: number; opsPerSec: number }[] = [];
|
|
266
|
+
|
|
267
|
+
for (const count of componentCounts) {
|
|
268
|
+
const components = Array.from({ length: count }, (_, i) => ({
|
|
269
|
+
tag: 'Button',
|
|
270
|
+
version: '1.0.0',
|
|
271
|
+
data: { id: `scale-btn-${i}`, label: `Button ${i}` }
|
|
272
|
+
}));
|
|
273
|
+
|
|
274
|
+
const { metrics } = measurePerformance(() => {
|
|
275
|
+
return ComponentTransformer.deserialize(components);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
results.push({
|
|
279
|
+
count,
|
|
280
|
+
duration: metrics.duration,
|
|
281
|
+
opsPerSec: metrics.opsPerSecond
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Verify scaling characteristics
|
|
286
|
+
for (let i = 1; i < results.length; i++) {
|
|
287
|
+
const prev = results[i - 1];
|
|
288
|
+
const curr = results[i];
|
|
289
|
+
|
|
290
|
+
// Duration should scale roughly linearly (with some tolerance)
|
|
291
|
+
const expectedDuration = (prev.duration * curr.count) / prev.count;
|
|
292
|
+
const tolerance = expectedDuration * 0.5; // 50% tolerance
|
|
293
|
+
|
|
294
|
+
expect(curr.duration).toBeLessThan(expectedDuration + tolerance);
|
|
295
|
+
|
|
296
|
+
console.log(`${curr.count} components: ${curr.duration.toFixed(2)}ms (${curr.opsPerSec.toFixed(0)} ops/sec)`);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('should handle deeply nested structures without performance degradation', () => {
|
|
301
|
+
const depths = [5, 10, 20, 30];
|
|
302
|
+
const results: { depth: number; duration: number }[] = [];
|
|
303
|
+
|
|
304
|
+
for (const depth of depths) {
|
|
305
|
+
// Create nested structure
|
|
306
|
+
let nestedData: any = {
|
|
307
|
+
tag: 'Button',
|
|
308
|
+
version: '1.0.0',
|
|
309
|
+
data: { id: 'deep-button', label: `Button at depth ${depth}` }
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
for (let level = 0; level < depth; level++) {
|
|
313
|
+
nestedData = {
|
|
314
|
+
tag: 'Section',
|
|
315
|
+
version: '1.0.0',
|
|
316
|
+
data: {
|
|
317
|
+
id: `section-level-${level}`,
|
|
318
|
+
children: [nestedData]
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const { metrics } = measurePerformance(() => {
|
|
324
|
+
return ComponentTransformer.deserialize(nestedData);
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
results.push({
|
|
328
|
+
depth,
|
|
329
|
+
duration: metrics.duration
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Verify that performance doesn't degrade exponentially with depth
|
|
334
|
+
for (let i = 1; i < results.length; i++) {
|
|
335
|
+
const prev = results[i - 1];
|
|
336
|
+
const curr = results[i];
|
|
337
|
+
|
|
338
|
+
// Each doubling of depth should not more than double the time
|
|
339
|
+
const depthRatio = curr.depth / prev.depth;
|
|
340
|
+
const timeRatio = curr.duration / prev.duration;
|
|
341
|
+
|
|
342
|
+
expect(timeRatio).toBeLessThan(depthRatio * 2);
|
|
343
|
+
|
|
344
|
+
console.log(`Depth ${curr.depth}: ${curr.duration.toFixed(2)}ms`);
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
describe('Stress Testing', () => {
|
|
350
|
+
it('should handle extreme component counts without crashing', () => {
|
|
351
|
+
// Test with 10,000 components
|
|
352
|
+
const extremeCount = 10000;
|
|
353
|
+
const components = Array.from({ length: extremeCount }, (_, i) => ({
|
|
354
|
+
tag: 'Button',
|
|
355
|
+
version: '1.0.0',
|
|
356
|
+
data: {
|
|
357
|
+
id: `extreme-btn-${i}`,
|
|
358
|
+
label: `Button ${i}`,
|
|
359
|
+
metadata: { batch: Math.floor(i / 1000) }
|
|
360
|
+
}
|
|
361
|
+
}));
|
|
362
|
+
|
|
363
|
+
expect(() => {
|
|
364
|
+
const startTime = performance.now();
|
|
365
|
+
const result = ComponentTransformer.deserialize(components);
|
|
366
|
+
const endTime = performance.now();
|
|
367
|
+
|
|
368
|
+
expect(Array.isArray(result)).toBe(true);
|
|
369
|
+
expect(result).toHaveLength(extremeCount);
|
|
370
|
+
|
|
371
|
+
const duration = endTime - startTime;
|
|
372
|
+
console.log(`Processed ${extremeCount} components in ${duration.toFixed(2)}ms`);
|
|
373
|
+
|
|
374
|
+
// Should complete within 1 second even for extreme loads
|
|
375
|
+
expect(duration).toBeLessThan(1000);
|
|
376
|
+
}).not.toThrow();
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
it('should handle concurrent serialization operations', async () => {
|
|
380
|
+
const concurrentOperations = 10;
|
|
381
|
+
const componentsPerOperation = 500;
|
|
382
|
+
|
|
383
|
+
const operations = Array.from({ length: concurrentOperations }, (_, opIndex) => {
|
|
384
|
+
const components = Array.from({ length: componentsPerOperation }, (_, compIndex) => ({
|
|
385
|
+
tag: 'Button',
|
|
386
|
+
version: '1.0.0',
|
|
387
|
+
data: {
|
|
388
|
+
id: `concurrent-op${opIndex}-btn${compIndex}`,
|
|
389
|
+
label: `Op ${opIndex} Button ${compIndex}`
|
|
390
|
+
}
|
|
391
|
+
}));
|
|
392
|
+
|
|
393
|
+
return () => ComponentTransformer.deserialize(components);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
const startTime = performance.now();
|
|
397
|
+
|
|
398
|
+
// Run all operations concurrently
|
|
399
|
+
const results = await Promise.all(
|
|
400
|
+
operations.map(async (operation) => {
|
|
401
|
+
return new Promise((resolve) => {
|
|
402
|
+
setTimeout(() => resolve(operation()), 0);
|
|
403
|
+
});
|
|
404
|
+
})
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
const endTime = performance.now();
|
|
408
|
+
const totalDuration = endTime - startTime;
|
|
409
|
+
|
|
410
|
+
// Verify all operations completed successfully
|
|
411
|
+
results.forEach((result, index) => {
|
|
412
|
+
expect(Array.isArray(result)).toBe(true);
|
|
413
|
+
expect((result as any[]).length).toBe(componentsPerOperation);
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
console.log(`${concurrentOperations} concurrent operations completed in ${totalDuration.toFixed(2)}ms`);
|
|
417
|
+
});
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
describe('Performance Regression Detection', () => {
|
|
421
|
+
it('should maintain consistent performance characteristics', () => {
|
|
422
|
+
const benchmarkData = Array.from({ length: 1000 }, (_, i) => ({
|
|
423
|
+
tag: 'Section',
|
|
424
|
+
version: '1.0.0',
|
|
425
|
+
data: {
|
|
426
|
+
id: `benchmark-section-${i}`,
|
|
427
|
+
children: [
|
|
428
|
+
{
|
|
429
|
+
tag: 'Button',
|
|
430
|
+
version: '1.0.0',
|
|
431
|
+
data: { id: `benchmark-btn-${i}`, label: `Button ${i}` }
|
|
432
|
+
}
|
|
433
|
+
]
|
|
434
|
+
}
|
|
435
|
+
}));
|
|
436
|
+
|
|
437
|
+
// Run benchmark multiple times to get consistent results
|
|
438
|
+
const runs = 5;
|
|
439
|
+
const durations: number[] = [];
|
|
440
|
+
|
|
441
|
+
for (let run = 0; run < runs; run++) {
|
|
442
|
+
const { metrics } = measurePerformance(() => {
|
|
443
|
+
return ComponentTransformer.deserialize(benchmarkData);
|
|
444
|
+
});
|
|
445
|
+
durations.push(metrics.duration);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const averageDuration = durations.reduce((a, b) => a + b, 0) / durations.length;
|
|
449
|
+
const maxDuration = Math.max(...durations);
|
|
450
|
+
const minDuration = Math.min(...durations);
|
|
451
|
+
const variance = maxDuration - minDuration;
|
|
452
|
+
|
|
453
|
+
// Performance should be consistent (low variance)
|
|
454
|
+
expect(variance).toBeLessThan(averageDuration * 0.5); // Variance should be < 50% of average
|
|
455
|
+
expect(averageDuration).toBeLessThan(50); // Average should be under 50ms for 1000 components
|
|
456
|
+
|
|
457
|
+
console.log(`Performance consistency: avg=${averageDuration.toFixed(2)}ms, min=${minDuration.toFixed(2)}ms, max=${maxDuration.toFixed(2)}ms, variance=${variance.toFixed(2)}ms`);
|
|
458
|
+
});
|
|
459
|
+
});
|
|
460
|
+
});
|