@salesforce/retail-react-app 1.0.0-preview.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/.eslintignore +7 -0
- package/.eslintrc.js +25 -0
- package/.prettierignore +4 -0
- package/.prettierrc.yaml +7 -0
- package/CHANGELOG.md +173 -0
- package/LICENSE +14 -0
- package/README.md +48 -0
- package/app/assets/svg/account.svg +3 -0
- package/app/assets/svg/alert.svg +3 -0
- package/app/assets/svg/basket.svg +3 -0
- package/app/assets/svg/brand-logo.svg +10 -0
- package/app/assets/svg/cc-amex.svg +7 -0
- package/app/assets/svg/cc-cvv.svg +8 -0
- package/app/assets/svg/cc-discover.svg +14 -0
- package/app/assets/svg/cc-mastercard.svg +8 -0
- package/app/assets/svg/cc-visa.svg +11 -0
- package/app/assets/svg/check-circle.svg +3 -0
- package/app/assets/svg/check.svg +3 -0
- package/app/assets/svg/chevron-down.svg +3 -0
- package/app/assets/svg/chevron-left.svg +3 -0
- package/app/assets/svg/chevron-right.svg +3 -0
- package/app/assets/svg/chevron-up.svg +3 -0
- package/app/assets/svg/close.svg +3 -0
- package/app/assets/svg/dashboard.svg +4 -0
- package/app/assets/svg/figma-logo.svg +14 -0
- package/app/assets/svg/file.svg +3 -0
- package/app/assets/svg/filter.svg +3 -0
- package/app/assets/svg/flag-ca.svg +5 -0
- package/app/assets/svg/flag-cn.svg +19 -0
- package/app/assets/svg/flag-fr.svg +19 -0
- package/app/assets/svg/flag-gb.svg +16 -0
- package/app/assets/svg/flag-it.svg +29 -0
- package/app/assets/svg/flag-jp.svg +10 -0
- package/app/assets/svg/flag-us.svg +7 -0
- package/app/assets/svg/github-logo.svg +40 -0
- package/app/assets/svg/hamburger.svg +8 -0
- package/app/assets/svg/heart-solid.svg +7 -0
- package/app/assets/svg/heart.svg +3 -0
- package/app/assets/svg/info.svg +3 -0
- package/app/assets/svg/like.svg +4 -0
- package/app/assets/svg/location.svg +3 -0
- package/app/assets/svg/lock.svg +3 -0
- package/app/assets/svg/paypal.svg +19 -0
- package/app/assets/svg/plug.svg +3 -0
- package/app/assets/svg/plus.svg +3 -0
- package/app/assets/svg/receipt.svg +3 -0
- package/app/assets/svg/search.svg +8 -0
- package/app/assets/svg/signout.svg +3 -0
- package/app/assets/svg/social-facebook.svg +3 -0
- package/app/assets/svg/social-instagram.svg +3 -0
- package/app/assets/svg/social-pinterest.svg +4 -0
- package/app/assets/svg/social-twitter.svg +3 -0
- package/app/assets/svg/social-youtube.svg +3 -0
- package/app/assets/svg/user.svg +3 -0
- package/app/assets/svg/visibility-off.svg +5 -0
- package/app/assets/svg/visibility.svg +3 -0
- package/app/components/_app/index.jsx +401 -0
- package/app/components/_app/index.test.js +85 -0
- package/app/components/_app/partials/above-header.jsx +10 -0
- package/app/components/_app-config/index.jsx +125 -0
- package/app/components/_app-config/index.test.js +77 -0
- package/app/components/_error/index.jsx +142 -0
- package/app/components/_error/index.test.js +25 -0
- package/app/components/action-card/index.jsx +75 -0
- package/app/components/address-display/index.jsx +30 -0
- package/app/components/basic-tile/index.jsx +65 -0
- package/app/components/basic-tile/index.test.js +23 -0
- package/app/components/breadcrumb/index.jsx +67 -0
- package/app/components/breadcrumb/index.test.js +30 -0
- package/app/components/confirmation-modal/index.jsx +111 -0
- package/app/components/confirmation-modal/index.test.js +98 -0
- package/app/components/drawer-menu/index.jsx +405 -0
- package/app/components/drawer-menu/index.test.js +33 -0
- package/app/components/dynamic-image/index.jsx +56 -0
- package/app/components/field/index.jsx +161 -0
- package/app/components/footer/index.jsx +269 -0
- package/app/components/footer/index.test.js +22 -0
- package/app/components/forms/address-fields.jsx +49 -0
- package/app/components/forms/credit-card-fields.jsx +149 -0
- package/app/components/forms/form-action-buttons.jsx +55 -0
- package/app/components/forms/login-fields.jsx +31 -0
- package/app/components/forms/password-requirements.jsx +99 -0
- package/app/components/forms/post-checkout-registration-fields.jsx +43 -0
- package/app/components/forms/profile-fields.jsx +36 -0
- package/app/components/forms/promo-code-fields.jsx +43 -0
- package/app/components/forms/registration-fields.jsx +42 -0
- package/app/components/forms/reset-password-fields.jsx +31 -0
- package/app/components/forms/state-province-options.jsx +75 -0
- package/app/components/forms/update-password-fields.jsx +49 -0
- package/app/components/forms/useAddressFields.jsx +196 -0
- package/app/components/forms/useCreditCardFields.jsx +146 -0
- package/app/components/forms/useLoginFields.jsx +52 -0
- package/app/components/forms/useProfileFields.jsx +95 -0
- package/app/components/forms/usePromoCodeFields.jsx +39 -0
- package/app/components/forms/useRegistrationFields.jsx +136 -0
- package/app/components/forms/useResetPasswordFields.jsx +40 -0
- package/app/components/forms/useUpdatePasswordFields.jsx +89 -0
- package/app/components/header/index.jsx +290 -0
- package/app/components/header/index.test.js +217 -0
- package/app/components/hero/index.jsx +84 -0
- package/app/components/hero/index.test.js +40 -0
- package/app/components/icons/index.jsx +158 -0
- package/app/components/icons/index.test.js +20 -0
- package/app/components/image-gallery/index.jsx +176 -0
- package/app/components/image-gallery/index.test.js +485 -0
- package/app/components/item-variant/index.jsx +33 -0
- package/app/components/item-variant/item-attributes.jsx +107 -0
- package/app/components/item-variant/item-image.jsx +73 -0
- package/app/components/item-variant/item-name.jsx +28 -0
- package/app/components/item-variant/item-price.jsx +117 -0
- package/app/components/link/index.jsx +32 -0
- package/app/components/link/index.test.js +72 -0
- package/app/components/links-list/index.jsx +89 -0
- package/app/components/links-list/index.test.js +62 -0
- package/app/components/list-menu/index.jsx +280 -0
- package/app/components/list-menu/index.test.js +44 -0
- package/app/components/loading-spinner/index.jsx +46 -0
- package/app/components/locale-selector/index.jsx +124 -0
- package/app/components/locale-selector/index.test.js +37 -0
- package/app/components/locale-text/index.jsx +97 -0
- package/app/components/locale-text/index.test.js +36 -0
- package/app/components/login/index.jsx +96 -0
- package/app/components/nested-accordion/index.jsx +185 -0
- package/app/components/nested-accordion/index.test.js +98 -0
- package/app/components/offline-banner/index.jsx +40 -0
- package/app/components/offline-banner/index.test.js +15 -0
- package/app/components/offline-boundary/index.jsx +104 -0
- package/app/components/offline-boundary/index.test.js +123 -0
- package/app/components/order-summary/index.jsx +331 -0
- package/app/components/page-action-placeholder/index.jsx +50 -0
- package/app/components/pagination/index.jsx +134 -0
- package/app/components/pagination/index.test.js +25 -0
- package/app/components/product-item/index.jsx +146 -0
- package/app/components/product-item/index.test.js +38 -0
- package/app/components/product-scroller/index.jsx +172 -0
- package/app/components/product-scroller/index.test.js +98 -0
- package/app/components/product-tile/index.jsx +195 -0
- package/app/components/product-tile/index.test.js +96 -0
- package/app/components/product-view/index.jsx +538 -0
- package/app/components/product-view/index.test.js +224 -0
- package/app/components/product-view-modal/index.jsx +48 -0
- package/app/components/product-view-modal/index.test.js +72 -0
- package/app/components/promo-code/index.jsx +162 -0
- package/app/components/promo-popover/index.jsx +83 -0
- package/app/components/quantity-picker/index.jsx +58 -0
- package/app/components/radio-card/index.jsx +75 -0
- package/app/components/recommended-products/index.jsx +227 -0
- package/app/components/register/index.jsx +114 -0
- package/app/components/reset-password/index.jsx +87 -0
- package/app/components/responsive/index.jsx +29 -0
- package/app/components/scroll-to-top/index.jsx +24 -0
- package/app/components/scroll-to-top/index.test.js +46 -0
- package/app/components/search/index.jsx +279 -0
- package/app/components/search/index.test.js +127 -0
- package/app/components/search/partials/recent-searches.jsx +76 -0
- package/app/components/search/partials/search-suggestions.jsx +45 -0
- package/app/components/search/partials/suggestions.jsx +43 -0
- package/app/components/section/index.jsx +68 -0
- package/app/components/seo/index.jsx +33 -0
- package/app/components/social-icons/index.jsx +101 -0
- package/app/components/social-icons/index.test.js +30 -0
- package/app/components/swatch-group/index.jsx +77 -0
- package/app/components/swatch-group/index.test.js +136 -0
- package/app/components/swatch-group/swatch.jsx +94 -0
- package/app/components/toggle-card/index.jsx +97 -0
- package/app/components/with-registration/index.jsx +58 -0
- package/app/components/with-registration/index.test.js +85 -0
- package/app/constants.js +109 -0
- package/app/contexts/index.js +92 -0
- package/app/hooks/einstein-mock-data.js +916 -0
- package/app/hooks/index.js +17 -0
- package/app/hooks/use-add-to-cart-modal.js +344 -0
- package/app/hooks/use-add-to-cart-modal.test.js +625 -0
- package/app/hooks/use-auth-modal.js +337 -0
- package/app/hooks/use-auth-modal.test.js +365 -0
- package/app/hooks/use-currency.js +20 -0
- package/app/hooks/use-currency.test.js +41 -0
- package/app/hooks/use-current-basket.js +39 -0
- package/app/hooks/use-current-customer.js +29 -0
- package/app/hooks/use-derived-product.js +77 -0
- package/app/hooks/use-derived-product.test.js +69 -0
- package/app/hooks/use-einstein.js +512 -0
- package/app/hooks/use-einstein.test.js +224 -0
- package/app/hooks/use-intersection-observer.js +64 -0
- package/app/hooks/use-limit-urls.js +31 -0
- package/app/hooks/use-limit-urls.test.js +40 -0
- package/app/hooks/use-multi-site.js +36 -0
- package/app/hooks/use-multi-site.test.js +53 -0
- package/app/hooks/use-navigation.js +37 -0
- package/app/hooks/use-navigation.test.js +109 -0
- package/app/hooks/use-page-urls.js +35 -0
- package/app/hooks/use-page-urls.test.js +39 -0
- package/app/hooks/use-pdp-search-params.js +16 -0
- package/app/hooks/use-pdp-search-params.test.js +52 -0
- package/app/hooks/use-previous.js +17 -0
- package/app/hooks/use-product-view-modal.js +93 -0
- package/app/hooks/use-product-view-modal.test.js +172 -0
- package/app/hooks/use-search-params.js +96 -0
- package/app/hooks/use-search-params.test.js +91 -0
- package/app/hooks/use-sort-urls.js +33 -0
- package/app/hooks/use-sort-urls.test.js +42 -0
- package/app/hooks/use-toast.js +68 -0
- package/app/hooks/use-toast.test.js +58 -0
- package/app/hooks/use-variant.js +32 -0
- package/app/hooks/use-variant.test.js +81 -0
- package/app/hooks/use-variation-attributes.js +138 -0
- package/app/hooks/use-variation-attributes.test.js +119 -0
- package/app/hooks/use-variation-params.js +31 -0
- package/app/hooks/use-variation-params.test.js +73 -0
- package/app/hooks/use-wish-list.js +42 -0
- package/app/main.jsx +14 -0
- package/app/mocks/basket-with-suit.js +146 -0
- package/app/mocks/empty-basket.js +39 -0
- package/app/mocks/mock-data.js +5632 -0
- package/app/mocks/product-set-winter-lookM.js +1224 -0
- package/app/mocks/searchResults.js +144 -0
- package/app/mocks/variant-750518699578M.js +434 -0
- package/app/page-designer/README.md +102 -0
- package/app/page-designer/assets/image-tile/index.jsx +51 -0
- package/app/page-designer/assets/image-tile/index.test.js +30 -0
- package/app/page-designer/assets/image-with-text/index.jsx +140 -0
- package/app/page-designer/assets/image-with-text/index.test.js +38 -0
- package/app/page-designer/assets/index.js +9 -0
- package/app/page-designer/index.js +10 -0
- package/app/page-designer/layouts/carousel/index.jsx +222 -0
- package/app/page-designer/layouts/carousel/index.test.js +43 -0
- package/app/page-designer/layouts/index.js +14 -0
- package/app/page-designer/layouts/mobileGrid1r1c/index.jsx +36 -0
- package/app/page-designer/layouts/mobileGrid1r1c/index.test.js +35 -0
- package/app/page-designer/layouts/mobileGrid2r1c/index.jsx +37 -0
- package/app/page-designer/layouts/mobileGrid2r1c/index.test.js +47 -0
- package/app/page-designer/layouts/mobileGrid2r2c/index.jsx +37 -0
- package/app/page-designer/layouts/mobileGrid2r2c/index.test.js +71 -0
- package/app/page-designer/layouts/mobileGrid2r3c/index.jsx +37 -0
- package/app/page-designer/layouts/mobileGrid2r3c/index.test.js +95 -0
- package/app/page-designer/layouts/mobileGrid3r1c/index.jsx +37 -0
- package/app/page-designer/layouts/mobileGrid3r1c/index.test.js +59 -0
- package/app/page-designer/layouts/mobileGrid3r2c/index.jsx +37 -0
- package/app/page-designer/layouts/mobileGrid3r2c/index.test.js +95 -0
- package/app/page-designer/utils.js +14 -0
- package/app/pages/account/addresses.jsx +382 -0
- package/app/pages/account/addresses.test.js +120 -0
- package/app/pages/account/constant.js +57 -0
- package/app/pages/account/index.jsx +237 -0
- package/app/pages/account/index.test.js +188 -0
- package/app/pages/account/order-detail.jsx +397 -0
- package/app/pages/account/order-history.jsx +264 -0
- package/app/pages/account/orders.jsx +30 -0
- package/app/pages/account/orders.test.js +95 -0
- package/app/pages/account/profile.jsx +357 -0
- package/app/pages/account/wishlist/index.jsx +195 -0
- package/app/pages/account/wishlist/index.mock.js +1481 -0
- package/app/pages/account/wishlist/index.test.js +56 -0
- package/app/pages/account/wishlist/partials/wishlist-primary-action.jsx +170 -0
- package/app/pages/account/wishlist/partials/wishlist-primary-action.mock.js +1623 -0
- package/app/pages/account/wishlist/partials/wishlist-primary-action.test.js +99 -0
- package/app/pages/account/wishlist/partials/wishlist-secondary-button-group.jsx +120 -0
- package/app/pages/account/wishlist/partials/wishlist-secondary-button-group.test.js +391 -0
- package/app/pages/cart/index.jsx +476 -0
- package/app/pages/cart/index.test.js +481 -0
- package/app/pages/cart/partials/cart-cta.jsx +46 -0
- package/app/pages/cart/partials/cart-secondary-button-group.jsx +135 -0
- package/app/pages/cart/partials/cart-secondary-button-group.test.js +103 -0
- package/app/pages/cart/partials/cart-skeleton.jsx +93 -0
- package/app/pages/cart/partials/cart-title.jsx +27 -0
- package/app/pages/cart/partials/empty-cart.jsx +86 -0
- package/app/pages/checkout/confirmation.jsx +541 -0
- package/app/pages/checkout/confirmation.mock.js +450 -0
- package/app/pages/checkout/confirmation.test.js +114 -0
- package/app/pages/checkout/index.jsx +169 -0
- package/app/pages/checkout/index.test.js +582 -0
- package/app/pages/checkout/partials/cc-radio-group.jsx +122 -0
- package/app/pages/checkout/partials/checkout-footer.jsx +140 -0
- package/app/pages/checkout/partials/checkout-footer.test.js +16 -0
- package/app/pages/checkout/partials/checkout-header.jsx +54 -0
- package/app/pages/checkout/partials/checkout-header.test.js +16 -0
- package/app/pages/checkout/partials/checkout-skeleton.jsx +52 -0
- package/app/pages/checkout/partials/contact-info.jsx +251 -0
- package/app/pages/checkout/partials/contact-info.test.js +43 -0
- package/app/pages/checkout/partials/payment-form.jsx +97 -0
- package/app/pages/checkout/partials/payment.jsx +276 -0
- package/app/pages/checkout/partials/shipping-address-selection.jsx +377 -0
- package/app/pages/checkout/partials/shipping-address.jsx +132 -0
- package/app/pages/checkout/partials/shipping-options.jsx +232 -0
- package/app/pages/checkout/util/checkout-context.js +94 -0
- package/app/pages/home/data.js +134 -0
- package/app/pages/home/index.jsx +301 -0
- package/app/pages/home/index.test.js +23 -0
- package/app/pages/login/index.jsx +123 -0
- package/app/pages/login/index.test.js +229 -0
- package/app/pages/login-redirect/index.jsx +23 -0
- package/app/pages/login-redirect/index.test.js +16 -0
- package/app/pages/page-not-found/index.jsx +90 -0
- package/app/pages/page-not-found/index.test.js +31 -0
- package/app/pages/product-detail/index.jsx +394 -0
- package/app/pages/product-detail/index.mock.js +197 -0
- package/app/pages/product-detail/index.test.js +162 -0
- package/app/pages/product-detail/partials/information-accordion.jsx +121 -0
- package/app/pages/product-list/index.jsx +735 -0
- package/app/pages/product-list/index.test.js +180 -0
- package/app/pages/product-list/partials/above-page-header.jsx +10 -0
- package/app/pages/product-list/partials/checkbox-refinements.jsx +41 -0
- package/app/pages/product-list/partials/checkbox-refinements.test.js +53 -0
- package/app/pages/product-list/partials/color-refinements.jsx +88 -0
- package/app/pages/product-list/partials/empty-results.jsx +118 -0
- package/app/pages/product-list/partials/link-refinements.jsx +38 -0
- package/app/pages/product-list/partials/page-header.jsx +42 -0
- package/app/pages/product-list/partials/radio-refinements.jsx +60 -0
- package/app/pages/product-list/partials/refinements.jsx +144 -0
- package/app/pages/product-list/partials/selected-refinements.jsx +100 -0
- package/app/pages/product-list/partials/size-refinements.jsx +55 -0
- package/app/pages/registration/index.jsx +87 -0
- package/app/pages/registration/index.test.jsx +132 -0
- package/app/pages/reset-password/index.jsx +112 -0
- package/app/pages/reset-password/index.test.jsx +141 -0
- package/app/request-processor.js +118 -0
- package/app/request-processor.test.js +23 -0
- package/app/routes.jsx +111 -0
- package/app/routes.test.js +13 -0
- package/app/ssr.js +70 -0
- package/app/static/ico/favicon.ico +0 -0
- package/app/static/img/global/app-icon-192.png +0 -0
- package/app/static/img/global/app-icon-512.png +0 -0
- package/app/static/img/global/apple-touch-icon.png +0 -0
- package/app/static/img/hero.png +0 -0
- package/app/static/manifest.json +19 -0
- package/app/static/robots.txt +2 -0
- package/app/theme/components/base/accordion.js +21 -0
- package/app/theme/components/base/alert.js +17 -0
- package/app/theme/components/base/badge.js +25 -0
- package/app/theme/components/base/button.js +77 -0
- package/app/theme/components/base/checkbox.js +30 -0
- package/app/theme/components/base/container.js +17 -0
- package/app/theme/components/base/drawer.js +26 -0
- package/app/theme/components/base/formLabel.js +13 -0
- package/app/theme/components/base/icon.js +13 -0
- package/app/theme/components/base/input.js +44 -0
- package/app/theme/components/base/modal.js +11 -0
- package/app/theme/components/base/popover.js +61 -0
- package/app/theme/components/base/radio.js +33 -0
- package/app/theme/components/base/select.js +15 -0
- package/app/theme/components/base/skeleton.js +12 -0
- package/app/theme/components/base/tooltip.js +19 -0
- package/app/theme/components/project/_app.js +25 -0
- package/app/theme/components/project/breadcrumb.js +25 -0
- package/app/theme/components/project/checkout-footer.js +35 -0
- package/app/theme/components/project/drawer-menu.js +66 -0
- package/app/theme/components/project/footer.js +84 -0
- package/app/theme/components/project/header.js +84 -0
- package/app/theme/components/project/image-gallery.js +59 -0
- package/app/theme/components/project/links-list.js +43 -0
- package/app/theme/components/project/list-menu.js +91 -0
- package/app/theme/components/project/locale-selector.js +42 -0
- package/app/theme/components/project/nested-accordion.js +26 -0
- package/app/theme/components/project/offline-banner.js +25 -0
- package/app/theme/components/project/pagination.js +22 -0
- package/app/theme/components/project/product-tile.js +32 -0
- package/app/theme/components/project/social-icons.js +52 -0
- package/app/theme/components/project/swatch-group.js +115 -0
- package/app/theme/foundations/colors.js +170 -0
- package/app/theme/foundations/gradients.js +9 -0
- package/app/theme/foundations/layerStyles.js +41 -0
- package/app/theme/foundations/shadows.js +9 -0
- package/app/theme/foundations/sizes.js +18 -0
- package/app/theme/foundations/space.js +9 -0
- package/app/theme/foundations/styles.js +21 -0
- package/app/theme/index.js +104 -0
- package/app/utils/cc-utils.js +112 -0
- package/app/utils/cc-utils.test.js +41 -0
- package/app/utils/image-groups-utils.js +62 -0
- package/app/utils/image-groups-utils.test.js +65 -0
- package/app/utils/locale.js +78 -0
- package/app/utils/locale.test.js +112 -0
- package/app/utils/password-utils.js +21 -0
- package/app/utils/phone-utils.js +22 -0
- package/app/utils/phone-utils.test.js +15 -0
- package/app/utils/product-utils.js +35 -0
- package/app/utils/product-utils.test.js +51 -0
- package/app/utils/responsive-image.js +198 -0
- package/app/utils/responsive-image.test.js +170 -0
- package/app/utils/routes-utils.js +111 -0
- package/app/utils/routes-utils.test.js +291 -0
- package/app/utils/site-utils.js +222 -0
- package/app/utils/site-utils.test.js +376 -0
- package/app/utils/test-utils.js +257 -0
- package/app/utils/url.js +291 -0
- package/app/utils/url.test.js +421 -0
- package/app/utils/utils.js +201 -0
- package/app/utils/utils.test.js +182 -0
- package/babel.config.js +7 -0
- package/cache-hash-config.json +8 -0
- package/config/default.js +64 -0
- package/config/mocks/default.js +131 -0
- package/config/sites.js +78 -0
- package/jest-setup.js +191 -0
- package/jest.config.js +50 -0
- package/jsconfig.json +13 -0
- package/package.json +105 -0
- package/scripts/extract-default-messages.js +92 -0
- package/tests/lighthouserc.js +37 -0
- package/translations/README.md +127 -0
- package/translations/compiled/de-DE.json +3212 -0
- package/translations/compiled/en-GB.json +3212 -0
- package/translations/compiled/en-US.json +3212 -0
- package/translations/compiled/en-XA.json +6948 -0
- package/translations/compiled/es-MX.json +3216 -0
- package/translations/compiled/fr-FR.json +3216 -0
- package/translations/compiled/it-IT.json +3188 -0
- package/translations/compiled/ja-JP.json +3200 -0
- package/translations/compiled/ko-KR.json +3180 -0
- package/translations/compiled/pt-BR.json +3220 -0
- package/translations/compiled/zh-CN.json +3212 -0
- package/translations/compiled/zh-TW.json +3208 -0
- package/translations/de-DE.json +1417 -0
- package/translations/en-GB.json +1417 -0
- package/translations/en-US.json +1417 -0
- package/translations/es-MX.json +1417 -0
- package/translations/fr-FR.json +1417 -0
- package/translations/it-IT.json +1417 -0
- package/translations/ja-JP.json +1417 -0
- package/translations/ko-KR.json +1417 -0
- package/translations/pt-BR.json +1417 -0
- package/translations/zh-CN.json +1417 -0
- package/translations/zh-TW.json +1417 -0
- package/worker/main.js +36 -0
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2021, salesforce.com, inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
5
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react'
|
|
8
|
+
import Checkout from '@salesforce/retail-react-app/app/pages/checkout/index'
|
|
9
|
+
import {Route, Switch} from 'react-router-dom'
|
|
10
|
+
import {screen, waitFor, within} from '@testing-library/react'
|
|
11
|
+
import {rest} from 'msw'
|
|
12
|
+
import {
|
|
13
|
+
renderWithProviders,
|
|
14
|
+
createPathWithDefaults,
|
|
15
|
+
registerUserToken
|
|
16
|
+
} from '@salesforce/retail-react-app/app/utils/test-utils'
|
|
17
|
+
import {
|
|
18
|
+
scapiBasketWithItem,
|
|
19
|
+
mockShippingMethods,
|
|
20
|
+
mockedRegisteredCustomer,
|
|
21
|
+
mockedCustomerProductLists
|
|
22
|
+
} from '@salesforce/retail-react-app/app/mocks/mock-data'
|
|
23
|
+
import mockConfig from '@salesforce/retail-react-app/config/mocks/default'
|
|
24
|
+
import userEvent from '@testing-library/user-event'
|
|
25
|
+
|
|
26
|
+
jest.setTimeout(30000)
|
|
27
|
+
|
|
28
|
+
// Minimal subset of `ocapiOrderResponse` in app/mocks/mock-data.js
|
|
29
|
+
const scapiOrderResponse = {
|
|
30
|
+
orderNo: '00000101',
|
|
31
|
+
customerInfo: {
|
|
32
|
+
customerId: 'customerid',
|
|
33
|
+
customerNo: 'jlebowski',
|
|
34
|
+
email: 'jeff@lebowski.com'
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const defaultShippingMethod = mockShippingMethods.applicableShippingMethods.find(
|
|
39
|
+
(method) => method.id === mockShippingMethods.defaultShippingMethodId
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
// This is our wrapped component for testing. It handles initialization of the customer
|
|
43
|
+
// and basket the same way it would be when rendered in the real app. We also set up
|
|
44
|
+
// fake routes to simulate moving from checkout to confirmation page.
|
|
45
|
+
const WrappedCheckout = () => {
|
|
46
|
+
return (
|
|
47
|
+
<Switch>
|
|
48
|
+
<Route exact path={createPathWithDefaults('/checkout')}>
|
|
49
|
+
<Checkout />
|
|
50
|
+
</Route>
|
|
51
|
+
<Route
|
|
52
|
+
exact
|
|
53
|
+
path={createPathWithDefaults(
|
|
54
|
+
`/checkout/confirmation/${scapiOrderResponse.orderNo}`
|
|
55
|
+
)}
|
|
56
|
+
>
|
|
57
|
+
<div>success</div>
|
|
58
|
+
</Route>
|
|
59
|
+
</Switch>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Set up and clean up
|
|
64
|
+
beforeEach(() => {
|
|
65
|
+
global.server.use(
|
|
66
|
+
// mock product details
|
|
67
|
+
rest.get('*/products', (req, res, ctx) => {
|
|
68
|
+
return res(ctx.json({data: [{id: '701642811398M'}]}))
|
|
69
|
+
}),
|
|
70
|
+
// mock the available shipping methods
|
|
71
|
+
rest.get('*/shipments/me/shipping-methods', (req, res, ctx) => {
|
|
72
|
+
return res(ctx.delay(0), ctx.json(mockShippingMethods))
|
|
73
|
+
})
|
|
74
|
+
)
|
|
75
|
+
})
|
|
76
|
+
afterEach(() => {
|
|
77
|
+
jest.resetModules()
|
|
78
|
+
localStorage.clear()
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
test('Renders skeleton until customer and basket are loaded', () => {
|
|
82
|
+
const {getByTestId, queryByTestId} = renderWithProviders(<Checkout />)
|
|
83
|
+
|
|
84
|
+
expect(getByTestId('sf-checkout-skeleton')).toBeInTheDocument()
|
|
85
|
+
expect(queryByTestId('sf-checkout-container')).not.toBeInTheDocument()
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
test('Can proceed through checkout steps as guest', async () => {
|
|
89
|
+
// Keep a *deep* copy of the initial mocked basket. Our mocked fetch responses will continuously
|
|
90
|
+
// update this object, which essentially mimics a saved basket on the backend.
|
|
91
|
+
let currentBasket = JSON.parse(JSON.stringify(scapiBasketWithItem))
|
|
92
|
+
|
|
93
|
+
// Set up additional requests for intercepting/mocking for just this test.
|
|
94
|
+
global.server.use(
|
|
95
|
+
// mock adding guest email to basket
|
|
96
|
+
rest.put('*/baskets/:basketId/customer', (req, res, ctx) => {
|
|
97
|
+
currentBasket.customerInfo.email = 'test@test.com'
|
|
98
|
+
return res(ctx.json(currentBasket))
|
|
99
|
+
}),
|
|
100
|
+
|
|
101
|
+
// mock add shipping and billing address to basket
|
|
102
|
+
rest.put('*/shipping-address', (req, res, ctx) => {
|
|
103
|
+
const shippingBillingAddress = {
|
|
104
|
+
address1: '123 Main St',
|
|
105
|
+
city: 'Tampa',
|
|
106
|
+
countryCode: 'US',
|
|
107
|
+
firstName: 'Tester',
|
|
108
|
+
fullName: 'Tester McTesting',
|
|
109
|
+
id: '047b18d4aaaf4138f693a4b931',
|
|
110
|
+
lastName: 'McTesting',
|
|
111
|
+
phone: '(727) 555-1234',
|
|
112
|
+
postalCode: '33610',
|
|
113
|
+
stateCode: 'FL'
|
|
114
|
+
}
|
|
115
|
+
currentBasket.shipments[0].shippingAddress = shippingBillingAddress
|
|
116
|
+
currentBasket.billingAddress = shippingBillingAddress
|
|
117
|
+
return res(ctx.json(currentBasket))
|
|
118
|
+
}),
|
|
119
|
+
|
|
120
|
+
// mock add billing address to basket
|
|
121
|
+
rest.put('*/billing-address', (req, res, ctx) => {
|
|
122
|
+
const shippingBillingAddress = {
|
|
123
|
+
address1: '123 Main St',
|
|
124
|
+
city: 'Tampa',
|
|
125
|
+
countryCode: 'US',
|
|
126
|
+
firstName: 'Tester',
|
|
127
|
+
fullName: 'Tester McTesting',
|
|
128
|
+
id: '047b18d4aaaf4138f693a4b931',
|
|
129
|
+
lastName: 'McTesting',
|
|
130
|
+
phone: '(727) 555-1234',
|
|
131
|
+
postalCode: '33610',
|
|
132
|
+
stateCode: 'FL'
|
|
133
|
+
}
|
|
134
|
+
currentBasket.shipments[0].shippingAddress = shippingBillingAddress
|
|
135
|
+
currentBasket.billingAddress = shippingBillingAddress
|
|
136
|
+
return res(ctx.json(currentBasket))
|
|
137
|
+
}),
|
|
138
|
+
|
|
139
|
+
// mock add shipping method
|
|
140
|
+
rest.put('*/shipments/me/shipping-method', (req, res, ctx) => {
|
|
141
|
+
currentBasket.shipments[0].shippingMethod = defaultShippingMethod
|
|
142
|
+
return res(ctx.json(currentBasket))
|
|
143
|
+
}),
|
|
144
|
+
|
|
145
|
+
// mock add payment instrument
|
|
146
|
+
rest.post('*/baskets/:basketId/payment-instruments', (req, res, ctx) => {
|
|
147
|
+
currentBasket.paymentInstruments = [
|
|
148
|
+
{
|
|
149
|
+
amount: 0,
|
|
150
|
+
paymentCard: {
|
|
151
|
+
cardType: 'Visa',
|
|
152
|
+
creditCardExpired: false,
|
|
153
|
+
expirationMonth: 12,
|
|
154
|
+
expirationYear: 2024,
|
|
155
|
+
holder: 'Testy McTester',
|
|
156
|
+
maskedNumber: '************1111',
|
|
157
|
+
numberLastDigits: '1111',
|
|
158
|
+
validFromMonth: 1,
|
|
159
|
+
validFromYear: 2020
|
|
160
|
+
},
|
|
161
|
+
paymentInstrumentId: '875cae2724408c9a3eb45715ba',
|
|
162
|
+
paymentMethodId: 'CREDIT_CARD'
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
return res(ctx.json(currentBasket))
|
|
166
|
+
}),
|
|
167
|
+
|
|
168
|
+
// mock place order
|
|
169
|
+
rest.post('*/orders', (req, res, ctx) => {
|
|
170
|
+
currentBasket = {
|
|
171
|
+
...scapiOrderResponse,
|
|
172
|
+
customerInfo: {...scapiOrderResponse.customerInfo, email: 'test@test.com'}
|
|
173
|
+
}
|
|
174
|
+
return res(ctx.json(currentBasket))
|
|
175
|
+
}),
|
|
176
|
+
|
|
177
|
+
rest.get('*/baskets', (req, res, ctx) => {
|
|
178
|
+
const baskets = {
|
|
179
|
+
baskets: [currentBasket],
|
|
180
|
+
total: 1
|
|
181
|
+
}
|
|
182
|
+
return res(ctx.json(baskets))
|
|
183
|
+
})
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
// Set the initial browser router path and render our component tree.
|
|
187
|
+
window.history.pushState({}, 'Checkout', createPathWithDefaults('/checkout'))
|
|
188
|
+
const {user} = renderWithProviders(<WrappedCheckout history={history} />, {
|
|
189
|
+
wrapperProps: {isGuest: true, siteAlias: 'uk', appConfig: mockConfig.app}
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
// Wait for checkout to load and display first step
|
|
193
|
+
await screen.findByText(/checkout as guest/i)
|
|
194
|
+
|
|
195
|
+
// Verify cart products display
|
|
196
|
+
await user.click(screen.getByText(/2 items in cart/i))
|
|
197
|
+
expect(await screen.findByText(/Long Sleeve Crew Neck/i)).toBeInTheDocument()
|
|
198
|
+
|
|
199
|
+
// Provide customer email and submit
|
|
200
|
+
const emailInput = screen.getByLabelText(/email/i)
|
|
201
|
+
const submitBtn = screen.getByText(/checkout as guest/i)
|
|
202
|
+
await user.type(emailInput, 'test@test.com')
|
|
203
|
+
await user.click(submitBtn)
|
|
204
|
+
|
|
205
|
+
// Wait for next step to render
|
|
206
|
+
await waitFor(() =>
|
|
207
|
+
expect(screen.getByTestId('sf-toggle-card-step-1-content')).not.toBeEmptyDOMElement()
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
// Email should be displayed in previous step summary
|
|
211
|
+
expect(screen.getByText('test@test.com')).toBeInTheDocument()
|
|
212
|
+
|
|
213
|
+
// Fill out shipping address form and submit
|
|
214
|
+
await user.type(screen.getByLabelText(/first name/i), 'Tester')
|
|
215
|
+
await user.type(screen.getByLabelText(/last name/i), 'McTesting')
|
|
216
|
+
await user.type(screen.getByLabelText(/phone/i), '(727) 555-1234')
|
|
217
|
+
await user.type(screen.getByLabelText(/address/i), '123 Main St')
|
|
218
|
+
await user.type(screen.getByLabelText(/city/i), 'Tampa')
|
|
219
|
+
await user.selectOptions(screen.getByLabelText(/state/i), ['FL'])
|
|
220
|
+
await user.type(screen.getByLabelText(/zip code/i), '33610')
|
|
221
|
+
await user.click(screen.getByText(/continue to shipping method/i))
|
|
222
|
+
|
|
223
|
+
// Wait for next step to render
|
|
224
|
+
await waitFor(() => {
|
|
225
|
+
expect(screen.getByTestId('sf-toggle-card-step-2-content')).not.toBeEmptyDOMElement()
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
// Shipping address displayed in previous step summary
|
|
229
|
+
expect(screen.getByText('Tester McTesting')).toBeInTheDocument()
|
|
230
|
+
expect(screen.getByText('123 Main St')).toBeInTheDocument()
|
|
231
|
+
expect(screen.getByText('Tampa, FL 33610')).toBeInTheDocument()
|
|
232
|
+
expect(screen.getByText('US')).toBeInTheDocument()
|
|
233
|
+
|
|
234
|
+
// Default shipping option should be selected
|
|
235
|
+
const shippingOptionsForm = screen.getByTestId('sf-checkout-shipping-options-form')
|
|
236
|
+
|
|
237
|
+
await waitFor(() =>
|
|
238
|
+
expect(shippingOptionsForm).toHaveFormValues({
|
|
239
|
+
'shipping-options-radiogroup': mockShippingMethods.defaultShippingMethodId
|
|
240
|
+
})
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
// Submit selected shipping method
|
|
244
|
+
await user.click(screen.getByText(/continue to payment/i))
|
|
245
|
+
|
|
246
|
+
// Wait for next step to render
|
|
247
|
+
await waitFor(() => {
|
|
248
|
+
expect(screen.getByTestId('sf-toggle-card-step-3-content')).not.toBeEmptyDOMElement()
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
// Applied shipping method should be displayed in previous step summary
|
|
252
|
+
expect(screen.getByText(defaultShippingMethod.name)).toBeInTheDocument()
|
|
253
|
+
|
|
254
|
+
// Fill out credit card payment form
|
|
255
|
+
await user.type(screen.getByLabelText(/card number/i), '4111111111111111')
|
|
256
|
+
await user.type(screen.getByLabelText(/name on card/i), 'Testy McTester')
|
|
257
|
+
await user.type(screen.getByLabelText(/expiration date/i), '1224')
|
|
258
|
+
await user.type(screen.getByLabelText(/security code/i), '123')
|
|
259
|
+
|
|
260
|
+
// Same as shipping checkbox selected by default
|
|
261
|
+
expect(screen.getByLabelText(/same as shipping address/i)).toBeChecked()
|
|
262
|
+
|
|
263
|
+
// Should display billing address that matches shipping address
|
|
264
|
+
const step3Content = within(screen.getByTestId('sf-toggle-card-step-3-content'))
|
|
265
|
+
expect(step3Content.getByText('Tester McTesting')).toBeInTheDocument()
|
|
266
|
+
expect(step3Content.getByText('123 Main St')).toBeInTheDocument()
|
|
267
|
+
expect(step3Content.getByText('Tampa, FL 33610')).toBeInTheDocument()
|
|
268
|
+
expect(step3Content.getByText('US')).toBeInTheDocument()
|
|
269
|
+
|
|
270
|
+
// Move to final review step
|
|
271
|
+
await user.click(screen.getByText(/review order/i))
|
|
272
|
+
|
|
273
|
+
const placeOrderBtn = await screen.findByTestId('sf-checkout-place-order-btn', undefined, {
|
|
274
|
+
timeout: 5000
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
// Verify applied payment and billing address
|
|
278
|
+
expect(step3Content.getByText('Visa')).toBeInTheDocument()
|
|
279
|
+
expect(step3Content.getByText('•••• 1111')).toBeInTheDocument()
|
|
280
|
+
expect(step3Content.getByText('12/2024')).toBeInTheDocument()
|
|
281
|
+
|
|
282
|
+
expect(step3Content.getByText('Tester McTesting')).toBeInTheDocument()
|
|
283
|
+
expect(step3Content.getByText('123 Main St')).toBeInTheDocument()
|
|
284
|
+
expect(step3Content.getByText('Tampa, FL 33610')).toBeInTheDocument()
|
|
285
|
+
expect(step3Content.getByText('US')).toBeInTheDocument()
|
|
286
|
+
// Place the order
|
|
287
|
+
await user.click(placeOrderBtn)
|
|
288
|
+
|
|
289
|
+
// Should now be on our mocked confirmation route/page
|
|
290
|
+
expect(await screen.findByText(/success/i)).toBeInTheDocument()
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
test('Can proceed through checkout as registered customer', async () => {
|
|
294
|
+
const user = userEvent.setup()
|
|
295
|
+
await logInDuringCheckout()
|
|
296
|
+
|
|
297
|
+
// Email should be displayed in previous step summary
|
|
298
|
+
expect(screen.getByText('customer@test.com')).toBeInTheDocument()
|
|
299
|
+
|
|
300
|
+
// Select a saved address and continue
|
|
301
|
+
await user.click(screen.getByDisplayValue('savedaddress1'))
|
|
302
|
+
await user.click(screen.getByText(/continue to shipping method/i))
|
|
303
|
+
|
|
304
|
+
// Wait for next step to render
|
|
305
|
+
await waitFor(() => {
|
|
306
|
+
expect(screen.getByTestId('sf-toggle-card-step-2-content')).not.toBeEmptyDOMElement()
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
// Shipping address displayed in previous step summary
|
|
310
|
+
expect(screen.getByText('Test McTester')).toBeInTheDocument()
|
|
311
|
+
expect(screen.getByText('123 Main St')).toBeInTheDocument()
|
|
312
|
+
|
|
313
|
+
// Default shipping option should be selected
|
|
314
|
+
const shippingOptionsForm = screen.getByTestId('sf-checkout-shipping-options-form')
|
|
315
|
+
await waitFor(() =>
|
|
316
|
+
expect(shippingOptionsForm).toHaveFormValues({
|
|
317
|
+
'shipping-options-radiogroup': mockShippingMethods.defaultShippingMethodId
|
|
318
|
+
})
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
// Submit selected shipping method
|
|
322
|
+
await user.click(screen.getByText(/continue to payment/i))
|
|
323
|
+
|
|
324
|
+
// Wait for next step to render
|
|
325
|
+
await waitFor(() => {
|
|
326
|
+
expect(screen.getByTestId('sf-toggle-card-step-3-content')).not.toBeEmptyDOMElement()
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
// Applied shipping method should be displayed in previous step summary
|
|
330
|
+
expect(screen.getByText(defaultShippingMethod.name)).toBeInTheDocument()
|
|
331
|
+
|
|
332
|
+
// Fill out credit card payment form
|
|
333
|
+
// (we no longer have saved payment methods)
|
|
334
|
+
await user.type(screen.getByLabelText(/card number/i), '4111111111111111')
|
|
335
|
+
await user.type(screen.getByLabelText(/name on card/i), 'Testy McTester')
|
|
336
|
+
await user.type(screen.getByLabelText(/expiration date/i), '1224')
|
|
337
|
+
await user.type(screen.getByLabelText(/security code/i), '123')
|
|
338
|
+
|
|
339
|
+
// Same as shipping checkbox selected by default
|
|
340
|
+
expect(screen.getByLabelText(/same as shipping address/i)).toBeChecked()
|
|
341
|
+
|
|
342
|
+
// Should display billing address that matches shipping address
|
|
343
|
+
const step3Content = within(screen.getByTestId('sf-toggle-card-step-3-content'))
|
|
344
|
+
expect(step3Content.getByText('123 Main St')).toBeInTheDocument()
|
|
345
|
+
|
|
346
|
+
// Move to final review step
|
|
347
|
+
await user.click(screen.getByText(/review order/i))
|
|
348
|
+
|
|
349
|
+
const placeOrderBtn = await screen.findByTestId('sf-checkout-place-order-btn', undefined, {
|
|
350
|
+
timeout: 5000
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
// Verify applied payment and billing address
|
|
354
|
+
expect(step3Content.getByText('Master Card')).toBeInTheDocument()
|
|
355
|
+
expect(step3Content.getByText('•••• 5454')).toBeInTheDocument()
|
|
356
|
+
expect(step3Content.getByText('1/2030')).toBeInTheDocument()
|
|
357
|
+
|
|
358
|
+
expect(step3Content.getByText('123 Main St')).toBeInTheDocument()
|
|
359
|
+
|
|
360
|
+
// Place the order
|
|
361
|
+
await user.click(placeOrderBtn)
|
|
362
|
+
|
|
363
|
+
// Should now be on our mocked confirmation route/page
|
|
364
|
+
expect(await screen.findByText(/success/i)).toBeInTheDocument()
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
test('Can edit address during checkout as a registered customer', async () => {
|
|
368
|
+
const user = userEvent.setup()
|
|
369
|
+
|
|
370
|
+
await logInDuringCheckout()
|
|
371
|
+
|
|
372
|
+
const firstAddress = screen.getByTestId('sf-checkout-shipping-address-0')
|
|
373
|
+
await user.click(within(firstAddress).getByText(/edit/i))
|
|
374
|
+
|
|
375
|
+
// Wait for the edit address form to render
|
|
376
|
+
await waitFor(() =>
|
|
377
|
+
expect(screen.getByTestId('sf-shipping-address-edit-form')).not.toBeEmptyDOMElement()
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
expect(screen.getByLabelText(/first name/i)).toBeInTheDocument()
|
|
381
|
+
|
|
382
|
+
// Edit and save the address
|
|
383
|
+
await user.clear(screen.getByLabelText('Address'))
|
|
384
|
+
await user.type(screen.getByLabelText('Address'), '369 Main Street')
|
|
385
|
+
await user.click(screen.getByText(/save & continue to shipping method/i))
|
|
386
|
+
|
|
387
|
+
// Wait for next step to render
|
|
388
|
+
await waitFor(() => {
|
|
389
|
+
expect(screen.getByTestId('sf-toggle-card-step-2-content')).not.toBeEmptyDOMElement()
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
expect(screen.getByText('369 Main Street')).toBeInTheDocument()
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
test('Can add address during checkout as a registered customer', async () => {
|
|
396
|
+
const user = userEvent.setup()
|
|
397
|
+
await logInDuringCheckout()
|
|
398
|
+
|
|
399
|
+
global.server.use(
|
|
400
|
+
rest.post('*/customers/:customerId/addresses', (req, res, ctx) => {
|
|
401
|
+
return res(ctx.delay(0), ctx.status(200), ctx.json(req.body))
|
|
402
|
+
})
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
// Add address
|
|
406
|
+
await user.click(screen.getByText(/add new address/i))
|
|
407
|
+
|
|
408
|
+
const firstName = await screen.findByLabelText(/first name/i)
|
|
409
|
+
await user.type(firstName, 'Test2')
|
|
410
|
+
await user.type(screen.getByLabelText(/last name/i), 'McTester')
|
|
411
|
+
await user.type(screen.getByLabelText(/phone/i), '7275551234')
|
|
412
|
+
await user.selectOptions(screen.getByLabelText(/country/i), ['US'])
|
|
413
|
+
await user.type(screen.getByLabelText(/address/i), 'Tropicana Field')
|
|
414
|
+
await user.type(screen.getByLabelText(/city/i), 'Tampa')
|
|
415
|
+
await user.selectOptions(screen.getByLabelText(/state/i), ['FL'])
|
|
416
|
+
await user.type(screen.getByLabelText(/zip code/i), '33712')
|
|
417
|
+
|
|
418
|
+
await user.click(screen.getByText(/save & continue to shipping method/i))
|
|
419
|
+
|
|
420
|
+
// Wait for next step to render
|
|
421
|
+
await waitFor(() => {
|
|
422
|
+
expect(screen.getByTestId('sf-toggle-card-step-2-content')).not.toBeEmptyDOMElement()
|
|
423
|
+
})
|
|
424
|
+
})
|
|
425
|
+
|
|
426
|
+
const logInDuringCheckout = async () => {
|
|
427
|
+
// Keep a *deep* of the initial mocked basket. Our mocked fetch responses will continuously
|
|
428
|
+
// update this object, which essentially mimics a saved basket on the backend.
|
|
429
|
+
let currentBasket = JSON.parse(JSON.stringify(scapiBasketWithItem))
|
|
430
|
+
|
|
431
|
+
// Set up additional requests for intercepting/mocking for just this test.
|
|
432
|
+
global.server.use(
|
|
433
|
+
// mock adding guest email to basket
|
|
434
|
+
rest.put('*/baskets/:basketId/customer', (req, res, ctx) => {
|
|
435
|
+
currentBasket.customerInfo.email = 'customer@test.com'
|
|
436
|
+
return res(ctx.json(currentBasket))
|
|
437
|
+
}),
|
|
438
|
+
|
|
439
|
+
// mock fetch product lists
|
|
440
|
+
rest.get('*/customers/:customerId/product-lists', (req, res, ctx) => {
|
|
441
|
+
return res(ctx.json(mockedCustomerProductLists))
|
|
442
|
+
}),
|
|
443
|
+
|
|
444
|
+
// mock add shipping and billing address to basket
|
|
445
|
+
rest.put('*/shipping-address', (req, res, ctx) => {
|
|
446
|
+
const shippingBillingAddress = {
|
|
447
|
+
address1: req.body.address1,
|
|
448
|
+
city: 'Tampa',
|
|
449
|
+
countryCode: 'US',
|
|
450
|
+
firstName: 'Test',
|
|
451
|
+
fullName: 'Test McTester',
|
|
452
|
+
id: '047b18d4aaaf4138f693a4b931',
|
|
453
|
+
lastName: 'McTester',
|
|
454
|
+
phone: '(727) 555-1234',
|
|
455
|
+
postalCode: '33712',
|
|
456
|
+
stateCode: 'FL'
|
|
457
|
+
}
|
|
458
|
+
currentBasket.shipments[0].shippingAddress = shippingBillingAddress
|
|
459
|
+
currentBasket.billingAddress = shippingBillingAddress
|
|
460
|
+
return res(ctx.json(currentBasket))
|
|
461
|
+
}),
|
|
462
|
+
|
|
463
|
+
// mock add billing address to basket
|
|
464
|
+
rest.put('*/billing-address', (req, res, ctx) => {
|
|
465
|
+
const shippingBillingAddress = {
|
|
466
|
+
address1: '123 Main St',
|
|
467
|
+
city: 'Tampa',
|
|
468
|
+
countryCode: 'US',
|
|
469
|
+
firstName: 'Test',
|
|
470
|
+
fullName: 'Test McTester',
|
|
471
|
+
id: '047b18d4aaaf4138f693a4b931',
|
|
472
|
+
lastName: 'McTester',
|
|
473
|
+
phone: '(727) 555-1234',
|
|
474
|
+
postalCode: '33712',
|
|
475
|
+
stateCode: 'FL',
|
|
476
|
+
_type: 'orderAddress'
|
|
477
|
+
}
|
|
478
|
+
currentBasket.shipments[0].shippingAddress = shippingBillingAddress
|
|
479
|
+
currentBasket.billingAddress = shippingBillingAddress
|
|
480
|
+
return res(ctx.json(currentBasket))
|
|
481
|
+
}),
|
|
482
|
+
|
|
483
|
+
// mock add shipping method
|
|
484
|
+
rest.put('*/shipments/me/shipping-method', (req, res, ctx) => {
|
|
485
|
+
currentBasket.shipments[0].shippingMethod = defaultShippingMethod
|
|
486
|
+
return res(ctx.json(currentBasket))
|
|
487
|
+
}),
|
|
488
|
+
|
|
489
|
+
// mock add payment instrument
|
|
490
|
+
rest.post('*/baskets/:basketId/payment-instruments', (req, res, ctx) => {
|
|
491
|
+
currentBasket.paymentInstruments = [
|
|
492
|
+
{
|
|
493
|
+
amount: 0,
|
|
494
|
+
paymentCard: {
|
|
495
|
+
cardType: 'Master Card',
|
|
496
|
+
creditCardExpired: false,
|
|
497
|
+
expirationMonth: 1,
|
|
498
|
+
expirationYear: 2030,
|
|
499
|
+
holder: 'Test McTester',
|
|
500
|
+
maskedNumber: '************5454',
|
|
501
|
+
numberLastDigits: '5454',
|
|
502
|
+
validFromMonth: 1,
|
|
503
|
+
validFromYear: 2020
|
|
504
|
+
},
|
|
505
|
+
paymentInstrumentId: 'testcard1',
|
|
506
|
+
paymentMethodId: 'CREDIT_CARD'
|
|
507
|
+
}
|
|
508
|
+
]
|
|
509
|
+
return res(ctx.json(currentBasket))
|
|
510
|
+
}),
|
|
511
|
+
|
|
512
|
+
// mock update address
|
|
513
|
+
rest.patch('*/addresses/savedaddress1', (req, res, ctx) => {
|
|
514
|
+
return res(ctx.json(mockedRegisteredCustomer.addresses[0]))
|
|
515
|
+
}),
|
|
516
|
+
|
|
517
|
+
// mock place order
|
|
518
|
+
rest.post('*/orders', (req, res, ctx) => {
|
|
519
|
+
currentBasket = {
|
|
520
|
+
...scapiOrderResponse,
|
|
521
|
+
customerInfo: {...scapiOrderResponse.customerInfo, email: 'customer@test.com'}
|
|
522
|
+
}
|
|
523
|
+
return res(ctx.json(currentBasket))
|
|
524
|
+
}),
|
|
525
|
+
|
|
526
|
+
rest.get('*/baskets', (req, res, ctx) => {
|
|
527
|
+
const baskets = {
|
|
528
|
+
baskets: [currentBasket],
|
|
529
|
+
total: 1
|
|
530
|
+
}
|
|
531
|
+
return res(ctx.json(baskets))
|
|
532
|
+
})
|
|
533
|
+
)
|
|
534
|
+
|
|
535
|
+
// Set the initial browser router path and render our component tree.
|
|
536
|
+
window.history.pushState({}, 'Checkout', createPathWithDefaults('/checkout'))
|
|
537
|
+
const {user} = renderWithProviders(<WrappedCheckout history={history} />, {
|
|
538
|
+
wrapperProps: {
|
|
539
|
+
// Not bypassing auth as usual, so we can test the guest-to-registered flow
|
|
540
|
+
bypassAuth: false,
|
|
541
|
+
siteAlias: 'uk',
|
|
542
|
+
locale: {id: 'en-GB'},
|
|
543
|
+
appConfig: mockConfig.app
|
|
544
|
+
}
|
|
545
|
+
})
|
|
546
|
+
|
|
547
|
+
// Switch to login
|
|
548
|
+
const haveAccountButton = await screen.findByText(/already have an account/i)
|
|
549
|
+
await user.click(haveAccountButton)
|
|
550
|
+
|
|
551
|
+
// Wait for checkout to load and display first step
|
|
552
|
+
const loginBtn = await screen.findByText(/log in/i)
|
|
553
|
+
|
|
554
|
+
// Planning to log in
|
|
555
|
+
global.server.use(
|
|
556
|
+
rest.post('*/oauth2/token', (req, res, ctx) => {
|
|
557
|
+
return res(
|
|
558
|
+
ctx.delay(0),
|
|
559
|
+
ctx.json({
|
|
560
|
+
customer_id: 'customerid_1',
|
|
561
|
+
access_token: registerUserToken,
|
|
562
|
+
refresh_token: 'testrefeshtoken_1',
|
|
563
|
+
usid: 'testusid_1',
|
|
564
|
+
enc_user_id: 'testEncUserId_1',
|
|
565
|
+
id_token: 'testIdToken_1'
|
|
566
|
+
})
|
|
567
|
+
)
|
|
568
|
+
})
|
|
569
|
+
)
|
|
570
|
+
|
|
571
|
+
// Provide customer email and submit
|
|
572
|
+
const emailInput = screen.getByLabelText('Email')
|
|
573
|
+
const pwInput = screen.getByLabelText('Password')
|
|
574
|
+
await user.type(emailInput, 'customer@test.com')
|
|
575
|
+
await user.type(pwInput, 'Password!1')
|
|
576
|
+
await user.click(loginBtn)
|
|
577
|
+
|
|
578
|
+
// Wait for next step to render
|
|
579
|
+
await waitFor(() =>
|
|
580
|
+
expect(screen.getByTestId('sf-toggle-card-step-1-content')).not.toBeEmptyDOMElement()
|
|
581
|
+
)
|
|
582
|
+
}
|