fontdue-js 2.22.4 → 3.0.0-alpha2
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/.babelrc.cjs +72 -0
- package/dist/__generated__/AddToCartBannerQuery.graphql.js +1 -8
- package/dist/__generated__/AddToCartBanner_item.graphql.js +1 -8
- package/dist/__generated__/AddToCartBanner_order.graphql.js +1 -8
- package/dist/__generated__/AddressFieldsRefetchQuery.graphql.js +1 -8
- package/dist/__generated__/AddressFields_viewer.graphql.js +3 -11
- package/dist/__generated__/BuyButtonIDQuery.graphql.js +1 -8
- package/dist/__generated__/BuyButtonSlugQuery.graphql.js +1 -8
- package/dist/__generated__/BuyButton_collection.graphql.js +1 -8
- package/dist/__generated__/CartButtonQuery.graphql.js +1 -8
- package/dist/__generated__/CartButton_order.graphql.js +1 -8
- package/dist/__generated__/CartItemAdditionalLicenses_licenses.graphql.js +1 -8
- package/dist/__generated__/CartItemAdditionalLicenses_orderItem.graphql.js +1 -8
- package/dist/__generated__/CartItemLicense_selection.graphql.js +1 -8
- package/dist/__generated__/CartItemProduct_product.graphql.js +1 -8
- package/dist/__generated__/CartItemVariable_selection.graphql.js +1 -8
- package/dist/__generated__/CartItemVariable_variable.graphql.js +1 -8
- package/dist/__generated__/CartItem_node.graphql.js +1 -8
- package/dist/__generated__/CartOrderCompleteOrderMutation.graphql.js +1 -8
- package/dist/__generated__/CartOrderRemoveDiscountMutation.graphql.js +1 -8
- package/dist/__generated__/CartOrderUpdateMutation.graphql.js +1 -8
- package/dist/__generated__/CartOrder_UpdateErrors.graphql.js +1 -8
- package/dist/__generated__/CartOrder_order.graphql.js +1 -8
- package/dist/__generated__/CartOrder_viewer.graphql.js +1 -8
- package/dist/__generated__/CartQuery.graphql.js +1 -8
- package/dist/__generated__/CartStateRemoveDiscountMutation.graphql.js +1 -8
- package/dist/__generated__/CartStateUpdateMutation.graphql.js +1 -8
- package/dist/__generated__/CartState_order.graphql.js +1 -8
- package/dist/__generated__/CartTotals_order.graphql.js +1 -8
- package/dist/__generated__/CharacterViewerIDQuery.graphql.js +1 -8
- package/dist/__generated__/CharacterViewerSlugQuery.graphql.js +1 -8
- package/dist/__generated__/CharacterViewerStyleRefetchQuery.graphql.js +1 -8
- package/dist/__generated__/CharacterViewer_collection.graphql.js +1 -8
- package/dist/__generated__/CharacterViewer_family.graphql.js +1 -8
- package/dist/__generated__/CharacterViewer_style.graphql.js +3 -11
- package/dist/__generated__/CheckoutUpdateCustomerMutation.graphql.js +1 -8
- package/dist/__generated__/CheckoutUpdateOrderMutation.graphql.js +1 -8
- package/dist/__generated__/Checkout_UpdateOrderErrors.graphql.js +1 -8
- package/dist/__generated__/Checkout_identity.graphql.js +1 -8
- package/dist/__generated__/Checkout_order.graphql.js +1 -8
- package/dist/__generated__/Checkout_viewer.graphql.js +1 -8
- package/dist/__generated__/CollectionAa_Query.graphql.js +1 -8
- package/dist/__generated__/CollectionAa_product.graphql.js +1 -8
- package/dist/__generated__/CouponCodeInputApplyCouponMutation.graphql.js +1 -8
- package/dist/__generated__/CouponText_coupon.graphql.js +1 -8
- package/dist/__generated__/CustomerLoginFormLoginMutation.graphql.js +1 -8
- package/dist/__generated__/CustomerLoginFormQuery.graphql.js +1 -8
- package/dist/__generated__/DownloadRefetchQuery.graphql.js +1 -8
- package/dist/__generated__/Download_order.graphql.js +1 -8
- package/dist/__generated__/FamilyList_node.graphql.js +1 -8
- package/dist/__generated__/Family_node.graphql.js +1 -8
- package/dist/__generated__/FontFamiliesQuery.graphql.js +1 -8
- package/dist/__generated__/FontStyle_fontStyle.graphql.js +1 -8
- package/dist/__generated__/FontdueProviderQuery.graphql.d.ts +19 -0
- package/dist/__generated__/FontdueProviderQuery.graphql.js +140 -0
- package/dist/__generated__/IdentityBox_identity.graphql.js +1 -8
- package/dist/__generated__/License_node.graphql.js +1 -8
- package/dist/__generated__/NewsletterSignupQuery.graphql.js +1 -8
- package/dist/__generated__/NewsletterSignupUpdateCustomerMutation.graphql.js +1 -8
- package/dist/__generated__/NodePasswordFormAccessNodeMutation.graphql.js +1 -8
- package/dist/__generated__/NodePasswordFormIDQuery.graphql.js +1 -8
- package/dist/__generated__/NodePasswordFormSlugQuery.graphql.js +1 -8
- package/dist/__generated__/OrderVariableSelectionReduxRefetchQuery.graphql.js +1 -8
- package/dist/__generated__/OrderVariableSelectionRedux_viewer.graphql.js +3 -11
- package/dist/__generated__/OrderVariableSelection_variables.graphql.js +1 -8
- package/dist/__generated__/PrecartAddToCartMutation.graphql.js +1 -8
- package/dist/__generated__/PrecartClearCartMutation.graphql.js +1 -8
- package/dist/__generated__/PrecartQuery.graphql.js +1 -8
- package/dist/__generated__/Precart_collection.graphql.js +1 -8
- package/dist/__generated__/Precart_license.graphql.js +1 -8
- package/dist/__generated__/Precart_viewer.graphql.js +1 -8
- package/dist/__generated__/PriceBarSectionRefetchQuery.graphql.js +1 -8
- package/dist/__generated__/PriceBarSection_node.graphql.js +3 -11
- package/dist/__generated__/PriceBar_node.graphql.js +1 -8
- package/dist/__generated__/Price_price.graphql.js +1 -8
- package/dist/__generated__/SKUPrice_sku.graphql.js +1 -8
- package/dist/__generated__/SelectButton_sku.graphql.js +1 -8
- package/dist/__generated__/ServerConfigProviderQuery.graphql.js +1 -8
- package/dist/__generated__/ServerConfigProvider_viewer.graphql.d.ts +23 -0
- package/dist/__generated__/ServerConfigProvider_viewer.graphql.js +57 -0
- package/dist/__generated__/ShareCartCreateSnapshotMutation.graphql.js +1 -8
- package/dist/__generated__/SpecimenLinkQuery.graphql.js +1 -8
- package/dist/__generated__/StoreModalBundleButton_bundle.graphql.js +1 -8
- package/dist/__generated__/StoreModalCartQuery.graphql.js +1 -8
- package/dist/__generated__/StoreModalCheckoutQuery.graphql.js +1 -8
- package/dist/__generated__/StoreModalContainerQuery.graphql.js +1 -8
- package/dist/__generated__/StoreModalDownloadRefetchQuery.graphql.js +1 -8
- package/dist/__generated__/StoreModalDownload_order.graphql.js +1 -8
- package/dist/__generated__/StoreModalFamilyButton_collection.graphql.js +1 -8
- package/dist/__generated__/StoreModalFamily_collection.graphql.js +1 -8
- package/dist/__generated__/StoreModalIndexItem_fontCollection.graphql.js +1 -8
- package/dist/__generated__/StoreModalIndexQuery.graphql.js +1 -8
- package/dist/__generated__/StoreModalOrderVariableSelection_order.graphql.js +1 -8
- package/dist/__generated__/StoreModalOrderVariableSelection_viewer.graphql.js +1 -8
- package/dist/__generated__/StoreModalProductContent_collection.graphql.js +3 -11
- package/dist/__generated__/StoreModalProductLicenseSelection_collection.graphql.js +1 -8
- package/dist/__generated__/StoreModalProductLicense_license.graphql.js +1 -8
- package/dist/__generated__/StoreModalProductQuery.graphql.js +1 -8
- package/dist/__generated__/StoreModalProductRefetchQuery.graphql.js +1 -8
- package/dist/__generated__/StoreModalProductSummaryAddToCartMutation.graphql.js +1 -8
- package/dist/__generated__/StoreModalProductSummaryClearCartMutation.graphql.js +1 -8
- package/dist/__generated__/StoreModalProductSummaryRefetchQuery.graphql.js +1 -8
- package/dist/__generated__/StoreModalProductSummary_viewer.graphql.js +3 -11
- package/dist/__generated__/StoreModalReviewIdentity_identity.graphql.js +1 -8
- package/dist/__generated__/StoreModalStyleButton_fontStyle.graphql.js +1 -8
- package/dist/__generated__/StoreModalUnifiedCheckoutCompleteOrderMutation.graphql.js +1 -8
- package/dist/__generated__/StoreModalUnifiedCheckoutUpdateCustomerMutation.graphql.js +1 -8
- package/dist/__generated__/StoreModalUnifiedCheckoutUpdateOrderMutation.graphql.js +1 -8
- package/dist/__generated__/StoreModalUnifiedCheckout_order.graphql.js +1 -8
- package/dist/__generated__/StoreModalUnifiedCheckout_viewer.graphql.js +1 -8
- package/dist/__generated__/StripeProviderCreateCheckoutSessionMutation.graphql.js +1 -8
- package/dist/__generated__/StripeProvider_viewer.graphql.js +1 -8
- package/dist/__generated__/TestFontsFormUpdateCustomerMutation.graphql.js +1 -8
- package/dist/__generated__/TestFontsForm_Query.graphql.js +1 -8
- package/dist/__generated__/TestModeBannerQuery.graphql.js +1 -8
- package/dist/__generated__/TestModeBanner_viewer.graphql.d.ts +19 -0
- package/dist/__generated__/TestModeBanner_viewer.graphql.js +36 -0
- package/dist/__generated__/ThemeConfigQuery.graphql.js +1 -8
- package/dist/__generated__/ThemeConfig_viewer.graphql.d.ts +19 -0
- package/dist/__generated__/ThemeConfig_viewer.graphql.js +36 -0
- package/dist/__generated__/TypeTesterFeaturesButton_fontStyle.graphql.js +1 -8
- package/dist/__generated__/TypeTesterFeatures_fontStyle.graphql.js +1 -8
- package/dist/__generated__/TypeTesterFloatingToolbar_testers.graphql.js +1 -8
- package/dist/__generated__/TypeTesterStandaloneChangedStylesQuery.graphql.js +1 -8
- package/dist/__generated__/TypeTesterStandaloneQuery.graphql.js +1 -8
- package/dist/__generated__/TypeTesterStyleSelectData_fontStyle.graphql.js +1 -8
- package/dist/__generated__/TypeTesterStyleSelectData_fontStyleData.graphql.js +1 -8
- package/dist/__generated__/TypeTesterStyleSelectData_viewer.graphql.js +1 -8
- package/dist/__generated__/TypeTesterToolbar_fontStyle.graphql.js +1 -8
- package/dist/__generated__/TypeTesterVariableAxes_fontStyle.graphql.js +1 -8
- package/dist/__generated__/TypeTester_fontStyle.graphql.js +1 -8
- package/dist/__generated__/TypeTester_viewer.graphql.js +1 -8
- package/dist/__generated__/TypeTestersChangedStylesQuery.graphql.js +1 -8
- package/dist/__generated__/TypeTestersIDQuery.graphql.js +1 -8
- package/dist/__generated__/TypeTestersRefetchQuery.graphql.js +1 -8
- package/dist/__generated__/TypeTestersSlugQuery.graphql.js +1 -8
- package/dist/__generated__/TypeTesters_collection.graphql.js +3 -11
- package/dist/__generated__/TypeTesters_viewer.graphql.js +1 -8
- package/dist/__generated__/VariableTableAmounts_option.graphql.js +1 -8
- package/dist/__generated__/VariableTableAmounts_variable.graphql.js +1 -8
- package/dist/__generated__/productState_Query.graphql.js +1 -8
- package/dist/__generated__/productState_bundle.graphql.js +1 -8
- package/dist/__generated__/productState_collection.graphql.js +1 -8
- package/dist/__generated__/productState_collectionBundle.graphql.js +1 -8
- package/dist/__generated__/productState_node.graphql.js +1 -8
- package/dist/__generated__/productState_sku.graphql.js +1 -8
- package/dist/__generated__/useFeaturesData_fontStyle.graphql.js +1 -8
- package/dist/__generated__/useFontStyle_fontStyle.graphql.js +1 -8
- package/dist/__generated__/useTotalStyles_fontCollection.graphql.js +1 -8
- package/dist/__tests__/collectionBundleSelection.test.js +221 -222
- package/dist/components/AddToCartBanner/index.js +19 -29
- package/dist/components/BuyButton/index.d.ts +26 -6
- package/dist/components/BuyButton/index.js +90 -57
- package/dist/components/BuyButton/index.server.d.ts +5 -2
- package/dist/components/BuyButton/index.server.js +15 -17
- package/dist/components/BuyingOptions/index.js +4 -12
- package/dist/components/Cart/AddressFields.d.ts +2 -2
- package/dist/components/Cart/AddressFields.js +25 -35
- package/dist/components/Cart/CartItem/CartItemAdditionalLicenses.d.ts +2 -2
- package/dist/components/Cart/CartItem/CartItemAdditionalLicenses.js +9 -16
- package/dist/components/Cart/CartItem/CartItemLicense.d.ts +2 -2
- package/dist/components/Cart/CartItem/CartItemLicense.js +15 -24
- package/dist/components/Cart/CartItem/CartItemProduct.d.ts +1 -1
- package/dist/components/Cart/CartItem/CartItemProduct.js +16 -23
- package/dist/components/Cart/CartItem/CartItemVariable.d.ts +3 -3
- package/dist/components/Cart/CartItem/CartItemVariable.js +16 -23
- package/dist/components/Cart/CartItem/VariableTextInput.js +13 -21
- package/dist/components/Cart/CartItem/index.d.ts +2 -2
- package/dist/components/Cart/CartItem/index.js +18 -27
- package/dist/components/Cart/CartOrder.d.ts +2 -2
- package/dist/components/Cart/CartOrder.js +99 -110
- package/dist/components/Cart/CartState.d.ts +3 -3
- package/dist/components/Cart/CartState.js +18 -25
- package/dist/components/Cart/CartTotals.d.ts +1 -1
- package/dist/components/Cart/CartTotals.js +31 -38
- package/dist/components/Cart/Checkout.d.ts +3 -3
- package/dist/components/Cart/Checkout.js +109 -118
- package/dist/components/Cart/CheckoutSteps.js +1 -8
- package/dist/components/Cart/CouponCodeInput.js +22 -32
- package/dist/components/Cart/CustomerFields.d.ts +1 -1
- package/dist/components/Cart/CustomerFields.js +21 -31
- package/dist/components/Cart/Download.d.ts +1 -1
- package/dist/components/Cart/Download.js +17 -27
- package/dist/components/Cart/EmptyCart.js +15 -23
- package/dist/components/Cart/IdentityBox.d.ts +1 -1
- package/dist/components/Cart/IdentityBox.js +12 -19
- package/dist/components/Cart/ShareCart.js +24 -32
- package/dist/components/Cart/index.js +13 -21
- package/dist/components/Cart/injectRelayEnvironment.js +5 -13
- package/dist/components/Cart/types.d.ts +1 -1
- package/dist/components/Cart/types.js +1 -5
- package/dist/components/Cart/utils.js +2 -9
- package/dist/components/CartButton/index.d.ts +9 -6
- package/dist/components/CartButton/index.js +47 -53
- package/dist/components/CartButton/index.server.d.ts +1 -1
- package/dist/components/CartButton/index.server.js +12 -14
- package/dist/components/CharacterViewer/StyleSelect.d.ts +1 -1
- package/dist/components/CharacterViewer/StyleSelect.js +10 -17
- package/dist/components/CharacterViewer/index.d.ts +26 -6
- package/dist/components/CharacterViewer/index.js +137 -97
- package/dist/components/CharacterViewer/index.server.d.ts +5 -2
- package/dist/components/CharacterViewer/index.server.js +16 -17
- package/dist/components/Checkbox/index.js +9 -19
- package/dist/components/CollectionAa/index.d.ts +1 -1
- package/dist/components/CollectionAa/index.js +12 -21
- package/dist/components/ComponentsContext.d.ts +1 -1
- package/dist/components/ComponentsContext.js +4 -10
- package/dist/components/ConfigContext.d.ts +12 -12
- package/dist/components/ConfigContext.js +4 -11
- package/dist/components/ConsentBanner/consent.js +6 -17
- package/dist/components/ConsentBanner/index.js +19 -29
- package/dist/components/CookieNotification/index.js +19 -27
- package/dist/components/CorsErrorModal.js +13 -20
- package/dist/components/CouponText/index.d.ts +1 -1
- package/dist/components/CouponText/index.js +9 -18
- package/dist/components/CustomerLoginForm/index.js +23 -32
- package/dist/components/Family/FamilyList.d.ts +1 -1
- package/dist/components/Family/FamilyList.js +10 -17
- package/dist/components/Family/index.d.ts +1 -1
- package/dist/components/Family/index.js +37 -46
- package/dist/components/FontFamilies/index.js +18 -28
- package/dist/components/FontStyle/index.d.ts +1 -1
- package/dist/components/FontStyle/index.js +8 -15
- package/dist/components/FontdueContextProvider/index.d.ts +17 -0
- package/dist/components/FontdueContextProvider/index.js +108 -0
- package/dist/components/FontdueContextProvider/index.server.d.ts +4 -0
- package/dist/components/FontdueContextProvider/index.server.js +7 -0
- package/dist/components/FontdueProvider/FontdueProviderClientComponent.d.ts +6 -4
- package/dist/components/FontdueProvider/FontdueProviderClientComponent.js +48 -39
- package/dist/components/FontdueProvider/index.d.ts +9 -3
- package/dist/components/FontdueProvider/index.js +68 -13
- package/dist/components/FontdueProvider/index.server.d.ts +3 -3
- package/dist/components/FontdueProvider/index.server.js +14 -22
- package/dist/components/Icons/Align.js +13 -22
- package/dist/components/Icons/ArrowDownRight.js +5 -13
- package/dist/components/Icons/ArrowLeft.js +5 -13
- package/dist/components/Icons/ArrowRight.js +5 -13
- package/dist/components/Icons/CarrotDown.js +5 -13
- package/dist/components/Icons/CarrotUp.js +5 -13
- package/dist/components/Icons/Cart.js +7 -15
- package/dist/components/Icons/CartNew.js +7 -15
- package/dist/components/Icons/Check.js +5 -13
- package/dist/components/Icons/Checkbox.js +5 -13
- package/dist/components/Icons/CheckboxChecked.js +5 -13
- package/dist/components/Icons/CheckboxCrossed.js +6 -14
- package/dist/components/Icons/CircledCheck.js +6 -14
- package/dist/components/Icons/CircledInfo.js +6 -14
- package/dist/components/Icons/CircledMinus.js +6 -14
- package/dist/components/Icons/ColorPicker.js +5 -13
- package/dist/components/Icons/CreditCard.js +6 -14
- package/dist/components/Icons/DownArrow.js +5 -13
- package/dist/components/Icons/DownloadFonts.js +8 -16
- package/dist/components/Icons/FrowningFace.js +8 -16
- package/dist/components/Icons/License.js +5 -13
- package/dist/components/Icons/Receipt.js +8 -16
- package/dist/components/Icons/User.js +5 -13
- package/dist/components/Icons/X.js +5 -13
- package/dist/components/Icons/index.d.ts +23 -23
- package/dist/components/Icons/index.js +23 -167
- package/dist/components/NewsletterSignup/NewsletterSignupElement.d.ts +1 -1
- package/dist/components/NewsletterSignup/NewsletterSignupElement.js +4 -11
- package/dist/components/NewsletterSignup/index.d.ts +9 -6
- package/dist/components/NewsletterSignup/index.js +66 -60
- package/dist/components/NewsletterSignup/index.server.d.ts +1 -1
- package/dist/components/NewsletterSignup/index.server.js +12 -14
- package/dist/components/NodePasswordForm/index.js +25 -33
- package/dist/components/OrderVariableSelection/OrderVariableSelectionRedux.d.ts +1 -1
- package/dist/components/OrderVariableSelection/OrderVariableSelectionRedux.js +18 -27
- package/dist/components/OrderVariableSelection/index.d.ts +1 -1
- package/dist/components/OrderVariableSelection/index.js +28 -36
- package/dist/components/Precart/License.d.ts +1 -1
- package/dist/components/Precart/License.js +22 -30
- package/dist/components/Precart/index.js +64 -74
- package/dist/components/Price/index.d.ts +1 -1
- package/dist/components/Price/index.js +10 -20
- package/dist/components/PriceBar/PriceBarSection.d.ts +1 -1
- package/dist/components/PriceBar/PriceBarSection.js +23 -33
- package/dist/components/PriceBar/index.d.ts +1 -1
- package/dist/components/PriceBar/index.js +13 -23
- package/dist/components/Root/index.d.ts +1 -1
- package/dist/components/Root/index.js +41 -51
- package/dist/components/Root/productState.d.ts +1 -1
- package/dist/components/Root/productState.js +20 -29
- package/dist/components/SKUPrice/index.d.ts +2 -2
- package/dist/components/SKUPrice/index.js +12 -20
- package/dist/components/Select/index.js +9 -17
- package/dist/components/SelectButton/index.d.ts +2 -2
- package/dist/components/SelectButton/index.js +20 -29
- package/dist/components/ServerConfigProvider/index.d.ts +4 -2
- package/dist/components/ServerConfigProvider/index.js +12 -20
- package/dist/components/SpecimenLink/index.js +12 -20
- package/dist/components/StickyNav/index.js +16 -26
- package/dist/components/StoreModal/StoreModalBundleButton.d.ts +1 -1
- package/dist/components/StoreModal/StoreModalBundleButton.js +16 -23
- package/dist/components/StoreModal/StoreModalCart.d.ts +1 -1
- package/dist/components/StoreModal/StoreModalCart.js +29 -38
- package/dist/components/StoreModal/StoreModalCheckout.js +9 -17
- package/dist/components/StoreModal/StoreModalCheckoutContext.d.ts +1 -1
- package/dist/components/StoreModal/StoreModalCheckoutContext.js +6 -12
- package/dist/components/StoreModal/StoreModalContainer.js +25 -35
- package/dist/components/StoreModal/StoreModalDownload.d.ts +1 -1
- package/dist/components/StoreModal/StoreModalDownload.js +14 -24
- package/dist/components/StoreModal/StoreModalFamily.d.ts +1 -1
- package/dist/components/StoreModal/StoreModalFamily.js +14 -23
- package/dist/components/StoreModal/StoreModalFamilyButton.d.ts +1 -1
- package/dist/components/StoreModal/StoreModalFamilyButton.js +23 -30
- package/dist/components/StoreModal/StoreModalIndex.d.ts +1 -1
- package/dist/components/StoreModal/StoreModalIndex.js +9 -17
- package/dist/components/StoreModal/StoreModalIndexItem.d.ts +1 -1
- package/dist/components/StoreModal/StoreModalIndexItem.js +20 -30
- package/dist/components/StoreModal/StoreModalLicenseeIsBillingSelection.js +8 -17
- package/dist/components/StoreModal/StoreModalLoader.js +6 -15
- package/dist/components/StoreModal/StoreModalOrderVariableSelection.d.ts +3 -3
- package/dist/components/StoreModal/StoreModalOrderVariableSelection.js +12 -21
- package/dist/components/StoreModal/StoreModalProduct.d.ts +1 -1
- package/dist/components/StoreModal/StoreModalProduct.js +51 -61
- package/dist/components/StoreModal/StoreModalReviewIdentity.d.ts +1 -1
- package/dist/components/StoreModal/StoreModalReviewIdentity.js +6 -15
- package/dist/components/StoreModal/StoreModalRouter.js +12 -22
- package/dist/components/StoreModal/StoreModalStyleButton.d.ts +1 -1
- package/dist/components/StoreModal/StoreModalStyleButton.js +20 -27
- package/dist/components/StoreModal/index.js +19 -21
- package/dist/components/StoreModal/routes.d.ts +4 -4
- package/dist/components/StoreModal/routes.js +18 -26
- package/dist/components/StoreModal/types.js +1 -5
- package/dist/components/StoreModalProductLicenseSelection/LicenseElement.js +12 -22
- package/dist/components/StoreModalProductLicenseSelection/LicenseVariableElement.js +7 -15
- package/dist/components/StoreModalProductLicenseSelection/LicenseVariableRadioElement.js +9 -19
- package/dist/components/StoreModalProductLicenseSelection/StoreModalProductLicense.d.ts +1 -1
- package/dist/components/StoreModalProductLicenseSelection/StoreModalProductLicense.js +19 -28
- package/dist/components/StoreModalProductLicenseSelection/index.d.ts +1 -1
- package/dist/components/StoreModalProductLicenseSelection/index.js +10 -17
- package/dist/components/StoreModalProductSummary/index.d.ts +1 -1
- package/dist/components/StoreModalProductSummary/index.js +45 -55
- package/dist/components/StripeLogo.js +4 -11
- package/dist/components/StripeProvider/index.d.ts +1 -1
- package/dist/components/StripeProvider/index.js +19 -29
- package/dist/components/Switch/index.js +1 -7
- package/dist/components/TestFontsForm/TestFontsFormElement.js +4 -12
- package/dist/components/TestFontsForm/index.d.ts +9 -4
- package/dist/components/TestFontsForm/index.js +71 -65
- package/dist/components/TestFontsForm/index.server.d.ts +1 -1
- package/dist/components/TestFontsForm/index.server.js +12 -14
- package/dist/components/TestModeBanner/index.d.ts +4 -1
- package/dist/components/TestModeBanner/index.js +13 -27
- package/dist/components/TextField/index.js +9 -17
- package/dist/components/ThemeConfig/index.d.ts +3 -5
- package/dist/components/ThemeConfig/index.js +12 -36
- package/dist/components/ThemeConfig/index.server.js +7 -14
- package/dist/components/Tracking/index.js +11 -18
- package/dist/components/TypeTester/TypeTesterAlignButtons.d.ts +1 -1
- package/dist/components/TypeTester/TypeTesterAlignButtons.js +8 -16
- package/dist/components/TypeTester/TypeTesterBullet.d.ts +1 -1
- package/dist/components/TypeTester/TypeTesterBullet.js +4 -12
- package/dist/components/TypeTester/TypeTesterContent.d.ts +2 -2
- package/dist/components/TypeTester/TypeTesterContent.js +22 -21
- package/dist/components/TypeTester/TypeTesterContext.d.ts +2 -2
- package/dist/components/TypeTester/TypeTesterContext.js +10 -17
- package/dist/components/TypeTester/TypeTesterEditAll.js +10 -20
- package/dist/components/TypeTester/TypeTesterFeatures.d.ts +1 -1
- package/dist/components/TypeTester/TypeTesterFeatures.js +28 -37
- package/dist/components/TypeTester/TypeTesterFeaturesButton.d.ts +1 -1
- package/dist/components/TypeTester/TypeTesterFeaturesButton.js +20 -30
- package/dist/components/TypeTester/TypeTesterFitter.d.ts +1 -1
- package/dist/components/TypeTester/TypeTesterFitter.js +5 -13
- package/dist/components/TypeTester/TypeTesterFloatingToolbar.d.ts +1 -1
- package/dist/components/TypeTester/TypeTesterFloatingToolbar.js +19 -28
- package/dist/components/TypeTester/TypeTesterInput.js +12 -22
- package/dist/components/TypeTester/TypeTesterSlider.js +7 -16
- package/dist/components/TypeTester/TypeTesterStandalone.d.ts +20 -6
- package/dist/components/TypeTester/TypeTesterStandalone.js +51 -41
- package/dist/components/TypeTester/TypeTesterStandalone.preload.d.ts +3 -3
- package/dist/components/TypeTester/TypeTesterStandalone.preload.js +10 -9
- package/dist/components/TypeTester/TypeTesterStandalone.server.d.ts +4 -2
- package/dist/components/TypeTester/TypeTesterStandalone.server.js +17 -17
- package/dist/components/TypeTester/TypeTesterStandaloneElement.js +7 -16
- package/dist/components/TypeTester/TypeTesterState.d.ts +2 -2
- package/dist/components/TypeTester/TypeTesterState.js +6 -14
- package/dist/components/TypeTester/TypeTesterStyleSelect.d.ts +1 -1
- package/dist/components/TypeTester/TypeTesterStyleSelect.js +9 -17
- package/dist/components/TypeTester/TypeTesterStyleSelectData.d.ts +4 -4
- package/dist/components/TypeTester/TypeTesterStyleSelectData.js +21 -30
- package/dist/components/TypeTester/TypeTesterToolbar.d.ts +2 -2
- package/dist/components/TypeTester/TypeTesterToolbar.js +29 -39
- package/dist/components/TypeTester/TypeTesterVariableAxes.d.ts +1 -1
- package/dist/components/TypeTester/TypeTesterVariableAxes.js +16 -24
- package/dist/components/TypeTester/features.js +1 -8
- package/dist/components/TypeTester/index.d.ts +3 -3
- package/dist/components/TypeTester/index.js +45 -55
- package/dist/components/TypeTester/types.js +3 -11
- package/dist/components/TypeTester/useFeaturesData.d.ts +1 -1
- package/dist/components/TypeTester/useFeaturesData.js +7 -15
- package/dist/components/TypeTester/useTypeTesterStyler.d.ts +2 -2
- package/dist/components/TypeTester/useTypeTesterStyler.js +6 -13
- package/dist/components/TypeTesters/TypeTestersElement.js +4 -12
- package/dist/components/TypeTesters/index.d.ts +21 -5
- package/dist/components/TypeTesters/index.js +116 -75
- package/dist/components/TypeTesters/index.server.d.ts +1 -1
- package/dist/components/TypeTesters/index.server.js +15 -17
- package/dist/components/UrlContext.js +6 -12
- package/dist/components/VariableTableAmounts/index.d.ts +2 -2
- package/dist/components/VariableTableAmounts/index.js +9 -16
- package/dist/components/elements/Button/index.js +3 -11
- package/dist/components/elements/EmptyCart/index.js +9 -19
- package/dist/components/elements/StoreModalCartLayout/index.js +10 -18
- package/dist/components/elements/StoreModalContainer/StoreModalContainerContext.js +3 -9
- package/dist/components/elements/StoreModalContainer/index.js +17 -27
- package/dist/components/elements/StoreModalDownloadLayout/index.js +7 -15
- package/dist/components/elements/StoreModalFamily/index.js +8 -16
- package/dist/components/elements/StoreModalFamilyButton/index.d.ts +1 -1
- package/dist/components/elements/StoreModalFamilyButton/index.js +11 -20
- package/dist/components/elements/StoreModalIndexItem/index.js +9 -17
- package/dist/components/elements/StoreModalLicenseeIsBillingIdentityElement.js +16 -25
- package/dist/components/elements/StoreModalLoadingScreen/index.js +4 -12
- package/dist/components/elements/StoreModalPageContainer/index.js +5 -13
- package/dist/components/elements/StoreModalStyleButton/index.d.ts +1 -1
- package/dist/components/elements/StoreModalStyleButton/index.js +10 -18
- package/dist/components/elements/StoreModalUnifiedCheckout.d.ts +2 -2
- package/dist/components/elements/StoreModalUnifiedCheckout.js +107 -115
- package/dist/components/useConsent.js +4 -9
- package/dist/components/useFont.js +8 -15
- package/dist/components/useFontStyle.d.ts +1 -1
- package/dist/components/useFontStyle.js +12 -20
- package/dist/components/useInterval.js +5 -12
- package/dist/components/useTotalStyles.d.ts +1 -1
- package/dist/components/useTotalStyles.js +4 -12
- package/dist/config.d.ts +2 -1
- package/dist/config.js +17 -6
- package/dist/corsError.js +4 -14
- package/dist/data/unicodeData.js +1 -1
- package/dist/fontLoader.js +2 -9
- package/dist/hooks/useAutofit.js +11 -19
- package/dist/hooks/useLicenseAndOrderVariables.d.ts +2 -2
- package/dist/hooks/useLicenseAndOrderVariables.js +7 -12
- package/dist/hooks/useRefetchOnLicenseChanges.d.ts +1 -1
- package/dist/hooks/useRefetchOnLicenseChanges.js +7 -13
- package/dist/hooks/useResizeObserver.d.ts +11 -0
- package/dist/hooks/useResizeObserver.js +23 -0
- package/dist/hooks.js +5 -12
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/loadFontdueProviderQuery.d.ts +4 -0
- package/dist/loadFontdueProviderQuery.js +10 -0
- package/dist/react-ranger.d.js +0 -1
- package/dist/react-ranger.js +17 -24
- package/dist/reducer.d.ts +5 -5
- package/dist/reducer.js +15 -36
- package/dist/relay/environment.d.ts +1 -0
- package/dist/relay/environment.js +57 -33
- package/dist/relay/loadSerializableQuery.d.ts +5 -1
- package/dist/relay/loadSerializableQuery.js +4 -8
- package/dist/relay/useSerializablePreloadedQuery.d.ts +3 -3
- package/dist/relay/useSerializablePreloadedQuery.js +26 -22
- package/dist/retryImport.js +1 -7
- package/dist/scripts/updateUnicodeData.js +0 -2
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +14 -36
- package/dist/vanilla/FontStyle.js +3 -11
- package/dist/vanilla/TruncatedMarkdown.js +2 -9
- package/dist/vite.d.ts +2 -0
- package/dist/vite.js +83 -0
- package/package.json +8 -4
- package/scripts/addJsExtensionsBabelPlugin.cjs +62 -0
- package/types/globals.d.ts +3 -0
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
2
|
|
|
3
|
-
var _vitest = require("vitest");
|
|
4
|
-
var _utils = require("../utils");
|
|
5
|
-
var _reducer = _interopRequireWildcard(require("../reducer"));
|
|
6
|
-
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
7
|
-
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
8
3
|
// Mock react-relay's graphql tag since productState.ts uses it at import time
|
|
9
|
-
|
|
4
|
+
vi.mock('react-relay', () => ({
|
|
10
5
|
graphql: () => null,
|
|
11
|
-
fetchQuery:
|
|
6
|
+
fetchQuery: vi.fn()
|
|
12
7
|
}));
|
|
8
|
+
import { collectionSkuIdsDifferences, collContainsSkuId, isSelected } from '../utils.js';
|
|
9
|
+
import { collectionSkuIdWithDiscount } from '../reducer.js';
|
|
10
|
+
import reducer from '../reducer.js';
|
|
11
|
+
|
|
13
12
|
// Helper to build a minimal FontdueState for testing
|
|
14
13
|
function makeState() {
|
|
15
14
|
let overrides = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -157,69 +156,69 @@ function makeThunderState() {
|
|
|
157
156
|
// =========================================================================
|
|
158
157
|
// collContainsSkuId
|
|
159
158
|
// =========================================================================
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
describe('collContainsSkuId', () => {
|
|
160
|
+
it('returns true when skuId is in childrenSkuIds', () => {
|
|
162
161
|
const coll = {
|
|
163
162
|
fontStyleSkuIds: [],
|
|
164
163
|
fontStyleIds: [],
|
|
165
164
|
childrenSkuIds: ['child-sku-1', 'child-sku-2'],
|
|
166
165
|
name: 'Test'
|
|
167
166
|
};
|
|
168
|
-
|
|
167
|
+
expect(collContainsSkuId(coll, 'child-sku-1')).toBe(true);
|
|
169
168
|
});
|
|
170
|
-
|
|
169
|
+
it('returns true when skuId is in fontStyleSkuIds', () => {
|
|
171
170
|
const coll = {
|
|
172
171
|
fontStyleSkuIds: ['style-sku-1'],
|
|
173
172
|
fontStyleIds: [],
|
|
174
173
|
childrenSkuIds: [],
|
|
175
174
|
name: 'Test'
|
|
176
175
|
};
|
|
177
|
-
|
|
176
|
+
expect(collContainsSkuId(coll, 'style-sku-1')).toBe(true);
|
|
178
177
|
});
|
|
179
|
-
|
|
178
|
+
it('returns true when id is in fontStyleIds', () => {
|
|
180
179
|
const coll = {
|
|
181
180
|
fontStyleSkuIds: [],
|
|
182
181
|
fontStyleIds: ['style-id-1'],
|
|
183
182
|
childrenSkuIds: [],
|
|
184
183
|
name: 'Test'
|
|
185
184
|
};
|
|
186
|
-
|
|
185
|
+
expect(collContainsSkuId(coll, 'style-id-1')).toBe(true);
|
|
187
186
|
});
|
|
188
|
-
|
|
187
|
+
it('returns false for unknown skuId', () => {
|
|
189
188
|
const coll = {
|
|
190
189
|
fontStyleSkuIds: ['style-sku-1'],
|
|
191
190
|
fontStyleIds: ['style-1'],
|
|
192
191
|
childrenSkuIds: ['child-sku-1'],
|
|
193
192
|
name: 'Test'
|
|
194
193
|
};
|
|
195
|
-
|
|
194
|
+
expect(collContainsSkuId(coll, 'unknown-sku')).toBe(false);
|
|
196
195
|
});
|
|
197
|
-
|
|
198
|
-
|
|
196
|
+
it('returns false for undefined collection', () => {
|
|
197
|
+
expect(collContainsSkuId(undefined, 'any-sku')).toBe(false);
|
|
199
198
|
});
|
|
200
199
|
});
|
|
201
200
|
|
|
202
201
|
// =========================================================================
|
|
203
202
|
// isSelected
|
|
204
203
|
// =========================================================================
|
|
205
|
-
|
|
206
|
-
|
|
204
|
+
describe('isSelected', () => {
|
|
205
|
+
it('returns true when the SKU is directly selected', () => {
|
|
207
206
|
const state = makeState({
|
|
208
207
|
selectedSkuIds: {
|
|
209
208
|
'sku-1': true
|
|
210
209
|
}
|
|
211
210
|
});
|
|
212
|
-
|
|
211
|
+
expect(isSelected('sku-1')(state)).toBe(true);
|
|
213
212
|
});
|
|
214
|
-
|
|
213
|
+
it('returns false when the SKU is explicitly deselected (false)', () => {
|
|
215
214
|
const state = makeState({
|
|
216
215
|
selectedSkuIds: {
|
|
217
216
|
'sku-1': false
|
|
218
217
|
}
|
|
219
218
|
});
|
|
220
|
-
|
|
219
|
+
expect(isSelected('sku-1')(state)).toBe(false);
|
|
221
220
|
});
|
|
222
|
-
|
|
221
|
+
it('returns true when a parent collection is selected', () => {
|
|
223
222
|
const state = makeState({
|
|
224
223
|
selectedSkuIds: {
|
|
225
224
|
'bundle-sku': true
|
|
@@ -234,13 +233,13 @@ function makeThunderState() {
|
|
|
234
233
|
}
|
|
235
234
|
});
|
|
236
235
|
// Style SKU contained via fontStyleSkuIds
|
|
237
|
-
|
|
236
|
+
expect(isSelected('s1')(state)).toBe(true);
|
|
238
237
|
// Family SKU contained via childrenSkuIds
|
|
239
|
-
|
|
238
|
+
expect(isSelected('family-sku')(state)).toBe(true);
|
|
240
239
|
// Font style ID contained via fontStyleIds
|
|
241
|
-
|
|
240
|
+
expect(isSelected('f1')(state)).toBe(true);
|
|
242
241
|
});
|
|
243
|
-
|
|
242
|
+
it('returns false when a parent collection is deselected', () => {
|
|
244
243
|
const state = makeState({
|
|
245
244
|
selectedSkuIds: {
|
|
246
245
|
'bundle-sku': false,
|
|
@@ -255,14 +254,14 @@ function makeThunderState() {
|
|
|
255
254
|
}
|
|
256
255
|
}
|
|
257
256
|
});
|
|
258
|
-
|
|
259
|
-
|
|
257
|
+
expect(isSelected('s1')(state)).toBe(false);
|
|
258
|
+
expect(isSelected('family-sku')(state)).toBe(false);
|
|
260
259
|
});
|
|
261
|
-
|
|
260
|
+
it('returns false for null skuId', () => {
|
|
262
261
|
const state = makeState();
|
|
263
|
-
|
|
262
|
+
expect(isSelected(null)(state)).toBe(false);
|
|
264
263
|
});
|
|
265
|
-
|
|
264
|
+
it('returns true for member when bundle is selected, even if member is explicitly false', () => {
|
|
266
265
|
// After auto-selection, members are set to false but should still appear
|
|
267
266
|
// selected because the parent bundle is true
|
|
268
267
|
const state = makeState({
|
|
@@ -280,17 +279,17 @@ function makeThunderState() {
|
|
|
280
279
|
}
|
|
281
280
|
}
|
|
282
281
|
});
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
282
|
+
expect(isSelected('family-sku')(state)).toBe(true);
|
|
283
|
+
expect(isSelected('var-sku')(state)).toBe(true);
|
|
284
|
+
expect(isSelected('s1')(state)).toBe(true);
|
|
286
285
|
});
|
|
287
286
|
});
|
|
288
287
|
|
|
289
288
|
// =========================================================================
|
|
290
289
|
// collectionSkuIdsDifferences
|
|
291
290
|
// =========================================================================
|
|
292
|
-
|
|
293
|
-
|
|
291
|
+
describe('collectionSkuIdsDifferences', () => {
|
|
292
|
+
it('includes self when skuId matches a collection', () => {
|
|
294
293
|
const state = makeState({
|
|
295
294
|
collectionStyleSkus: {
|
|
296
295
|
'family-sku': {
|
|
@@ -306,11 +305,11 @@ function makeThunderState() {
|
|
|
306
305
|
s2: 40
|
|
307
306
|
}
|
|
308
307
|
});
|
|
309
|
-
const diffs =
|
|
310
|
-
|
|
311
|
-
|
|
308
|
+
const diffs = collectionSkuIdsDifferences(state, 'family-sku');
|
|
309
|
+
expect(diffs).toHaveProperty('family-sku');
|
|
310
|
+
expect(diffs['family-sku']).toBe(500);
|
|
312
311
|
});
|
|
313
|
-
|
|
312
|
+
it('includes parent collections that contain the skuId', () => {
|
|
314
313
|
const state = makeState({
|
|
315
314
|
collectionStyleSkus: {
|
|
316
315
|
'family-sku': {
|
|
@@ -335,11 +334,11 @@ function makeThunderState() {
|
|
|
335
334
|
vs1: 40
|
|
336
335
|
}
|
|
337
336
|
});
|
|
338
|
-
const diffs =
|
|
339
|
-
|
|
340
|
-
|
|
337
|
+
const diffs = collectionSkuIdsDifferences(state, 'family-sku');
|
|
338
|
+
expect(diffs).toHaveProperty('family-sku');
|
|
339
|
+
expect(diffs).toHaveProperty('bundle-sku');
|
|
341
340
|
});
|
|
342
|
-
|
|
341
|
+
it('subtracts already-selected items from the difference', () => {
|
|
343
342
|
const state = makeState({
|
|
344
343
|
selectedSkuIds: {
|
|
345
344
|
'family-sku': true
|
|
@@ -364,10 +363,10 @@ function makeThunderState() {
|
|
|
364
363
|
'var-family-sku': 300
|
|
365
364
|
}
|
|
366
365
|
});
|
|
367
|
-
const diffs =
|
|
368
|
-
|
|
366
|
+
const diffs = collectionSkuIdsDifferences(state, 'var-family-sku');
|
|
367
|
+
expect(diffs['bundle-sku']).toBe(0);
|
|
369
368
|
});
|
|
370
|
-
|
|
369
|
+
it('treats missing prices as 0 rather than producing NaN', () => {
|
|
371
370
|
const state = makeState({
|
|
372
371
|
selectedSkuIds: {
|
|
373
372
|
'orphan-sku': true
|
|
@@ -385,11 +384,11 @@ function makeThunderState() {
|
|
|
385
384
|
// 'orphan-sku' deliberately missing
|
|
386
385
|
}
|
|
387
386
|
});
|
|
388
|
-
const diffs =
|
|
387
|
+
const diffs = collectionSkuIdsDifferences(state, 'orphan-sku');
|
|
389
388
|
// Missing price treated as 0, so difference = 500 - 0 = 500
|
|
390
|
-
|
|
389
|
+
expect(diffs['family-sku']).toBe(500);
|
|
391
390
|
});
|
|
392
|
-
|
|
391
|
+
it('only counts items that are selected true, not false', () => {
|
|
393
392
|
const state = makeState({
|
|
394
393
|
selectedSkuIds: {
|
|
395
394
|
'family-sku': false
|
|
@@ -413,11 +412,11 @@ function makeThunderState() {
|
|
|
413
412
|
'family-sku': 300
|
|
414
413
|
}
|
|
415
414
|
});
|
|
416
|
-
const diffs =
|
|
415
|
+
const diffs = collectionSkuIdsDifferences(state, 'family-sku');
|
|
417
416
|
// family-sku is false, not true, so it shouldn't be subtracted
|
|
418
|
-
|
|
417
|
+
expect(diffs['bundle-sku']).toBe(500);
|
|
419
418
|
});
|
|
420
|
-
|
|
419
|
+
it('returns empty object when no collections contain the skuId', () => {
|
|
421
420
|
const state = makeState({
|
|
422
421
|
collectionStyleSkus: {
|
|
423
422
|
'other-sku': {
|
|
@@ -432,16 +431,16 @@ function makeThunderState() {
|
|
|
432
431
|
'lonely-style': 40
|
|
433
432
|
}
|
|
434
433
|
});
|
|
435
|
-
const diffs =
|
|
436
|
-
|
|
434
|
+
const diffs = collectionSkuIdsDifferences(state, 'lonely-style');
|
|
435
|
+
expect(Object.keys(diffs)).toHaveLength(0);
|
|
437
436
|
});
|
|
438
437
|
});
|
|
439
438
|
|
|
440
439
|
// =========================================================================
|
|
441
440
|
// collectionSkuIdWithDiscount
|
|
442
441
|
// =========================================================================
|
|
443
|
-
|
|
444
|
-
|
|
442
|
+
describe('collectionSkuIdWithDiscount', () => {
|
|
443
|
+
it('returns null when no collection is a better deal', () => {
|
|
445
444
|
const state = makeState({
|
|
446
445
|
collectionStyleSkus: {
|
|
447
446
|
'family-sku': {
|
|
@@ -456,11 +455,11 @@ function makeThunderState() {
|
|
|
456
455
|
'family-sku': 500
|
|
457
456
|
}
|
|
458
457
|
});
|
|
459
|
-
const [collId, amount] =
|
|
460
|
-
|
|
461
|
-
|
|
458
|
+
const [collId, amount] = collectionSkuIdWithDiscount(state, 's1');
|
|
459
|
+
expect(collId).toBe(null);
|
|
460
|
+
expect(amount).toBe(null);
|
|
462
461
|
});
|
|
463
|
-
|
|
462
|
+
it('returns parent collection when it is cheaper for individual style', () => {
|
|
464
463
|
const state = makeState({
|
|
465
464
|
selectedSkuIds: {
|
|
466
465
|
s1: true,
|
|
@@ -485,11 +484,11 @@ function makeThunderState() {
|
|
|
485
484
|
s5: 40
|
|
486
485
|
}
|
|
487
486
|
});
|
|
488
|
-
const [collId, amount] =
|
|
489
|
-
|
|
490
|
-
|
|
487
|
+
const [collId, amount] = collectionSkuIdWithDiscount(state, 's5');
|
|
488
|
+
expect(collId).toBe('family-sku');
|
|
489
|
+
expect(amount).toBe(40);
|
|
491
490
|
});
|
|
492
|
-
|
|
491
|
+
it('prefers collection bundle over self when prices are equal', () => {
|
|
493
492
|
const state = makeState({
|
|
494
493
|
collectionStyleSkus: {
|
|
495
494
|
'family-sku': {
|
|
@@ -531,11 +530,11 @@ function makeThunderState() {
|
|
|
531
530
|
vis1: 40
|
|
532
531
|
}
|
|
533
532
|
});
|
|
534
|
-
const [collId, amount] =
|
|
535
|
-
|
|
536
|
-
|
|
533
|
+
const [collId, amount] = collectionSkuIdWithDiscount(state, 'family-sku');
|
|
534
|
+
expect(collId).toBe('bundle-sku');
|
|
535
|
+
expect(amount).toBe(500);
|
|
537
536
|
});
|
|
538
|
-
|
|
537
|
+
it('prefers collection bundle regardless of object key order', () => {
|
|
539
538
|
const state = makeState({
|
|
540
539
|
collectionStyleSkus: {
|
|
541
540
|
'bundle-sku': {
|
|
@@ -557,10 +556,10 @@ function makeThunderState() {
|
|
|
557
556
|
'var-family-sku': 300
|
|
558
557
|
}
|
|
559
558
|
});
|
|
560
|
-
const [collId] =
|
|
561
|
-
|
|
559
|
+
const [collId] = collectionSkuIdWithDiscount(state, 'family-sku');
|
|
560
|
+
expect(collId).toBe('bundle-sku');
|
|
562
561
|
});
|
|
563
|
-
|
|
562
|
+
it('still returns self for display pricing (superfamily with no parent)', () => {
|
|
564
563
|
const state = makeState({
|
|
565
564
|
selectedSkuIds: {
|
|
566
565
|
'family-sku': true
|
|
@@ -591,11 +590,11 @@ function makeThunderState() {
|
|
|
591
590
|
'display-family-sku': 500
|
|
592
591
|
}
|
|
593
592
|
});
|
|
594
|
-
const [collId, amount] =
|
|
595
|
-
|
|
596
|
-
|
|
593
|
+
const [collId, amount] = collectionSkuIdWithDiscount(state, 'superfamily-sku');
|
|
594
|
+
expect(collId).toBe('superfamily-sku');
|
|
595
|
+
expect(amount).toBe(250);
|
|
597
596
|
});
|
|
598
|
-
|
|
597
|
+
it('prefers bundle at $0 when family is already selected', () => {
|
|
599
598
|
const state = makeState({
|
|
600
599
|
selectedSkuIds: {
|
|
601
600
|
'family-sku': true
|
|
@@ -626,11 +625,11 @@ function makeThunderState() {
|
|
|
626
625
|
'bundle-sku': 500
|
|
627
626
|
}
|
|
628
627
|
});
|
|
629
|
-
const [collId, amount] =
|
|
630
|
-
|
|
631
|
-
|
|
628
|
+
const [collId, amount] = collectionSkuIdWithDiscount(state, 'var-family-sku');
|
|
629
|
+
expect(collId).toBe('bundle-sku');
|
|
630
|
+
expect(amount).toBe(0);
|
|
632
631
|
});
|
|
633
|
-
|
|
632
|
+
it('does not upgrade when collection bundle is more expensive', () => {
|
|
634
633
|
const state = makeState({
|
|
635
634
|
collectionStyleSkus: {
|
|
636
635
|
'family-sku': {
|
|
@@ -651,10 +650,10 @@ function makeThunderState() {
|
|
|
651
650
|
'bundle-sku': 600
|
|
652
651
|
}
|
|
653
652
|
});
|
|
654
|
-
const [collId] =
|
|
655
|
-
|
|
653
|
+
const [collId] = collectionSkuIdWithDiscount(state, 'family-sku');
|
|
654
|
+
expect(collId).toBe('family-sku');
|
|
656
655
|
});
|
|
657
|
-
|
|
656
|
+
it('returns null when the selected SKU has no price (undefined)', () => {
|
|
658
657
|
// If skuPrices[skuId] is undefined, the filter comparison
|
|
659
658
|
// `difference <= undefined` is always false → no collection found
|
|
660
659
|
const state = makeState({
|
|
@@ -670,11 +669,11 @@ function makeThunderState() {
|
|
|
670
669
|
'family-sku': 500
|
|
671
670
|
} // s1 deliberately missing
|
|
672
671
|
});
|
|
673
|
-
const [collId, amount] =
|
|
674
|
-
|
|
675
|
-
|
|
672
|
+
const [collId, amount] = collectionSkuIdWithDiscount(state, 's1');
|
|
673
|
+
expect(collId).toBe(null);
|
|
674
|
+
expect(amount).toBe(null);
|
|
676
675
|
});
|
|
677
|
-
|
|
676
|
+
it('treats collections with missing price as price 0', () => {
|
|
678
677
|
// A collection with no price entry is treated as $0, meaning its
|
|
679
678
|
// difference = 0 - sum_selected. With nothing selected, diff = 0.
|
|
680
679
|
const state = makeState({
|
|
@@ -698,13 +697,13 @@ function makeThunderState() {
|
|
|
698
697
|
}
|
|
699
698
|
// 'ghost-bundle' price deliberately missing → treated as 0
|
|
700
699
|
});
|
|
701
|
-
const [collId, amount] =
|
|
700
|
+
const [collId, amount] = collectionSkuIdWithDiscount(state, 'family-sku');
|
|
702
701
|
// ghost-bundle diff = 0, family diff = 500. ghost-bundle is cheaper.
|
|
703
702
|
// 0 <= 500 ✓ → ghost-bundle wins
|
|
704
|
-
|
|
705
|
-
|
|
703
|
+
expect(collId).toBe('ghost-bundle');
|
|
704
|
+
expect(amount).toBe(0);
|
|
706
705
|
});
|
|
707
|
-
|
|
706
|
+
it('handles zero-price SKUs without errors', () => {
|
|
708
707
|
const state = makeState({
|
|
709
708
|
collectionStyleSkus: {
|
|
710
709
|
'free-family': {
|
|
@@ -730,11 +729,11 @@ function makeThunderState() {
|
|
|
730
729
|
});
|
|
731
730
|
|
|
732
731
|
// Both have diff = 0, filter: 0 <= 0 ✓, tie-break prefers bundle
|
|
733
|
-
const [collId, amount] =
|
|
734
|
-
|
|
735
|
-
|
|
732
|
+
const [collId, amount] = collectionSkuIdWithDiscount(state, 'free-family');
|
|
733
|
+
expect(collId).toBe('free-bundle');
|
|
734
|
+
expect(amount).toBe(0);
|
|
736
735
|
});
|
|
737
|
-
|
|
736
|
+
it('handles negative difference (collection cheaper than sum of selected)', () => {
|
|
738
737
|
// Unusual but possible: if prices change or a collection is deeply discounted
|
|
739
738
|
const state = makeState({
|
|
740
739
|
selectedSkuIds: {
|
|
@@ -761,108 +760,108 @@ function makeThunderState() {
|
|
|
761
760
|
|
|
762
761
|
// Family costs $100, 3 styles selected = $120, diff = $100 - $120 = -$20
|
|
763
762
|
// This means the collection is $20 cheaper than what's already selected
|
|
764
|
-
const [collId, amount] =
|
|
765
|
-
|
|
766
|
-
|
|
763
|
+
const [collId, amount] = collectionSkuIdWithDiscount(state, 's4');
|
|
764
|
+
expect(collId).toBe('family-sku');
|
|
765
|
+
expect(amount).toBe(-20);
|
|
767
766
|
});
|
|
768
767
|
});
|
|
769
768
|
|
|
770
769
|
// =========================================================================
|
|
771
770
|
// reducer SELECT_SKU_ID — core auto-selection
|
|
772
771
|
// =========================================================================
|
|
773
|
-
|
|
774
|
-
|
|
772
|
+
describe('reducer SELECT_SKU_ID with collection bundles', () => {
|
|
773
|
+
it('auto-selects collection bundle when selecting a family at the same price', () => {
|
|
775
774
|
const state = makeThunderState();
|
|
776
|
-
const newState = (
|
|
775
|
+
const newState = reducer(state, {
|
|
777
776
|
type: 'SELECT_SKU_ID',
|
|
778
777
|
skuId: 'text-sku',
|
|
779
778
|
selected: true
|
|
780
779
|
});
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
780
|
+
expect(newState.selectedSkuIds['text-bundle-sku']).toBe(true);
|
|
781
|
+
expect(newState.selectedSkuIds['text-sku']).toBe(false);
|
|
782
|
+
expect(newState.selectedSkuIds['text-var-sku']).toBe(false);
|
|
783
|
+
expect(newState.selectedSkuIds['text-var-italic-sku']).toBe(false);
|
|
785
784
|
});
|
|
786
|
-
|
|
785
|
+
it('does not auto-select bundle when bundle is more expensive', () => {
|
|
787
786
|
const state = makeThunderState({
|
|
788
787
|
skuPrices: {
|
|
789
788
|
...makeThunderState().skuPrices,
|
|
790
789
|
'text-bundle-sku': 600 // more expensive than text-sku ($500)
|
|
791
790
|
}
|
|
792
791
|
});
|
|
793
|
-
const newState = (
|
|
792
|
+
const newState = reducer(state, {
|
|
794
793
|
type: 'SELECT_SKU_ID',
|
|
795
794
|
skuId: 'text-sku',
|
|
796
795
|
selected: true
|
|
797
796
|
});
|
|
798
|
-
|
|
799
|
-
|
|
797
|
+
expect(newState.selectedSkuIds['text-sku']).toBe(true);
|
|
798
|
+
expect(newState.selectedSkuIds['text-bundle-sku']).toBeUndefined();
|
|
800
799
|
});
|
|
801
|
-
|
|
800
|
+
it('auto-selects bundle when clicking variable family with static already selected', () => {
|
|
802
801
|
const state = makeThunderState({
|
|
803
802
|
selectedSkuIds: {
|
|
804
803
|
'text-sku': true
|
|
805
804
|
}
|
|
806
805
|
});
|
|
807
|
-
const newState = (
|
|
806
|
+
const newState = reducer(state, {
|
|
808
807
|
type: 'SELECT_SKU_ID',
|
|
809
808
|
skuId: 'text-var-sku',
|
|
810
809
|
selected: true
|
|
811
810
|
});
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
811
|
+
expect(newState.selectedSkuIds['text-bundle-sku']).toBe(true);
|
|
812
|
+
expect(newState.selectedSkuIds['text-sku']).toBe(false);
|
|
813
|
+
expect(newState.selectedSkuIds['text-var-sku']).toBe(false);
|
|
815
814
|
});
|
|
816
815
|
});
|
|
817
816
|
|
|
818
817
|
// =========================================================================
|
|
819
818
|
// reducer SELECT_SKU_ID — multiple bundles don't interfere
|
|
820
819
|
// =========================================================================
|
|
821
|
-
|
|
822
|
-
|
|
820
|
+
describe('reducer SELECT_SKU_ID with multiple bundles', () => {
|
|
821
|
+
it('only selects the correct bundle for the family being clicked', () => {
|
|
823
822
|
const state = makeThunderState();
|
|
824
|
-
const newState = (
|
|
823
|
+
const newState = reducer(state, {
|
|
825
824
|
type: 'SELECT_SKU_ID',
|
|
826
825
|
skuId: 'display-sku',
|
|
827
826
|
selected: true
|
|
828
827
|
});
|
|
829
828
|
|
|
830
829
|
// Display bundle should be selected
|
|
831
|
-
|
|
832
|
-
|
|
830
|
+
expect(newState.selectedSkuIds['display-bundle-sku']).toBe(true);
|
|
831
|
+
expect(newState.selectedSkuIds['display-sku']).toBe(false);
|
|
833
832
|
// Text and caption bundles should be untouched
|
|
834
|
-
|
|
835
|
-
|
|
833
|
+
expect(newState.selectedSkuIds['text-bundle-sku']).toBeUndefined();
|
|
834
|
+
expect(newState.selectedSkuIds['caption-bundle-sku']).toBeUndefined();
|
|
836
835
|
});
|
|
837
|
-
|
|
836
|
+
it('upgrades to superfamily when selecting a second family bundle', () => {
|
|
838
837
|
// Selecting two families ($500+$500) costs more than the superfamily ($750),
|
|
839
838
|
// so the system correctly upgrades to the superfamily on the second click
|
|
840
839
|
const state = makeThunderState();
|
|
841
|
-
let newState = (
|
|
840
|
+
let newState = reducer(state, {
|
|
842
841
|
type: 'SELECT_SKU_ID',
|
|
843
842
|
skuId: 'text-sku',
|
|
844
843
|
selected: true
|
|
845
844
|
});
|
|
846
|
-
|
|
847
|
-
newState = (
|
|
845
|
+
expect(newState.selectedSkuIds['text-bundle-sku']).toBe(true);
|
|
846
|
+
newState = reducer(newState, {
|
|
848
847
|
type: 'SELECT_SKU_ID',
|
|
849
848
|
skuId: 'display-sku',
|
|
850
849
|
selected: true
|
|
851
850
|
});
|
|
852
851
|
|
|
853
852
|
// Superfamily ($750) beats two bundles ($500 + $500 = $1000)
|
|
854
|
-
|
|
853
|
+
expect(newState.selectedSkuIds['super-sku']).toBe(true);
|
|
855
854
|
// Previous bundle should be deselected (subsumed by superfamily)
|
|
856
|
-
|
|
857
|
-
|
|
855
|
+
expect(newState.selectedSkuIds['text-bundle-sku']).toBe(false);
|
|
856
|
+
expect(newState.selectedSkuIds['display-bundle-sku']).toBe(false);
|
|
858
857
|
});
|
|
859
858
|
});
|
|
860
859
|
|
|
861
860
|
// =========================================================================
|
|
862
861
|
// reducer SELECT_SKU_ID — deselection flow
|
|
863
862
|
// =========================================================================
|
|
864
|
-
|
|
865
|
-
|
|
863
|
+
describe('reducer deselection', () => {
|
|
864
|
+
it('deselecting a bundle member deselects the entire bundle', () => {
|
|
866
865
|
// Start with the text bundle selected (members are false)
|
|
867
866
|
const state = makeThunderState({
|
|
868
867
|
selectedSkuIds: {
|
|
@@ -878,16 +877,16 @@ function makeThunderState() {
|
|
|
878
877
|
});
|
|
879
878
|
|
|
880
879
|
// User clicks to deselect "Thunder Text Variable"
|
|
881
|
-
const newState = (
|
|
880
|
+
const newState = reducer(state, {
|
|
882
881
|
type: 'SELECT_SKU_ID',
|
|
883
882
|
skuId: 'text-var-sku',
|
|
884
883
|
selected: false
|
|
885
884
|
});
|
|
886
885
|
|
|
887
886
|
// The bundle should be deselected
|
|
888
|
-
|
|
887
|
+
expect(newState.selectedSkuIds['text-bundle-sku']).toBe(false);
|
|
889
888
|
});
|
|
890
|
-
|
|
889
|
+
it('deselecting a font style deselects the parent bundle', () => {
|
|
891
890
|
const state = makeThunderState({
|
|
892
891
|
selectedSkuIds: {
|
|
893
892
|
'text-bundle-sku': true,
|
|
@@ -902,14 +901,14 @@ function makeThunderState() {
|
|
|
902
901
|
});
|
|
903
902
|
|
|
904
903
|
// User clicks to deselect individual style "s1"
|
|
905
|
-
const newState = (
|
|
904
|
+
const newState = reducer(state, {
|
|
906
905
|
type: 'SELECT_SKU_ID',
|
|
907
906
|
skuId: 's1',
|
|
908
907
|
selected: false
|
|
909
908
|
});
|
|
910
|
-
|
|
909
|
+
expect(newState.selectedSkuIds['text-bundle-sku']).toBe(false);
|
|
911
910
|
});
|
|
912
|
-
|
|
911
|
+
it('deselecting a family bundle deselects the parent collection bundle (transitive)', () => {
|
|
913
912
|
// Collection bundle is selected. A family bundle (style package) within
|
|
914
913
|
// it is shown as selected via transitive isSelected. Clicking to deselect
|
|
915
914
|
// it should find and deselect the collection bundle.
|
|
@@ -973,23 +972,23 @@ function makeThunderState() {
|
|
|
973
972
|
});
|
|
974
973
|
|
|
975
974
|
// Bundle shows as selected via transitive isSelected
|
|
976
|
-
|
|
975
|
+
expect(isSelected('pkg-upright-sku')(state)).toBe(true);
|
|
977
976
|
|
|
978
977
|
// Click to deselect the bundle
|
|
979
|
-
const newState = (
|
|
978
|
+
const newState = reducer(state, {
|
|
980
979
|
type: 'SELECT_SKU_ID',
|
|
981
980
|
skuId: 'pkg-upright-sku',
|
|
982
981
|
selected: false
|
|
983
982
|
});
|
|
984
983
|
|
|
985
984
|
// Collection bundle should be deselected
|
|
986
|
-
|
|
985
|
+
expect(newState.selectedSkuIds['coll-bundle-sku']).toBe(false);
|
|
987
986
|
// Nothing should be selected anymore
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
987
|
+
expect(isSelected('pkg-upright-sku')(newState)).toBe(false);
|
|
988
|
+
expect(isSelected('family-sku')(newState)).toBe(false);
|
|
989
|
+
expect(isSelected('s1')(newState)).toBe(false);
|
|
991
990
|
});
|
|
992
|
-
|
|
991
|
+
it('deselecting a bundle does not affect other bundles', () => {
|
|
993
992
|
const state = makeThunderState({
|
|
994
993
|
selectedSkuIds: {
|
|
995
994
|
'text-bundle-sku': true,
|
|
@@ -1010,22 +1009,22 @@ function makeThunderState() {
|
|
|
1010
1009
|
dvis1: false
|
|
1011
1010
|
}
|
|
1012
1011
|
});
|
|
1013
|
-
const newState = (
|
|
1012
|
+
const newState = reducer(state, {
|
|
1014
1013
|
type: 'SELECT_SKU_ID',
|
|
1015
1014
|
skuId: 'text-var-sku',
|
|
1016
1015
|
selected: false
|
|
1017
1016
|
});
|
|
1018
|
-
|
|
1017
|
+
expect(newState.selectedSkuIds['text-bundle-sku']).toBe(false);
|
|
1019
1018
|
// Display bundle should be unaffected
|
|
1020
|
-
|
|
1019
|
+
expect(newState.selectedSkuIds['display-bundle-sku']).toBe(true);
|
|
1021
1020
|
});
|
|
1022
1021
|
});
|
|
1023
1022
|
|
|
1024
1023
|
// =========================================================================
|
|
1025
1024
|
// reducer SELECT_SKU_ID — re-selection after deselection
|
|
1026
1025
|
// =========================================================================
|
|
1027
|
-
|
|
1028
|
-
|
|
1026
|
+
describe('reducer re-selection cycle', () => {
|
|
1027
|
+
it('re-selecting family after bundle was deselected re-selects the bundle', () => {
|
|
1029
1028
|
// 1. Start with bundle selected
|
|
1030
1029
|
const state = makeThunderState({
|
|
1031
1030
|
selectedSkuIds: {
|
|
@@ -1041,30 +1040,30 @@ function makeThunderState() {
|
|
|
1041
1040
|
});
|
|
1042
1041
|
|
|
1043
1042
|
// 2. Deselect a member → bundle goes away
|
|
1044
|
-
const afterDeselect = (
|
|
1043
|
+
const afterDeselect = reducer(state, {
|
|
1045
1044
|
type: 'SELECT_SKU_ID',
|
|
1046
1045
|
skuId: 'text-var-sku',
|
|
1047
1046
|
selected: false
|
|
1048
1047
|
});
|
|
1049
|
-
|
|
1048
|
+
expect(afterDeselect.selectedSkuIds['text-bundle-sku']).toBe(false);
|
|
1050
1049
|
|
|
1051
1050
|
// 3. Re-select the family → bundle should come back
|
|
1052
|
-
const afterReselect = (
|
|
1051
|
+
const afterReselect = reducer(afterDeselect, {
|
|
1053
1052
|
type: 'SELECT_SKU_ID',
|
|
1054
1053
|
skuId: 'text-sku',
|
|
1055
1054
|
selected: true
|
|
1056
1055
|
});
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1056
|
+
expect(afterReselect.selectedSkuIds['text-bundle-sku']).toBe(true);
|
|
1057
|
+
expect(afterReselect.selectedSkuIds['text-sku']).toBe(false);
|
|
1058
|
+
expect(afterReselect.selectedSkuIds['text-var-sku']).toBe(false);
|
|
1060
1059
|
});
|
|
1061
1060
|
});
|
|
1062
1061
|
|
|
1063
1062
|
// =========================================================================
|
|
1064
1063
|
// reducer SELECT_SKU_ID — superfamily upgrade
|
|
1065
1064
|
// =========================================================================
|
|
1066
|
-
|
|
1067
|
-
|
|
1065
|
+
describe('reducer superfamily upgrade', () => {
|
|
1066
|
+
it('upgrades to superfamily when cumulative selections make it cheaper', () => {
|
|
1068
1067
|
// With two bundles selected ($500 each = $1000 total), the superfamily
|
|
1069
1068
|
// at $750 should be a better deal when selecting the third family
|
|
1070
1069
|
const state = makeThunderState({
|
|
@@ -1087,7 +1086,7 @@ function makeThunderState() {
|
|
|
1087
1086
|
dvis1: false
|
|
1088
1087
|
}
|
|
1089
1088
|
});
|
|
1090
|
-
const newState = (
|
|
1089
|
+
const newState = reducer(state, {
|
|
1091
1090
|
type: 'SELECT_SKU_ID',
|
|
1092
1091
|
skuId: 'caption-sku',
|
|
1093
1092
|
selected: true
|
|
@@ -1095,15 +1094,15 @@ function makeThunderState() {
|
|
|
1095
1094
|
|
|
1096
1095
|
// Superfamily ($750) - two bundles ($500+$500) = -$250 difference
|
|
1097
1096
|
// Caption-sku costs $500, so -$250 <= $500 → superfamily is preferred
|
|
1098
|
-
|
|
1097
|
+
expect(newState.selectedSkuIds['super-sku']).toBe(true);
|
|
1099
1098
|
});
|
|
1100
1099
|
});
|
|
1101
1100
|
|
|
1102
1101
|
// =========================================================================
|
|
1103
1102
|
// reducer SELECT_SKU_ID — individual style to family upgrade
|
|
1104
1103
|
// =========================================================================
|
|
1105
|
-
|
|
1106
|
-
|
|
1104
|
+
describe('reducer individual style upgrade', () => {
|
|
1105
|
+
it('upgrades to family when enough styles are individually selected', () => {
|
|
1107
1106
|
const state = makeState({
|
|
1108
1107
|
selectedSkuIds: {
|
|
1109
1108
|
s1: true,
|
|
@@ -1131,17 +1130,17 @@ function makeThunderState() {
|
|
|
1131
1130
|
|
|
1132
1131
|
// Family is $200, 4 selected = $160, diff = $40. Style s5 costs $40.
|
|
1133
1132
|
// $40 <= $40 → family is a better deal
|
|
1134
|
-
const newState = (
|
|
1133
|
+
const newState = reducer(state, {
|
|
1135
1134
|
type: 'SELECT_SKU_ID',
|
|
1136
1135
|
skuId: 's5',
|
|
1137
1136
|
selected: true
|
|
1138
1137
|
});
|
|
1139
|
-
|
|
1138
|
+
expect(newState.selectedSkuIds['family-sku']).toBe(true);
|
|
1140
1139
|
// Individual styles should be deselected (included via family)
|
|
1141
|
-
|
|
1142
|
-
|
|
1140
|
+
expect(newState.selectedSkuIds['s1']).toBe(false);
|
|
1141
|
+
expect(newState.selectedSkuIds['s5']).toBe(false);
|
|
1143
1142
|
});
|
|
1144
|
-
|
|
1143
|
+
it('does not upgrade to family when not yet cost-effective', () => {
|
|
1145
1144
|
const state = makeState({
|
|
1146
1145
|
selectedSkuIds: {
|
|
1147
1146
|
s1: true
|
|
@@ -1166,35 +1165,35 @@ function makeThunderState() {
|
|
|
1166
1165
|
|
|
1167
1166
|
// Family is $200, 1 selected = $40, diff = $160. Style s2 costs $40.
|
|
1168
1167
|
// $160 > $40 → not worth upgrading
|
|
1169
|
-
const newState = (
|
|
1168
|
+
const newState = reducer(state, {
|
|
1170
1169
|
type: 'SELECT_SKU_ID',
|
|
1171
1170
|
skuId: 's2',
|
|
1172
1171
|
selected: true
|
|
1173
1172
|
});
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1173
|
+
expect(newState.selectedSkuIds['family-sku']).toBeUndefined();
|
|
1174
|
+
expect(newState.selectedSkuIds['s1']).toBe(true);
|
|
1175
|
+
expect(newState.selectedSkuIds['s2']).toBe(true);
|
|
1177
1176
|
});
|
|
1178
1177
|
});
|
|
1179
1178
|
|
|
1180
1179
|
// =========================================================================
|
|
1181
1180
|
// reducer SELECT_SKU_ID — edge cases with missing data
|
|
1182
1181
|
// =========================================================================
|
|
1183
|
-
|
|
1184
|
-
|
|
1182
|
+
describe('reducer edge cases', () => {
|
|
1183
|
+
it('handles selection when collectionStyleSkus is empty', () => {
|
|
1185
1184
|
const state = makeState({
|
|
1186
1185
|
skuPrices: {
|
|
1187
1186
|
'some-sku': 100
|
|
1188
1187
|
}
|
|
1189
1188
|
});
|
|
1190
|
-
const newState = (
|
|
1189
|
+
const newState = reducer(state, {
|
|
1191
1190
|
type: 'SELECT_SKU_ID',
|
|
1192
1191
|
skuId: 'some-sku',
|
|
1193
1192
|
selected: true
|
|
1194
1193
|
});
|
|
1195
|
-
|
|
1194
|
+
expect(newState.selectedSkuIds['some-sku']).toBe(true);
|
|
1196
1195
|
});
|
|
1197
|
-
|
|
1196
|
+
it('handles selection when skuPrices is empty', () => {
|
|
1198
1197
|
const state = makeState({
|
|
1199
1198
|
collectionStyleSkus: {
|
|
1200
1199
|
'family-sku': {
|
|
@@ -1207,15 +1206,15 @@ function makeThunderState() {
|
|
|
1207
1206
|
});
|
|
1208
1207
|
|
|
1209
1208
|
// No prices → no collection upgrade possible, just select directly
|
|
1210
|
-
const newState = (
|
|
1209
|
+
const newState = reducer(state, {
|
|
1211
1210
|
type: 'SELECT_SKU_ID',
|
|
1212
1211
|
skuId: 's1',
|
|
1213
1212
|
selected: true
|
|
1214
1213
|
});
|
|
1215
|
-
|
|
1216
|
-
|
|
1214
|
+
expect(newState.selectedSkuIds['s1']).toBe(true);
|
|
1215
|
+
expect(newState.selectedSkuIds['family-sku']).toBeUndefined();
|
|
1217
1216
|
});
|
|
1218
|
-
|
|
1217
|
+
it('re-selecting a bundle member may upgrade to superfamily', () => {
|
|
1219
1218
|
// When the text bundle is selected and the user clicks text-sku (a member),
|
|
1220
1219
|
// the system re-evaluates: the superfamily sees the text bundle ($500) as
|
|
1221
1220
|
// already selected, making its difference only $250 — cheaper than text-sku
|
|
@@ -1236,15 +1235,15 @@ function makeThunderState() {
|
|
|
1236
1235
|
vis1: false
|
|
1237
1236
|
}
|
|
1238
1237
|
});
|
|
1239
|
-
const newState = (
|
|
1238
|
+
const newState = reducer(state, {
|
|
1240
1239
|
type: 'SELECT_SKU_ID',
|
|
1241
1240
|
skuId: 'text-sku',
|
|
1242
1241
|
selected: true
|
|
1243
1242
|
});
|
|
1244
|
-
|
|
1245
|
-
|
|
1243
|
+
expect(newState.selectedSkuIds['super-sku']).toBe(true);
|
|
1244
|
+
expect(newState.selectedSkuIds['text-bundle-sku']).toBe(false);
|
|
1246
1245
|
});
|
|
1247
|
-
|
|
1246
|
+
it('UNSELECT_SKUS clears all selections cleanly', () => {
|
|
1248
1247
|
const state = makeThunderState({
|
|
1249
1248
|
selectedSkuIds: {
|
|
1250
1249
|
'text-bundle-sku': true,
|
|
@@ -1252,17 +1251,17 @@ function makeThunderState() {
|
|
|
1252
1251
|
'text-var-sku': false
|
|
1253
1252
|
}
|
|
1254
1253
|
});
|
|
1255
|
-
const newState = (
|
|
1254
|
+
const newState = reducer(state, {
|
|
1256
1255
|
type: 'UNSELECT_SKUS'
|
|
1257
1256
|
});
|
|
1258
|
-
|
|
1257
|
+
expect(Object.keys(newState.selectedSkuIds)).toHaveLength(0);
|
|
1259
1258
|
});
|
|
1260
1259
|
});
|
|
1261
1260
|
|
|
1262
1261
|
// =========================================================================
|
|
1263
1262
|
// isSelected — family bundles (style packages within a family)
|
|
1264
1263
|
// =========================================================================
|
|
1265
|
-
|
|
1264
|
+
describe('isSelected with family bundles (style packages)', () => {
|
|
1266
1265
|
// Helper: a family with two style bundles (upright + italic packages)
|
|
1267
1266
|
function makeFamilyWithBundlesState() {
|
|
1268
1267
|
let overrides = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -1305,7 +1304,7 @@ function makeThunderState() {
|
|
|
1305
1304
|
...overrides
|
|
1306
1305
|
});
|
|
1307
1306
|
}
|
|
1308
|
-
|
|
1307
|
+
it('bundles show selected when family is directly selected', () => {
|
|
1309
1308
|
const state = makeFamilyWithBundlesState({
|
|
1310
1309
|
selectedSkuIds: {
|
|
1311
1310
|
'family-sku': true,
|
|
@@ -1323,12 +1322,12 @@ function makeThunderState() {
|
|
|
1323
1322
|
si5: false
|
|
1324
1323
|
}
|
|
1325
1324
|
});
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1325
|
+
expect(isSelected('pkg-upright-sku')(state)).toBe(true);
|
|
1326
|
+
expect(isSelected('pkg-italic-sku')(state)).toBe(true);
|
|
1327
|
+
expect(isSelected('s1')(state)).toBe(true);
|
|
1328
|
+
expect(isSelected('si1')(state)).toBe(true);
|
|
1330
1329
|
});
|
|
1331
|
-
|
|
1330
|
+
it('bundles show selected when collection bundle is selected (transitive)', () => {
|
|
1332
1331
|
// Collection bundle is selected → family is false → family bundles should
|
|
1333
1332
|
// still show selected because the collection bundle covers all styles
|
|
1334
1333
|
const state = makeFamilyWithBundlesState({
|
|
@@ -1386,39 +1385,39 @@ function makeThunderState() {
|
|
|
1386
1385
|
});
|
|
1387
1386
|
|
|
1388
1387
|
// Family shows selected (direct child of collection bundle)
|
|
1389
|
-
|
|
1388
|
+
expect(isSelected('family-sku')(state)).toBe(true);
|
|
1390
1389
|
// Bundles should show selected (grandchildren — family is child of
|
|
1391
1390
|
// collection bundle, bundles are children of family)
|
|
1392
|
-
|
|
1393
|
-
|
|
1391
|
+
expect(isSelected('pkg-upright-sku')(state)).toBe(true);
|
|
1392
|
+
expect(isSelected('pkg-italic-sku')(state)).toBe(true);
|
|
1394
1393
|
// Individual styles should also show selected
|
|
1395
|
-
|
|
1394
|
+
expect(isSelected('s1')(state)).toBe(true);
|
|
1396
1395
|
});
|
|
1397
|
-
|
|
1396
|
+
it('selecting one bundle then another upgrades to family via reducer', () => {
|
|
1398
1397
|
const state = makeFamilyWithBundlesState();
|
|
1399
1398
|
|
|
1400
1399
|
// Select first bundle
|
|
1401
|
-
let newState = (
|
|
1400
|
+
let newState = reducer(state, {
|
|
1402
1401
|
type: 'SELECT_SKU_ID',
|
|
1403
1402
|
skuId: 'pkg-upright-sku',
|
|
1404
1403
|
selected: true
|
|
1405
1404
|
});
|
|
1406
|
-
|
|
1405
|
+
expect(newState.selectedSkuIds['pkg-upright-sku']).toBe(true);
|
|
1407
1406
|
|
|
1408
1407
|
// Select second bundle — should upgrade to family
|
|
1409
|
-
newState = (
|
|
1408
|
+
newState = reducer(newState, {
|
|
1410
1409
|
type: 'SELECT_SKU_ID',
|
|
1411
1410
|
skuId: 'pkg-italic-sku',
|
|
1412
1411
|
selected: true
|
|
1413
1412
|
});
|
|
1414
1413
|
|
|
1415
1414
|
// Family should be selected since family ($500) = two bundles ($250+$250)
|
|
1416
|
-
|
|
1415
|
+
expect(newState.selectedSkuIds['family-sku']).toBe(true);
|
|
1417
1416
|
// Both bundles should report as selected
|
|
1418
|
-
|
|
1419
|
-
|
|
1417
|
+
expect(isSelected('pkg-upright-sku')(newState)).toBe(true);
|
|
1418
|
+
expect(isSelected('pkg-italic-sku')(newState)).toBe(true);
|
|
1420
1419
|
});
|
|
1421
|
-
|
|
1420
|
+
it('auto-upgrades transitively: bundle → family → collection bundle', () => {
|
|
1422
1421
|
// When a collection bundle exists at the same price as the family,
|
|
1423
1422
|
// selecting both bundles should upgrade all the way to the collection
|
|
1424
1423
|
// bundle (not stop at the family)
|
|
@@ -1477,26 +1476,26 @@ function makeThunderState() {
|
|
|
1477
1476
|
'pkg-upright-sku': true
|
|
1478
1477
|
}
|
|
1479
1478
|
});
|
|
1480
|
-
const newState = (
|
|
1479
|
+
const newState = reducer(state, {
|
|
1481
1480
|
type: 'SELECT_SKU_ID',
|
|
1482
1481
|
skuId: 'pkg-italic-sku',
|
|
1483
1482
|
selected: true
|
|
1484
1483
|
});
|
|
1485
1484
|
|
|
1486
1485
|
// Should transitively upgrade: bundle → family → collection bundle
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1486
|
+
expect(newState.selectedSkuIds['coll-bundle-sku']).toBe(true);
|
|
1487
|
+
expect(newState.selectedSkuIds['family-sku']).toBe(false);
|
|
1488
|
+
expect(newState.selectedSkuIds['pkg-upright-sku']).toBe(false);
|
|
1489
|
+
expect(newState.selectedSkuIds['pkg-italic-sku']).toBe(false);
|
|
1491
1490
|
|
|
1492
1491
|
// All items should report as selected via isSelected
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1492
|
+
expect(isSelected('family-sku')(newState)).toBe(true);
|
|
1493
|
+
expect(isSelected('pkg-upright-sku')(newState)).toBe(true);
|
|
1494
|
+
expect(isSelected('pkg-italic-sku')(newState)).toBe(true);
|
|
1495
|
+
expect(isSelected('s1')(newState)).toBe(true);
|
|
1496
|
+
expect(isSelected('vs1')(newState)).toBe(true);
|
|
1498
1497
|
});
|
|
1499
|
-
|
|
1498
|
+
it('prefers collection bundle over family when family has duplicate fontStyleSkuIds from bundles', () => {
|
|
1500
1499
|
// In production data, flattenSkuData produces a family entry whose
|
|
1501
1500
|
// fontStyleSkuIds includes BOTH the family's own styles AND the
|
|
1502
1501
|
// overlapping styles from its child bundles, creating duplicates.
|
|
@@ -1561,10 +1560,10 @@ function makeThunderState() {
|
|
|
1561
1560
|
// family-sku fontStyleSkuIds.length is 20 (duplicates), coll-bundle is 12.
|
|
1562
1561
|
// A naive .length comparison would pick the family. The non-self
|
|
1563
1562
|
// preference must win so the collection bundle is auto-selected.
|
|
1564
|
-
const [collId] =
|
|
1565
|
-
|
|
1563
|
+
const [collId] = collectionSkuIdWithDiscount(state, 'family-sku');
|
|
1564
|
+
expect(collId).toBe('coll-bundle-sku');
|
|
1566
1565
|
});
|
|
1567
|
-
|
|
1566
|
+
it('transitive upgrade prefers the collection with the most font styles', () => {
|
|
1568
1567
|
// When two collections have the same price difference, prefer the one
|
|
1569
1568
|
// covering more font styles
|
|
1570
1569
|
const state = makeFamilyWithBundlesState({
|
|
@@ -1626,8 +1625,8 @@ function makeThunderState() {
|
|
|
1626
1625
|
vs1: 100
|
|
1627
1626
|
}
|
|
1628
1627
|
});
|
|
1629
|
-
const [collId] =
|
|
1628
|
+
const [collId] = collectionSkuIdWithDiscount(state, 'family-sku');
|
|
1630
1629
|
// Both bundles have the same price, but big-bundle has more styles
|
|
1631
|
-
|
|
1630
|
+
expect(collId).toBe('big-bundle-sku');
|
|
1632
1631
|
});
|
|
1633
1632
|
});
|