@shopgate/pwa-common-commerce 7.30.0-alpha.6 → 7.30.0-alpha.8

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 (315) hide show
  1. package/cart/action-creators/addCouponsToCart.js +9 -2
  2. package/cart/action-creators/addProductsToCart.js +9 -2
  3. package/cart/action-creators/deleteCouponsFromCart.js +9 -2
  4. package/cart/action-creators/deleteProductsFromCart.js +9 -2
  5. package/cart/action-creators/errorAddCouponsToCart.js +10 -2
  6. package/cart/action-creators/errorAddProductsToCart.js +10 -2
  7. package/cart/action-creators/errorCart.js +8 -2
  8. package/cart/action-creators/errorDeleteCouponsFromCart.js +10 -2
  9. package/cart/action-creators/errorDeleteProductsFromCart.js +10 -2
  10. package/cart/action-creators/errorUpdateProductsInCart.js +10 -2
  11. package/cart/action-creators/receiveCart.js +9 -2
  12. package/cart/action-creators/requestCart.js +8 -2
  13. package/cart/action-creators/setCartProductPendingCount.js +9 -2
  14. package/cart/action-creators/setCouponFieldError.js +9 -2
  15. package/cart/action-creators/setCouponFieldValue.js +9 -2
  16. package/cart/action-creators/setFulfillmentSlot.js +9 -2
  17. package/cart/action-creators/successAddCouponsToCart.js +10 -2
  18. package/cart/action-creators/successAddProductsToCart.js +8 -2
  19. package/cart/action-creators/successDeleteCouponsFromCart.js +8 -2
  20. package/cart/action-creators/successDeleteProductsFromCart.js +8 -2
  21. package/cart/action-creators/successUpdateProductsInCart.js +8 -2
  22. package/cart/action-creators/updateProductsInCart.js +9 -2
  23. package/cart/actions/addCouponsToCart.js +52 -8
  24. package/cart/actions/addProductsToCart.js +80 -11
  25. package/cart/actions/deleteCouponsFromCart.js +39 -6
  26. package/cart/actions/deleteProductsFromCart.js +38 -6
  27. package/cart/actions/fetchCart.js +52 -8
  28. package/cart/actions/updateProductsInCart.js +44 -6
  29. package/cart/constants/PipelineErrors.js +6 -1
  30. package/cart/constants/Pipelines.js +6 -1
  31. package/cart/constants/Portals.js +85 -1
  32. package/cart/constants/index.js +39 -2
  33. package/cart/helpers/config.js +47 -2
  34. package/cart/helpers/createPipelineErrorList.js +30 -4
  35. package/cart/helpers/fulfillmentSlots.js +37 -4
  36. package/cart/helpers/index.js +14 -3
  37. package/cart/helpers/quantity.js +23 -4
  38. package/cart/helpers/shipping.js +57 -2
  39. package/cart/helpers/tax.js +26 -2
  40. package/cart/index.js +25 -5
  41. package/cart/mock.js +130 -1
  42. package/cart/reducers/couponField.js +30 -2
  43. package/cart/reducers/data.js +98 -6
  44. package/cart/reducers/index.js +7 -1
  45. package/cart/selectors/index.js +181 -31
  46. package/cart/selectors/spec.js +189 -2
  47. package/cart/streams/index.js +176 -29
  48. package/cart/subscriptions/index.js +307 -30
  49. package/category/action-creators/errorCategory.js +10 -2
  50. package/category/action-creators/errorCategoryChildren.js +9 -2
  51. package/category/action-creators/errorRootCategories.js +8 -2
  52. package/category/action-creators/receiveCategory.js +12 -2
  53. package/category/action-creators/receiveCategoryChildren.js +10 -2
  54. package/category/action-creators/receiveRootCategories.js +9 -2
  55. package/category/action-creators/requestCategory.js +9 -2
  56. package/category/action-creators/requestCategoryChildren.js +9 -2
  57. package/category/action-creators/requestRootCategories.js +8 -2
  58. package/category/actions/fetchCategory.js +47 -5
  59. package/category/actions/fetchCategoryChildren.js +30 -2
  60. package/category/actions/fetchCategoryOrRootCategories.js +16 -2
  61. package/category/actions/fetchCategoryProducts.js +36 -2
  62. package/category/actions/fetchRootCategories.js +31 -2
  63. package/category/actions/getCategory.js +10 -2
  64. package/category/constants/Pipelines.js +3 -1
  65. package/category/constants/Portals.js +56 -3
  66. package/category/constants/index.js +17 -2
  67. package/category/helpers/index.js +27 -3
  68. package/category/index.js +19 -5
  69. package/category/mock.js +176 -1
  70. package/category/reducers/categoriesById.js +65 -3
  71. package/category/reducers/childrenByCategoryId.js +55 -4
  72. package/category/reducers/helpers/handleCategoryCollection.js +24 -3
  73. package/category/reducers/helpers/handleReceivedCategories.js +3 -1
  74. package/category/reducers/index.js +12 -2
  75. package/category/reducers/rootCategories.js +31 -2
  76. package/category/selectors/index.js +115 -16
  77. package/category/streams/index.js +82 -4
  78. package/category/subscriptions/index.js +96 -3
  79. package/checkout/action-creators/successCheckout.js +9 -2
  80. package/checkout/actions/fetchCheckoutUrl.js +28 -3
  81. package/checkout/constants/Pipelines.js +1 -1
  82. package/checkout/constants/index.js +3 -2
  83. package/checkout/index.js +11 -4
  84. package/checkout/selectors/index.js +7 -2
  85. package/checkout/streams/index.js +8 -2
  86. package/checkout/subscriptions/index.js +35 -6
  87. package/favorites/action-creators/index.js +206 -24
  88. package/favorites/actions/addFavorites.js +41 -3
  89. package/favorites/actions/addFavoritesList.js +27 -2
  90. package/favorites/actions/fetchFavoriteIds.js +49 -5
  91. package/favorites/actions/fetchFavorites.js +60 -5
  92. package/favorites/actions/fetchFavoritesList.js +47 -3
  93. package/favorites/actions/fetchFavoritesListsWithItems.js +32 -3
  94. package/favorites/actions/getFavorites.js +6 -2
  95. package/favorites/actions/removeFavorites.js +32 -3
  96. package/favorites/actions/removeFavoritesList.js +24 -2
  97. package/favorites/actions/toggleFavorites.js +68 -10
  98. package/favorites/actions/updateFavorites.js +39 -3
  99. package/favorites/actions/updateFavoritesList.js +26 -2
  100. package/favorites/constants/Pipelines.js +9 -1
  101. package/favorites/constants/Portals.js +32 -4
  102. package/favorites/constants/index.js +37 -5
  103. package/favorites/index.js +14 -4
  104. package/favorites/mock.js +89 -4
  105. package/favorites/reducers/index.js +7 -1
  106. package/favorites/reducers/lists.js +74 -2
  107. package/favorites/reducers/products.js +231 -24
  108. package/favorites/selectors/index.js +188 -24
  109. package/favorites/streams/index.js +135 -23
  110. package/favorites/streams/spec.js +517 -8
  111. package/favorites/subscriptions/index.js +260 -25
  112. package/favorites/subscriptions/spec.js +701 -28
  113. package/filter/action-creators/errorFilters.js +9 -2
  114. package/filter/action-creators/index.js +4 -1
  115. package/filter/action-creators/receiveFilters.js +10 -2
  116. package/filter/action-creators/requestFilters.js +9 -2
  117. package/filter/action-creators/updateFilters.js +8 -2
  118. package/filter/actions/fetchFilters.js +46 -3
  119. package/filter/actions/getFilters.js +6 -2
  120. package/filter/actions/helpers/buildFilterParams.js +34 -2
  121. package/filter/actions/helpers/buildRequestFilters.js +35 -2
  122. package/filter/actions/helpers/processFilters.js +10 -2
  123. package/filter/actions/helpers/processParams.js +26 -2
  124. package/filter/constants/Pipelines.js +1 -1
  125. package/filter/constants/Portals.js +39 -3
  126. package/filter/constants/index.js +8 -1
  127. package/filter/index.js +12 -4
  128. package/filter/reducers/helpers/enrichFilters.js +11 -3
  129. package/filter/reducers/index.js +5 -1
  130. package/filter/reducers/resultsByHash.js +43 -3
  131. package/filter/selectors/index.js +47 -6
  132. package/filter/streams/index.js +30 -1
  133. package/filter/subscriptions/index.js +34 -2
  134. package/market/constants/Portals.js +22 -4
  135. package/market/constants/index.js +2 -1
  136. package/market/helpers/showReturnPolicy.js +3 -1
  137. package/market/helpers/showTaxDisclaimer.js +3 -1
  138. package/market/index.js +6 -2
  139. package/orders/constants.js +2 -1
  140. package/package.json +3 -3
  141. package/product/action-creators/deleteProductsByIds.js +10 -2
  142. package/product/action-creators/errorProduct.js +10 -2
  143. package/product/action-creators/errorProductDescription.js +10 -2
  144. package/product/action-creators/errorProductImages.js +10 -2
  145. package/product/action-creators/errorProductMedia.js +10 -2
  146. package/product/action-creators/errorProductOptions.js +10 -2
  147. package/product/action-creators/errorProductProperties.js +10 -2
  148. package/product/action-creators/errorProductRelations.js +9 -2
  149. package/product/action-creators/errorProductShipping.js +10 -2
  150. package/product/action-creators/errorProductVariants.js +10 -2
  151. package/product/action-creators/errorProducts.js +9 -2
  152. package/product/action-creators/expireProductById.js +10 -2
  153. package/product/action-creators/expireProductData.js +11 -2
  154. package/product/action-creators/expireProductsByHash.js +9 -2
  155. package/product/action-creators/productNotAvailable.js +10 -2
  156. package/product/action-creators/provideProduct.js +9 -2
  157. package/product/action-creators/receiveProduct.js +10 -2
  158. package/product/action-creators/receiveProductCached.js +9 -2
  159. package/product/action-creators/receiveProductDescription.js +10 -2
  160. package/product/action-creators/receiveProductImages.js +10 -2
  161. package/product/action-creators/receiveProductMedia.js +10 -2
  162. package/product/action-creators/receiveProductOptions.js +10 -2
  163. package/product/action-creators/receiveProductProperties.js +10 -2
  164. package/product/action-creators/receiveProductRelations.js +12 -2
  165. package/product/action-creators/receiveProductShipping.js +10 -2
  166. package/product/action-creators/receiveProductVariants.js +10 -2
  167. package/product/action-creators/receiveProducts.js +16 -2
  168. package/product/action-creators/receiveProductsCached.js +9 -2
  169. package/product/action-creators/refreshExpiredPDPData.js +8 -2
  170. package/product/action-creators/requestProduct.js +10 -2
  171. package/product/action-creators/requestProductDescription.js +9 -2
  172. package/product/action-creators/requestProductImages.js +9 -2
  173. package/product/action-creators/requestProductMedia.js +9 -2
  174. package/product/action-creators/requestProductOptions.js +9 -2
  175. package/product/action-creators/requestProductProperties.js +9 -2
  176. package/product/action-creators/requestProductRelations.js +10 -2
  177. package/product/action-creators/requestProductShipping.js +9 -2
  178. package/product/action-creators/requestProductVariants.js +9 -2
  179. package/product/action-creators/requestProducts.js +9 -2
  180. package/product/action-creators/setProductId.js +9 -2
  181. package/product/action-creators/setProductQuantity.js +9 -2
  182. package/product/action-creators/setProductVariantId.js +9 -2
  183. package/product/actions/changeSortOrder.js +21 -2
  184. package/product/actions/fetchHighlightProducts.js +18 -2
  185. package/product/actions/fetchLiveshoppingProducts.js +14 -2
  186. package/product/actions/fetchProduct.js +52 -3
  187. package/product/actions/fetchProductDescription.js +30 -2
  188. package/product/actions/fetchProductImages.js +31 -2
  189. package/product/actions/fetchProductMedia.js +35 -2
  190. package/product/actions/fetchProductOptions.js +31 -2
  191. package/product/actions/fetchProductProperties.js +30 -2
  192. package/product/actions/fetchProductRelations.js +63 -2
  193. package/product/actions/fetchProductShipping.js +31 -2
  194. package/product/actions/fetchProductVariants.js +31 -2
  195. package/product/actions/fetchProducts.js +189 -17
  196. package/product/actions/fetchProductsById.js +68 -8
  197. package/product/actions/fetchProductsByQuery.js +102 -18
  198. package/product/actions/getHighlightProducts.js +6 -2
  199. package/product/actions/getLiveshoppingProducts.js +6 -2
  200. package/product/actions/getProduct.js +6 -2
  201. package/product/actions/getProductDescription.js +6 -2
  202. package/product/actions/getProductImages.js +6 -2
  203. package/product/actions/getProductOptions.js +6 -2
  204. package/product/actions/getProductProperties.js +6 -2
  205. package/product/actions/getProductRelations.js +6 -2
  206. package/product/actions/getProductShipping.js +6 -2
  207. package/product/actions/getProductVariants.js +6 -2
  208. package/product/actions/getProducts.js +6 -2
  209. package/product/actions/getProductsById.js +6 -2
  210. package/product/actions/getProductsByQuery.js +6 -2
  211. package/product/actions/processProductFlags.js +35 -3
  212. package/product/actions/updateMetadata.js +17 -2
  213. package/product/collections/ProductImageFormats.js +48 -8
  214. package/product/collections/index.js +1 -1
  215. package/product/constants/Pipelines.js +12 -1
  216. package/product/constants/Portals.js +200 -33
  217. package/product/constants/index.js +90 -18
  218. package/product/helpers/index.js +61 -8
  219. package/product/index.js +36 -6
  220. package/product/mock.js +1002 -2
  221. package/product/reducers/descriptionsByProductId.js +54 -5
  222. package/product/reducers/helpers/formatOptions.js +17 -2
  223. package/product/reducers/helpers/handleProductCollection.js +19 -2
  224. package/product/reducers/imagesByProductId.js +51 -4
  225. package/product/reducers/index.js +23 -1
  226. package/product/reducers/mediaByProductId.js +55 -3
  227. package/product/reducers/optionsByProductId.js +41 -2
  228. package/product/reducers/productRelationsByHash.js +43 -2
  229. package/product/reducers/productsById.js +122 -7
  230. package/product/reducers/propertiesByProductId.js +48 -2
  231. package/product/reducers/resultsByHash.js +125 -9
  232. package/product/reducers/shippingByProductId.js +37 -2
  233. package/product/reducers/variantsByProductId.js +56 -2
  234. package/product/selectors/options.js +90 -13
  235. package/product/selectors/page.js +62 -13
  236. package/product/selectors/price.js +81 -18
  237. package/product/selectors/product.js +549 -59
  238. package/product/selectors/product.mock.js +327 -12
  239. package/product/selectors/relations.js +35 -5
  240. package/product/selectors/variants.js +91 -15
  241. package/product/streams/index.js +167 -13
  242. package/product/subscriptions/index.js +210 -4
  243. package/reviews/action-creators/errorProductReviews.js +9 -2
  244. package/reviews/action-creators/errorReviews.js +9 -2
  245. package/reviews/action-creators/errorSubmitReview.js +9 -2
  246. package/reviews/action-creators/errorUserReview.js +9 -2
  247. package/reviews/action-creators/flushUserReview.js +8 -2
  248. package/reviews/action-creators/receiveProductReviews.js +11 -2
  249. package/reviews/action-creators/receiveReviews.js +12 -2
  250. package/reviews/action-creators/receiveSubmitReview.js +9 -2
  251. package/reviews/action-creators/receiveUserReview.js +10 -2
  252. package/reviews/action-creators/requestProductReviews.js +10 -2
  253. package/reviews/action-creators/requestReviews.js +9 -2
  254. package/reviews/action-creators/requestSubmitReview.js +9 -2
  255. package/reviews/action-creators/requestUserReview.js +9 -2
  256. package/reviews/action-creators/resetSubmittedReview.js +9 -2
  257. package/reviews/action-creators/spec.js +40 -1
  258. package/reviews/actions/fetchProductReviews.js +37 -2
  259. package/reviews/actions/fetchReviews.js +38 -2
  260. package/reviews/actions/fetchUserReview.js +31 -2
  261. package/reviews/actions/flushUserReview.js +5 -1
  262. package/reviews/actions/getProductReviews.js +6 -2
  263. package/reviews/actions/getUserReview.js +6 -2
  264. package/reviews/actions/spec.js +241 -4
  265. package/reviews/actions/submitReview.js +63 -3
  266. package/reviews/constants/Pipelines.js +4 -1
  267. package/reviews/constants/Portals.js +4 -1
  268. package/reviews/constants/index.js +26 -7
  269. package/reviews/index.js +15 -4
  270. package/reviews/mock.js +172 -11
  271. package/reviews/reducers/index.js +11 -1
  272. package/reviews/reducers/mock.js +14 -2
  273. package/reviews/reducers/reviewsByHash.js +52 -6
  274. package/reviews/reducers/reviewsById.js +27 -2
  275. package/reviews/reducers/reviewsByProductId.js +47 -2
  276. package/reviews/reducers/spec.js +211 -2
  277. package/reviews/reducers/userReviewsByProductId.js +68 -2
  278. package/reviews/selectors/index.js +123 -19
  279. package/reviews/selectors/mock.js +100 -1
  280. package/reviews/selectors/spec.js +100 -1
  281. package/reviews/streams/index.js +37 -5
  282. package/reviews/streams/spec.js +25 -1
  283. package/reviews/subscriptions/index.js +27 -2
  284. package/scanner/action-creators/errorHandleScanner.js +11 -2
  285. package/scanner/action-creators/scannerFinished.js +11 -2
  286. package/scanner/action-creators/startScanner.js +8 -2
  287. package/scanner/action-creators/successHandleScanner.js +11 -2
  288. package/scanner/actions/handleBarCode.js +22 -2
  289. package/scanner/actions/handleNoResults.js +23 -2
  290. package/scanner/actions/handleQrCode.js +116 -6
  291. package/scanner/actions/handleSearch.js +33 -2
  292. package/scanner/constants/Portals.js +22 -1
  293. package/scanner/constants/index.js +17 -1
  294. package/scanner/helpers/index.js +115 -5
  295. package/scanner/index.js +19 -5
  296. package/scanner/streams/index.js +36 -1
  297. package/scanner/subscriptions/index.js +78 -8
  298. package/search/action-creators/errorSearchResults.js +10 -2
  299. package/search/action-creators/receiveSearchResults.js +11 -2
  300. package/search/action-creators/receiveSearchSuggestions.js +10 -2
  301. package/search/action-creators/requestSearchResults.js +10 -2
  302. package/search/action-creators/requestSearchSuggestions.js +9 -2
  303. package/search/actions/fetchSearchResults.js +66 -8
  304. package/search/actions/fetchSearchSuggestions.js +36 -2
  305. package/search/constants/Pipelines.js +1 -1
  306. package/search/constants/Portals.js +9 -2
  307. package/search/constants/index.js +10 -2
  308. package/search/helpers/index.js +5 -2
  309. package/search/helpers/removeHighlightingPlaceholders.js +4 -1
  310. package/search/helpers/spec.js +19 -1
  311. package/search/index.js +17 -5
  312. package/search/reducers/index.js +38 -2
  313. package/search/selectors/index.js +23 -4
  314. package/search/streams/index.js +51 -3
  315. package/search/subscriptions/index.js +132 -5
@@ -1,30 +1,703 @@
1
- import _regeneratorRuntime from"@babel/runtime/regenerator";function asyncGeneratorStep(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg);var value=info.value;}catch(error){reject(error);return;}if(info.done){resolve(value);}else{Promise.resolve(value).then(_next,_throw);}}function _asyncToGenerator(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"next",value);}function _throw(err){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"throw",err);}_next(undefined);});};}import{subscribe,invoke,getSubscriptionCount,resetSubscriptions}from'@shopgate/pwa-common/subscriptions/mock';import pipelineDependencies from'@shopgate/pwa-core/classes/PipelineDependencies';import showModal from'@shopgate/pwa-common/actions/modal/showModal';import{appDidStart$}from'@shopgate/pwa-common/streams';import{favoritesWillEnter$,shouldFetchFreshFavorites$,addProductToFavoritesDebounced$,removeProductFromFavoritesDebounced$,didReceiveFlushFavoritesBuffer$,errorFavoritesLimit$,refreshFavorites$,updateProductInFavoritesDebounced$}from"../streams";import favorites from"./index";import fetchFavorites from"../actions/fetchFavorites";import addFavorites from"../actions/addFavorites";import removeFavorites from"../actions/removeFavorites";import updateFavorites from"../actions/updateFavorites";import{FAVORITES_LIMIT_ERROR}from"../constants";import{SHOPGATE_USER_ADD_FAVORITES,SHOPGATE_USER_DELETE_FAVORITES}from"../constants/Pipelines";import{addProductToFavorites,removeProductFromFavorites,requestAddFavorites,requestRemoveFavorites,cancelRequestSyncFavorites,errorFavorites,idleSyncFavorites,updateProductInFavorites,requestUpdateFavorites}from"../action-creators";import{getFavoritesProducts,getFavoritesCount,makeGetProductRelativesOnFavorites}from"../selectors";import fetchFavoritesListsWithItems from"../actions/fetchFavoritesListsWithItems";// Required for custom runner without env-setup
2
- jest.mock('@shopgate/pwa-core',function(){});jest.mock('@shopgate/pwa-common/actions/modal/showModal',function(){return jest.fn().mockReturnValue('showModal');});jest.mock('@shopgate/pwa-common-commerce/product',function(){return{fetchProductsById:jest.fn()};});jest.mock('@shopgate/pwa-common/providers',function(){return{LoadingProvider:{setLoading:jest.fn(),unsetLoading:jest.fn()}};});var mockedDefaultListId='DEFAULT';jest.mock("../actions/fetchFavorites",function(){return jest.fn().mockReturnValue('fetchFavoritesResult');});jest.mock("../actions/fetchFavoritesList",function(){return jest.fn().mockResolvedValue([{id:'DEFAULT',name:'Wish List'}]);});jest.mock("../actions/fetchFavoritesListsWithItems",function(){var original=jest.requireActual('../actions/fetchFavoritesListsWithItems');return{__esModule:true,"default":jest.fn(original["default"])};});// Mock all used selectors to avoid mocking the store
3
- var mockedGetFavoritesProductsIdsReturnValue;var mockedGetFavoritesCountReturnValue;var mockedGetFavoritesCountByListReturnValue;var mockedGetFavoritesProductsReturnValue;var mockedGetProductRelativesOnFavoritesReturnValue;var mockedMakeGetFavoritesReturnValue;var mockedMakeGetFavoritesCountByList=jest.fn(function(){return mockedGetFavoritesCountByListReturnValue||0;});jest.mock("../selectors",function(){return{getFavoritesProductsIds:jest.fn(function(){return mockedGetFavoritesProductsIdsReturnValue;}),getFavoritesProducts:jest.fn(function(){return mockedGetFavoritesProductsReturnValue;}),getFavoritesCount:jest.fn(function(){return mockedGetFavoritesCountReturnValue;}),makeGetFavoritesCountByList:jest.fn(function(){return mockedMakeGetFavoritesCountByList;}),makeGetFavorites:jest.fn(function(){return mockedMakeGetFavoritesReturnValue;}),makeGetProductRelativesOnFavorites:jest.fn(function(){return jest.fn().mockReturnValue(mockedGetProductRelativesOnFavoritesReturnValue);}),getUseGetFavoriteIdsPipeline:jest.fn().mockReturnValue(false)};});jest.mock("../actions/addFavorites",function(){return jest.fn().mockReturnValue('addFavoritesResult');});jest.mock("../actions/removeFavorites",function(){return jest.fn().mockReturnValue('removeFavoritesResult');});jest.mock("../actions/updateFavorites",function(){return jest.fn().mockReturnValue('updateFavoritesResult');});var mockedHasFavorites=true;var mockedFavoritesLimit=100;jest.mock('@shopgate/pwa-common/helpers/config',function(){return{get hasFavorites(){return mockedHasFavorites;},get favorites(){return{limit:mockedFavoritesLimit};},get themeConfig(){return{colors:{}};}};});/**
1
+ import "core-js/modules/web.immediate.js";
2
+ import { subscribe, invoke, getSubscriptionCount, resetSubscriptions } from '@shopgate/pwa-common/subscriptions/mock';
3
+ import pipelineDependencies from '@shopgate/pwa-core/classes/PipelineDependencies';
4
+ import showModal from '@shopgate/pwa-common/actions/modal/showModal';
5
+ import { appDidStart$ } from '@shopgate/pwa-common/streams';
6
+ import { favoritesWillEnter$, shouldFetchFreshFavorites$, addProductToFavoritesDebounced$, removeProductFromFavoritesDebounced$, didReceiveFlushFavoritesBuffer$, errorFavoritesLimit$, refreshFavorites$, updateProductInFavoritesDebounced$ } from "../streams";
7
+ import favorites from "./index";
8
+ import fetchFavorites from "../actions/fetchFavorites";
9
+ import addFavorites from "../actions/addFavorites";
10
+ import removeFavorites from "../actions/removeFavorites";
11
+ import updateFavorites from "../actions/updateFavorites";
12
+ import { FAVORITES_LIMIT_ERROR } from "../constants";
13
+ import { SHOPGATE_USER_ADD_FAVORITES, SHOPGATE_USER_DELETE_FAVORITES } from "../constants/Pipelines";
14
+ import { addProductToFavorites, removeProductFromFavorites, requestAddFavorites, requestRemoveFavorites, cancelRequestSyncFavorites, errorFavorites, idleSyncFavorites, updateProductInFavorites, requestUpdateFavorites } from "../action-creators";
15
+ import { getFavoritesProducts, getFavoritesCount, makeGetProductRelativesOnFavorites } from "../selectors";
16
+ import fetchFavoritesListsWithItems from "../actions/fetchFavoritesListsWithItems";
17
+
18
+ // Required for custom runner without env-setup
19
+ jest.mock('@shopgate/pwa-core', () => {});
20
+ jest.mock('@shopgate/pwa-common/actions/modal/showModal', () => jest.fn().mockReturnValue('showModal'));
21
+ jest.mock('@shopgate/pwa-common-commerce/product', () => ({
22
+ fetchProductsById: jest.fn()
23
+ }));
24
+ jest.mock('@shopgate/pwa-common/providers', () => ({
25
+ LoadingProvider: {
26
+ setLoading: jest.fn(),
27
+ unsetLoading: jest.fn()
28
+ }
29
+ }));
30
+ const mockedDefaultListId = 'DEFAULT';
31
+ jest.mock("../actions/fetchFavorites", () => jest.fn().mockReturnValue('fetchFavoritesResult'));
32
+ jest.mock("../actions/fetchFavoritesList", () => jest.fn().mockResolvedValue([{
33
+ id: 'DEFAULT',
34
+ name: 'Wish List'
35
+ }]));
36
+ jest.mock("../actions/fetchFavoritesListsWithItems", () => {
37
+ const original = jest.requireActual("../actions/fetchFavoritesListsWithItems");
38
+ return {
39
+ __esModule: true,
40
+ default: jest.fn(original.default)
41
+ };
42
+ });
43
+
44
+ // Mock all used selectors to avoid mocking the store
45
+ let mockedGetFavoritesProductsIdsReturnValue;
46
+ let mockedGetFavoritesCountReturnValue;
47
+ let mockedGetFavoritesCountByListReturnValue;
48
+ let mockedGetFavoritesProductsReturnValue;
49
+ let mockedGetProductRelativesOnFavoritesReturnValue;
50
+ let mockedMakeGetFavoritesReturnValue;
51
+ const mockedMakeGetFavoritesCountByList = jest.fn(() => mockedGetFavoritesCountByListReturnValue || 0);
52
+ jest.mock("../selectors", () => ({
53
+ getFavoritesProductsIds: jest.fn(() => mockedGetFavoritesProductsIdsReturnValue),
54
+ getFavoritesProducts: jest.fn(() => mockedGetFavoritesProductsReturnValue),
55
+ getFavoritesCount: jest.fn(() => mockedGetFavoritesCountReturnValue),
56
+ makeGetFavoritesCountByList: jest.fn(() => mockedMakeGetFavoritesCountByList),
57
+ makeGetFavorites: jest.fn(() => mockedMakeGetFavoritesReturnValue),
58
+ makeGetProductRelativesOnFavorites: jest.fn(() => jest.fn().mockReturnValue(mockedGetProductRelativesOnFavoritesReturnValue)),
59
+ getUseGetFavoriteIdsPipeline: jest.fn().mockReturnValue(false)
60
+ }));
61
+ jest.mock("../actions/addFavorites", () => jest.fn().mockReturnValue('addFavoritesResult'));
62
+ jest.mock("../actions/removeFavorites", () => jest.fn().mockReturnValue('removeFavoritesResult'));
63
+ jest.mock("../actions/updateFavorites", () => jest.fn().mockReturnValue('updateFavoritesResult'));
64
+ let mockedHasFavorites = true;
65
+ let mockedFavoritesLimit = 100;
66
+ jest.mock('@shopgate/pwa-common/helpers/config', () => ({
67
+ get hasFavorites() {
68
+ return mockedHasFavorites;
69
+ },
70
+ get favorites() {
71
+ return {
72
+ limit: mockedFavoritesLimit
73
+ };
74
+ },
75
+ get themeConfig() {
76
+ return {
77
+ colors: {}
78
+ };
79
+ }
80
+ }));
81
+
82
+ /**
4
83
  * Flushes the promise queue.
5
84
  * @returns {Promise}
6
- */var flushPromises=function flushPromises(){return new Promise(function(resolve){return setImmediate(resolve);});};describe('Favorites - subscriptions',function(){describe('Favorites enabled',function(){var pipelineDependenciesSet=pipelineDependencies.set;beforeAll(function(){// Make sure no conflicting subscriptions exist
7
- resetSubscriptions();// Replace singleton object property with a mock
8
- pipelineDependencies.set=jest.fn();// Subscribe all streams
9
- favorites(subscribe);});afterAll(function(){// Clean up subscriptions
10
- resetSubscriptions();// Restore singleton
11
- pipelineDependencies.set=pipelineDependenciesSet;});var getState=jest.fn().mockReturnValue(function(){});// Dispatch always resolves it's promise by default
12
- var dispatch=jest.fn(function(result){if(typeof result==='function'){return result(dispatch,getState);}return result;});var productIds=['prod1','prod2'];var defaultListItems=[{quantity:1,notes:null,productId:productIds[0]},{quantity:1,notes:null,productId:productIds[1]}];beforeEach(function(){jest.clearAllMocks();// Reset selector return values
13
- mockedGetFavoritesProductsIdsReturnValue=productIds;mockedGetFavoritesCountReturnValue=productIds.length;mockedGetProductRelativesOnFavoritesReturnValue=[];mockedGetFavoritesProductsReturnValue={byList:{DEFAULT:{items:defaultListItems,isFetching:false}}};mockedMakeGetFavoritesReturnValue=jest.fn().mockReturnValue(defaultListItems);});describe('appDidStart$',function(){it('should subscribe to the stream',function(){expect(getSubscriptionCount(appDidStart$)).toBe(1);});it('should not return any value',/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(){return _regeneratorRuntime.wrap(function _callee$(_context){while(1)switch(_context.prev=_context.next){case 0:_context.next=2;return expect(invoke(appDidStart$,{dispatch:dispatch,getState:getState})).resolves.toBeUndefined();case 2:case"end":return _context.stop();}},_callee);})));it('should set up pipeline dependencies correctly',function(){invoke(appDidStart$,{dispatch:dispatch,getState:getState});// Expect pipeline dependencies to be set correctly
14
- expect(pipelineDependencies.set).toHaveBeenCalledTimes(2);expect(pipelineDependencies.set.mock.calls[0][0]).toBe(SHOPGATE_USER_ADD_FAVORITES);expect(pipelineDependencies.set.mock.calls[0][1]).toEqual([SHOPGATE_USER_ADD_FAVORITES,SHOPGATE_USER_DELETE_FAVORITES]);expect(pipelineDependencies.set.mock.calls[1][0]).toBe(SHOPGATE_USER_DELETE_FAVORITES);expect(pipelineDependencies.set.mock.calls[1][1]).toEqual([SHOPGATE_USER_ADD_FAVORITES,SHOPGATE_USER_DELETE_FAVORITES]);});it('should fetch favorites',/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(){return _regeneratorRuntime.wrap(function _callee2$(_context2){while(1)switch(_context2.prev=_context2.next){case 0:_context2.next=2;return invoke(appDidStart$,{dispatch:dispatch,getState:getState});case 2:expect(fetchFavoritesListsWithItems).toHaveBeenCalledTimes(1);expect(fetchFavoritesListsWithItems).toHaveBeenCalledWith(false);expect(dispatch).toHaveBeenCalledTimes(3);case 5:case"end":return _context2.stop();}},_callee2);})));});describe('favoritesWillEnter$',function(){it('should subscribe to the stream',function(){expect(getSubscriptionCount(favoritesWillEnter$)).toBe(1);});it('should not return any value',/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3(){return _regeneratorRuntime.wrap(function _callee3$(_context3){while(1)switch(_context3.prev=_context3.next){case 0:_context3.t0=expect;_context3.next=3;return invoke(favoritesWillEnter$,{dispatch:dispatch,getState:getState});case 3:_context3.t1=_context3.sent;(0,_context3.t0)(_context3.t1).toBeUndefined();case 5:case"end":return _context3.stop();}},_callee3);})));it('should handle fetch and map favorites',/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4(){return _regeneratorRuntime.wrap(function _callee4$(_context4){while(1)switch(_context4.prev=_context4.next){case 0:_context4.next=2;return invoke(favoritesWillEnter$,{dispatch:dispatch,getState:getState});case 2:expect(fetchFavoritesListsWithItems).toHaveBeenCalledTimes(1);expect(fetchFavoritesListsWithItems).toHaveBeenCalledWith(true);expect(dispatch).toHaveBeenCalledTimes(3);case 5:case"end":return _context4.stop();}},_callee4);})));});describe('shouldFetchFreshFavorites$',function(){it('should subscribe to the stream',function(){expect(getSubscriptionCount(shouldFetchFreshFavorites$)).toBe(1);});it('should not return any value',/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5(){return _regeneratorRuntime.wrap(function _callee5$(_context5){while(1)switch(_context5.prev=_context5.next){case 0:_context5.next=2;return expect(invoke(shouldFetchFreshFavorites$,{dispatch:dispatch})).resolves.toBeUndefined();case 2:case"end":return _context5.stop();}},_callee5);})));it('should fetch fresh favorites without using the cache',/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee6(){return _regeneratorRuntime.wrap(function _callee6$(_context6){while(1)switch(_context6.prev=_context6.next){case 0:_context6.next=2;return invoke(shouldFetchFreshFavorites$,{dispatch:dispatch,getState:getState});case 2:expect(fetchFavoritesListsWithItems).toHaveBeenCalledTimes(1);expect(fetchFavoritesListsWithItems).toHaveBeenCalledWith(true);expect(dispatch).toHaveBeenCalledTimes(3);case 5:case"end":return _context6.stop();}},_callee6);})));});describe('addProductToFavoritesDebounced$',function(){it('should subscribe to the stream',function(){expect(getSubscriptionCount(addProductToFavoritesDebounced$)).toBe(1);});it('should not return any value',function(){expect(invoke(addProductToFavoritesDebounced$,{action:addProductToFavorites('prod3'),dispatch:dispatch,getState:getState})).toBeUndefined();});it('should cancel the request when the product is already there',function(){invoke(addProductToFavoritesDebounced$,{action:addProductToFavorites('prod1',mockedDefaultListId),dispatch:dispatch,getState:getState});expect(getState).toHaveBeenCalledTimes(1);expect(getFavoritesProducts).toHaveBeenCalledWith(getState());expect(getFavoritesProducts).toHaveBeenCalledTimes(1);expect(dispatch).toHaveBeenCalledWith(cancelRequestSyncFavorites(0,mockedDefaultListId));expect(dispatch).toHaveBeenCalledTimes(1);});it('should proceed and dispatch an error if the product is not yet on the list and the limit is reached',function(){var favoritesLimit=mockedFavoritesLimit;var productId='prod3';mockedFavoritesLimit=2;mockedGetFavoritesCountByListReturnValue=2;invoke(addProductToFavoritesDebounced$,{action:addProductToFavorites(productId,'DEFAULT'),dispatch:dispatch,getState:getState});expect(getState).toHaveBeenCalledTimes(1);expect(getFavoritesProducts).toHaveBeenCalledWith(getState());expect(getFavoritesProducts).toHaveBeenCalledTimes(1);expect(mockedMakeGetFavoritesCountByList).toHaveBeenCalledWith(getState());expect(mockedMakeGetFavoritesCountByList).toHaveBeenCalledTimes(1);expect(mockedMakeGetFavoritesCountByList).toHaveReturnedWith(mockedGetFavoritesCountByListReturnValue);var error=new Error('Limit exceeded');error.code=FAVORITES_LIMIT_ERROR;expect(dispatch).toHaveBeenCalledWith(errorFavorites(productId,error));expect(dispatch).toHaveBeenCalledTimes(1);mockedFavoritesLimit=favoritesLimit;});it('should proceed and dispatch an add request if all is good',function(){var productId='prod3';invoke(addProductToFavoritesDebounced$,{action:addProductToFavorites(productId),dispatch:dispatch,getState:getState});expect(getState).toHaveBeenCalledTimes(1);expect(getFavoritesProducts).toHaveBeenCalledWith(getState());expect(getFavoritesProducts).toHaveBeenCalledTimes(1);expect(mockedMakeGetFavoritesCountByList).toHaveBeenCalledWith(getState());expect(mockedMakeGetFavoritesCountByList).toHaveBeenCalledTimes(1);expect(dispatch).toHaveBeenCalledWith(requestAddFavorites(productId));expect(dispatch).toHaveBeenCalledTimes(1);});});describe('updateProductInFavoritesDebounced$',function(){it('should subscribe to the stream',function(){expect(getSubscriptionCount(updateProductInFavoritesDebounced$)).toBe(1);});it('should not return any value',function(){expect(invoke(updateProductInFavoritesDebounced$,{action:updateProductInFavorites('prod3'),dispatch:dispatch,getState:getState})).toBeUndefined();});it('should proceed and dispatch an add request if all is good',function(){var productId='prod3';invoke(updateProductInFavoritesDebounced$,{action:updateProductInFavorites(productId),dispatch:dispatch,getState:getState});expect(dispatch).toHaveBeenCalledWith(requestUpdateFavorites(productId));expect(dispatch).toHaveBeenCalledTimes(1);});});describe('removeProductFromFavoritesDebounced$',function(){it('should subscribe to the stream',function(){expect(getSubscriptionCount(removeProductFromFavoritesDebounced$)).toBe(1);});it('should not return any value',function(){expect(invoke(removeProductFromFavoritesDebounced$,{action:removeProductFromFavorites('prod1',true,mockedDefaultListId),dispatch:dispatch,getState:getState})).toBeUndefined();expect(invoke(removeProductFromFavoritesDebounced$,{action:removeProductFromFavorites('prod1',false,mockedDefaultListId),dispatch:dispatch,getState:getState})).toBeUndefined();});it('should not do anything if no products are on the list and currently fetching',function(){mockedGetFavoritesCountReturnValue=0;mockedGetFavoritesProductsReturnValue.isFetching=true;invoke(removeProductFromFavoritesDebounced$,{action:removeProductFromFavorites('prod1',false,mockedDefaultListId),dispatch:dispatch,getState:getState});expect(getFavoritesCount).toHaveBeenCalledTimes(1);expect(makeGetProductRelativesOnFavorites).toHaveBeenCalledTimes(0);expect(getFavoritesProducts).toHaveBeenCalledTimes(1);expect(getState).toHaveBeenCalledTimes(2);expect(dispatch).toHaveBeenCalledTimes(1);});it('should idle-sync when no products are on the list and not fetching',function(){mockedGetFavoritesCountReturnValue=0;invoke(removeProductFromFavoritesDebounced$,{action:removeProductFromFavorites('prod1',false,mockedDefaultListId),dispatch:dispatch,getState:getState});expect(getFavoritesCount).toHaveBeenCalledTimes(1);expect(makeGetProductRelativesOnFavorites).toHaveBeenCalledTimes(0);expect(getFavoritesProducts).toHaveBeenCalledTimes(1);expect(getState).toHaveBeenCalledTimes(2);expect(dispatch).toHaveBeenCalledTimes(1);expect(dispatch).toHaveBeenCalledWith(idleSyncFavorites(mockedDefaultListId));});it('should dispatch a remove request for each relative',function(){var productId='prod0';var mock=jest.fn(function(){return productIds;});makeGetProductRelativesOnFavorites.mockReturnValueOnce(mock);invoke(removeProductFromFavoritesDebounced$,{action:removeProductFromFavorites(productId,true,mockedDefaultListId),dispatch:dispatch,getState:getState});// Expect multiple remove requests to be dispatched
15
- expect(makeGetProductRelativesOnFavorites).toHaveBeenCalledTimes(1);expect(dispatch).toHaveBeenCalledTimes(4);expect(dispatch.mock.calls[1][0]).toEqual(requestRemoveFavorites(productIds[0],mockedDefaultListId)(dispatch,getState));expect(dispatch.mock.calls[3][0]).toEqual(requestRemoveFavorites(productIds[1],mockedDefaultListId)(dispatch,getState));});it('should cancel the remove request if the product is not on the list',function(){var productId='prod0';mockedGetProductRelativesOnFavoritesReturnValue=productIds;invoke(removeProductFromFavoritesDebounced$,{action:removeProductFromFavorites(productId,false,mockedDefaultListId),dispatch:dispatch,getState:getState});// Don't expect any remove requests to be triggered
16
- expect(makeGetProductRelativesOnFavorites).toHaveBeenCalledTimes(0);expect(dispatch).toHaveBeenCalledTimes(1);expect(dispatch).toHaveBeenCalledWith(cancelRequestSyncFavorites(0,mockedDefaultListId));});it('should request the removal of the single favorite item',function(){var productId='prod0';mockedGetFavoritesProductsReturnValue={byList:{DEFAULT:{items:[].concat(mockedGetFavoritesProductsReturnValue.byList.DEFAULT.items,[{productId:productId,quantity:1,notes:null}])}}};var mock=jest.fn(function(){return productIds;});makeGetProductRelativesOnFavorites.mockReturnValueOnce(mock);invoke(removeProductFromFavoritesDebounced$,{action:removeProductFromFavorites(productId,false,mockedDefaultListId),dispatch:dispatch,getState:getState});// Only one removal request is expected
17
- expect(makeGetProductRelativesOnFavorites).toHaveBeenCalledTimes(0);expect(dispatch).toHaveBeenCalledTimes(2);expect(dispatch.mock.calls[1][0]).toEqual(requestRemoveFavorites(productId,mockedDefaultListId)(dispatch,getState));});});describe('errorFavoritesLimit$',function(){it('should subscribe to the stream',function(){expect(getSubscriptionCount(errorFavoritesLimit$)).toBe(1);});it('should not return any value',function(){expect(invoke(errorFavoritesLimit$,{dispatch:dispatch})).toBeUndefined();});it('should dispatch an action to show a modal',function(){invoke(errorFavoritesLimit$,{dispatch:dispatch});expect(showModal).toHaveBeenCalledTimes(1);expect(dispatch).toHaveBeenCalledTimes(1);expect(dispatch).toHaveBeenCalledWith(showModal({confirm:null,dismiss:'modal.ok',title:'modal.title_error',message:'favorites.error_limit'}));});});describe('refreshFavorites$',function(){it('should subscribe to the stream',function(){expect(getSubscriptionCount(refreshFavorites$)).toBe(1);});it('should not return any value',/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee7(){return _regeneratorRuntime.wrap(function _callee7$(_context7){while(1)switch(_context7.prev=_context7.next){case 0:_context7.next=2;return expect(invoke(refreshFavorites$,{dispatch:dispatch,action:{listId:mockedDefaultListId},getState:getState})).resolves.toBeUndefined();case 2:case"end":return _context7.stop();}},_callee7);})));it('should refresh favorites by fetching them without using the cache',/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee8(){return _regeneratorRuntime.wrap(function _callee8$(_context8){while(1)switch(_context8.prev=_context8.next){case 0:_context8.next=2;return invoke(refreshFavorites$,{dispatch:dispatch,action:{listId:mockedDefaultListId},getState:getState});case 2:expect(fetchFavorites).toHaveBeenCalledTimes(1);expect(dispatch).toHaveBeenCalledTimes(1);expect(dispatch).toHaveBeenCalledWith(fetchFavorites(true));case 5:case"end":return _context8.stop();}},_callee8);})));});describe('didReceiveFlushFavoritesBuffer$',function(){it('should subscribe to the stream',function(){expect(getSubscriptionCount(didReceiveFlushFavoritesBuffer$)).toBe(1);});it('should not return any value',/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee9(){var productId;return _regeneratorRuntime.wrap(function _callee9$(_context9){while(1)switch(_context9.prev=_context9.next){case 0:productId='prod1';_context9.t0=expect;_context9.next=4;return invoke(didReceiveFlushFavoritesBuffer$,null);case 4:_context9.t1=_context9.sent;(0,_context9.t0)(_context9.t1).toBeUndefined();_context9.t2=expect;_context9.next=9;return invoke(didReceiveFlushFavoritesBuffer$,[]);case 9:_context9.t3=_context9.sent;(0,_context9.t2)(_context9.t3).toBeUndefined();_context9.t4=expect;_context9.next=14;return invoke(didReceiveFlushFavoritesBuffer$,[{action:requestAddFavorites(productId,mockedDefaultListId),dispatch:dispatch,getState:getState}]);case 14:_context9.t5=_context9.sent;(0,_context9.t4)(_context9.t5).toBeUndefined();_context9.t6=expect;_context9.next=19;return invoke(didReceiveFlushFavoritesBuffer$,[{action:requestAddFavorites(productId,mockedDefaultListId),dispatch:dispatch,getState:getState},{action:requestUpdateFavorites(productId,mockedDefaultListId),dispatch:dispatch,getState:getState},{action:requestRemoveFavorites(productId,mockedDefaultListId)(dispatch,getState),dispatch:dispatch,getState:getState}]);case 19:_context9.t7=_context9.sent;(0,_context9.t6)(_context9.t7).toBeUndefined();case 21:case"end":return _context9.stop();}},_callee9);})));it('should cancel all redundant requests',/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee10(){var productId;return _regeneratorRuntime.wrap(function _callee10$(_context10){while(1)switch(_context10.prev=_context10.next){case 0:productId='prod1';// Add and remove the same product to make both redundant
18
- _context10.next=3;return invoke(didReceiveFlushFavoritesBuffer$,[{action:requestAddFavorites(productId,mockedDefaultListId),dispatch:dispatch,getState:getState},{action:requestRemoveFavorites(productId,mockedDefaultListId)(dispatch,getState),dispatch:dispatch,getState:getState}]);case 3:expect(dispatch).toHaveBeenCalledTimes(2);expect(dispatch).toHaveBeenCalledWith(cancelRequestSyncFavorites(2,mockedDefaultListId));case 5:case"end":return _context10.stop();}},_callee10);})));it('should filter out duplicated add requests',/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee11(){var productId;return _regeneratorRuntime.wrap(function _callee11$(_context11){while(1)switch(_context11.prev=_context11.next){case 0:productId='prod1';// Add the same product twice
19
- _context11.next=3;return invoke(didReceiveFlushFavoritesBuffer$,[{action:requestAddFavorites(productId,mockedDefaultListId),dispatch:dispatch,getState:getState},{action:requestAddFavorites(productId,mockedDefaultListId),dispatch:dispatch,getState:getState}]);case 3:_context11.next=5;return flushPromises();case 5:// One cancel and one add action call as well as one idle-sync afterwards
20
- expect(addFavorites).toHaveBeenCalledTimes(1);expect(addFavorites.mock.calls[0][0]).toBe(productId);expect(dispatch).toHaveBeenCalledTimes(2);expect(dispatch.mock.calls[0][0]).toEqual(addFavorites());expect(dispatch.mock.calls[1][0]).toEqual(idleSyncFavorites(mockedDefaultListId));case 10:case"end":return _context11.stop();}},_callee11);})));it('should filter out duplicated remove requests',/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee12(){var productId;return _regeneratorRuntime.wrap(function _callee12$(_context12){while(1)switch(_context12.prev=_context12.next){case 0:productId='prod1';// Remove the same product twice
21
- _context12.next=3;return invoke(didReceiveFlushFavoritesBuffer$,[{action:requestRemoveFavorites(productId,mockedDefaultListId)(dispatch,getState),dispatch:dispatch,getState:getState},{action:requestRemoveFavorites(productId,mockedDefaultListId)(dispatch,getState),dispatch:dispatch,getState:getState}]);case 3:_context12.next=5;return flushPromises();case 5:// One cancel and one add action call as well as one idle-sync afterwards
22
- expect(removeFavorites).toHaveBeenCalledTimes(1);expect(removeFavorites.mock.calls[0][0]).toBe(productId);expect(dispatch).toHaveBeenCalledTimes(4);expect(dispatch.mock.calls[2][0]).toEqual(removeFavorites());expect(dispatch.mock.calls[3][0]).toEqual(idleSyncFavorites(mockedDefaultListId));case 10:case"end":return _context12.stop();}},_callee12);})));it('should not filter out unique add or remove requests',/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee13(){return _regeneratorRuntime.wrap(function _callee13$(_context13){while(1)switch(_context13.prev=_context13.next){case 0:_context13.next=2;return invoke(didReceiveFlushFavoritesBuffer$,[{action:requestAddFavorites('prod3',mockedDefaultListId),dispatch:dispatch,getState:getState},{action:requestAddFavorites('prod4',mockedDefaultListId),dispatch:dispatch,getState:getState},{action:requestRemoveFavorites('prod1',mockedDefaultListId)(dispatch,getState),dispatch:dispatch,getState:getState},{action:requestRemoveFavorites('prod2',mockedDefaultListId)(dispatch,getState),dispatch:dispatch,getState:getState}]);case 2:_context13.next=4;return flushPromises();case 4:// Only dispatch add and remove actions, no cancellation
23
- expect(addFavorites).toHaveBeenCalledTimes(2);expect(addFavorites.mock.calls[0][0]).toBe('prod3');expect(addFavorites.mock.calls[1][0]).toBe('prod4');expect(removeFavorites).toHaveBeenCalledTimes(2);expect(removeFavorites.mock.calls[0][0]).toBe('prod1');expect(removeFavorites.mock.calls[1][0]).toBe('prod2');expect(dispatch).toHaveBeenCalledTimes(7);expect(dispatch.mock.calls[2][0]).toEqual(addFavorites());expect(dispatch.mock.calls[3][0]).toEqual(addFavorites());expect(dispatch.mock.calls[4][0]).toEqual(removeFavorites());expect(dispatch.mock.calls[5][0]).toEqual(removeFavorites());expect(dispatch.mock.calls[6][0]).toEqual(idleSyncFavorites(mockedDefaultListId));case 16:case"end":return _context13.stop();}},_callee13);})));it('should filter out duplicated update requests',/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee14(){var productId;return _regeneratorRuntime.wrap(function _callee14$(_context14){while(1)switch(_context14.prev=_context14.next){case 0:productId='prod1';// Add the same product twice
24
- _context14.next=3;return invoke(didReceiveFlushFavoritesBuffer$,[{action:requestUpdateFavorites(productId,mockedDefaultListId,2),dispatch:dispatch,getState:getState},{action:requestUpdateFavorites(productId,mockedDefaultListId,3),dispatch:dispatch,getState:getState}]);case 3:_context14.next=5;return flushPromises();case 5:// One cancel and one add action call as well as one idle-sync afterwards
25
- expect(updateFavorites).toHaveBeenCalledTimes(1);expect(updateFavorites.mock.calls[0][0]).toBe(productId);expect(updateFavorites.mock.calls[0][1]).toBe(mockedDefaultListId);expect(updateFavorites.mock.calls[0][2]).toBe(3);expect(dispatch).toHaveBeenCalledTimes(2);expect(dispatch.mock.calls[0][0]).toEqual(updateFavorites());expect(dispatch.mock.calls[1][0]).toEqual(idleSyncFavorites(mockedDefaultListId));case 12:case"end":return _context14.stop();}},_callee14);})));it('should properly handle conflicts and duplicates when they occur at once',/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee15(){return _regeneratorRuntime.wrap(function _callee15$(_context15){while(1)switch(_context15.prev=_context15.next){case 0:_context15.next=2;return invoke(didReceiveFlushFavoritesBuffer$,[{action:requestAddFavorites('prod3',mockedDefaultListId),dispatch:dispatch,getState:getState},{action:requestAddFavorites('prod4',mockedDefaultListId),dispatch:dispatch,getState:getState},{action:requestAddFavorites('prod4',mockedDefaultListId),// duplicated
26
- dispatch:dispatch,getState:getState},{action:requestRemoveFavorites('prod1',mockedDefaultListId)(dispatch,getState),dispatch:dispatch,getState:getState},{action:requestAddFavorites('prod1',mockedDefaultListId),// conflict
27
- dispatch:dispatch,getState:getState},{action:requestRemoveFavorites('prod2',mockedDefaultListId)(dispatch,getState),dispatch:dispatch,getState:getState}]);case 2:_context15.next=4;return flushPromises();case 4:// Cancel three calls (conflict -> 2 + duplicate -> 1 => 3), handle the rest
28
- expect(addFavorites).toHaveBeenCalledTimes(2);expect(addFavorites.mock.calls[0][0]).toBe('prod3');expect(addFavorites.mock.calls[1][0]).toBe('prod4');expect(removeFavorites).toHaveBeenCalledTimes(1);expect(removeFavorites.mock.calls[0][0]).toBe('prod2');expect(dispatch).toHaveBeenCalledTimes(7);expect(dispatch.mock.calls[2][0]).toEqual(addFavorites());expect(dispatch.mock.calls[3][0]).toEqual(addFavorites());expect(dispatch.mock.calls[4][0]).toEqual(cancelRequestSyncFavorites(2,mockedDefaultListId));expect(dispatch.mock.calls[5][0]).toEqual(removeFavorites());expect(dispatch.mock.calls[6][0]).toEqual(idleSyncFavorites(mockedDefaultListId));case 15:case"end":return _context15.stop();}},_callee15);})));it('should not break on any failing request',/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee17(){return _regeneratorRuntime.wrap(function _callee17$(_context17){while(1)switch(_context17.prev=_context17.next){case 0:dispatch.mockImplementation(/*#__PURE__*/function(){var _ref17=_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee16(action){return _regeneratorRuntime.wrap(function _callee16$(_context16){while(1)switch(_context16.prev=_context16.next){case 0:if(!(action===addFavorites()||action===removeFavorites()||action===updateFavorites())){_context16.next=2;break;}throw new Error('Failed to add/remove favorite');case 2:case"end":return _context16.stop();}},_callee16);}));return function(_x){return _ref17.apply(this,arguments);};}());// Remove the same product twice
29
- _context17.next=3;return expect(invoke(didReceiveFlushFavoritesBuffer$,[{action:requestAddFavorites('prod3'),dispatch:dispatch,getState:getState},{action:requestUpdateFavorites('prod3'),dispatch:dispatch,getState:getState},{action:requestRemoveFavorites('prod1')(dispatch,getState),dispatch:dispatch,getState:getState}])).resolves.toBeUndefined();case 3:case"end":return _context17.stop();}},_callee17);})));it('should dispatch only the requests and one idle-sync if any error occurs',/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee19(){return _regeneratorRuntime.wrap(function _callee19$(_context19){while(1)switch(_context19.prev=_context19.next){case 0:dispatch.mockImplementation(/*#__PURE__*/function(){var _ref19=_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee18(action){return _regeneratorRuntime.wrap(function _callee18$(_context18){while(1)switch(_context18.prev=_context18.next){case 0:if(!(action===addFavorites()||action===updateFavorites()||action===removeFavorites())){_context18.next=2;break;}throw new Error('Failed to add/remove favorite');case 2:if(!(typeof action==='function')){_context18.next=4;break;}return _context18.abrupt("return",action(dispatch,getState));case 4:return _context18.abrupt("return",action);case 5:case"end":return _context18.stop();}},_callee18);}));return function(_x2){return _ref19.apply(this,arguments);};}());// Remove the same product twice
30
- _context19.t0=invoke;_context19.t1=didReceiveFlushFavoritesBuffer$;_context19.t2={action:requestAddFavorites('prod3',mockedDefaultListId),dispatch:dispatch,getState:getState};_context19.t3={action:requestUpdateFavorites('prod2',mockedDefaultListId,3),dispatch:dispatch,getState:getState};_context19.next=7;return requestRemoveFavorites('prod1',mockedDefaultListId)(dispatch,getState);case 7:_context19.t4=_context19.sent;_context19.t5=dispatch;_context19.t6=getState;_context19.t7={action:_context19.t4,dispatch:_context19.t5,getState:_context19.t6};_context19.t8=[_context19.t2,_context19.t3,_context19.t7];_context19.next=14;return(0,_context19.t0)(_context19.t1,_context19.t8);case 14:_context19.next=16;return flushPromises();case 16:expect(dispatch).toHaveBeenCalledTimes(5);expect(dispatch.mock.calls[1][0]).toEqual(addFavorites());expect(dispatch.mock.calls[2][0]).toEqual(updateFavorites());expect(dispatch.mock.calls[3][0]).toEqual(removeFavorites());expect(dispatch.mock.calls[4][0]).toEqual(idleSyncFavorites(mockedDefaultListId));case 21:case"end":return _context19.stop();}},_callee19);})));});});describe('Favorites disabled',function(){it('should not subscribe to anything',function(){var hasFavorites=mockedHasFavorites;mockedHasFavorites=false;favorites(subscribe);expect(getSubscriptionCount()).toBe(0);mockedHasFavorites=hasFavorites;});});});
85
+ */
86
+ const flushPromises = () => new Promise(resolve => setImmediate(resolve));
87
+ describe('Favorites - subscriptions', () => {
88
+ describe('Favorites enabled', () => {
89
+ const pipelineDependenciesSet = pipelineDependencies.set;
90
+ beforeAll(() => {
91
+ // Make sure no conflicting subscriptions exist
92
+ resetSubscriptions();
93
+
94
+ // Replace singleton object property with a mock
95
+ pipelineDependencies.set = jest.fn();
96
+
97
+ // Subscribe all streams
98
+ favorites(subscribe);
99
+ });
100
+ afterAll(() => {
101
+ // Clean up subscriptions
102
+ resetSubscriptions();
103
+
104
+ // Restore singleton
105
+ pipelineDependencies.set = pipelineDependenciesSet;
106
+ });
107
+ const getState = jest.fn().mockReturnValue(() => {});
108
+ // Dispatch always resolves it's promise by default
109
+ const dispatch = jest.fn(result => {
110
+ if (typeof result === 'function') {
111
+ return result(dispatch, getState);
112
+ }
113
+ return result;
114
+ });
115
+ const productIds = ['prod1', 'prod2'];
116
+ const defaultListItems = [{
117
+ quantity: 1,
118
+ notes: null,
119
+ productId: productIds[0]
120
+ }, {
121
+ quantity: 1,
122
+ notes: null,
123
+ productId: productIds[1]
124
+ }];
125
+ beforeEach(() => {
126
+ jest.clearAllMocks();
127
+
128
+ // Reset selector return values
129
+ mockedGetFavoritesProductsIdsReturnValue = productIds;
130
+ mockedGetFavoritesCountReturnValue = productIds.length;
131
+ mockedGetProductRelativesOnFavoritesReturnValue = [];
132
+ mockedGetFavoritesProductsReturnValue = {
133
+ byList: {
134
+ DEFAULT: {
135
+ items: defaultListItems,
136
+ isFetching: false
137
+ }
138
+ }
139
+ };
140
+ mockedMakeGetFavoritesReturnValue = jest.fn().mockReturnValue(defaultListItems);
141
+ });
142
+ describe('appDidStart$', () => {
143
+ it('should subscribe to the stream', () => {
144
+ expect(getSubscriptionCount(appDidStart$)).toBe(1);
145
+ });
146
+ it('should not return any value', async () => {
147
+ await expect(invoke(appDidStart$, {
148
+ dispatch,
149
+ getState
150
+ })).resolves.toBeUndefined();
151
+ });
152
+ it('should set up pipeline dependencies correctly', () => {
153
+ invoke(appDidStart$, {
154
+ dispatch,
155
+ getState
156
+ });
157
+
158
+ // Expect pipeline dependencies to be set correctly
159
+ expect(pipelineDependencies.set).toHaveBeenCalledTimes(2);
160
+ expect(pipelineDependencies.set.mock.calls[0][0]).toBe(SHOPGATE_USER_ADD_FAVORITES);
161
+ expect(pipelineDependencies.set.mock.calls[0][1]).toEqual([SHOPGATE_USER_ADD_FAVORITES, SHOPGATE_USER_DELETE_FAVORITES]);
162
+ expect(pipelineDependencies.set.mock.calls[1][0]).toBe(SHOPGATE_USER_DELETE_FAVORITES);
163
+ expect(pipelineDependencies.set.mock.calls[1][1]).toEqual([SHOPGATE_USER_ADD_FAVORITES, SHOPGATE_USER_DELETE_FAVORITES]);
164
+ });
165
+ it('should fetch favorites', async () => {
166
+ await invoke(appDidStart$, {
167
+ dispatch,
168
+ getState
169
+ });
170
+ expect(fetchFavoritesListsWithItems).toHaveBeenCalledTimes(1);
171
+ expect(fetchFavoritesListsWithItems).toHaveBeenCalledWith(false);
172
+ expect(dispatch).toHaveBeenCalledTimes(3);
173
+ });
174
+ });
175
+ describe('favoritesWillEnter$', () => {
176
+ it('should subscribe to the stream', () => {
177
+ expect(getSubscriptionCount(favoritesWillEnter$)).toBe(1);
178
+ });
179
+ it('should not return any value', async () => {
180
+ expect(await invoke(favoritesWillEnter$, {
181
+ dispatch,
182
+ getState
183
+ })).toBeUndefined();
184
+ });
185
+ it('should handle fetch and map favorites', async () => {
186
+ // eslint-disable-next-line extra-rules/no-single-line-objects
187
+ await invoke(favoritesWillEnter$, {
188
+ dispatch,
189
+ getState
190
+ });
191
+ expect(fetchFavoritesListsWithItems).toHaveBeenCalledTimes(1);
192
+ expect(fetchFavoritesListsWithItems).toHaveBeenCalledWith(true);
193
+ expect(dispatch).toHaveBeenCalledTimes(3);
194
+ });
195
+ });
196
+ describe('shouldFetchFreshFavorites$', () => {
197
+ it('should subscribe to the stream', () => {
198
+ expect(getSubscriptionCount(shouldFetchFreshFavorites$)).toBe(1);
199
+ });
200
+ it('should not return any value', async () => {
201
+ await expect(invoke(shouldFetchFreshFavorites$, {
202
+ dispatch
203
+ })).resolves.toBeUndefined();
204
+ });
205
+ it('should fetch fresh favorites without using the cache', async () => {
206
+ await invoke(shouldFetchFreshFavorites$, {
207
+ dispatch,
208
+ getState
209
+ });
210
+ expect(fetchFavoritesListsWithItems).toHaveBeenCalledTimes(1);
211
+ expect(fetchFavoritesListsWithItems).toHaveBeenCalledWith(true);
212
+ expect(dispatch).toHaveBeenCalledTimes(3);
213
+ });
214
+ });
215
+ describe('addProductToFavoritesDebounced$', () => {
216
+ it('should subscribe to the stream', () => {
217
+ expect(getSubscriptionCount(addProductToFavoritesDebounced$)).toBe(1);
218
+ });
219
+ it('should not return any value', () => {
220
+ expect(invoke(addProductToFavoritesDebounced$, {
221
+ action: addProductToFavorites('prod3'),
222
+ dispatch,
223
+ getState
224
+ })).toBeUndefined();
225
+ });
226
+ it('should cancel the request when the product is already there', () => {
227
+ invoke(addProductToFavoritesDebounced$, {
228
+ action: addProductToFavorites('prod1', mockedDefaultListId),
229
+ dispatch,
230
+ getState
231
+ });
232
+ expect(getState).toHaveBeenCalledTimes(1);
233
+ expect(getFavoritesProducts).toHaveBeenCalledWith(getState());
234
+ expect(getFavoritesProducts).toHaveBeenCalledTimes(1);
235
+ expect(dispatch).toHaveBeenCalledWith(cancelRequestSyncFavorites(0, mockedDefaultListId));
236
+ expect(dispatch).toHaveBeenCalledTimes(1);
237
+ });
238
+ it('should proceed and dispatch an error if the product is not yet on the list and the limit is reached', () => {
239
+ const favoritesLimit = mockedFavoritesLimit;
240
+ const productId = 'prod3';
241
+ mockedFavoritesLimit = 2;
242
+ mockedGetFavoritesCountByListReturnValue = 2;
243
+ invoke(addProductToFavoritesDebounced$, {
244
+ action: addProductToFavorites(productId, 'DEFAULT'),
245
+ dispatch,
246
+ getState
247
+ });
248
+ expect(getState).toHaveBeenCalledTimes(1);
249
+ expect(getFavoritesProducts).toHaveBeenCalledWith(getState());
250
+ expect(getFavoritesProducts).toHaveBeenCalledTimes(1);
251
+ expect(mockedMakeGetFavoritesCountByList).toHaveBeenCalledWith(getState());
252
+ expect(mockedMakeGetFavoritesCountByList).toHaveBeenCalledTimes(1);
253
+ expect(mockedMakeGetFavoritesCountByList).toHaveReturnedWith(mockedGetFavoritesCountByListReturnValue);
254
+ const error = new Error('Limit exceeded');
255
+ error.code = FAVORITES_LIMIT_ERROR;
256
+ expect(dispatch).toHaveBeenCalledWith(errorFavorites(productId, error));
257
+ expect(dispatch).toHaveBeenCalledTimes(1);
258
+ mockedFavoritesLimit = favoritesLimit;
259
+ });
260
+ it('should proceed and dispatch an add request if all is good', () => {
261
+ const productId = 'prod3';
262
+ invoke(addProductToFavoritesDebounced$, {
263
+ action: addProductToFavorites(productId),
264
+ dispatch,
265
+ getState
266
+ });
267
+ expect(getState).toHaveBeenCalledTimes(1);
268
+ expect(getFavoritesProducts).toHaveBeenCalledWith(getState());
269
+ expect(getFavoritesProducts).toHaveBeenCalledTimes(1);
270
+ expect(mockedMakeGetFavoritesCountByList).toHaveBeenCalledWith(getState());
271
+ expect(mockedMakeGetFavoritesCountByList).toHaveBeenCalledTimes(1);
272
+ expect(dispatch).toHaveBeenCalledWith(requestAddFavorites(productId));
273
+ expect(dispatch).toHaveBeenCalledTimes(1);
274
+ });
275
+ });
276
+ describe('updateProductInFavoritesDebounced$', () => {
277
+ it('should subscribe to the stream', () => {
278
+ expect(getSubscriptionCount(updateProductInFavoritesDebounced$)).toBe(1);
279
+ });
280
+ it('should not return any value', () => {
281
+ expect(invoke(updateProductInFavoritesDebounced$, {
282
+ action: updateProductInFavorites('prod3'),
283
+ dispatch,
284
+ getState
285
+ })).toBeUndefined();
286
+ });
287
+ it('should proceed and dispatch an add request if all is good', () => {
288
+ const productId = 'prod3';
289
+ invoke(updateProductInFavoritesDebounced$, {
290
+ action: updateProductInFavorites(productId),
291
+ dispatch,
292
+ getState
293
+ });
294
+ expect(dispatch).toHaveBeenCalledWith(requestUpdateFavorites(productId));
295
+ expect(dispatch).toHaveBeenCalledTimes(1);
296
+ });
297
+ });
298
+ describe('removeProductFromFavoritesDebounced$', () => {
299
+ it('should subscribe to the stream', () => {
300
+ expect(getSubscriptionCount(removeProductFromFavoritesDebounced$)).toBe(1);
301
+ });
302
+ it('should not return any value', () => {
303
+ expect(invoke(removeProductFromFavoritesDebounced$, {
304
+ action: removeProductFromFavorites('prod1', true, mockedDefaultListId),
305
+ dispatch,
306
+ getState
307
+ })).toBeUndefined();
308
+ expect(invoke(removeProductFromFavoritesDebounced$, {
309
+ action: removeProductFromFavorites('prod1', false, mockedDefaultListId),
310
+ dispatch,
311
+ getState
312
+ })).toBeUndefined();
313
+ });
314
+ it('should not do anything if no products are on the list and currently fetching', () => {
315
+ mockedGetFavoritesCountReturnValue = 0;
316
+ mockedGetFavoritesProductsReturnValue.isFetching = true;
317
+ invoke(removeProductFromFavoritesDebounced$, {
318
+ action: removeProductFromFavorites('prod1', false, mockedDefaultListId),
319
+ dispatch,
320
+ getState
321
+ });
322
+ expect(getFavoritesCount).toHaveBeenCalledTimes(1);
323
+ expect(makeGetProductRelativesOnFavorites).toHaveBeenCalledTimes(0);
324
+ expect(getFavoritesProducts).toHaveBeenCalledTimes(1);
325
+ expect(getState).toHaveBeenCalledTimes(2);
326
+ expect(dispatch).toHaveBeenCalledTimes(1);
327
+ });
328
+ it('should idle-sync when no products are on the list and not fetching', () => {
329
+ mockedGetFavoritesCountReturnValue = 0;
330
+ invoke(removeProductFromFavoritesDebounced$, {
331
+ action: removeProductFromFavorites('prod1', false, mockedDefaultListId),
332
+ dispatch,
333
+ getState
334
+ });
335
+ expect(getFavoritesCount).toHaveBeenCalledTimes(1);
336
+ expect(makeGetProductRelativesOnFavorites).toHaveBeenCalledTimes(0);
337
+ expect(getFavoritesProducts).toHaveBeenCalledTimes(1);
338
+ expect(getState).toHaveBeenCalledTimes(2);
339
+ expect(dispatch).toHaveBeenCalledTimes(1);
340
+ expect(dispatch).toHaveBeenCalledWith(idleSyncFavorites(mockedDefaultListId));
341
+ });
342
+ it('should dispatch a remove request for each relative', () => {
343
+ const productId = 'prod0';
344
+ const mock = jest.fn(() => productIds);
345
+ makeGetProductRelativesOnFavorites.mockReturnValueOnce(mock);
346
+ invoke(removeProductFromFavoritesDebounced$, {
347
+ action: removeProductFromFavorites(productId, true, mockedDefaultListId),
348
+ dispatch,
349
+ getState
350
+ });
351
+
352
+ // Expect multiple remove requests to be dispatched
353
+ expect(makeGetProductRelativesOnFavorites).toHaveBeenCalledTimes(1);
354
+ expect(dispatch).toHaveBeenCalledTimes(4);
355
+ expect(dispatch.mock.calls[1][0]).toEqual(requestRemoveFavorites(productIds[0], mockedDefaultListId)(dispatch, getState));
356
+ expect(dispatch.mock.calls[3][0]).toEqual(requestRemoveFavorites(productIds[1], mockedDefaultListId)(dispatch, getState));
357
+ });
358
+ it('should cancel the remove request if the product is not on the list', () => {
359
+ const productId = 'prod0';
360
+ mockedGetProductRelativesOnFavoritesReturnValue = productIds;
361
+ invoke(removeProductFromFavoritesDebounced$, {
362
+ action: removeProductFromFavorites(productId, false, mockedDefaultListId),
363
+ dispatch,
364
+ getState
365
+ });
366
+
367
+ // Don't expect any remove requests to be triggered
368
+ expect(makeGetProductRelativesOnFavorites).toHaveBeenCalledTimes(0);
369
+ expect(dispatch).toHaveBeenCalledTimes(1);
370
+ expect(dispatch).toHaveBeenCalledWith(cancelRequestSyncFavorites(0, mockedDefaultListId));
371
+ });
372
+ it('should request the removal of the single favorite item', () => {
373
+ const productId = 'prod0';
374
+ mockedGetFavoritesProductsReturnValue = {
375
+ byList: {
376
+ DEFAULT: {
377
+ items: [...mockedGetFavoritesProductsReturnValue.byList.DEFAULT.items, {
378
+ productId,
379
+ quantity: 1,
380
+ notes: null
381
+ }]
382
+ }
383
+ }
384
+ };
385
+ const mock = jest.fn(() => productIds);
386
+ makeGetProductRelativesOnFavorites.mockReturnValueOnce(mock);
387
+ invoke(removeProductFromFavoritesDebounced$, {
388
+ action: removeProductFromFavorites(productId, false, mockedDefaultListId),
389
+ dispatch,
390
+ getState
391
+ });
392
+
393
+ // Only one removal request is expected
394
+ expect(makeGetProductRelativesOnFavorites).toHaveBeenCalledTimes(0);
395
+ expect(dispatch).toHaveBeenCalledTimes(2);
396
+ expect(dispatch.mock.calls[1][0]).toEqual(requestRemoveFavorites(productId, mockedDefaultListId)(dispatch, getState));
397
+ });
398
+ });
399
+ describe('errorFavoritesLimit$', () => {
400
+ it('should subscribe to the stream', () => {
401
+ expect(getSubscriptionCount(errorFavoritesLimit$)).toBe(1);
402
+ });
403
+ it('should not return any value', () => {
404
+ expect(invoke(errorFavoritesLimit$, {
405
+ dispatch
406
+ })).toBeUndefined();
407
+ });
408
+ it('should dispatch an action to show a modal', () => {
409
+ invoke(errorFavoritesLimit$, {
410
+ dispatch
411
+ });
412
+ expect(showModal).toHaveBeenCalledTimes(1);
413
+ expect(dispatch).toHaveBeenCalledTimes(1);
414
+ expect(dispatch).toHaveBeenCalledWith(showModal({
415
+ confirm: null,
416
+ dismiss: 'modal.ok',
417
+ title: 'modal.title_error',
418
+ message: 'favorites.error_limit'
419
+ }));
420
+ });
421
+ });
422
+ describe('refreshFavorites$', () => {
423
+ it('should subscribe to the stream', () => {
424
+ expect(getSubscriptionCount(refreshFavorites$)).toBe(1);
425
+ });
426
+ it('should not return any value', async () => {
427
+ await expect(invoke(refreshFavorites$, {
428
+ dispatch,
429
+ action: {
430
+ listId: mockedDefaultListId
431
+ },
432
+ getState
433
+ })).resolves.toBeUndefined();
434
+ });
435
+ it('should refresh favorites by fetching them without using the cache', async () => {
436
+ await invoke(refreshFavorites$, {
437
+ dispatch,
438
+ action: {
439
+ listId: mockedDefaultListId
440
+ },
441
+ getState
442
+ });
443
+ expect(fetchFavorites).toHaveBeenCalledTimes(1);
444
+ expect(dispatch).toHaveBeenCalledTimes(1);
445
+ expect(dispatch).toHaveBeenCalledWith(fetchFavorites(true));
446
+ });
447
+ });
448
+ describe('didReceiveFlushFavoritesBuffer$', () => {
449
+ it('should subscribe to the stream', () => {
450
+ expect(getSubscriptionCount(didReceiveFlushFavoritesBuffer$)).toBe(1);
451
+ });
452
+ it('should not return any value', async () => {
453
+ const productId = 'prod1';
454
+ expect(await invoke(didReceiveFlushFavoritesBuffer$, null)).toBeUndefined();
455
+ expect(await invoke(didReceiveFlushFavoritesBuffer$, [])).toBeUndefined();
456
+ expect(await invoke(didReceiveFlushFavoritesBuffer$, [{
457
+ action: requestAddFavorites(productId, mockedDefaultListId),
458
+ dispatch,
459
+ getState
460
+ }])).toBeUndefined();
461
+ expect(await invoke(didReceiveFlushFavoritesBuffer$, [{
462
+ action: requestAddFavorites(productId, mockedDefaultListId),
463
+ dispatch,
464
+ getState
465
+ }, {
466
+ action: requestUpdateFavorites(productId, mockedDefaultListId),
467
+ dispatch,
468
+ getState
469
+ }, {
470
+ action: requestRemoveFavorites(productId, mockedDefaultListId)(dispatch, getState),
471
+ dispatch,
472
+ getState
473
+ }])).toBeUndefined();
474
+ });
475
+ it('should cancel all redundant requests', async () => {
476
+ const productId = 'prod1';
477
+
478
+ // Add and remove the same product to make both redundant
479
+ await invoke(didReceiveFlushFavoritesBuffer$, [{
480
+ action: requestAddFavorites(productId, mockedDefaultListId),
481
+ dispatch,
482
+ getState
483
+ }, {
484
+ action: requestRemoveFavorites(productId, mockedDefaultListId)(dispatch, getState),
485
+ dispatch,
486
+ getState
487
+ }]);
488
+ expect(dispatch).toHaveBeenCalledTimes(2);
489
+ expect(dispatch).toHaveBeenCalledWith(cancelRequestSyncFavorites(2, mockedDefaultListId));
490
+ });
491
+ it('should filter out duplicated add requests', async () => {
492
+ const productId = 'prod1';
493
+
494
+ // Add the same product twice
495
+ await invoke(didReceiveFlushFavoritesBuffer$, [{
496
+ action: requestAddFavorites(productId, mockedDefaultListId),
497
+ dispatch,
498
+ getState
499
+ }, {
500
+ action: requestAddFavorites(productId, mockedDefaultListId),
501
+ dispatch,
502
+ getState
503
+ }]);
504
+ await flushPromises();
505
+
506
+ // One cancel and one add action call as well as one idle-sync afterwards
507
+ expect(addFavorites).toHaveBeenCalledTimes(1);
508
+ expect(addFavorites.mock.calls[0][0]).toBe(productId);
509
+ expect(dispatch).toHaveBeenCalledTimes(2);
510
+ expect(dispatch.mock.calls[0][0]).toEqual(addFavorites());
511
+ expect(dispatch.mock.calls[1][0]).toEqual(idleSyncFavorites(mockedDefaultListId));
512
+ });
513
+ it('should filter out duplicated remove requests', async () => {
514
+ const productId = 'prod1';
515
+
516
+ // Remove the same product twice
517
+ await invoke(didReceiveFlushFavoritesBuffer$, [{
518
+ action: requestRemoveFavorites(productId, mockedDefaultListId)(dispatch, getState),
519
+ dispatch,
520
+ getState
521
+ }, {
522
+ action: requestRemoveFavorites(productId, mockedDefaultListId)(dispatch, getState),
523
+ dispatch,
524
+ getState
525
+ }]);
526
+ await flushPromises();
527
+
528
+ // One cancel and one add action call as well as one idle-sync afterwards
529
+ expect(removeFavorites).toHaveBeenCalledTimes(1);
530
+ expect(removeFavorites.mock.calls[0][0]).toBe(productId);
531
+ expect(dispatch).toHaveBeenCalledTimes(4);
532
+ expect(dispatch.mock.calls[2][0]).toEqual(removeFavorites());
533
+ expect(dispatch.mock.calls[3][0]).toEqual(idleSyncFavorites(mockedDefaultListId));
534
+ });
535
+ it('should not filter out unique add or remove requests', async () => {
536
+ // Remove the same product twice
537
+ await invoke(didReceiveFlushFavoritesBuffer$, [{
538
+ action: requestAddFavorites('prod3', mockedDefaultListId),
539
+ dispatch,
540
+ getState
541
+ }, {
542
+ action: requestAddFavorites('prod4', mockedDefaultListId),
543
+ dispatch,
544
+ getState
545
+ }, {
546
+ action: requestRemoveFavorites('prod1', mockedDefaultListId)(dispatch, getState),
547
+ dispatch,
548
+ getState
549
+ }, {
550
+ action: requestRemoveFavorites('prod2', mockedDefaultListId)(dispatch, getState),
551
+ dispatch,
552
+ getState
553
+ }]);
554
+ await flushPromises();
555
+
556
+ // Only dispatch add and remove actions, no cancellation
557
+ expect(addFavorites).toHaveBeenCalledTimes(2);
558
+ expect(addFavorites.mock.calls[0][0]).toBe('prod3');
559
+ expect(addFavorites.mock.calls[1][0]).toBe('prod4');
560
+ expect(removeFavorites).toHaveBeenCalledTimes(2);
561
+ expect(removeFavorites.mock.calls[0][0]).toBe('prod1');
562
+ expect(removeFavorites.mock.calls[1][0]).toBe('prod2');
563
+ expect(dispatch).toHaveBeenCalledTimes(7);
564
+ expect(dispatch.mock.calls[2][0]).toEqual(addFavorites());
565
+ expect(dispatch.mock.calls[3][0]).toEqual(addFavorites());
566
+ expect(dispatch.mock.calls[4][0]).toEqual(removeFavorites());
567
+ expect(dispatch.mock.calls[5][0]).toEqual(removeFavorites());
568
+ expect(dispatch.mock.calls[6][0]).toEqual(idleSyncFavorites(mockedDefaultListId));
569
+ });
570
+ it('should filter out duplicated update requests', async () => {
571
+ const productId = 'prod1';
572
+
573
+ // Add the same product twice
574
+ await invoke(didReceiveFlushFavoritesBuffer$, [{
575
+ action: requestUpdateFavorites(productId, mockedDefaultListId, 2),
576
+ dispatch,
577
+ getState
578
+ }, {
579
+ action: requestUpdateFavorites(productId, mockedDefaultListId, 3),
580
+ dispatch,
581
+ getState
582
+ }]);
583
+ await flushPromises();
584
+
585
+ // One cancel and one add action call as well as one idle-sync afterwards
586
+ expect(updateFavorites).toHaveBeenCalledTimes(1);
587
+ expect(updateFavorites.mock.calls[0][0]).toBe(productId);
588
+ expect(updateFavorites.mock.calls[0][1]).toBe(mockedDefaultListId);
589
+ expect(updateFavorites.mock.calls[0][2]).toBe(3);
590
+ expect(dispatch).toHaveBeenCalledTimes(2);
591
+ expect(dispatch.mock.calls[0][0]).toEqual(updateFavorites());
592
+ expect(dispatch.mock.calls[1][0]).toEqual(idleSyncFavorites(mockedDefaultListId));
593
+ });
594
+ it('should properly handle conflicts and duplicates when they occur at once', async () => {
595
+ // Remove the same product twice
596
+ await invoke(didReceiveFlushFavoritesBuffer$, [{
597
+ action: requestAddFavorites('prod3', mockedDefaultListId),
598
+ dispatch,
599
+ getState
600
+ }, {
601
+ action: requestAddFavorites('prod4', mockedDefaultListId),
602
+ dispatch,
603
+ getState
604
+ }, {
605
+ action: requestAddFavorites('prod4', mockedDefaultListId),
606
+ // duplicated
607
+ dispatch,
608
+ getState
609
+ }, {
610
+ action: requestRemoveFavorites('prod1', mockedDefaultListId)(dispatch, getState),
611
+ dispatch,
612
+ getState
613
+ }, {
614
+ action: requestAddFavorites('prod1', mockedDefaultListId),
615
+ // conflict
616
+ dispatch,
617
+ getState
618
+ }, {
619
+ action: requestRemoveFavorites('prod2', mockedDefaultListId)(dispatch, getState),
620
+ dispatch,
621
+ getState
622
+ }]);
623
+ await flushPromises();
624
+
625
+ // Cancel three calls (conflict -> 2 + duplicate -> 1 => 3), handle the rest
626
+ expect(addFavorites).toHaveBeenCalledTimes(2);
627
+ expect(addFavorites.mock.calls[0][0]).toBe('prod3');
628
+ expect(addFavorites.mock.calls[1][0]).toBe('prod4');
629
+ expect(removeFavorites).toHaveBeenCalledTimes(1);
630
+ expect(removeFavorites.mock.calls[0][0]).toBe('prod2');
631
+ expect(dispatch).toHaveBeenCalledTimes(7);
632
+ expect(dispatch.mock.calls[2][0]).toEqual(addFavorites());
633
+ expect(dispatch.mock.calls[3][0]).toEqual(addFavorites());
634
+ expect(dispatch.mock.calls[4][0]).toEqual(cancelRequestSyncFavorites(2, mockedDefaultListId));
635
+ expect(dispatch.mock.calls[5][0]).toEqual(removeFavorites());
636
+ expect(dispatch.mock.calls[6][0]).toEqual(idleSyncFavorites(mockedDefaultListId));
637
+ });
638
+ it('should not break on any failing request', async () => {
639
+ dispatch.mockImplementation(async action => {
640
+ if (action === addFavorites() || action === removeFavorites() || action === updateFavorites()) {
641
+ throw new Error('Failed to add/remove favorite');
642
+ }
643
+ });
644
+
645
+ // Remove the same product twice
646
+ await expect(invoke(didReceiveFlushFavoritesBuffer$, [{
647
+ action: requestAddFavorites('prod3'),
648
+ dispatch,
649
+ getState
650
+ }, {
651
+ action: requestUpdateFavorites('prod3'),
652
+ dispatch,
653
+ getState
654
+ }, {
655
+ action: requestRemoveFavorites('prod1')(dispatch, getState),
656
+ dispatch,
657
+ getState
658
+ }])).resolves.toBeUndefined();
659
+ });
660
+ it('should dispatch only the requests and one idle-sync if any error occurs', async () => {
661
+ dispatch.mockImplementation(async action => {
662
+ if (action === addFavorites() || action === updateFavorites() || action === removeFavorites()) {
663
+ throw new Error('Failed to add/remove favorite');
664
+ }
665
+ if (typeof action === 'function') {
666
+ return action(dispatch, getState);
667
+ }
668
+ return action;
669
+ });
670
+
671
+ // Remove the same product twice
672
+ await invoke(didReceiveFlushFavoritesBuffer$, [{
673
+ action: requestAddFavorites('prod3', mockedDefaultListId),
674
+ dispatch,
675
+ getState
676
+ }, {
677
+ action: requestUpdateFavorites('prod2', mockedDefaultListId, 3),
678
+ dispatch,
679
+ getState
680
+ }, {
681
+ action: await requestRemoveFavorites('prod1', mockedDefaultListId)(dispatch, getState),
682
+ dispatch,
683
+ getState
684
+ }]);
685
+ await flushPromises();
686
+ expect(dispatch).toHaveBeenCalledTimes(5);
687
+ expect(dispatch.mock.calls[1][0]).toEqual(addFavorites());
688
+ expect(dispatch.mock.calls[2][0]).toEqual(updateFavorites());
689
+ expect(dispatch.mock.calls[3][0]).toEqual(removeFavorites());
690
+ expect(dispatch.mock.calls[4][0]).toEqual(idleSyncFavorites(mockedDefaultListId));
691
+ });
692
+ });
693
+ });
694
+ describe('Favorites disabled', () => {
695
+ it('should not subscribe to anything', () => {
696
+ const hasFavorites = mockedHasFavorites;
697
+ mockedHasFavorites = false;
698
+ favorites(subscribe);
699
+ expect(getSubscriptionCount()).toBe(0);
700
+ mockedHasFavorites = hasFavorites;
701
+ });
702
+ });
703
+ });