@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.
Files changed (425) hide show
  1. package/.eslintignore +7 -0
  2. package/.eslintrc.js +25 -0
  3. package/.prettierignore +4 -0
  4. package/.prettierrc.yaml +7 -0
  5. package/CHANGELOG.md +173 -0
  6. package/LICENSE +14 -0
  7. package/README.md +48 -0
  8. package/app/assets/svg/account.svg +3 -0
  9. package/app/assets/svg/alert.svg +3 -0
  10. package/app/assets/svg/basket.svg +3 -0
  11. package/app/assets/svg/brand-logo.svg +10 -0
  12. package/app/assets/svg/cc-amex.svg +7 -0
  13. package/app/assets/svg/cc-cvv.svg +8 -0
  14. package/app/assets/svg/cc-discover.svg +14 -0
  15. package/app/assets/svg/cc-mastercard.svg +8 -0
  16. package/app/assets/svg/cc-visa.svg +11 -0
  17. package/app/assets/svg/check-circle.svg +3 -0
  18. package/app/assets/svg/check.svg +3 -0
  19. package/app/assets/svg/chevron-down.svg +3 -0
  20. package/app/assets/svg/chevron-left.svg +3 -0
  21. package/app/assets/svg/chevron-right.svg +3 -0
  22. package/app/assets/svg/chevron-up.svg +3 -0
  23. package/app/assets/svg/close.svg +3 -0
  24. package/app/assets/svg/dashboard.svg +4 -0
  25. package/app/assets/svg/figma-logo.svg +14 -0
  26. package/app/assets/svg/file.svg +3 -0
  27. package/app/assets/svg/filter.svg +3 -0
  28. package/app/assets/svg/flag-ca.svg +5 -0
  29. package/app/assets/svg/flag-cn.svg +19 -0
  30. package/app/assets/svg/flag-fr.svg +19 -0
  31. package/app/assets/svg/flag-gb.svg +16 -0
  32. package/app/assets/svg/flag-it.svg +29 -0
  33. package/app/assets/svg/flag-jp.svg +10 -0
  34. package/app/assets/svg/flag-us.svg +7 -0
  35. package/app/assets/svg/github-logo.svg +40 -0
  36. package/app/assets/svg/hamburger.svg +8 -0
  37. package/app/assets/svg/heart-solid.svg +7 -0
  38. package/app/assets/svg/heart.svg +3 -0
  39. package/app/assets/svg/info.svg +3 -0
  40. package/app/assets/svg/like.svg +4 -0
  41. package/app/assets/svg/location.svg +3 -0
  42. package/app/assets/svg/lock.svg +3 -0
  43. package/app/assets/svg/paypal.svg +19 -0
  44. package/app/assets/svg/plug.svg +3 -0
  45. package/app/assets/svg/plus.svg +3 -0
  46. package/app/assets/svg/receipt.svg +3 -0
  47. package/app/assets/svg/search.svg +8 -0
  48. package/app/assets/svg/signout.svg +3 -0
  49. package/app/assets/svg/social-facebook.svg +3 -0
  50. package/app/assets/svg/social-instagram.svg +3 -0
  51. package/app/assets/svg/social-pinterest.svg +4 -0
  52. package/app/assets/svg/social-twitter.svg +3 -0
  53. package/app/assets/svg/social-youtube.svg +3 -0
  54. package/app/assets/svg/user.svg +3 -0
  55. package/app/assets/svg/visibility-off.svg +5 -0
  56. package/app/assets/svg/visibility.svg +3 -0
  57. package/app/components/_app/index.jsx +401 -0
  58. package/app/components/_app/index.test.js +85 -0
  59. package/app/components/_app/partials/above-header.jsx +10 -0
  60. package/app/components/_app-config/index.jsx +125 -0
  61. package/app/components/_app-config/index.test.js +77 -0
  62. package/app/components/_error/index.jsx +142 -0
  63. package/app/components/_error/index.test.js +25 -0
  64. package/app/components/action-card/index.jsx +75 -0
  65. package/app/components/address-display/index.jsx +30 -0
  66. package/app/components/basic-tile/index.jsx +65 -0
  67. package/app/components/basic-tile/index.test.js +23 -0
  68. package/app/components/breadcrumb/index.jsx +67 -0
  69. package/app/components/breadcrumb/index.test.js +30 -0
  70. package/app/components/confirmation-modal/index.jsx +111 -0
  71. package/app/components/confirmation-modal/index.test.js +98 -0
  72. package/app/components/drawer-menu/index.jsx +405 -0
  73. package/app/components/drawer-menu/index.test.js +33 -0
  74. package/app/components/dynamic-image/index.jsx +56 -0
  75. package/app/components/field/index.jsx +161 -0
  76. package/app/components/footer/index.jsx +269 -0
  77. package/app/components/footer/index.test.js +22 -0
  78. package/app/components/forms/address-fields.jsx +49 -0
  79. package/app/components/forms/credit-card-fields.jsx +149 -0
  80. package/app/components/forms/form-action-buttons.jsx +55 -0
  81. package/app/components/forms/login-fields.jsx +31 -0
  82. package/app/components/forms/password-requirements.jsx +99 -0
  83. package/app/components/forms/post-checkout-registration-fields.jsx +43 -0
  84. package/app/components/forms/profile-fields.jsx +36 -0
  85. package/app/components/forms/promo-code-fields.jsx +43 -0
  86. package/app/components/forms/registration-fields.jsx +42 -0
  87. package/app/components/forms/reset-password-fields.jsx +31 -0
  88. package/app/components/forms/state-province-options.jsx +75 -0
  89. package/app/components/forms/update-password-fields.jsx +49 -0
  90. package/app/components/forms/useAddressFields.jsx +196 -0
  91. package/app/components/forms/useCreditCardFields.jsx +146 -0
  92. package/app/components/forms/useLoginFields.jsx +52 -0
  93. package/app/components/forms/useProfileFields.jsx +95 -0
  94. package/app/components/forms/usePromoCodeFields.jsx +39 -0
  95. package/app/components/forms/useRegistrationFields.jsx +136 -0
  96. package/app/components/forms/useResetPasswordFields.jsx +40 -0
  97. package/app/components/forms/useUpdatePasswordFields.jsx +89 -0
  98. package/app/components/header/index.jsx +290 -0
  99. package/app/components/header/index.test.js +217 -0
  100. package/app/components/hero/index.jsx +84 -0
  101. package/app/components/hero/index.test.js +40 -0
  102. package/app/components/icons/index.jsx +158 -0
  103. package/app/components/icons/index.test.js +20 -0
  104. package/app/components/image-gallery/index.jsx +176 -0
  105. package/app/components/image-gallery/index.test.js +485 -0
  106. package/app/components/item-variant/index.jsx +33 -0
  107. package/app/components/item-variant/item-attributes.jsx +107 -0
  108. package/app/components/item-variant/item-image.jsx +73 -0
  109. package/app/components/item-variant/item-name.jsx +28 -0
  110. package/app/components/item-variant/item-price.jsx +117 -0
  111. package/app/components/link/index.jsx +32 -0
  112. package/app/components/link/index.test.js +72 -0
  113. package/app/components/links-list/index.jsx +89 -0
  114. package/app/components/links-list/index.test.js +62 -0
  115. package/app/components/list-menu/index.jsx +280 -0
  116. package/app/components/list-menu/index.test.js +44 -0
  117. package/app/components/loading-spinner/index.jsx +46 -0
  118. package/app/components/locale-selector/index.jsx +124 -0
  119. package/app/components/locale-selector/index.test.js +37 -0
  120. package/app/components/locale-text/index.jsx +97 -0
  121. package/app/components/locale-text/index.test.js +36 -0
  122. package/app/components/login/index.jsx +96 -0
  123. package/app/components/nested-accordion/index.jsx +185 -0
  124. package/app/components/nested-accordion/index.test.js +98 -0
  125. package/app/components/offline-banner/index.jsx +40 -0
  126. package/app/components/offline-banner/index.test.js +15 -0
  127. package/app/components/offline-boundary/index.jsx +104 -0
  128. package/app/components/offline-boundary/index.test.js +123 -0
  129. package/app/components/order-summary/index.jsx +331 -0
  130. package/app/components/page-action-placeholder/index.jsx +50 -0
  131. package/app/components/pagination/index.jsx +134 -0
  132. package/app/components/pagination/index.test.js +25 -0
  133. package/app/components/product-item/index.jsx +146 -0
  134. package/app/components/product-item/index.test.js +38 -0
  135. package/app/components/product-scroller/index.jsx +172 -0
  136. package/app/components/product-scroller/index.test.js +98 -0
  137. package/app/components/product-tile/index.jsx +195 -0
  138. package/app/components/product-tile/index.test.js +96 -0
  139. package/app/components/product-view/index.jsx +538 -0
  140. package/app/components/product-view/index.test.js +224 -0
  141. package/app/components/product-view-modal/index.jsx +48 -0
  142. package/app/components/product-view-modal/index.test.js +72 -0
  143. package/app/components/promo-code/index.jsx +162 -0
  144. package/app/components/promo-popover/index.jsx +83 -0
  145. package/app/components/quantity-picker/index.jsx +58 -0
  146. package/app/components/radio-card/index.jsx +75 -0
  147. package/app/components/recommended-products/index.jsx +227 -0
  148. package/app/components/register/index.jsx +114 -0
  149. package/app/components/reset-password/index.jsx +87 -0
  150. package/app/components/responsive/index.jsx +29 -0
  151. package/app/components/scroll-to-top/index.jsx +24 -0
  152. package/app/components/scroll-to-top/index.test.js +46 -0
  153. package/app/components/search/index.jsx +279 -0
  154. package/app/components/search/index.test.js +127 -0
  155. package/app/components/search/partials/recent-searches.jsx +76 -0
  156. package/app/components/search/partials/search-suggestions.jsx +45 -0
  157. package/app/components/search/partials/suggestions.jsx +43 -0
  158. package/app/components/section/index.jsx +68 -0
  159. package/app/components/seo/index.jsx +33 -0
  160. package/app/components/social-icons/index.jsx +101 -0
  161. package/app/components/social-icons/index.test.js +30 -0
  162. package/app/components/swatch-group/index.jsx +77 -0
  163. package/app/components/swatch-group/index.test.js +136 -0
  164. package/app/components/swatch-group/swatch.jsx +94 -0
  165. package/app/components/toggle-card/index.jsx +97 -0
  166. package/app/components/with-registration/index.jsx +58 -0
  167. package/app/components/with-registration/index.test.js +85 -0
  168. package/app/constants.js +109 -0
  169. package/app/contexts/index.js +92 -0
  170. package/app/hooks/einstein-mock-data.js +916 -0
  171. package/app/hooks/index.js +17 -0
  172. package/app/hooks/use-add-to-cart-modal.js +344 -0
  173. package/app/hooks/use-add-to-cart-modal.test.js +625 -0
  174. package/app/hooks/use-auth-modal.js +337 -0
  175. package/app/hooks/use-auth-modal.test.js +365 -0
  176. package/app/hooks/use-currency.js +20 -0
  177. package/app/hooks/use-currency.test.js +41 -0
  178. package/app/hooks/use-current-basket.js +39 -0
  179. package/app/hooks/use-current-customer.js +29 -0
  180. package/app/hooks/use-derived-product.js +77 -0
  181. package/app/hooks/use-derived-product.test.js +69 -0
  182. package/app/hooks/use-einstein.js +512 -0
  183. package/app/hooks/use-einstein.test.js +224 -0
  184. package/app/hooks/use-intersection-observer.js +64 -0
  185. package/app/hooks/use-limit-urls.js +31 -0
  186. package/app/hooks/use-limit-urls.test.js +40 -0
  187. package/app/hooks/use-multi-site.js +36 -0
  188. package/app/hooks/use-multi-site.test.js +53 -0
  189. package/app/hooks/use-navigation.js +37 -0
  190. package/app/hooks/use-navigation.test.js +109 -0
  191. package/app/hooks/use-page-urls.js +35 -0
  192. package/app/hooks/use-page-urls.test.js +39 -0
  193. package/app/hooks/use-pdp-search-params.js +16 -0
  194. package/app/hooks/use-pdp-search-params.test.js +52 -0
  195. package/app/hooks/use-previous.js +17 -0
  196. package/app/hooks/use-product-view-modal.js +93 -0
  197. package/app/hooks/use-product-view-modal.test.js +172 -0
  198. package/app/hooks/use-search-params.js +96 -0
  199. package/app/hooks/use-search-params.test.js +91 -0
  200. package/app/hooks/use-sort-urls.js +33 -0
  201. package/app/hooks/use-sort-urls.test.js +42 -0
  202. package/app/hooks/use-toast.js +68 -0
  203. package/app/hooks/use-toast.test.js +58 -0
  204. package/app/hooks/use-variant.js +32 -0
  205. package/app/hooks/use-variant.test.js +81 -0
  206. package/app/hooks/use-variation-attributes.js +138 -0
  207. package/app/hooks/use-variation-attributes.test.js +119 -0
  208. package/app/hooks/use-variation-params.js +31 -0
  209. package/app/hooks/use-variation-params.test.js +73 -0
  210. package/app/hooks/use-wish-list.js +42 -0
  211. package/app/main.jsx +14 -0
  212. package/app/mocks/basket-with-suit.js +146 -0
  213. package/app/mocks/empty-basket.js +39 -0
  214. package/app/mocks/mock-data.js +5632 -0
  215. package/app/mocks/product-set-winter-lookM.js +1224 -0
  216. package/app/mocks/searchResults.js +144 -0
  217. package/app/mocks/variant-750518699578M.js +434 -0
  218. package/app/page-designer/README.md +102 -0
  219. package/app/page-designer/assets/image-tile/index.jsx +51 -0
  220. package/app/page-designer/assets/image-tile/index.test.js +30 -0
  221. package/app/page-designer/assets/image-with-text/index.jsx +140 -0
  222. package/app/page-designer/assets/image-with-text/index.test.js +38 -0
  223. package/app/page-designer/assets/index.js +9 -0
  224. package/app/page-designer/index.js +10 -0
  225. package/app/page-designer/layouts/carousel/index.jsx +222 -0
  226. package/app/page-designer/layouts/carousel/index.test.js +43 -0
  227. package/app/page-designer/layouts/index.js +14 -0
  228. package/app/page-designer/layouts/mobileGrid1r1c/index.jsx +36 -0
  229. package/app/page-designer/layouts/mobileGrid1r1c/index.test.js +35 -0
  230. package/app/page-designer/layouts/mobileGrid2r1c/index.jsx +37 -0
  231. package/app/page-designer/layouts/mobileGrid2r1c/index.test.js +47 -0
  232. package/app/page-designer/layouts/mobileGrid2r2c/index.jsx +37 -0
  233. package/app/page-designer/layouts/mobileGrid2r2c/index.test.js +71 -0
  234. package/app/page-designer/layouts/mobileGrid2r3c/index.jsx +37 -0
  235. package/app/page-designer/layouts/mobileGrid2r3c/index.test.js +95 -0
  236. package/app/page-designer/layouts/mobileGrid3r1c/index.jsx +37 -0
  237. package/app/page-designer/layouts/mobileGrid3r1c/index.test.js +59 -0
  238. package/app/page-designer/layouts/mobileGrid3r2c/index.jsx +37 -0
  239. package/app/page-designer/layouts/mobileGrid3r2c/index.test.js +95 -0
  240. package/app/page-designer/utils.js +14 -0
  241. package/app/pages/account/addresses.jsx +382 -0
  242. package/app/pages/account/addresses.test.js +120 -0
  243. package/app/pages/account/constant.js +57 -0
  244. package/app/pages/account/index.jsx +237 -0
  245. package/app/pages/account/index.test.js +188 -0
  246. package/app/pages/account/order-detail.jsx +397 -0
  247. package/app/pages/account/order-history.jsx +264 -0
  248. package/app/pages/account/orders.jsx +30 -0
  249. package/app/pages/account/orders.test.js +95 -0
  250. package/app/pages/account/profile.jsx +357 -0
  251. package/app/pages/account/wishlist/index.jsx +195 -0
  252. package/app/pages/account/wishlist/index.mock.js +1481 -0
  253. package/app/pages/account/wishlist/index.test.js +56 -0
  254. package/app/pages/account/wishlist/partials/wishlist-primary-action.jsx +170 -0
  255. package/app/pages/account/wishlist/partials/wishlist-primary-action.mock.js +1623 -0
  256. package/app/pages/account/wishlist/partials/wishlist-primary-action.test.js +99 -0
  257. package/app/pages/account/wishlist/partials/wishlist-secondary-button-group.jsx +120 -0
  258. package/app/pages/account/wishlist/partials/wishlist-secondary-button-group.test.js +391 -0
  259. package/app/pages/cart/index.jsx +476 -0
  260. package/app/pages/cart/index.test.js +481 -0
  261. package/app/pages/cart/partials/cart-cta.jsx +46 -0
  262. package/app/pages/cart/partials/cart-secondary-button-group.jsx +135 -0
  263. package/app/pages/cart/partials/cart-secondary-button-group.test.js +103 -0
  264. package/app/pages/cart/partials/cart-skeleton.jsx +93 -0
  265. package/app/pages/cart/partials/cart-title.jsx +27 -0
  266. package/app/pages/cart/partials/empty-cart.jsx +86 -0
  267. package/app/pages/checkout/confirmation.jsx +541 -0
  268. package/app/pages/checkout/confirmation.mock.js +450 -0
  269. package/app/pages/checkout/confirmation.test.js +114 -0
  270. package/app/pages/checkout/index.jsx +169 -0
  271. package/app/pages/checkout/index.test.js +582 -0
  272. package/app/pages/checkout/partials/cc-radio-group.jsx +122 -0
  273. package/app/pages/checkout/partials/checkout-footer.jsx +140 -0
  274. package/app/pages/checkout/partials/checkout-footer.test.js +16 -0
  275. package/app/pages/checkout/partials/checkout-header.jsx +54 -0
  276. package/app/pages/checkout/partials/checkout-header.test.js +16 -0
  277. package/app/pages/checkout/partials/checkout-skeleton.jsx +52 -0
  278. package/app/pages/checkout/partials/contact-info.jsx +251 -0
  279. package/app/pages/checkout/partials/contact-info.test.js +43 -0
  280. package/app/pages/checkout/partials/payment-form.jsx +97 -0
  281. package/app/pages/checkout/partials/payment.jsx +276 -0
  282. package/app/pages/checkout/partials/shipping-address-selection.jsx +377 -0
  283. package/app/pages/checkout/partials/shipping-address.jsx +132 -0
  284. package/app/pages/checkout/partials/shipping-options.jsx +232 -0
  285. package/app/pages/checkout/util/checkout-context.js +94 -0
  286. package/app/pages/home/data.js +134 -0
  287. package/app/pages/home/index.jsx +301 -0
  288. package/app/pages/home/index.test.js +23 -0
  289. package/app/pages/login/index.jsx +123 -0
  290. package/app/pages/login/index.test.js +229 -0
  291. package/app/pages/login-redirect/index.jsx +23 -0
  292. package/app/pages/login-redirect/index.test.js +16 -0
  293. package/app/pages/page-not-found/index.jsx +90 -0
  294. package/app/pages/page-not-found/index.test.js +31 -0
  295. package/app/pages/product-detail/index.jsx +394 -0
  296. package/app/pages/product-detail/index.mock.js +197 -0
  297. package/app/pages/product-detail/index.test.js +162 -0
  298. package/app/pages/product-detail/partials/information-accordion.jsx +121 -0
  299. package/app/pages/product-list/index.jsx +735 -0
  300. package/app/pages/product-list/index.test.js +180 -0
  301. package/app/pages/product-list/partials/above-page-header.jsx +10 -0
  302. package/app/pages/product-list/partials/checkbox-refinements.jsx +41 -0
  303. package/app/pages/product-list/partials/checkbox-refinements.test.js +53 -0
  304. package/app/pages/product-list/partials/color-refinements.jsx +88 -0
  305. package/app/pages/product-list/partials/empty-results.jsx +118 -0
  306. package/app/pages/product-list/partials/link-refinements.jsx +38 -0
  307. package/app/pages/product-list/partials/page-header.jsx +42 -0
  308. package/app/pages/product-list/partials/radio-refinements.jsx +60 -0
  309. package/app/pages/product-list/partials/refinements.jsx +144 -0
  310. package/app/pages/product-list/partials/selected-refinements.jsx +100 -0
  311. package/app/pages/product-list/partials/size-refinements.jsx +55 -0
  312. package/app/pages/registration/index.jsx +87 -0
  313. package/app/pages/registration/index.test.jsx +132 -0
  314. package/app/pages/reset-password/index.jsx +112 -0
  315. package/app/pages/reset-password/index.test.jsx +141 -0
  316. package/app/request-processor.js +118 -0
  317. package/app/request-processor.test.js +23 -0
  318. package/app/routes.jsx +111 -0
  319. package/app/routes.test.js +13 -0
  320. package/app/ssr.js +70 -0
  321. package/app/static/ico/favicon.ico +0 -0
  322. package/app/static/img/global/app-icon-192.png +0 -0
  323. package/app/static/img/global/app-icon-512.png +0 -0
  324. package/app/static/img/global/apple-touch-icon.png +0 -0
  325. package/app/static/img/hero.png +0 -0
  326. package/app/static/manifest.json +19 -0
  327. package/app/static/robots.txt +2 -0
  328. package/app/theme/components/base/accordion.js +21 -0
  329. package/app/theme/components/base/alert.js +17 -0
  330. package/app/theme/components/base/badge.js +25 -0
  331. package/app/theme/components/base/button.js +77 -0
  332. package/app/theme/components/base/checkbox.js +30 -0
  333. package/app/theme/components/base/container.js +17 -0
  334. package/app/theme/components/base/drawer.js +26 -0
  335. package/app/theme/components/base/formLabel.js +13 -0
  336. package/app/theme/components/base/icon.js +13 -0
  337. package/app/theme/components/base/input.js +44 -0
  338. package/app/theme/components/base/modal.js +11 -0
  339. package/app/theme/components/base/popover.js +61 -0
  340. package/app/theme/components/base/radio.js +33 -0
  341. package/app/theme/components/base/select.js +15 -0
  342. package/app/theme/components/base/skeleton.js +12 -0
  343. package/app/theme/components/base/tooltip.js +19 -0
  344. package/app/theme/components/project/_app.js +25 -0
  345. package/app/theme/components/project/breadcrumb.js +25 -0
  346. package/app/theme/components/project/checkout-footer.js +35 -0
  347. package/app/theme/components/project/drawer-menu.js +66 -0
  348. package/app/theme/components/project/footer.js +84 -0
  349. package/app/theme/components/project/header.js +84 -0
  350. package/app/theme/components/project/image-gallery.js +59 -0
  351. package/app/theme/components/project/links-list.js +43 -0
  352. package/app/theme/components/project/list-menu.js +91 -0
  353. package/app/theme/components/project/locale-selector.js +42 -0
  354. package/app/theme/components/project/nested-accordion.js +26 -0
  355. package/app/theme/components/project/offline-banner.js +25 -0
  356. package/app/theme/components/project/pagination.js +22 -0
  357. package/app/theme/components/project/product-tile.js +32 -0
  358. package/app/theme/components/project/social-icons.js +52 -0
  359. package/app/theme/components/project/swatch-group.js +115 -0
  360. package/app/theme/foundations/colors.js +170 -0
  361. package/app/theme/foundations/gradients.js +9 -0
  362. package/app/theme/foundations/layerStyles.js +41 -0
  363. package/app/theme/foundations/shadows.js +9 -0
  364. package/app/theme/foundations/sizes.js +18 -0
  365. package/app/theme/foundations/space.js +9 -0
  366. package/app/theme/foundations/styles.js +21 -0
  367. package/app/theme/index.js +104 -0
  368. package/app/utils/cc-utils.js +112 -0
  369. package/app/utils/cc-utils.test.js +41 -0
  370. package/app/utils/image-groups-utils.js +62 -0
  371. package/app/utils/image-groups-utils.test.js +65 -0
  372. package/app/utils/locale.js +78 -0
  373. package/app/utils/locale.test.js +112 -0
  374. package/app/utils/password-utils.js +21 -0
  375. package/app/utils/phone-utils.js +22 -0
  376. package/app/utils/phone-utils.test.js +15 -0
  377. package/app/utils/product-utils.js +35 -0
  378. package/app/utils/product-utils.test.js +51 -0
  379. package/app/utils/responsive-image.js +198 -0
  380. package/app/utils/responsive-image.test.js +170 -0
  381. package/app/utils/routes-utils.js +111 -0
  382. package/app/utils/routes-utils.test.js +291 -0
  383. package/app/utils/site-utils.js +222 -0
  384. package/app/utils/site-utils.test.js +376 -0
  385. package/app/utils/test-utils.js +257 -0
  386. package/app/utils/url.js +291 -0
  387. package/app/utils/url.test.js +421 -0
  388. package/app/utils/utils.js +201 -0
  389. package/app/utils/utils.test.js +182 -0
  390. package/babel.config.js +7 -0
  391. package/cache-hash-config.json +8 -0
  392. package/config/default.js +64 -0
  393. package/config/mocks/default.js +131 -0
  394. package/config/sites.js +78 -0
  395. package/jest-setup.js +191 -0
  396. package/jest.config.js +50 -0
  397. package/jsconfig.json +13 -0
  398. package/package.json +105 -0
  399. package/scripts/extract-default-messages.js +92 -0
  400. package/tests/lighthouserc.js +37 -0
  401. package/translations/README.md +127 -0
  402. package/translations/compiled/de-DE.json +3212 -0
  403. package/translations/compiled/en-GB.json +3212 -0
  404. package/translations/compiled/en-US.json +3212 -0
  405. package/translations/compiled/en-XA.json +6948 -0
  406. package/translations/compiled/es-MX.json +3216 -0
  407. package/translations/compiled/fr-FR.json +3216 -0
  408. package/translations/compiled/it-IT.json +3188 -0
  409. package/translations/compiled/ja-JP.json +3200 -0
  410. package/translations/compiled/ko-KR.json +3180 -0
  411. package/translations/compiled/pt-BR.json +3220 -0
  412. package/translations/compiled/zh-CN.json +3212 -0
  413. package/translations/compiled/zh-TW.json +3208 -0
  414. package/translations/de-DE.json +1417 -0
  415. package/translations/en-GB.json +1417 -0
  416. package/translations/en-US.json +1417 -0
  417. package/translations/es-MX.json +1417 -0
  418. package/translations/fr-FR.json +1417 -0
  419. package/translations/it-IT.json +1417 -0
  420. package/translations/ja-JP.json +1417 -0
  421. package/translations/ko-KR.json +1417 -0
  422. package/translations/pt-BR.json +1417 -0
  423. package/translations/zh-CN.json +1417 -0
  424. package/translations/zh-TW.json +1417 -0
  425. package/worker/main.js +36 -0
@@ -0,0 +1,182 @@
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 * as utils from '@salesforce/retail-react-app/app/utils/utils'
8
+ import EventEmitter from 'events'
9
+ import {flatten, shallowEquals} from '@salesforce/retail-react-app/app/utils/utils'
10
+
11
+ afterEach(() => {
12
+ jest.clearAllMocks()
13
+ })
14
+
15
+ jest.mock('./site-utils', () => {
16
+ const origin = jest.requireActual('./site-utils')
17
+ return {
18
+ ...origin,
19
+ getSites: jest.fn()
20
+ }
21
+ })
22
+
23
+ describe('requestIdleCallback should be a working shim', () => {
24
+ test('without a working implementation built in', async () => {
25
+ const result = new Promise((resolve) => utils.requestIdleCallback(resolve))
26
+ await expect(result).resolves.toBeUndefined()
27
+ })
28
+
29
+ test('with a working implementation built in', async () => {
30
+ window.requestIdleCallback = (fn) => setTimeout(() => fn(), 1)
31
+ const result = new Promise((resolve) => utils.requestIdleCallback(resolve))
32
+ await expect(result).resolves.toBeUndefined()
33
+ })
34
+ })
35
+
36
+ describe('WatchOnlineStatus', () => {
37
+ test('responds to offline/online events', () => {
38
+ const emitter = new EventEmitter()
39
+ const win = {
40
+ addEventListener: emitter.addListener.bind(emitter),
41
+ removeEventListener: emitter.removeListener.bind(emitter)
42
+ }
43
+ const collected = []
44
+ const callback = (isOnline) => collected.push(isOnline)
45
+ const unsubscribe = utils.watchOnlineStatus(callback, win)
46
+ emitter.emit('online')
47
+ emitter.emit('offline')
48
+ emitter.emit('online')
49
+ expect(collected).toEqual([true, false, true])
50
+ unsubscribe()
51
+ expect(emitter.listenerCount('online')).toBe(0)
52
+ expect(emitter.listenerCount('offline')).toBe(0)
53
+ })
54
+ })
55
+
56
+ describe('escapeRegexChars', () => {
57
+ test('escapes special characters', () => {
58
+ const escapedString = utils.escapeRegexChars('{}()*+?.,\\^$|#')
59
+ expect(escapedString).toBe('\\{\\}\\(\\)\\*\\+\\?\\.\\,\\\\\\^\\$\\|\\#')
60
+ })
61
+ })
62
+
63
+ describe('boldString & Capitalize test', () => {
64
+ test('boldString returns provided part of string bolded html', () => {
65
+ const boldedString = utils.boldString('boldedString', 'bolded')
66
+ expect(boldedString).toBe('<b>bolded</b>String')
67
+ })
68
+
69
+ test('boldString handles special regex characters', () => {
70
+ const boldedString = utils.boldString('some (*special!) chars', '(*special!)')
71
+ expect(boldedString).toBe('some <b>(*special!)</b> chars')
72
+ })
73
+
74
+ test('capitalize capitalizes a string', () => {
75
+ const stringToCapitlize = utils.capitalize('capitalize string test')
76
+ expect(stringToCapitlize).toBe('Capitalize String Test')
77
+ })
78
+ })
79
+
80
+ describe('session storage tests', () => {
81
+ test('sets,gets and removes item in session storage', () => {
82
+ utils.setSessionJSONItem('test', ['text'])
83
+ let testing = utils.getSessionJSONItem('test')
84
+ expect(testing).toHaveLength(1)
85
+ utils.clearSessionJSONItem('test')
86
+ testing = utils.getSessionJSONItem('test')
87
+ expect(testing).toBeUndefined()
88
+ })
89
+ })
90
+
91
+ describe('flatten', () => {
92
+ test('return a an array', () => {
93
+ const result = flatten({
94
+ id: 1,
95
+ item: 1,
96
+ children: [{id: 2, item: 2, children: [{id: 3, item: 3}]}]
97
+ })
98
+
99
+ expect(JSON.stringify(result)).toBe(
100
+ '{"1":{"id":1,"item":1,"children":[{"id":2,"item":2,"children":[{"id":3,"item":3}]}]},"2":{"id":2,"item":2,"children":[{"id":3,"item":3}]},"3":{"id":3,"item":3}}'
101
+ )
102
+ })
103
+ })
104
+
105
+ describe('shallow', function () {
106
+ test('should return false', () => {
107
+ const a = {a: '123'}
108
+ const b = {a: '123', b: '456'}
109
+ const result = shallowEquals(a, b)
110
+ expect(result).toBeFalsy()
111
+ })
112
+ })
113
+
114
+ describe('keysToCamel', () => {
115
+ test('converts object keys to camelcase', () => {
116
+ const input = {
117
+ numba_one: true,
118
+ 'numba-two': false,
119
+ number3: 'un-changed',
120
+ c_Custom: 'un_changed',
121
+ _custom: 'unchanged'
122
+ }
123
+
124
+ const result = utils.keysToCamel(input)
125
+
126
+ expect(result).toEqual({
127
+ numbaOne: true,
128
+ numbaTwo: false,
129
+ number3: 'un-changed',
130
+ c_Custom: 'un_changed',
131
+ _custom: 'unchanged'
132
+ })
133
+ })
134
+
135
+ test('converts arrays of objects to camelcase', () => {
136
+ const input = [
137
+ {
138
+ numba_one: true,
139
+ number3: 'un-changed',
140
+ c_Custom: 'un_changed',
141
+ _custom: 'unchanged'
142
+ },
143
+ {
144
+ 'numba-two': false
145
+ }
146
+ ]
147
+
148
+ const result = utils.keysToCamel(input)
149
+
150
+ expect(result).toEqual([
151
+ {
152
+ numbaOne: true,
153
+ number3: 'un-changed',
154
+ c_Custom: 'un_changed',
155
+ _custom: 'unchanged'
156
+ },
157
+ {
158
+ numbaTwo: false
159
+ }
160
+ ])
161
+ })
162
+
163
+ test('converts nested keys to camelcase', () => {
164
+ const input = {
165
+ numba_one: {
166
+ sub1: 'unchanged',
167
+ sub2: {sub_sub_2: 'changed'},
168
+ sub3: [{sub_sub_3: 'changed', sub3Sub4: 'unchanged'}]
169
+ }
170
+ }
171
+
172
+ const result = utils.keysToCamel(input)
173
+
174
+ expect(result).toEqual({
175
+ numbaOne: {
176
+ sub1: 'unchanged',
177
+ sub2: {subSub_2: 'changed'},
178
+ sub3: [{subSub_3: 'changed', sub3Sub4: 'unchanged'}]
179
+ }
180
+ })
181
+ })
182
+ })
@@ -0,0 +1,7 @@
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
+ module.exports = require('@salesforce/pwa-kit-dev/configs/babel/babel-config')
@@ -0,0 +1,8 @@
1
+ {
2
+ "files": [
3
+ "app/static/**/*"
4
+ ],
5
+ "baseDir": "app",
6
+ "hashLength": 8,
7
+ "destinationFolder": "app"
8
+ }
@@ -0,0 +1,64 @@
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
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
8
+ const sites = require('./sites.js')
9
+
10
+ module.exports = {
11
+ app: {
12
+ url: {
13
+ site: 'path',
14
+ locale: 'path',
15
+ showDefaults: true
16
+ },
17
+ defaultSite: 'RefArchGlobal',
18
+ siteAliases: {
19
+ RefArch: 'us',
20
+ RefArchGlobal: 'global'
21
+ },
22
+ sites,
23
+ commerceAPI: {
24
+ proxyPath: `/mobify/proxy/api`,
25
+ parameters: {
26
+ clientId: 'c9c45bfd-0ed3-4aa2-9971-40f88962b836',
27
+ organizationId: 'f_ecom_zzrf_001',
28
+ shortCode: '8o7m175y',
29
+ siteId: 'RefArchGlobal'
30
+ }
31
+ },
32
+ einsteinAPI: {
33
+ host: 'https://api.cquotient.com',
34
+ einsteinId: '1ea06c6e-c936-4324-bcf0-fada93f83bb1',
35
+ // This differs from the siteId in commerceAPIConfig for testing purposes
36
+ siteId: 'aaij-MobileFirst',
37
+ isProduction: false
38
+ }
39
+ },
40
+ externals: [],
41
+ pageNotFoundURL: '/page-not-found',
42
+ ssrEnabled: true,
43
+ ssrOnly: ['ssr.js', 'ssr.js.map', 'node_modules/**/*.*'],
44
+ ssrShared: [
45
+ 'static/ico/favicon.ico',
46
+ 'static/robots.txt',
47
+ '**/*.js',
48
+ '**/*.js.map',
49
+ '**/*.json'
50
+ ],
51
+ ssrParameters: {
52
+ ssrFunctionNodeVersion: '16.x',
53
+ proxyConfigs: [
54
+ {
55
+ host: 'kv7kzm78.api.commercecloud.salesforce.com',
56
+ path: 'api'
57
+ },
58
+ {
59
+ host: 'zzrf-001.dx.commercecloud.salesforce.com',
60
+ path: 'ocapi'
61
+ }
62
+ ]
63
+ }
64
+ }
@@ -0,0 +1,131 @@
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
+ /**
8
+ * This is a mock config to be used for unit tests
9
+ *
10
+ * By default, a generated project is a single-site and single-locale app
11
+ * However, it can be extended to multi-site with multi-locale easily.
12
+ * To ensure that feature work correctly, we test our code with multi-site config in mind, so we created this mock config.
13
+ * A single-site, single-locale config is a special case of multi-site case.
14
+ */
15
+ module.exports = {
16
+ app: {
17
+ url: {
18
+ locale: 'path',
19
+ site: 'path',
20
+ showDefaults: true
21
+ },
22
+ siteAliases: {
23
+ 'site-1': 'uk',
24
+ 'site-2': 'us'
25
+ },
26
+ defaultSite: 'site-1',
27
+ sites: [
28
+ {
29
+ id: 'site-1',
30
+ l10n: {
31
+ defaultLocale: 'en-GB',
32
+ defaultCurrency: 'GBP',
33
+ supportedLocales: [
34
+ {
35
+ id: 'en-GB',
36
+ preferredCurrency: 'GBP'
37
+ },
38
+ {
39
+ id: 'fr-FR',
40
+ alias: 'fr',
41
+ preferredCurrency: 'EUR'
42
+ },
43
+ {
44
+ id: 'it-IT',
45
+ preferredCurrency: 'EUR'
46
+ }
47
+ ]
48
+ }
49
+ },
50
+ {
51
+ id: 'site-2',
52
+ l10n: {
53
+ defaultLocale: 'en-US',
54
+ defaultCurrency: 'USD',
55
+ supportedLocales: [
56
+ {
57
+ id: 'en-US',
58
+ preferredCurrency: 'USD'
59
+ },
60
+ {
61
+ id: 'en-CA',
62
+ preferredCurrency: 'USD'
63
+ }
64
+ ]
65
+ }
66
+ }
67
+ ],
68
+ commerceAPI: {
69
+ proxyPath: `/mobify/proxy/api`,
70
+ parameters: {
71
+ clientId: 'c9c45bfd-0ed3-4aa2-9971-40f88962b836',
72
+ organizationId: 'f_ecom_zzrf_001',
73
+ shortCode: '11111111',
74
+ siteId: 'site-1'
75
+ }
76
+ },
77
+ einsteinAPI: {
78
+ host: 'http://localhost:7777',
79
+ einsteinId: '11111111',
80
+ // This differs from the siteId in commerceAPIConfig for testing purposes
81
+ siteId: 'EinsteinTestSite',
82
+ // Flag Einstein activities as coming from a production environment.
83
+ // By setting this to true, the Einstein activities generated by the environment will appear
84
+ // in production environment reports
85
+ // This is temporary and is meant as a placeholder until there is a mechanism for reading
86
+ // the is_production property from an MRT target
87
+ isProduction: false
88
+ }
89
+ },
90
+ // This list contains server-side only libraries that you don't want to be compiled by webpack
91
+ externals: [],
92
+ // Page not found url for your app
93
+ pageNotFoundURL: '/page-not-found',
94
+ // Enables or disables building the files necessary for server-side rendering.
95
+ ssrEnabled: true,
96
+ // This list determines which files are available exclusively to the server-side rendering system
97
+ // and are not available through the /mobify/bundle/ path.
98
+ ssrOnly: ['ssr.js', 'ssr.js.map', 'node_modules/**/*.*'],
99
+ // This list determines which files are available to the server-side rendering system
100
+ // and available through the /mobify/bundle/ path.
101
+ ssrShared: [
102
+ 'static/ico/favicon.ico',
103
+ 'static/robots.txt',
104
+ '**/*.js',
105
+ '**/*.js.map',
106
+ '**/*.json'
107
+ ],
108
+ // Additional parameters that configure Express app behavior.
109
+ ssrParameters: {
110
+ ssrFunctionNodeVersion: '16.x',
111
+ proxyConfigs: [
112
+ {
113
+ host: 'localhost:8888',
114
+ path: 'api'
115
+ },
116
+ {
117
+ host: 'localhost:9999',
118
+ path: 'ocapi'
119
+ }
120
+ ]
121
+ },
122
+ mockFetchOCAPISessions: (url) => {
123
+ if (url.includes('/sessions')) {
124
+ return {
125
+ ok: true,
126
+ status: 200
127
+ }
128
+ }
129
+ throw new Error(`Unhandled request: ${url}`)
130
+ }
131
+ }
@@ -0,0 +1,78 @@
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
+ // Provide the sites for your app. Each site includes site id, and its localization configuration.
8
+ // You can also provide alias for your locale. They will be used in place of your locale id when generating paths across the app
9
+ module.exports = [
10
+ {
11
+ id: 'RefArch',
12
+ l10n: {
13
+ supportedCurrencies: ['USD'],
14
+ defaultCurrency: 'USD',
15
+ defaultLocale: 'en-US',
16
+ supportedLocales: [
17
+ {
18
+ id: 'en-US',
19
+ preferredCurrency: 'USD'
20
+ },
21
+ {
22
+ id: 'en-CA',
23
+ preferredCurrency: 'USD'
24
+ }
25
+ ]
26
+ }
27
+ },
28
+ {
29
+ id: 'RefArchGlobal',
30
+ l10n: {
31
+ supportedCurrencies: ['GBP', 'EUR', 'CNY', 'JPY'],
32
+ defaultCurrency: 'GBP',
33
+ supportedLocales: [
34
+ {
35
+ id: 'de-DE',
36
+ preferredCurrency: 'EUR'
37
+ },
38
+ {
39
+ id: 'en-GB',
40
+ preferredCurrency: 'GBP'
41
+ },
42
+ {
43
+ id: 'es-MX',
44
+ preferredCurrency: 'MXN'
45
+ },
46
+ {
47
+ id: 'fr-FR',
48
+ preferredCurrency: 'EUR'
49
+ },
50
+ {
51
+ id: 'it-IT',
52
+ preferredCurrency: 'EUR'
53
+ },
54
+ {
55
+ id: 'ja-JP',
56
+ preferredCurrency: 'JPY'
57
+ },
58
+ {
59
+ id: 'ko-KR',
60
+ preferredCurrency: 'KRW'
61
+ },
62
+ {
63
+ id: 'pt-BR',
64
+ preferredCurrency: 'BRL'
65
+ },
66
+ {
67
+ id: 'zh-CN',
68
+ preferredCurrency: 'CNY'
69
+ },
70
+ {
71
+ id: 'zh-TW',
72
+ preferredCurrency: 'TWD'
73
+ }
74
+ ],
75
+ defaultLocale: 'en-GB'
76
+ }
77
+ }
78
+ ]
package/jest-setup.js ADDED
@@ -0,0 +1,191 @@
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
+ /* eslint-env jest */
8
+ /* eslint-disable @typescript-eslint/no-var-requires */
9
+ const path = require('path')
10
+ const mockConfig = require(path.join(__dirname, 'config/mocks/default.js'))
11
+ require('raf/polyfill') // fix requestAnimationFrame issue with polyfill
12
+ require('@testing-library/jest-dom/extend-expect')
13
+ const {configure: configureTestingLibrary} = require('@testing-library/react')
14
+ const {Crypto} = require('@peculiar/webcrypto')
15
+ const {setupServer} = require('msw/node')
16
+ const {rest} = require('msw')
17
+ const {
18
+ mockCategory,
19
+ mockedRegisteredCustomer,
20
+ exampleTokenReponse,
21
+ mockCustomerBaskets
22
+ } = require('./app/mocks/mock-data')
23
+
24
+ configureTestingLibrary({
25
+ // Increase to: 6 x default timeout of 1 second
26
+ ...(process.env.CI ? {asyncUtilTimeout: 6000} : {})
27
+ })
28
+
29
+ /**
30
+ * Set up an API mocking server for testing purposes.
31
+ * This mock server includes the basic oauth flow endpoints.
32
+ */
33
+ export const setupMockServer = () => {
34
+ return setupServer(
35
+ rest.post('*/oauth2/authorize', (req, res, ctx) => res(ctx.delay(0), ctx.status(200))),
36
+ rest.get('*/oauth2/authorize', (req, res, ctx) => res(ctx.delay(0), ctx.status(200))),
37
+ rest.post('*/oauth2/login', (req, res, ctx) =>
38
+ res(ctx.delay(0), ctx.status(200), ctx.json(mockedRegisteredCustomer))
39
+ ),
40
+ rest.get('*/oauth2/logout', (req, res, ctx) =>
41
+ res(ctx.delay(0), ctx.status(200), ctx.json(exampleTokenReponse))
42
+ ),
43
+ rest.get('*/customers/:customerId', (req, res, ctx) =>
44
+ res(ctx.delay(0), ctx.status(200), ctx.json(mockedRegisteredCustomer))
45
+ ),
46
+ rest.get('*/customers/:customerId/baskets', (req, res, ctx) =>
47
+ res(ctx.delay(0), ctx.status(200), ctx.json(mockCustomerBaskets))
48
+ ),
49
+ rest.post('*/sessions', (req, res, ctx) => res(ctx.delay(0), ctx.status(200))),
50
+ rest.post('*/oauth2/token', (req, res, ctx) =>
51
+ res(
52
+ ctx.delay(0),
53
+ ctx.json({
54
+ customer_id: 'customerid',
55
+ // Is this token for guest or registered user?
56
+ access_token:
57
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiZXhwIjoyNjczOTExMjYxLCJpYXQiOjI2NzM5MDk0NjF9.BDAp9G8nmArdBqAbsE5GUWZ3fiv2LwQKClEFDCGIyy8',
58
+ refresh_token: 'testrefeshtoken',
59
+ usid: 'testusid',
60
+ enc_user_id: 'testEncUserId',
61
+ id_token: 'testIdToken'
62
+ })
63
+ )
64
+ ),
65
+ rest.get('*/categories/:categoryId', (req, res, ctx) =>
66
+ res(ctx.delay(0), ctx.status(200), ctx.json(mockCategory))
67
+ ),
68
+ rest.post('*/baskets/actions/merge', (req, res, ctx) => res(ctx.delay(0), ctx.status(200))),
69
+ rest.post('*/v3/activities/EinsteinTestSite/*', (req, res, ctx) => {
70
+ return res(ctx.delay(0), ctx.status(200), ctx.json({}))
71
+ }),
72
+ rest.post('*/activities/EinsteinTestSite/*', (req, res, ctx) => {
73
+ return res(ctx.delay(0), ctx.status(200), ctx.json({}))
74
+ }),
75
+ rest.post('*/v3/personalization/recs/EinsteinTestSite/*', (req, res, ctx) => {
76
+ return res(ctx.delay(0), ctx.status(200), ctx.json({}))
77
+ })
78
+ )
79
+ }
80
+
81
+ beforeAll(() => {
82
+ global.server = setupMockServer()
83
+ global.server.listen({
84
+ onUnhandledRequest(req) {
85
+ console.error('Found an unhandled %s request to %s', req.method, req.url.href)
86
+ }
87
+ })
88
+ })
89
+ afterEach(() => {
90
+ global.server.resetHandlers()
91
+ })
92
+ afterAll(() => {
93
+ global.server.close()
94
+ })
95
+
96
+ // Mock the application configuration to be used in all tests.
97
+ jest.mock('@salesforce/pwa-kit-runtime/utils/ssr-config', () => {
98
+ return {
99
+ getConfig: () => mockConfig
100
+ }
101
+ })
102
+
103
+ // TextEncoder is a web API, need to import it
104
+ // from nodejs util in testing environment.
105
+ global.TextEncoder = require('util').TextEncoder
106
+ global.TextDecoder = require('util').TextDecoder
107
+
108
+ // This file consists of global mocks for jsdom.
109
+ class StorageMock {
110
+ constructor() {
111
+ this.store = {}
112
+ }
113
+ clear() {
114
+ this.store = {}
115
+ }
116
+ getItem(key) {
117
+ return this.store[key] || null
118
+ }
119
+ setItem(key, value) {
120
+ this.store[key] = value?.toString()
121
+ }
122
+ removeItem(key) {
123
+ delete this.store[key]
124
+ }
125
+ }
126
+
127
+ Object.defineProperty(window, 'crypto', {
128
+ value: new Crypto()
129
+ })
130
+
131
+ Object.defineProperty(window, 'localStorage', {
132
+ value: new StorageMock()
133
+ })
134
+
135
+ Object.defineProperty(window, 'sessionStorage', {
136
+ value: new StorageMock()
137
+ })
138
+
139
+ Object.defineProperty(window, 'scrollTo', {
140
+ value: () => null
141
+ })
142
+
143
+ if (typeof window.matchMedia !== 'function') {
144
+ Object.defineProperty(window, 'matchMedia', {
145
+ enumerable: true,
146
+ configurable: true,
147
+ writable: true,
148
+ value: jest.fn().mockImplementation((query) => ({
149
+ matches: false,
150
+ media: query,
151
+ onchange: null,
152
+ addListener: jest.fn(), // Deprecated
153
+ removeListener: jest.fn(), // Deprecated
154
+ addEventListener: jest.fn(),
155
+ removeEventListener: jest.fn(),
156
+ dispatchEvent: jest.fn()
157
+ }))
158
+ })
159
+ }
160
+
161
+ const prepareHandlers = (handlerConfig = []) => {
162
+ return handlerConfig.map((config) => {
163
+ return rest[config.method?.toLowerCase() || 'get'](config.path, (req, res, ctx) => {
164
+ return res(
165
+ ctx.delay(0),
166
+ ctx.status(config.status || 200),
167
+ config.res && ctx.json(config.res(req, res, ctx))
168
+ )
169
+ })
170
+ })
171
+ }
172
+
173
+ /**
174
+ * This util function allows developer to prepend handlers to the mock server by passing a config array of objects
175
+ *
176
+ * @param handlerConfig
177
+ * @example
178
+ * const handlers = [
179
+ * {
180
+ * path: "*\/products/"
181
+ * method: 'post',
182
+ * res: (req, res, ctx) => {
183
+ * return mockData
184
+ * }
185
+ * }
186
+ * ]
187
+ */
188
+ export const prependHandlersToServer = (handlerConfig) => {
189
+ const handlers = prepareHandlers(handlerConfig)
190
+ global.server.use(...handlers)
191
+ }