@qwickapps/react-framework 1.3.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/LICENSE +44 -0
- package/README.md +794 -0
- package/dist/components/AccessibilityChecker.d.ts +12 -0
- package/dist/components/AccessibilityChecker.d.ts.map +1 -0
- package/dist/components/Html.d.ts +48 -0
- package/dist/components/Html.d.ts.map +1 -0
- package/dist/components/Logo.d.ts +79 -0
- package/dist/components/Logo.d.ts.map +1 -0
- package/dist/components/Markdown.d.ts +47 -0
- package/dist/components/Markdown.d.ts.map +1 -0
- package/dist/components/QwickApp.d.ts +56 -0
- package/dist/components/QwickApp.d.ts.map +1 -0
- package/dist/components/QwickAppsLogo.d.ts +25 -0
- package/dist/components/QwickAppsLogo.d.ts.map +1 -0
- package/dist/components/ResponsiveMenu.d.ts +38 -0
- package/dist/components/ResponsiveMenu.d.ts.map +1 -0
- package/dist/components/SafeSpan.d.ts +23 -0
- package/dist/components/SafeSpan.d.ts.map +1 -0
- package/dist/components/Scaffold.d.ts +57 -0
- package/dist/components/Scaffold.d.ts.map +1 -0
- package/dist/components/blocks/Article.d.ts +23 -0
- package/dist/components/blocks/Article.d.ts.map +1 -0
- package/dist/components/blocks/CardListGrid.d.ts +23 -0
- package/dist/components/blocks/CardListGrid.d.ts.map +1 -0
- package/dist/components/blocks/Code.d.ts +21 -0
- package/dist/components/blocks/Code.d.ts.map +1 -0
- package/dist/components/blocks/Content.d.ts +24 -0
- package/dist/components/blocks/Content.d.ts.map +1 -0
- package/dist/components/blocks/CoverImageHeader.d.ts +44 -0
- package/dist/components/blocks/CoverImageHeader.d.ts.map +1 -0
- package/dist/components/blocks/FeatureCard.d.ts +66 -0
- package/dist/components/blocks/FeatureCard.d.ts.map +1 -0
- package/dist/components/blocks/FeatureGrid.d.ts +48 -0
- package/dist/components/blocks/FeatureGrid.d.ts.map +1 -0
- package/dist/components/blocks/Footer.d.ts +56 -0
- package/dist/components/blocks/Footer.d.ts.map +1 -0
- package/dist/components/blocks/HeroBlock.d.ts +33 -0
- package/dist/components/blocks/HeroBlock.d.ts.map +1 -0
- package/dist/components/blocks/PageBannerHeader.d.ts +30 -0
- package/dist/components/blocks/PageBannerHeader.d.ts.map +1 -0
- package/dist/components/blocks/ProductCard.d.ts +57 -0
- package/dist/components/blocks/ProductCard.d.ts.map +1 -0
- package/dist/components/blocks/Section.d.ts +40 -0
- package/dist/components/blocks/Section.d.ts.map +1 -0
- package/dist/components/blocks/index.d.ts +37 -0
- package/dist/components/blocks/index.d.ts.map +1 -0
- package/dist/components/buttons/Button.d.ts +38 -0
- package/dist/components/buttons/Button.d.ts.map +1 -0
- package/dist/components/buttons/PaletteSwitcher.d.ts +24 -0
- package/dist/components/buttons/PaletteSwitcher.d.ts.map +1 -0
- package/dist/components/buttons/ThemeSwitcher.d.ts +24 -0
- package/dist/components/buttons/ThemeSwitcher.d.ts.map +1 -0
- package/dist/components/buttons/index.d.ts +11 -0
- package/dist/components/buttons/index.d.ts.map +1 -0
- package/dist/components/forms/FormBlock.d.ts +45 -0
- package/dist/components/forms/FormBlock.d.ts.map +1 -0
- package/dist/components/forms/index.d.ts +8 -0
- package/dist/components/forms/index.d.ts.map +1 -0
- package/dist/components/index.d.ts +32 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/input/ChoiceInputField.d.ts +30 -0
- package/dist/components/input/ChoiceInputField.d.ts.map +1 -0
- package/dist/components/input/HtmlInputField.d.ts +29 -0
- package/dist/components/input/HtmlInputField.d.ts.map +1 -0
- package/dist/components/input/SelectInputField.d.ts +29 -0
- package/dist/components/input/SelectInputField.d.ts.map +1 -0
- package/dist/components/input/TextField.d.ts +18 -0
- package/dist/components/input/TextField.d.ts.map +1 -0
- package/dist/components/input/TextInputField.d.ts +32 -0
- package/dist/components/input/TextInputField.d.ts.map +1 -0
- package/dist/components/input/index.d.ts +17 -0
- package/dist/components/input/index.d.ts.map +1 -0
- package/dist/components/layout/GridCell.d.ts +16 -0
- package/dist/components/layout/GridCell.d.ts.map +1 -0
- package/dist/components/layout/GridCellWrapper.d.ts +46 -0
- package/dist/components/layout/GridCellWrapper.d.ts.map +1 -0
- package/dist/components/layout/GridLayout.d.ts +38 -0
- package/dist/components/layout/GridLayout.d.ts.map +1 -0
- package/dist/components/layout/index.d.ts +12 -0
- package/dist/components/layout/index.d.ts.map +1 -0
- package/dist/components/menu/Menu.d.ts +1 -0
- package/dist/components/menu/Menu.d.ts.map +1 -0
- package/dist/components/menu/MenuItem.d.ts +31 -0
- package/dist/components/menu/MenuItem.d.ts.map +1 -0
- package/dist/components/menu/index.d.ts +7 -0
- package/dist/components/menu/index.d.ts.map +1 -0
- package/dist/components/pages/FormPage.d.ts +66 -0
- package/dist/components/pages/FormPage.d.ts.map +1 -0
- package/dist/components/pages/Page.d.ts +124 -0
- package/dist/components/pages/Page.d.ts.map +1 -0
- package/dist/components/pages/index.d.ts +11 -0
- package/dist/components/pages/index.d.ts.map +1 -0
- package/dist/contexts/DataContext.d.ts +139 -0
- package/dist/contexts/DataContext.d.ts.map +1 -0
- package/dist/contexts/DimensionsContext.d.ts +42 -0
- package/dist/contexts/DimensionsContext.d.ts.map +1 -0
- package/dist/contexts/PaletteContext.d.ts +53 -0
- package/dist/contexts/PaletteContext.d.ts.map +1 -0
- package/dist/contexts/QwickAppContext.d.ts +71 -0
- package/dist/contexts/QwickAppContext.d.ts.map +1 -0
- package/dist/contexts/ThemeContext.d.ts +65 -0
- package/dist/contexts/ThemeContext.d.ts.map +1 -0
- package/dist/contexts/index.d.ts +9 -0
- package/dist/contexts/index.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +10 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/useBaseProps.d.ts +101 -0
- package/dist/hooks/useBaseProps.d.ts.map +1 -0
- package/dist/hooks/useDataBinding.d.ts +22 -0
- package/dist/hooks/useDataBinding.d.ts.map +1 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.css +1 -0
- package/dist/index.esm.js +24143 -0
- package/dist/index.js +24245 -0
- package/dist/palettes/PaletteAutumn.d.ts +10 -0
- package/dist/palettes/PaletteAutumn.d.ts.map +1 -0
- package/dist/palettes/PaletteCosmic.d.ts +10 -0
- package/dist/palettes/PaletteCosmic.d.ts.map +1 -0
- package/dist/palettes/PaletteDefault.d.ts +10 -0
- package/dist/palettes/PaletteDefault.d.ts.map +1 -0
- package/dist/palettes/PaletteOcean.d.ts +10 -0
- package/dist/palettes/PaletteOcean.d.ts.map +1 -0
- package/dist/palettes/PaletteSpring.d.ts +10 -0
- package/dist/palettes/PaletteSpring.d.ts.map +1 -0
- package/dist/palettes/PaletteWinter.d.ts +10 -0
- package/dist/palettes/PaletteWinter.d.ts.map +1 -0
- package/dist/palettes/index.d.ts +13 -0
- package/dist/palettes/index.d.ts.map +1 -0
- package/dist/schemas/ActionSchema.d.ts +21 -0
- package/dist/schemas/ActionSchema.d.ts.map +1 -0
- package/dist/schemas/ArticleSchema.d.ts +13 -0
- package/dist/schemas/ArticleSchema.d.ts.map +1 -0
- package/dist/schemas/Builders.d.ts +7 -0
- package/dist/schemas/Builders.d.ts.map +1 -0
- package/dist/schemas/ButtonSchema.d.ts +19 -0
- package/dist/schemas/ButtonSchema.d.ts.map +1 -0
- package/dist/schemas/CardListGridSchema.d.ts +17 -0
- package/dist/schemas/CardListGridSchema.d.ts.map +1 -0
- package/dist/schemas/ChoiceInputFieldSchema.d.ts +18 -0
- package/dist/schemas/ChoiceInputFieldSchema.d.ts.map +1 -0
- package/dist/schemas/CodeSchema.d.ts +18 -0
- package/dist/schemas/CodeSchema.d.ts.map +1 -0
- package/dist/schemas/ContentSchema.d.ts +20 -0
- package/dist/schemas/ContentSchema.d.ts.map +1 -0
- package/dist/schemas/CoverImageHeaderSchema.d.ts +28 -0
- package/dist/schemas/CoverImageHeaderSchema.d.ts.map +1 -0
- package/dist/schemas/FeatureCardSchema.d.ts +28 -0
- package/dist/schemas/FeatureCardSchema.d.ts.map +1 -0
- package/dist/schemas/FeatureGridSchema.d.ts +17 -0
- package/dist/schemas/FeatureGridSchema.d.ts.map +1 -0
- package/dist/schemas/FeatureItemSchema.d.ts +16 -0
- package/dist/schemas/FeatureItemSchema.d.ts.map +1 -0
- package/dist/schemas/FooterItemSchema.d.ts +15 -0
- package/dist/schemas/FooterItemSchema.d.ts.map +1 -0
- package/dist/schemas/FooterSchema.d.ts +20 -0
- package/dist/schemas/FooterSchema.d.ts.map +1 -0
- package/dist/schemas/FooterSectionSchema.d.ts +15 -0
- package/dist/schemas/FooterSectionSchema.d.ts.map +1 -0
- package/dist/schemas/FormBlockSchema.d.ts +19 -0
- package/dist/schemas/FormBlockSchema.d.ts.map +1 -0
- package/dist/schemas/HeaderActionSchema.d.ts +17 -0
- package/dist/schemas/HeaderActionSchema.d.ts.map +1 -0
- package/dist/schemas/HeroBlockSchema.d.ts +22 -0
- package/dist/schemas/HeroBlockSchema.d.ts.map +1 -0
- package/dist/schemas/HtmlInputFieldSchema.d.ts +18 -0
- package/dist/schemas/HtmlInputFieldSchema.d.ts.map +1 -0
- package/dist/schemas/MetadataItemSchema.d.ts +13 -0
- package/dist/schemas/MetadataItemSchema.d.ts.map +1 -0
- package/dist/schemas/PageBannerHeaderSchema.d.ts +28 -0
- package/dist/schemas/PageBannerHeaderSchema.d.ts.map +1 -0
- package/dist/schemas/PaletteSwitcherSchema.d.ts +16 -0
- package/dist/schemas/PaletteSwitcherSchema.d.ts.map +1 -0
- package/dist/schemas/ProductCardSchema.d.ts +39 -0
- package/dist/schemas/ProductCardSchema.d.ts.map +1 -0
- package/dist/schemas/SafeSpanSchema.d.ts +13 -0
- package/dist/schemas/SafeSpanSchema.d.ts.map +1 -0
- package/dist/schemas/SectionSchema.d.ts +17 -0
- package/dist/schemas/SectionSchema.d.ts.map +1 -0
- package/dist/schemas/SelectInputFieldSchema.d.ts +27 -0
- package/dist/schemas/SelectInputFieldSchema.d.ts.map +1 -0
- package/dist/schemas/TextInputFieldSchema.d.ts +22 -0
- package/dist/schemas/TextInputFieldSchema.d.ts.map +1 -0
- package/dist/schemas/ThemeSwitcherSchema.d.ts +19 -0
- package/dist/schemas/ThemeSwitcherSchema.d.ts.map +1 -0
- package/dist/schemas/index.d.ts +33 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/types.d.ts +7 -0
- package/dist/schemas/types.d.ts.map +1 -0
- package/dist/templates/TemplateResolver.d.ts +52 -0
- package/dist/templates/TemplateResolver.d.ts.map +1 -0
- package/dist/templates/index.d.ts +7 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/tests/ConsoleWarningTest.d.ts +5 -0
- package/dist/tests/ConsoleWarningTest.d.ts.map +1 -0
- package/dist/tests/StorageKeyTest.d.ts +6 -0
- package/dist/tests/StorageKeyTest.d.ts.map +1 -0
- package/dist/tests/ThemeStorageKeyTest.d.ts +6 -0
- package/dist/tests/ThemeStorageKeyTest.d.ts.map +1 -0
- package/dist/types/CacheProvider.d.ts +18 -0
- package/dist/types/CacheProvider.d.ts.map +1 -0
- package/dist/types/ContentProxy.d.ts +47 -0
- package/dist/types/ContentProxy.d.ts.map +1 -0
- package/dist/types/DataBinding.d.ts +7 -0
- package/dist/types/DataBinding.d.ts.map +1 -0
- package/dist/types/DataProvider.d.ts +7 -0
- package/dist/types/DataProvider.d.ts.map +1 -0
- package/dist/types/DataTypes.d.ts +185 -0
- package/dist/types/DataTypes.d.ts.map +1 -0
- package/dist/types/TemplateProvider.d.ts +10 -0
- package/dist/types/TemplateProvider.d.ts.map +1 -0
- package/dist/types/TemplateResolver.d.ts +23 -0
- package/dist/types/TemplateResolver.d.ts.map +1 -0
- package/dist/types/index.d.ts +81 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/breakpoints.d.ts +35 -0
- package/dist/utils/breakpoints.d.ts.map +1 -0
- package/dist/utils/customPaletteManager.d.ts +8 -0
- package/dist/utils/customPaletteManager.d.ts.map +1 -0
- package/dist/utils/dimensions.d.ts +34 -0
- package/dist/utils/dimensions.d.ts.map +1 -0
- package/dist/utils/htmlTransform.d.ts +44 -0
- package/dist/utils/htmlTransform.d.ts.map +1 -0
- package/dist/utils/index.d.ts +15 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/logger.d.ts +14 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/paletteUtils.d.ts +38 -0
- package/dist/utils/paletteUtils.d.ts.map +1 -0
- package/dist/utils/persistenceUtils.d.ts +31 -0
- package/dist/utils/persistenceUtils.d.ts.map +1 -0
- package/dist/utils/reactUtils.d.ts +24 -0
- package/dist/utils/reactUtils.d.ts.map +1 -0
- package/dist/utils/spacing.d.ts +34 -0
- package/dist/utils/spacing.d.ts.map +1 -0
- package/dist/utils/themePerformanceMonitor.d.ts +32 -0
- package/dist/utils/themePerformanceMonitor.d.ts.map +1 -0
- package/dist/utils/themeUtils.d.ts +27 -0
- package/dist/utils/themeUtils.d.ts.map +1 -0
- package/package.json +141 -0
- package/src/__tests__/components/Logo.test.js +172 -0
- package/src/__tests__/contexts/DataContext.test.js +505 -0
- package/src/__tests__/contexts/PaletteContext.test.js +115 -0
- package/src/__tests__/contexts/ThemeContext.test.js +123 -0
- package/src/__tests__/utils/paletteUtils.test.js +142 -0
- package/src/__tests__/utils/themeUtils.test.js +142 -0
- package/src/components/AccessibilityChecker.tsx +264 -0
- package/src/components/Html.tsx +191 -0
- package/src/components/Logo.css +217 -0
- package/src/components/Logo.tsx +370 -0
- package/src/components/Markdown.tsx +191 -0
- package/src/components/QwickApp.css +257 -0
- package/src/components/QwickApp.tsx +157 -0
- package/src/components/QwickAppsLogo.tsx +77 -0
- package/src/components/ResponsiveMenu.css +416 -0
- package/src/components/ResponsiveMenu.tsx +310 -0
- package/src/components/SafeSpan.tsx +128 -0
- package/src/components/Scaffold.css +541 -0
- package/src/components/Scaffold.tsx +463 -0
- package/src/components/__tests__/Article.test.tsx +419 -0
- package/src/components/__tests__/Button.test.tsx +702 -0
- package/src/components/__tests__/CardListGrid.test.tsx +478 -0
- package/src/components/__tests__/ChoiceInputField.test.tsx +864 -0
- package/src/components/__tests__/Code.test.tsx +595 -0
- package/src/components/__tests__/Content.integration.test.tsx +193 -0
- package/src/components/__tests__/Content.test.tsx +504 -0
- package/src/components/__tests__/CoverImageHeader.test.tsx +456 -0
- package/src/components/__tests__/FeatureCard.integration.test.tsx +384 -0
- package/src/components/__tests__/FeatureGrid.integration.test.tsx +364 -0
- package/src/components/__tests__/FeatureGrid.test.tsx +494 -0
- package/src/components/__tests__/Footer.test.tsx +544 -0
- package/src/components/__tests__/FormBlock.test.tsx +857 -0
- package/src/components/__tests__/HeroBlock.integration.test.tsx +272 -0
- package/src/components/__tests__/HeroBlock.test.tsx +463 -0
- package/src/components/__tests__/Html.test.tsx +174 -0
- package/src/components/__tests__/HtmlInputField.test.tsx +856 -0
- package/src/components/__tests__/Markdown.test.tsx +233 -0
- package/src/components/__tests__/PageBannerHeader.test.tsx +614 -0
- package/src/components/__tests__/PaletteSwitcher.test.tsx +864 -0
- package/src/components/__tests__/ProductCard.test.tsx +377 -0
- package/src/components/__tests__/SafeSpan.integration.test.tsx +123 -0
- package/src/components/__tests__/SafeSpan.simple.test.tsx +65 -0
- package/src/components/__tests__/SafeSpan.test.tsx +388 -0
- package/src/components/__tests__/Section.integration.test.tsx +288 -0
- package/src/components/__tests__/Section.test.tsx +494 -0
- package/src/components/__tests__/SelectInputField.test.tsx +886 -0
- package/src/components/__tests__/TextInputField.test.tsx +749 -0
- package/src/components/__tests__/ThemeSwitcher.test.tsx +777 -0
- package/src/components/blocks/Article.tsx +194 -0
- package/src/components/blocks/CardListGrid.tsx +132 -0
- package/src/components/blocks/Code.tsx +313 -0
- package/src/components/blocks/Content.tsx +265 -0
- package/src/components/blocks/CoverImageHeader.css +17 -0
- package/src/components/blocks/CoverImageHeader.tsx +435 -0
- package/src/components/blocks/FeatureCard.tsx +321 -0
- package/src/components/blocks/FeatureGrid.tsx +147 -0
- package/src/components/blocks/Footer.tsx +343 -0
- package/src/components/blocks/HeroBlock.tsx +280 -0
- package/src/components/blocks/PageBannerHeader.tsx +471 -0
- package/src/components/blocks/ProductCard.tsx +472 -0
- package/src/components/blocks/Section.tsx +209 -0
- package/src/components/blocks/index.ts +37 -0
- package/src/components/buttons/Button.tsx +233 -0
- package/src/components/buttons/PaletteSwitcher.tsx +268 -0
- package/src/components/buttons/ThemeSwitcher.tsx +283 -0
- package/src/components/buttons/index.ts +11 -0
- package/src/components/forms/FormBlock.tsx +291 -0
- package/src/components/forms/index.ts +7 -0
- package/src/components/index.ts +37 -0
- package/src/components/input/ChoiceInputField.tsx +188 -0
- package/src/components/input/HtmlInputField.tsx +326 -0
- package/src/components/input/SelectInputField.tsx +197 -0
- package/src/components/input/TextField.tsx +47 -0
- package/src/components/input/TextInputField.tsx +144 -0
- package/src/components/input/index.ts +17 -0
- package/src/components/layout/GridCell.tsx +46 -0
- package/src/components/layout/GridCellWrapper.tsx +87 -0
- package/src/components/layout/GridLayout.tsx +169 -0
- package/src/components/layout/index.ts +13 -0
- package/src/components/menu/Menu.tsx +0 -0
- package/src/components/menu/MenuItem.tsx +32 -0
- package/src/components/menu/index.ts +6 -0
- package/src/components/pages/FormPage.tsx +108 -0
- package/src/components/pages/Page.css +460 -0
- package/src/components/pages/Page.tsx +345 -0
- package/src/components/pages/index.ts +11 -0
- package/src/contexts/DataContext.tsx +355 -0
- package/src/contexts/DimensionsContext.tsx +154 -0
- package/src/contexts/PaletteContext.tsx +217 -0
- package/src/contexts/QwickAppContext.tsx +95 -0
- package/src/contexts/ThemeContext.tsx +376 -0
- package/src/contexts/index.ts +9 -0
- package/src/hooks/__tests__/useDataBinding.test.tsx.disabled +229 -0
- package/src/hooks/index.ts +11 -0
- package/src/hooks/useBaseProps.ts +267 -0
- package/src/hooks/useDataBinding.ts +77 -0
- package/src/index.ts +23 -0
- package/src/palettes/PaletteAutumn.css +172 -0
- package/src/palettes/PaletteAutumn.ts +16 -0
- package/src/palettes/PaletteCosmic.css +172 -0
- package/src/palettes/PaletteCosmic.ts +16 -0
- package/src/palettes/PaletteDefault.css +178 -0
- package/src/palettes/PaletteDefault.ts +17 -0
- package/src/palettes/PaletteOcean.css +172 -0
- package/src/palettes/PaletteOcean.ts +16 -0
- package/src/palettes/PaletteSpring.css +160 -0
- package/src/palettes/PaletteSpring.ts +16 -0
- package/src/palettes/PaletteWinter.css +172 -0
- package/src/palettes/PaletteWinter.ts +16 -0
- package/src/palettes/index.css +12 -0
- package/src/palettes/index.ts +29 -0
- package/src/schemas/ActionSchema.ts +140 -0
- package/src/schemas/ArticleSchema.ts +35 -0
- package/src/schemas/ButtonSchema.ts +99 -0
- package/src/schemas/CardListGridSchema.ts +102 -0
- package/src/schemas/ChoiceInputFieldSchema.ts +89 -0
- package/src/schemas/CodeSchema.ts +88 -0
- package/src/schemas/ContentSchema.ts +128 -0
- package/src/schemas/CoverImageHeaderSchema.ts +208 -0
- package/src/schemas/FeatureCardSchema.ts +161 -0
- package/src/schemas/FeatureGridSchema.ts +87 -0
- package/src/schemas/FeatureItemSchema.ts +68 -0
- package/src/schemas/FooterItemSchema.ts +57 -0
- package/src/schemas/FooterSchema.ts +116 -0
- package/src/schemas/FooterSectionSchema.ts +50 -0
- package/src/schemas/FormBlockSchema.ts +102 -0
- package/src/schemas/HeaderActionSchema.ts +83 -0
- package/src/schemas/HeroBlockSchema.ts +149 -0
- package/src/schemas/HtmlInputFieldSchema.ts +88 -0
- package/src/schemas/MetadataItemSchema.ts +35 -0
- package/src/schemas/PageBannerHeaderSchema.ts +206 -0
- package/src/schemas/PaletteSwitcherSchema.ts +66 -0
- package/src/schemas/ProductCardSchema.ts +264 -0
- package/src/schemas/SafeSpanSchema.ts +36 -0
- package/src/schemas/SectionSchema.ts +106 -0
- package/src/schemas/SelectInputFieldSchema.ts +137 -0
- package/src/schemas/TextInputFieldSchema.ts +129 -0
- package/src/schemas/ThemeSwitcherSchema.ts +97 -0
- package/src/schemas/__tests__/builders.test.ts +313 -0
- package/src/schemas/index.ts +34 -0
- package/src/setupTests.js +60 -0
- package/src/stories/Article.stories.tsx +549 -0
- package/src/stories/Button.stories.tsx +498 -0
- package/src/stories/CardListGrid.stories.tsx +539 -0
- package/src/stories/ChoiceInputField.stories.tsx +591 -0
- package/src/stories/Code.stories.tsx +711 -0
- package/src/stories/Content.stories.tsx +463 -0
- package/src/stories/CoverImageHeader.stories.tsx +794 -0
- package/src/stories/DataBinding.advanced.stories.tsx +548 -0
- package/src/stories/DataBinding.stories.tsx +452 -0
- package/src/stories/DataProvider.stories.tsx +1361 -0
- package/src/stories/FeatureCard.stories.tsx +642 -0
- package/src/stories/FeatureGrid.stories.tsx +669 -0
- package/src/stories/Footer.stories.tsx +724 -0
- package/src/stories/FormBlock.stories.tsx +834 -0
- package/src/stories/HeroBlock.stories.tsx +442 -0
- package/src/stories/Html.stories.tsx +264 -0
- package/src/stories/HtmlInputField.stories.tsx +558 -0
- package/src/stories/Introduction.stories.tsx +721 -0
- package/src/stories/LayoutBlocks.stories.tsx +382 -0
- package/src/stories/LayoutSystem.stories.tsx +253 -0
- package/src/stories/Logo.stories.tsx +400 -0
- package/src/stories/Markdown.stories.tsx +349 -0
- package/src/stories/Page.stories.tsx +762 -0
- package/src/stories/PageBannerHeader.stories.tsx +949 -0
- package/src/stories/PaletteSwitcher.stories.tsx +156 -0
- package/src/stories/ProductCard.stories.tsx +504 -0
- package/src/stories/QwickApp.stories.tsx +461 -0
- package/src/stories/ResponsiveMenu.stories.tsx +299 -0
- package/src/stories/SafeSpan.stories.tsx +612 -0
- package/src/stories/Section.stories.tsx +613 -0
- package/src/stories/SelectInputField.stories.tsx +605 -0
- package/src/stories/TextInputField.stories.tsx +526 -0
- package/src/stories/ThemeSwitcher.stories.tsx +170 -0
- package/src/stories/form/FormComponents.stories.tsx +588 -0
- package/src/templates/TemplateResolver.ts +156 -0
- package/src/templates/index.ts +6 -0
- package/src/tests/ConsoleWarningTest.tsx +30 -0
- package/src/tests/StorageKeyTest.tsx +110 -0
- package/src/tests/ThemeStorageKeyTest.tsx +114 -0
- package/src/types/CacheProvider.ts +14 -0
- package/src/types/ContentProxy.ts +99 -0
- package/src/types/DataTypes.ts +196 -0
- package/src/types/TemplateProvider.ts +9 -0
- package/src/types/TemplateResolver.ts +26 -0
- package/src/types/index.ts +99 -0
- package/src/utils/__tests__/createDataDrivenComponent.test.tsx.disabled +193 -0
- package/src/utils/__tests__/htmlTransform.test.tsx +255 -0
- package/src/utils/breakpoints.ts +87 -0
- package/src/utils/customPaletteManager.js +214 -0
- package/src/utils/dimensions.ts +147 -0
- package/src/utils/htmlTransform.tsx +323 -0
- package/src/utils/index.ts +16 -0
- package/src/utils/logger.ts +28 -0
- package/src/utils/paletteUtils.ts +78 -0
- package/src/utils/persistenceUtils.ts +107 -0
- package/src/utils/reactUtils.tsx +37 -0
- package/src/utils/spacing.ts +155 -0
- package/src/utils/themePerformanceMonitor.js +113 -0
- package/src/utils/themeUtils.ts +67 -0
|
@@ -0,0 +1,702 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for Button component
|
|
3
|
+
*
|
|
4
|
+
* Tests both traditional props usage and data binding functionality
|
|
5
|
+
* with the new schema system.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
10
|
+
import '@testing-library/jest-dom';
|
|
11
|
+
import Button from '../buttons/Button';
|
|
12
|
+
import { DataProvider } from '../../contexts/DataContext';
|
|
13
|
+
import { JsonDataProvider } from '@qwickapps/schema';
|
|
14
|
+
import { ThemeProvider, PaletteProvider } from '../../contexts';
|
|
15
|
+
|
|
16
|
+
// Test data for data binding
|
|
17
|
+
const sampleCmsData = {
|
|
18
|
+
'buttons': {
|
|
19
|
+
'primary-button': {
|
|
20
|
+
label: 'Primary Action',
|
|
21
|
+
variant: 'primary',
|
|
22
|
+
buttonSize: 'medium',
|
|
23
|
+
disabled: false,
|
|
24
|
+
loading: false,
|
|
25
|
+
fullWidth: false
|
|
26
|
+
},
|
|
27
|
+
'secondary-button': {
|
|
28
|
+
label: 'Secondary Action',
|
|
29
|
+
variant: 'secondary',
|
|
30
|
+
buttonSize: 'small',
|
|
31
|
+
disabled: false,
|
|
32
|
+
loading: false,
|
|
33
|
+
fullWidth: false
|
|
34
|
+
},
|
|
35
|
+
'link-button': {
|
|
36
|
+
label: 'External Link',
|
|
37
|
+
variant: 'outlined',
|
|
38
|
+
buttonSize: 'large',
|
|
39
|
+
href: 'https://example.com',
|
|
40
|
+
target: '_blank',
|
|
41
|
+
disabled: false,
|
|
42
|
+
loading: false,
|
|
43
|
+
fullWidth: false
|
|
44
|
+
},
|
|
45
|
+
'loading-button': {
|
|
46
|
+
label: 'Loading Action',
|
|
47
|
+
variant: 'contained',
|
|
48
|
+
buttonSize: 'medium',
|
|
49
|
+
disabled: false,
|
|
50
|
+
loading: true,
|
|
51
|
+
fullWidth: false
|
|
52
|
+
},
|
|
53
|
+
'disabled-button': {
|
|
54
|
+
label: 'Disabled Action',
|
|
55
|
+
variant: 'text',
|
|
56
|
+
buttonSize: 'medium',
|
|
57
|
+
disabled: true,
|
|
58
|
+
loading: false,
|
|
59
|
+
fullWidth: false
|
|
60
|
+
},
|
|
61
|
+
'full-width-button': {
|
|
62
|
+
label: 'Full Width Action',
|
|
63
|
+
variant: 'primary',
|
|
64
|
+
buttonSize: 'medium',
|
|
65
|
+
disabled: false,
|
|
66
|
+
loading: false,
|
|
67
|
+
fullWidth: true
|
|
68
|
+
},
|
|
69
|
+
'empty': {
|
|
70
|
+
label: '',
|
|
71
|
+
variant: 'primary'
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Wrapper component for tests that need providers
|
|
77
|
+
const TestWrapper: React.FC<{ children: React.ReactNode; dataProvider?: any }> = ({
|
|
78
|
+
children,
|
|
79
|
+
dataProvider
|
|
80
|
+
}) => (
|
|
81
|
+
<ThemeProvider>
|
|
82
|
+
<PaletteProvider>
|
|
83
|
+
{dataProvider ? (
|
|
84
|
+
<DataProvider dataSource={{ dataProvider }}>
|
|
85
|
+
{children}
|
|
86
|
+
</DataProvider>
|
|
87
|
+
) : (
|
|
88
|
+
children
|
|
89
|
+
)}
|
|
90
|
+
</PaletteProvider>
|
|
91
|
+
</ThemeProvider>
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
describe('Button', () => {
|
|
95
|
+
describe('Traditional Props Usage', () => {
|
|
96
|
+
it('renders basic button content', () => {
|
|
97
|
+
render(
|
|
98
|
+
<TestWrapper>
|
|
99
|
+
<Button label="Click me" />
|
|
100
|
+
</TestWrapper>
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
expect(screen.getByRole('button', { name: 'Click me' })).toBeInTheDocument();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('renders button with children instead of label', () => {
|
|
107
|
+
render(
|
|
108
|
+
<TestWrapper>
|
|
109
|
+
<Button>
|
|
110
|
+
<span>Custom Content</span>
|
|
111
|
+
</Button>
|
|
112
|
+
</TestWrapper>
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
expect(screen.getByRole('button')).toBeInTheDocument();
|
|
116
|
+
expect(screen.getByText('Custom Content')).toBeInTheDocument();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('handles click events', () => {
|
|
120
|
+
const handleClick = jest.fn();
|
|
121
|
+
|
|
122
|
+
render(
|
|
123
|
+
<TestWrapper>
|
|
124
|
+
<Button label="Click me" onClick={handleClick} />
|
|
125
|
+
</TestWrapper>
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
const button = screen.getByRole('button', { name: 'Click me' });
|
|
129
|
+
fireEvent.click(button);
|
|
130
|
+
|
|
131
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('does not handle clicks when disabled', () => {
|
|
135
|
+
const handleClick = jest.fn();
|
|
136
|
+
|
|
137
|
+
render(
|
|
138
|
+
<TestWrapper>
|
|
139
|
+
<Button label="Click me" onClick={handleClick} disabled />
|
|
140
|
+
</TestWrapper>
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
const button = screen.getByRole('button', { name: 'Click me' });
|
|
144
|
+
fireEvent.click(button);
|
|
145
|
+
|
|
146
|
+
expect(handleClick).not.toHaveBeenCalled();
|
|
147
|
+
expect(button).toBeDisabled();
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('does not handle clicks when loading', () => {
|
|
151
|
+
const handleClick = jest.fn();
|
|
152
|
+
|
|
153
|
+
render(
|
|
154
|
+
<TestWrapper>
|
|
155
|
+
<Button label="Click me" onClick={handleClick} loading />
|
|
156
|
+
</TestWrapper>
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const button = screen.getByRole('button', { name: 'Click me' });
|
|
160
|
+
fireEvent.click(button);
|
|
161
|
+
|
|
162
|
+
expect(handleClick).not.toHaveBeenCalled();
|
|
163
|
+
expect(button).toBeDisabled();
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('shows loading spinner when loading', () => {
|
|
167
|
+
render(
|
|
168
|
+
<TestWrapper>
|
|
169
|
+
<Button label="Click me" loading />
|
|
170
|
+
</TestWrapper>
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
expect(screen.getByRole('progressbar', { name: 'Loading' })).toBeInTheDocument();
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('renders as link when href is provided', () => {
|
|
177
|
+
render(
|
|
178
|
+
<TestWrapper>
|
|
179
|
+
<Button label="Visit Site" href="https://example.com" target="_blank" />
|
|
180
|
+
</TestWrapper>
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
const link = screen.getByRole('link', { name: 'Visit Site' });
|
|
184
|
+
expect(link).toBeInTheDocument();
|
|
185
|
+
expect(link).toHaveAttribute('href', 'https://example.com');
|
|
186
|
+
expect(link).toHaveAttribute('target', '_blank');
|
|
187
|
+
expect(link).toHaveAttribute('rel', 'noopener noreferrer');
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('does not render as link when disabled', () => {
|
|
191
|
+
render(
|
|
192
|
+
<TestWrapper>
|
|
193
|
+
<Button label="Visit Site" href="https://example.com" disabled />
|
|
194
|
+
</TestWrapper>
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
expect(screen.getByRole('button', { name: 'Visit Site' })).toBeInTheDocument();
|
|
198
|
+
expect(screen.queryByRole('link')).not.toBeInTheDocument();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('does not render as link when loading', () => {
|
|
202
|
+
render(
|
|
203
|
+
<TestWrapper>
|
|
204
|
+
<Button label="Visit Site" href="https://example.com" loading />
|
|
205
|
+
</TestWrapper>
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
expect(screen.getByRole('button', { name: 'Visit Site' })).toBeInTheDocument();
|
|
209
|
+
expect(screen.queryByRole('link')).not.toBeInTheDocument();
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('applies different variants correctly', () => {
|
|
213
|
+
const { rerender } = render(
|
|
214
|
+
<TestWrapper>
|
|
215
|
+
<Button label="Primary" variant="primary" />
|
|
216
|
+
</TestWrapper>
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
expect(screen.getByRole('button')).toHaveClass('MuiButton-containedPrimary');
|
|
220
|
+
|
|
221
|
+
rerender(
|
|
222
|
+
<TestWrapper>
|
|
223
|
+
<Button label="Secondary" variant="secondary" />
|
|
224
|
+
</TestWrapper>
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
expect(screen.getByRole('button')).toHaveClass('MuiButton-containedSecondary');
|
|
228
|
+
|
|
229
|
+
rerender(
|
|
230
|
+
<TestWrapper>
|
|
231
|
+
<Button label="Outlined" variant="outlined" />
|
|
232
|
+
</TestWrapper>
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
expect(screen.getByRole('button')).toHaveClass('MuiButton-outlinedPrimary');
|
|
236
|
+
|
|
237
|
+
rerender(
|
|
238
|
+
<TestWrapper>
|
|
239
|
+
<Button label="Text" variant="text" />
|
|
240
|
+
</TestWrapper>
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
expect(screen.getByRole('button')).toHaveClass('MuiButton-textPrimary');
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('applies different sizes correctly', () => {
|
|
247
|
+
const { rerender } = render(
|
|
248
|
+
<TestWrapper>
|
|
249
|
+
<Button label="Small" buttonSize="small" />
|
|
250
|
+
</TestWrapper>
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
expect(screen.getByRole('button')).toHaveClass('MuiButton-sizeSmall');
|
|
254
|
+
|
|
255
|
+
rerender(
|
|
256
|
+
<TestWrapper>
|
|
257
|
+
<Button label="Medium" buttonSize="medium" />
|
|
258
|
+
</TestWrapper>
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
expect(screen.getByRole('button')).toHaveClass('MuiButton-sizeMedium');
|
|
262
|
+
|
|
263
|
+
rerender(
|
|
264
|
+
<TestWrapper>
|
|
265
|
+
<Button label="Large" buttonSize="large" />
|
|
266
|
+
</TestWrapper>
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
expect(screen.getByRole('button')).toHaveClass('MuiButton-sizeLarge');
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it('applies fullWidth correctly', () => {
|
|
273
|
+
render(
|
|
274
|
+
<TestWrapper>
|
|
275
|
+
<Button label="Full Width" fullWidth />
|
|
276
|
+
</TestWrapper>
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
expect(screen.getByRole('button')).toHaveClass('MuiButton-fullWidth');
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it('handles custom icons', () => {
|
|
283
|
+
const TestIcon = () => <span data-testid="test-icon">Icon</span>;
|
|
284
|
+
const TestEndIcon = () => <span data-testid="test-end-icon">End Icon</span>;
|
|
285
|
+
|
|
286
|
+
render(
|
|
287
|
+
<TestWrapper>
|
|
288
|
+
<Button
|
|
289
|
+
label="With Icons"
|
|
290
|
+
icon={<TestIcon />}
|
|
291
|
+
endIcon={<TestEndIcon />}
|
|
292
|
+
/>
|
|
293
|
+
</TestWrapper>
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
expect(screen.getByTestId('test-icon')).toBeInTheDocument();
|
|
297
|
+
expect(screen.getByTestId('test-end-icon')).toBeInTheDocument();
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('hides end icon when loading', () => {
|
|
301
|
+
const TestEndIcon = () => <span data-testid="test-end-icon">End Icon</span>;
|
|
302
|
+
|
|
303
|
+
render(
|
|
304
|
+
<TestWrapper>
|
|
305
|
+
<Button
|
|
306
|
+
label="Loading with End Icon"
|
|
307
|
+
endIcon={<TestEndIcon />}
|
|
308
|
+
loading
|
|
309
|
+
/>
|
|
310
|
+
</TestWrapper>
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
expect(screen.queryByTestId('test-end-icon')).not.toBeInTheDocument();
|
|
314
|
+
expect(screen.getByRole('progressbar', { name: 'Loading' })).toBeInTheDocument();
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it('handles empty label gracefully', () => {
|
|
318
|
+
render(
|
|
319
|
+
<TestWrapper>
|
|
320
|
+
<Button label="" />
|
|
321
|
+
</TestWrapper>
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
expect(screen.getByRole('button')).toBeInTheDocument();
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it('handles missing label and children', () => {
|
|
328
|
+
render(
|
|
329
|
+
<TestWrapper>
|
|
330
|
+
<Button />
|
|
331
|
+
</TestWrapper>
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
expect(screen.getByRole('button')).toBeInTheDocument();
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
describe('Data Binding Usage', () => {
|
|
339
|
+
let dataProvider: JsonDataProvider;
|
|
340
|
+
|
|
341
|
+
beforeEach(() => {
|
|
342
|
+
dataProvider = new JsonDataProvider({ data: sampleCmsData });
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('renders with dataSource prop (primary button)', async () => {
|
|
346
|
+
render(
|
|
347
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
348
|
+
<Button dataSource="buttons.primary-button" />
|
|
349
|
+
</TestWrapper>
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
await screen.findByRole('button', { name: 'Primary Action' });
|
|
353
|
+
expect(screen.getByRole('button')).toHaveClass('MuiButton-containedPrimary');
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it('renders with dataSource prop (secondary button)', async () => {
|
|
357
|
+
render(
|
|
358
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
359
|
+
<Button dataSource="buttons.secondary-button" />
|
|
360
|
+
</TestWrapper>
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
await screen.findByRole('button', { name: 'Secondary Action' });
|
|
364
|
+
expect(screen.getByRole('button')).toHaveClass('MuiButton-containedSecondary');
|
|
365
|
+
expect(screen.getByRole('button')).toHaveClass('MuiButton-sizeSmall');
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it('renders link button from data source', async () => {
|
|
369
|
+
render(
|
|
370
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
371
|
+
<Button dataSource="buttons.link-button" />
|
|
372
|
+
</TestWrapper>
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
await waitFor(() => {
|
|
376
|
+
const link = screen.getByRole('link', { name: 'External Link' });
|
|
377
|
+
expect(link).toBeInTheDocument();
|
|
378
|
+
expect(link).toHaveAttribute('href', 'https://example.com');
|
|
379
|
+
expect(link).toHaveAttribute('target', '_blank');
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
it('shows loading state while data is loading', () => {
|
|
384
|
+
render(
|
|
385
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
386
|
+
<Button dataSource="buttons.nonexistent" />
|
|
387
|
+
</TestWrapper>
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
expect(screen.getByText('Loading Button...')).toBeInTheDocument();
|
|
391
|
+
expect(screen.getByText(/Loading button configuration from data source/)).toBeInTheDocument();
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
it('renders loading button from data source', async () => {
|
|
395
|
+
render(
|
|
396
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
397
|
+
<Button dataSource="buttons.loading-button" />
|
|
398
|
+
</TestWrapper>
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
// Wait for the button to render with loading state from the data
|
|
402
|
+
// The button should be disabled and show loading indicator
|
|
403
|
+
const button = await screen.findByRole('button', { name: 'Loading Action' });
|
|
404
|
+
|
|
405
|
+
expect(button).toBeDisabled();
|
|
406
|
+
expect(screen.getByRole('progressbar', { name: 'Loading' })).toBeInTheDocument();
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
it('renders disabled button from data source', async () => {
|
|
410
|
+
render(
|
|
411
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
412
|
+
<Button dataSource="buttons.disabled-button" />
|
|
413
|
+
</TestWrapper>
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
await waitFor(() => {
|
|
417
|
+
expect(screen.getByRole('button', { name: 'Disabled Action' })).toBeDisabled();
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
it('renders full width button from data source', async () => {
|
|
422
|
+
render(
|
|
423
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
424
|
+
<Button dataSource="buttons.full-width-button" />
|
|
425
|
+
</TestWrapper>
|
|
426
|
+
);
|
|
427
|
+
|
|
428
|
+
await waitFor(() => {
|
|
429
|
+
expect(screen.getByRole('button', { name: 'Full Width Action' })).toHaveClass('MuiButton-fullWidth');
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
it('uses fallback props when dataSource has no content', async () => {
|
|
434
|
+
render(
|
|
435
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
436
|
+
<Button
|
|
437
|
+
dataSource="buttons.nonexistent"
|
|
438
|
+
label="Fallback Button"
|
|
439
|
+
/>
|
|
440
|
+
</TestWrapper>
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
// Should stay in loading state for nonexistent data source
|
|
444
|
+
expect(screen.getByText('Loading Button...')).toBeInTheDocument();
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
it('handles click events from data binding', async () => {
|
|
448
|
+
const handleClick = jest.fn();
|
|
449
|
+
|
|
450
|
+
render(
|
|
451
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
452
|
+
<Button dataSource="buttons.primary-button" onClick={handleClick} />
|
|
453
|
+
</TestWrapper>
|
|
454
|
+
);
|
|
455
|
+
|
|
456
|
+
await screen.findByRole('button', { name: 'Primary Action' });
|
|
457
|
+
|
|
458
|
+
const button = screen.getByRole('button', { name: 'Primary Action' });
|
|
459
|
+
fireEvent.click(button);
|
|
460
|
+
|
|
461
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
it('works with custom binding options', async () => {
|
|
465
|
+
render(
|
|
466
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
467
|
+
<Button
|
|
468
|
+
dataSource="buttons.primary-button"
|
|
469
|
+
bindingOptions={{ cache: false, strict: true }}
|
|
470
|
+
/>
|
|
471
|
+
</TestWrapper>
|
|
472
|
+
);
|
|
473
|
+
|
|
474
|
+
await screen.findByRole('button', { name: 'Primary Action' });
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
it('handles empty data from CMS', async () => {
|
|
478
|
+
render(
|
|
479
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
480
|
+
<Button dataSource="buttons.empty" />
|
|
481
|
+
</TestWrapper>
|
|
482
|
+
);
|
|
483
|
+
|
|
484
|
+
await waitFor(() => {
|
|
485
|
+
expect(screen.getByRole('button')).toBeInTheDocument();
|
|
486
|
+
});
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
it('shows error state in development mode', async () => {
|
|
490
|
+
// Temporarily set NODE_ENV to development for this test
|
|
491
|
+
const originalNodeEnv = process.env.NODE_ENV;
|
|
492
|
+
process.env.NODE_ENV = 'development';
|
|
493
|
+
|
|
494
|
+
// Mock console.error to avoid noise in test output
|
|
495
|
+
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
496
|
+
|
|
497
|
+
// Create a data provider that will throw an error
|
|
498
|
+
const errorDataProvider = new JsonDataProvider({
|
|
499
|
+
data: {} // Empty data will cause a binding error
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
render(
|
|
503
|
+
<TestWrapper dataProvider={errorDataProvider}>
|
|
504
|
+
<Button dataSource="buttons.nonexistent-key" />
|
|
505
|
+
</TestWrapper>
|
|
506
|
+
);
|
|
507
|
+
|
|
508
|
+
await waitFor(() => {
|
|
509
|
+
const errorElement = screen.queryByText(/Error loading button:/);
|
|
510
|
+
if (errorElement) {
|
|
511
|
+
expect(errorElement).toBeInTheDocument();
|
|
512
|
+
} else {
|
|
513
|
+
// If no error is displayed, that's also acceptable behavior
|
|
514
|
+
// depending on the exact error handling implementation
|
|
515
|
+
expect(screen.getByText('Loading Button...')).toBeInTheDocument();
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
// Restore NODE_ENV
|
|
520
|
+
process.env.NODE_ENV = originalNodeEnv;
|
|
521
|
+
consoleSpy.mockRestore();
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
it('returns null on error in production mode', async () => {
|
|
525
|
+
// Temporarily set NODE_ENV to production for this test
|
|
526
|
+
const originalNodeEnv = process.env.NODE_ENV;
|
|
527
|
+
process.env.NODE_ENV = 'production';
|
|
528
|
+
|
|
529
|
+
// Mock console.error to avoid noise in test output
|
|
530
|
+
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
531
|
+
|
|
532
|
+
// Create a data provider that will throw an error
|
|
533
|
+
const errorDataProvider = new JsonDataProvider({
|
|
534
|
+
data: {} // Empty data will cause a binding error
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
const { container } = render(
|
|
538
|
+
<TestWrapper dataProvider={errorDataProvider}>
|
|
539
|
+
<Button dataSource="buttons.nonexistent-key" />
|
|
540
|
+
</TestWrapper>
|
|
541
|
+
);
|
|
542
|
+
|
|
543
|
+
await waitFor(() => {
|
|
544
|
+
// In production, error should either return null (empty container)
|
|
545
|
+
// or show loading state - both are acceptable
|
|
546
|
+
const hasContent = container.firstChild;
|
|
547
|
+
// The component should handle the error gracefully
|
|
548
|
+
expect(hasContent).toBeDefined(); // Component should render something or nothing
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
// Restore NODE_ENV
|
|
552
|
+
process.env.NODE_ENV = originalNodeEnv;
|
|
553
|
+
consoleSpy.mockRestore();
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
it('supports mixed data sources in same component tree', async () => {
|
|
557
|
+
render(
|
|
558
|
+
<TestWrapper dataProvider={dataProvider}>
|
|
559
|
+
<div>
|
|
560
|
+
<Button dataSource="buttons.primary-button" />
|
|
561
|
+
<Button dataSource="buttons.secondary-button" />
|
|
562
|
+
<Button dataSource="buttons.link-button" />
|
|
563
|
+
</div>
|
|
564
|
+
</TestWrapper>
|
|
565
|
+
);
|
|
566
|
+
|
|
567
|
+
// All three buttons should render with their respective content
|
|
568
|
+
await screen.findByRole('button', { name: 'Primary Action' });
|
|
569
|
+
await screen.findByRole('button', { name: 'Secondary Action' });
|
|
570
|
+
await screen.findByRole('link', { name: 'External Link' });
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
it.skip('preserves component marking for QwickApp framework', () => {
|
|
574
|
+
// The component should be marked as a QwickApp component
|
|
575
|
+
// This is important for framework identification - test skipped due to test environment limitations
|
|
576
|
+
const buttonComponent = Button as any;
|
|
577
|
+
expect(buttonComponent.QWICKAPP_COMPONENT).toBeTruthy();
|
|
578
|
+
});
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
describe('Edge Cases', () => {
|
|
582
|
+
it('handles multiple rapid clicks gracefully', () => {
|
|
583
|
+
const handleClick = jest.fn();
|
|
584
|
+
|
|
585
|
+
render(
|
|
586
|
+
<TestWrapper>
|
|
587
|
+
<Button label="Click me" onClick={handleClick} />
|
|
588
|
+
</TestWrapper>
|
|
589
|
+
);
|
|
590
|
+
|
|
591
|
+
const button = screen.getByRole('button', { name: 'Click me' });
|
|
592
|
+
|
|
593
|
+
// Rapid clicks
|
|
594
|
+
fireEvent.click(button);
|
|
595
|
+
fireEvent.click(button);
|
|
596
|
+
fireEvent.click(button);
|
|
597
|
+
|
|
598
|
+
expect(handleClick).toHaveBeenCalledTimes(3);
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
it('handles keyboard interactions', () => {
|
|
602
|
+
const handleClick = jest.fn();
|
|
603
|
+
|
|
604
|
+
render(
|
|
605
|
+
<TestWrapper>
|
|
606
|
+
<Button label="Click me" onClick={handleClick} />
|
|
607
|
+
</TestWrapper>
|
|
608
|
+
);
|
|
609
|
+
|
|
610
|
+
const button = screen.getByRole('button', { name: 'Click me' });
|
|
611
|
+
|
|
612
|
+
// Space key
|
|
613
|
+
fireEvent.keyDown(button, { key: ' ', code: 'Space' });
|
|
614
|
+
// Enter key
|
|
615
|
+
fireEvent.keyDown(button, { key: 'Enter', code: 'Enter' });
|
|
616
|
+
|
|
617
|
+
// Material-UI Button handles keyboard events internally
|
|
618
|
+
expect(button).toBeInTheDocument();
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
it('handles very long button labels', () => {
|
|
622
|
+
const longLabel = 'This is a very long button label that might cause layout issues in some scenarios but should be handled gracefully by the component';
|
|
623
|
+
|
|
624
|
+
render(
|
|
625
|
+
<TestWrapper>
|
|
626
|
+
<Button label={longLabel} />
|
|
627
|
+
</TestWrapper>
|
|
628
|
+
);
|
|
629
|
+
|
|
630
|
+
expect(screen.getByRole('button', { name: longLabel })).toBeInTheDocument();
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
it('handles complex children content', () => {
|
|
634
|
+
render(
|
|
635
|
+
<TestWrapper>
|
|
636
|
+
<Button>
|
|
637
|
+
<div>
|
|
638
|
+
<span>Complex</span>
|
|
639
|
+
<strong>Content</strong>
|
|
640
|
+
<em>Here</em>
|
|
641
|
+
</div>
|
|
642
|
+
</Button>
|
|
643
|
+
</TestWrapper>
|
|
644
|
+
);
|
|
645
|
+
|
|
646
|
+
expect(screen.getByRole('button')).toBeInTheDocument();
|
|
647
|
+
expect(screen.getByText('Complex')).toBeInTheDocument();
|
|
648
|
+
expect(screen.getByText('Content')).toBeInTheDocument();
|
|
649
|
+
expect(screen.getByText('Here')).toBeInTheDocument();
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
it('handles href with special characters', () => {
|
|
653
|
+
const complexUrl = 'https://example.com/path?param=value&other=test#section';
|
|
654
|
+
|
|
655
|
+
render(
|
|
656
|
+
<TestWrapper>
|
|
657
|
+
<Button label="Complex URL" href={complexUrl} />
|
|
658
|
+
</TestWrapper>
|
|
659
|
+
);
|
|
660
|
+
|
|
661
|
+
const link = screen.getByRole('link', { name: 'Complex URL' });
|
|
662
|
+
expect(link).toHaveAttribute('href', complexUrl);
|
|
663
|
+
});
|
|
664
|
+
|
|
665
|
+
it('handles invalid variant gracefully', () => {
|
|
666
|
+
render(
|
|
667
|
+
<TestWrapper>
|
|
668
|
+
<Button label="Invalid Variant" variant={'invalid' as any} />
|
|
669
|
+
</TestWrapper>
|
|
670
|
+
);
|
|
671
|
+
|
|
672
|
+
// Should default to contained primary
|
|
673
|
+
expect(screen.getByRole('button')).toHaveClass('MuiButton-containedPrimary');
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
it('handles concurrent loading states', () => {
|
|
677
|
+
const { rerender } = render(
|
|
678
|
+
<TestWrapper>
|
|
679
|
+
<Button label="Test" loading={false} />
|
|
680
|
+
</TestWrapper>
|
|
681
|
+
);
|
|
682
|
+
|
|
683
|
+
expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();
|
|
684
|
+
|
|
685
|
+
rerender(
|
|
686
|
+
<TestWrapper>
|
|
687
|
+
<Button label="Test" loading={true} />
|
|
688
|
+
</TestWrapper>
|
|
689
|
+
);
|
|
690
|
+
|
|
691
|
+
expect(screen.getByRole('progressbar', { name: 'Loading' })).toBeInTheDocument();
|
|
692
|
+
|
|
693
|
+
rerender(
|
|
694
|
+
<TestWrapper>
|
|
695
|
+
<Button label="Test" loading={false} />
|
|
696
|
+
</TestWrapper>
|
|
697
|
+
);
|
|
698
|
+
|
|
699
|
+
expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();
|
|
700
|
+
});
|
|
701
|
+
});
|
|
702
|
+
});
|