@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,602 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component Serialization Error Handling Tests
|
|
3
|
+
*
|
|
4
|
+
* Comprehensive error handling validation for the serialization system
|
|
5
|
+
* covering malformed data, unknown components, version incompatibility,
|
|
6
|
+
* and various failure scenarios.
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import React, { ReactElement } from 'react';
|
|
12
|
+
import { ComponentTransformer } from '../ComponentTransformer';
|
|
13
|
+
import { Serializable, SerializableConstructor } from '../../types/Serializable';
|
|
14
|
+
|
|
15
|
+
// Mock components for error testing
|
|
16
|
+
class ErrorTestButton implements Serializable {
|
|
17
|
+
constructor(public props: { label?: string; throwOnFromJson?: boolean; throwOnToJson?: boolean }) {}
|
|
18
|
+
|
|
19
|
+
static fromJson(jsonData: any): ReactElement {
|
|
20
|
+
if (jsonData.throwOnFromJson) {
|
|
21
|
+
throw new Error('Intentional fromJson error for testing');
|
|
22
|
+
}
|
|
23
|
+
return React.createElement('button', {}, jsonData.label || 'Button');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
toJson(): any {
|
|
27
|
+
if (this.props.throwOnToJson) {
|
|
28
|
+
throw new Error('Intentional toJson error for testing');
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
label: this.props.label,
|
|
32
|
+
throwOnFromJson: this.props.throwOnFromJson,
|
|
33
|
+
throwOnToJson: this.props.throwOnToJson
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
class InvalidComponentClass {
|
|
39
|
+
// This class does not implement Serializable interface
|
|
40
|
+
static fromJson(jsonData: any): ReactElement {
|
|
41
|
+
return React.createElement('div', {}, 'Invalid component');
|
|
42
|
+
}
|
|
43
|
+
// Missing toJson method
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
class MalformedFromJsonComponent implements Serializable {
|
|
47
|
+
constructor(public props: any) {}
|
|
48
|
+
|
|
49
|
+
static fromJson(jsonData: any): any {
|
|
50
|
+
// Returns non-ReactElement (invalid)
|
|
51
|
+
return { invalid: 'return value' };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
toJson(): any {
|
|
55
|
+
return this.props;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
describe('Component Serialization Error Handling', () => {
|
|
60
|
+
beforeEach(() => {
|
|
61
|
+
ComponentTransformer.clearRegistry();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
afterEach(() => {
|
|
65
|
+
ComponentTransformer.clearRegistry();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('Unknown Component Errors', () => {
|
|
69
|
+
it('should throw descriptive error for unregistered component', () => {
|
|
70
|
+
const unknownComponent = {
|
|
71
|
+
tag: 'UnknownWidget',
|
|
72
|
+
version: '1.0.0',
|
|
73
|
+
data: { prop: 'value' }
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// With the new fallback system, unknown components should not throw but use ReactNodeTransformer
|
|
77
|
+
const result = ComponentTransformer.deserialize(unknownComponent);
|
|
78
|
+
expect(result).toBeDefined(); // Should fallback gracefully
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should throw error for component with special characters in tag name', () => {
|
|
82
|
+
const invalidTagComponent = {
|
|
83
|
+
tag: 'Invalid<>Tag',
|
|
84
|
+
version: '1.0.0',
|
|
85
|
+
data: {}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
expect(() => {
|
|
89
|
+
ComponentTransformer.deserialize(invalidTagComponent);
|
|
90
|
+
}).toThrow('Unknown component: Invalid<>Tag');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should throw error for component with numeric tag name', () => {
|
|
94
|
+
const numericTagComponent = {
|
|
95
|
+
tag: '123Component',
|
|
96
|
+
version: '1.0.0',
|
|
97
|
+
data: {}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
expect(() => {
|
|
101
|
+
ComponentTransformer.deserialize(numericTagComponent);
|
|
102
|
+
}).toThrow('Unknown component: 123Component');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should throw error for empty tag name', () => {
|
|
106
|
+
const emptyTagComponent = {
|
|
107
|
+
tag: '',
|
|
108
|
+
version: '1.0.0',
|
|
109
|
+
data: {}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
expect(() => {
|
|
113
|
+
ComponentTransformer.deserialize(emptyTagComponent);
|
|
114
|
+
}).toThrow('Unknown component: ');
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should handle array of components with unknown component gracefully', () => {
|
|
118
|
+
ComponentTransformer.registerComponent(ErrorTestButton as SerializableConstructor);
|
|
119
|
+
|
|
120
|
+
const mixedComponents = [
|
|
121
|
+
{
|
|
122
|
+
tag: 'ErrorTestButton',
|
|
123
|
+
version: '1.0.0',
|
|
124
|
+
data: { label: 'Valid Button' }
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
tag: 'UnknownComponent',
|
|
128
|
+
version: '1.0.0',
|
|
129
|
+
data: {}
|
|
130
|
+
}
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
expect(() => {
|
|
134
|
+
ComponentTransformer.deserialize(mixedComponents);
|
|
135
|
+
}).toThrow('Unknown component: UnknownComponent');
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
describe('Malformed Component Data Errors', () => {
|
|
140
|
+
beforeEach(() => {
|
|
141
|
+
ComponentTransformer.registerComponent(ErrorTestButton as SerializableConstructor);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('should throw error when data property is missing', () => {
|
|
145
|
+
const missingDataComponent = {
|
|
146
|
+
tag: 'ErrorTestButton',
|
|
147
|
+
version: '1.0.0'
|
|
148
|
+
// Missing data property
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
expect(() => {
|
|
152
|
+
ComponentTransformer.deserialize(missingDataComponent);
|
|
153
|
+
}).toThrow('Malformed component data: missing \'data\' property for component \'ErrorTestButton\'');
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should handle undefined data property', () => {
|
|
157
|
+
const undefinedDataComponent = {
|
|
158
|
+
tag: 'ErrorTestButton',
|
|
159
|
+
version: '1.0.0',
|
|
160
|
+
data: undefined
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
expect(() => {
|
|
164
|
+
ComponentTransformer.deserialize(undefinedDataComponent);
|
|
165
|
+
}).toThrow('Malformed component data: missing \'data\' property for component \'ErrorTestButton\'');
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('should handle null data property gracefully', () => {
|
|
169
|
+
const nullDataComponent = {
|
|
170
|
+
tag: 'ErrorTestButton',
|
|
171
|
+
version: '1.0.0',
|
|
172
|
+
data: null
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
expect(() => {
|
|
176
|
+
const result = ComponentTransformer.deserialize(nullDataComponent);
|
|
177
|
+
expect(React.isValidElement(result)).toBe(true);
|
|
178
|
+
}).not.toThrow();
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('should throw error when tag property is missing', () => {
|
|
182
|
+
const missingTagComponent = {
|
|
183
|
+
version: '1.0.0',
|
|
184
|
+
data: { label: 'Test' }
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
expect(() => {
|
|
188
|
+
ComponentTransformer.deserialize(missingTagComponent);
|
|
189
|
+
}).not.toThrow(); // Should be handled as non-component data
|
|
190
|
+
|
|
191
|
+
// The result should be the object itself
|
|
192
|
+
const result = ComponentTransformer.deserialize(missingTagComponent);
|
|
193
|
+
expect(result).toEqual(missingTagComponent);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('should handle missing version property', () => {
|
|
197
|
+
const missingVersionComponent = {
|
|
198
|
+
tag: 'ErrorTestButton',
|
|
199
|
+
data: { label: 'Test' }
|
|
200
|
+
// Missing version property
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
expect(() => {
|
|
204
|
+
const result = ComponentTransformer.deserialize(missingVersionComponent);
|
|
205
|
+
expect(React.isValidElement(result)).toBe(true);
|
|
206
|
+
}).not.toThrow();
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('should handle invalid version format', () => {
|
|
210
|
+
const invalidVersions = [
|
|
211
|
+
{ tag: 'ErrorTestButton', version: 123, data: {} },
|
|
212
|
+
{ tag: 'ErrorTestButton', version: null, data: {} },
|
|
213
|
+
{ tag: 'ErrorTestButton', version: {}, data: {} },
|
|
214
|
+
{ tag: 'ErrorTestButton', version: 'invalid.version.format.too.long', data: {} }
|
|
215
|
+
];
|
|
216
|
+
|
|
217
|
+
invalidVersions.forEach((component, index) => {
|
|
218
|
+
expect(() => {
|
|
219
|
+
const result = ComponentTransformer.deserialize(component);
|
|
220
|
+
expect(React.isValidElement(result)).toBe(true);
|
|
221
|
+
}).not.toThrow(`Should not throw for invalid version case ${index}`);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
describe('Invalid JSON Input Errors', () => {
|
|
227
|
+
it('should throw descriptive error for malformed JSON string', () => {
|
|
228
|
+
const malformedJsonInputs = [
|
|
229
|
+
'{invalid json',
|
|
230
|
+
'{"unclosed": "object"',
|
|
231
|
+
'{key: "value"}', // Missing quotes around key
|
|
232
|
+
'[1, 2, 3,]', // Trailing comma
|
|
233
|
+
'{"duplicate": "key", "duplicate": "key2"}', // Valid JSON but semantically questionable
|
|
234
|
+
];
|
|
235
|
+
|
|
236
|
+
malformedJsonInputs.forEach((input, index) => {
|
|
237
|
+
if (input !== '{"duplicate": "key", "duplicate": "key2"}') { // This is actually valid JSON
|
|
238
|
+
expect(() => {
|
|
239
|
+
ComponentTransformer.deserialize(input);
|
|
240
|
+
}).toThrow(/Invalid JSON input/);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('should handle very large JSON input', () => {
|
|
246
|
+
const largeObject = {
|
|
247
|
+
tag: 'ErrorTestButton',
|
|
248
|
+
version: '1.0.0',
|
|
249
|
+
data: {
|
|
250
|
+
largeText: 'x'.repeat(10000000) // 10MB string
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
expect(() => {
|
|
255
|
+
const jsonString = JSON.stringify(largeObject);
|
|
256
|
+
ComponentTransformer.deserialize(jsonString);
|
|
257
|
+
}).not.toThrow();
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it('should handle deeply nested JSON structures', () => {
|
|
261
|
+
let deepObject: any = { tag: 'ErrorTestButton', version: '1.0.0', data: {} };
|
|
262
|
+
|
|
263
|
+
// Create 1000 levels of nesting
|
|
264
|
+
for (let i = 0; i < 1000; i++) {
|
|
265
|
+
deepObject = { nested: deepObject };
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
expect(() => {
|
|
269
|
+
const jsonString = JSON.stringify(deepObject);
|
|
270
|
+
ComponentTransformer.deserialize(jsonString);
|
|
271
|
+
}).not.toThrow();
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('should handle JSON with circular references (after JSON.stringify)', () => {
|
|
275
|
+
// Since JSON.stringify removes circular references, we test the behavior
|
|
276
|
+
const obj: any = { tag: 'ErrorTestButton', version: '1.0.0', data: {} };
|
|
277
|
+
obj.circular = obj;
|
|
278
|
+
|
|
279
|
+
expect(() => {
|
|
280
|
+
// This will throw during JSON.stringify, not during deserialize
|
|
281
|
+
JSON.stringify(obj);
|
|
282
|
+
}).toThrow();
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
describe('Component Implementation Errors', () => {
|
|
287
|
+
it('should handle component fromJson method throwing errors', () => {
|
|
288
|
+
ComponentTransformer.registerComponent(ErrorTestButton as SerializableConstructor);
|
|
289
|
+
|
|
290
|
+
const componentThatWillThrow = {
|
|
291
|
+
tag: 'ErrorTestButton',
|
|
292
|
+
version: '1.0.0',
|
|
293
|
+
data: { throwOnFromJson: true }
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
expect(() => {
|
|
297
|
+
ComponentTransformer.deserialize(componentThatWillThrow);
|
|
298
|
+
}).toThrow('Intentional fromJson error for testing');
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it('should handle component returning non-ReactElement from fromJson', () => {
|
|
302
|
+
ComponentTransformer.registerComponent(MalformedFromJsonComponent as SerializableConstructor);
|
|
303
|
+
|
|
304
|
+
const malformedComponent = {
|
|
305
|
+
tag: 'MalformedFromJsonComponent',
|
|
306
|
+
version: '1.0.0',
|
|
307
|
+
data: {}
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
// This should not crash, but the result might not be a valid React element
|
|
311
|
+
expect(() => {
|
|
312
|
+
const result = ComponentTransformer.deserialize(malformedComponent);
|
|
313
|
+
// The result will be whatever fromJson returns, even if invalid
|
|
314
|
+
expect(result).toEqual({ invalid: 'return value' });
|
|
315
|
+
}).not.toThrow();
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it('should handle component class without proper static methods', () => {
|
|
319
|
+
// Try to register a class that doesn't properly implement the interface
|
|
320
|
+
expect(() => {
|
|
321
|
+
ComponentTransformer.registerComponent('InvalidClass', InvalidComponentClass as any);
|
|
322
|
+
}).not.toThrow(); // Registration succeeds, but usage will fail
|
|
323
|
+
|
|
324
|
+
const invalidComponent = {
|
|
325
|
+
tag: 'InvalidClass',
|
|
326
|
+
version: '1.0.0',
|
|
327
|
+
data: {}
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
expect(() => {
|
|
331
|
+
ComponentTransformer.deserialize(invalidComponent);
|
|
332
|
+
}).not.toThrow(); // fromJson exists, so it will be called
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('should handle component toJson method throwing errors during serialization', () => {
|
|
336
|
+
ComponentTransformer.registerComponent(ErrorTestButton as SerializableConstructor);
|
|
337
|
+
|
|
338
|
+
// Create an instance that will throw during toJson
|
|
339
|
+
const instance = new ErrorTestButton({ throwOnToJson: true });
|
|
340
|
+
|
|
341
|
+
expect(() => {
|
|
342
|
+
instance.toJson();
|
|
343
|
+
}).toThrow('Intentional toJson error for testing');
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
describe('Type Safety and Validation Errors', () => {
|
|
348
|
+
beforeEach(() => {
|
|
349
|
+
ComponentTransformer.registerComponent(ErrorTestButton as SerializableConstructor);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('should handle non-object input gracefully', () => {
|
|
353
|
+
const nonObjectInputs = [
|
|
354
|
+
'plain string',
|
|
355
|
+
42,
|
|
356
|
+
true,
|
|
357
|
+
false,
|
|
358
|
+
null,
|
|
359
|
+
undefined,
|
|
360
|
+
Symbol('test'),
|
|
361
|
+
() => {}
|
|
362
|
+
];
|
|
363
|
+
|
|
364
|
+
nonObjectInputs.forEach((input, index) => {
|
|
365
|
+
expect(() => {
|
|
366
|
+
const result = ComponentTransformer.deserialize(input as any);
|
|
367
|
+
// Should return the input as-is for primitive values
|
|
368
|
+
if (input !== undefined && typeof input !== 'symbol' && typeof input !== 'function') {
|
|
369
|
+
expect(result).toBe(input);
|
|
370
|
+
}
|
|
371
|
+
}).not.toThrow(`Should not throw for input type ${typeof input} at index ${index}`);
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
it('should handle array with mixed valid and invalid elements', () => {
|
|
376
|
+
const mixedArray = [
|
|
377
|
+
'string',
|
|
378
|
+
{
|
|
379
|
+
tag: 'ErrorTestButton',
|
|
380
|
+
version: '1.0.0',
|
|
381
|
+
data: { label: 'Valid' }
|
|
382
|
+
},
|
|
383
|
+
42,
|
|
384
|
+
{
|
|
385
|
+
tag: 'UnknownComponent',
|
|
386
|
+
version: '1.0.0',
|
|
387
|
+
data: {}
|
|
388
|
+
},
|
|
389
|
+
null
|
|
390
|
+
];
|
|
391
|
+
|
|
392
|
+
expect(() => {
|
|
393
|
+
ComponentTransformer.deserialize(mixedArray);
|
|
394
|
+
}).toThrow('Unknown component: UnknownComponent');
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it('should handle object with component-like structure but missing required fields', () => {
|
|
398
|
+
const fakeComponentData = [
|
|
399
|
+
{ tag: 'ErrorTestButton' }, // Missing version and data
|
|
400
|
+
{ version: '1.0.0', data: {} }, // Missing tag
|
|
401
|
+
{ tag: null, version: '1.0.0', data: {} }, // Null tag
|
|
402
|
+
{ tag: 123, version: '1.0.0', data: {} }, // Non-string tag
|
|
403
|
+
];
|
|
404
|
+
|
|
405
|
+
fakeComponentData.forEach((fake, index) => {
|
|
406
|
+
expect(() => {
|
|
407
|
+
const result = ComponentTransformer.deserialize(fake);
|
|
408
|
+
// Should handle gracefully - some might deserialize, others might throw
|
|
409
|
+
}).not.toThrow(`Fake component ${index} should not crash the system`);
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
describe('Nested Error Propagation', () => {
|
|
415
|
+
beforeEach(() => {
|
|
416
|
+
ComponentTransformer.registerComponent(ErrorTestButton as SerializableConstructor);
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
it('should propagate errors from deeply nested components', () => {
|
|
420
|
+
const deeplyNested = {
|
|
421
|
+
tag: 'ErrorTestButton',
|
|
422
|
+
version: '1.0.0',
|
|
423
|
+
data: {
|
|
424
|
+
children: [
|
|
425
|
+
{
|
|
426
|
+
tag: 'ErrorTestButton',
|
|
427
|
+
version: '1.0.0',
|
|
428
|
+
data: {
|
|
429
|
+
children: [
|
|
430
|
+
{
|
|
431
|
+
tag: 'UnknownDeepComponent',
|
|
432
|
+
version: '1.0.0',
|
|
433
|
+
data: {}
|
|
434
|
+
}
|
|
435
|
+
]
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
]
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
expect(() => {
|
|
443
|
+
ComponentTransformer.deserialize(deeplyNested);
|
|
444
|
+
}).toThrow('Unknown component: UnknownDeepComponent');
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
it('should handle partial failures in component arrays gracefully', () => {
|
|
448
|
+
const componentsWithError = [
|
|
449
|
+
{
|
|
450
|
+
tag: 'ErrorTestButton',
|
|
451
|
+
version: '1.0.0',
|
|
452
|
+
data: { label: 'Button 1' }
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
tag: 'ErrorTestButton',
|
|
456
|
+
version: '1.0.0',
|
|
457
|
+
data: { label: 'Button 2' }
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
tag: 'UnknownComponent',
|
|
461
|
+
version: '1.0.0',
|
|
462
|
+
data: {}
|
|
463
|
+
}
|
|
464
|
+
];
|
|
465
|
+
|
|
466
|
+
expect(() => {
|
|
467
|
+
ComponentTransformer.deserialize(componentsWithError);
|
|
468
|
+
}).toThrow('Unknown component: UnknownComponent');
|
|
469
|
+
});
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
describe('Error Message Quality', () => {
|
|
473
|
+
it('should provide helpful error messages for common mistakes', () => {
|
|
474
|
+
const commonMistakes = [
|
|
475
|
+
{
|
|
476
|
+
data: { tag: 'Button', version: '1.0.0', data: {} },
|
|
477
|
+
expectedError: /Unknown component: Button/
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
data: { tag: 'ErrorTestButton', version: '1.0.0' },
|
|
481
|
+
expectedError: /missing 'data' property/
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
data: '{"invalid": json}',
|
|
485
|
+
expectedError: /Invalid JSON input/
|
|
486
|
+
}
|
|
487
|
+
];
|
|
488
|
+
|
|
489
|
+
commonMistakes.forEach(({ data, expectedError }, index) => {
|
|
490
|
+
expect(() => {
|
|
491
|
+
if (index === 0) {
|
|
492
|
+
// Don't register the component for the first test
|
|
493
|
+
ComponentTransformer.deserialize(data);
|
|
494
|
+
} else {
|
|
495
|
+
ComponentTransformer.registerComponent(ErrorTestButton as SerializableConstructor);
|
|
496
|
+
ComponentTransformer.deserialize(data);
|
|
497
|
+
}
|
|
498
|
+
}).toThrow(expectedError);
|
|
499
|
+
});
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
it('should include context information in error messages', () => {
|
|
503
|
+
const contextualErrors = [
|
|
504
|
+
{
|
|
505
|
+
component: 'SpecialCharComponent!@#',
|
|
506
|
+
expectedInError: 'SpecialCharComponent!@#'
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
component: 'VeryLongComponentNameThatShouldStillBeIncludedInErrorMessage',
|
|
510
|
+
expectedInError: 'VeryLongComponentNameThatShouldStillBeIncludedInErrorMessage'
|
|
511
|
+
}
|
|
512
|
+
];
|
|
513
|
+
|
|
514
|
+
contextualErrors.forEach(({ component, expectedInError }) => {
|
|
515
|
+
expect(() => {
|
|
516
|
+
ComponentTransformer.deserialize({
|
|
517
|
+
tag: component,
|
|
518
|
+
version: '1.0.0',
|
|
519
|
+
data: {}
|
|
520
|
+
});
|
|
521
|
+
}).toThrow(expect.stringContaining(expectedInError));
|
|
522
|
+
});
|
|
523
|
+
});
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
describe('Recovery and Graceful Degradation', () => {
|
|
527
|
+
beforeEach(() => {
|
|
528
|
+
ComponentTransformer.registerComponent(ErrorTestButton as SerializableConstructor);
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
it('should handle registry corruption gracefully', () => {
|
|
532
|
+
// Simulate registry corruption
|
|
533
|
+
ComponentTransformer.clearRegistry();
|
|
534
|
+
|
|
535
|
+
expect(() => {
|
|
536
|
+
ComponentTransformer.deserialize({
|
|
537
|
+
tag: 'ErrorTestButton',
|
|
538
|
+
version: '1.0.0',
|
|
539
|
+
data: { label: 'Test' }
|
|
540
|
+
});
|
|
541
|
+
}).toThrow('Unknown component: ErrorTestButton');
|
|
542
|
+
|
|
543
|
+
// Registry should still work after error
|
|
544
|
+
ComponentTransformer.registerComponent(ErrorTestButton as SerializableConstructor);
|
|
545
|
+
expect(() => {
|
|
546
|
+
const result = ComponentTransformer.deserialize({
|
|
547
|
+
tag: 'ErrorTestButton',
|
|
548
|
+
version: '1.0.0',
|
|
549
|
+
data: { label: 'Recovery Test' }
|
|
550
|
+
});
|
|
551
|
+
expect(React.isValidElement(result)).toBe(true);
|
|
552
|
+
}).not.toThrow();
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
it('should maintain component registry state after errors', () => {
|
|
556
|
+
// Verify initial state
|
|
557
|
+
const initialComponents = ComponentTransformer.getRegisteredComponents();
|
|
558
|
+
expect(initialComponents).toContain('ErrorTestButton');
|
|
559
|
+
|
|
560
|
+
// Cause an error
|
|
561
|
+
expect(() => {
|
|
562
|
+
ComponentTransformer.deserialize({
|
|
563
|
+
tag: 'UnknownComponent',
|
|
564
|
+
version: '1.0.0',
|
|
565
|
+
data: {}
|
|
566
|
+
});
|
|
567
|
+
}).toThrow();
|
|
568
|
+
|
|
569
|
+
// Verify registry is unchanged after error
|
|
570
|
+
const componentsAfterError = ComponentTransformer.getRegisteredComponents();
|
|
571
|
+
expect(componentsAfterError).toEqual(initialComponents);
|
|
572
|
+
expect(componentsAfterError).toContain('ErrorTestButton');
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
it('should handle memory pressure during error conditions', () => {
|
|
576
|
+
// Create memory pressure with large failing operations
|
|
577
|
+
const largeFailingOperations = Array.from({ length: 100 }, (_, i) => ({
|
|
578
|
+
tag: `UnknownComponent${i}`,
|
|
579
|
+
version: '1.0.0',
|
|
580
|
+
data: {
|
|
581
|
+
largeData: 'x'.repeat(1000)
|
|
582
|
+
}
|
|
583
|
+
}));
|
|
584
|
+
|
|
585
|
+
largeFailingOperations.forEach((operation) => {
|
|
586
|
+
expect(() => {
|
|
587
|
+
ComponentTransformer.deserialize(operation);
|
|
588
|
+
}).toThrow(/Unknown component/);
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
// System should still be responsive
|
|
592
|
+
expect(() => {
|
|
593
|
+
const result = ComponentTransformer.deserialize({
|
|
594
|
+
tag: 'ErrorTestButton',
|
|
595
|
+
version: '1.0.0',
|
|
596
|
+
data: { label: 'After Memory Pressure' }
|
|
597
|
+
});
|
|
598
|
+
expect(React.isValidElement(result)).toBe(true);
|
|
599
|
+
}).not.toThrow();
|
|
600
|
+
});
|
|
601
|
+
});
|
|
602
|
+
});
|