@shopgate/pwa-common-commerce 7.31.5 → 7.31.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/cart/selectors/spec.js +0 -189
- package/favorites/streams/spec.js +0 -517
- package/favorites/subscriptions/spec.js +0 -702
- package/reviews/action-creators/spec.js +0 -40
- package/reviews/actions/spec.js +0 -255
- package/reviews/reducers/spec.js +0 -214
- package/reviews/selectors/spec.js +0 -100
- package/reviews/streams/spec.js +0 -26
- package/search/helpers/spec.js +0 -19
|
@@ -1,702 +0,0 @@
|
|
|
1
|
-
import { subscribe, invoke, getSubscriptionCount, resetSubscriptions } from '@shopgate/pwa-common/subscriptions/mock';
|
|
2
|
-
import pipelineDependencies from '@shopgate/pwa-core/classes/PipelineDependencies';
|
|
3
|
-
import showModal from '@shopgate/pwa-common/actions/modal/showModal';
|
|
4
|
-
import { appDidStart$ } from '@shopgate/pwa-common/streams';
|
|
5
|
-
import { favoritesWillEnter$, shouldFetchFreshFavorites$, addProductToFavoritesDebounced$, removeProductFromFavoritesDebounced$, didReceiveFlushFavoritesBuffer$, errorFavoritesLimit$, refreshFavorites$, updateProductInFavoritesDebounced$ } from "../streams";
|
|
6
|
-
import favorites from "./index";
|
|
7
|
-
import fetchFavorites from "../actions/fetchFavorites";
|
|
8
|
-
import addFavorites from "../actions/addFavorites";
|
|
9
|
-
import removeFavorites from "../actions/removeFavorites";
|
|
10
|
-
import updateFavorites from "../actions/updateFavorites";
|
|
11
|
-
import { FAVORITES_LIMIT_ERROR } from "../constants";
|
|
12
|
-
import { SHOPGATE_USER_ADD_FAVORITES, SHOPGATE_USER_DELETE_FAVORITES } from "../constants/Pipelines";
|
|
13
|
-
import { addProductToFavorites, removeProductFromFavorites, requestAddFavorites, requestRemoveFavorites, cancelRequestSyncFavorites, errorFavorites, idleSyncFavorites, updateProductInFavorites, requestUpdateFavorites } from "../action-creators";
|
|
14
|
-
import { getFavoritesProducts, getFavoritesCount, makeGetProductRelativesOnFavorites } from "../selectors";
|
|
15
|
-
import fetchFavoritesListsWithItems from "../actions/fetchFavoritesListsWithItems";
|
|
16
|
-
|
|
17
|
-
// Required for custom runner without env-setup
|
|
18
|
-
jest.mock('@shopgate/pwa-core', () => {});
|
|
19
|
-
jest.mock('@shopgate/pwa-common/actions/modal/showModal', () => jest.fn().mockReturnValue('showModal'));
|
|
20
|
-
jest.mock('@shopgate/pwa-common-commerce/product', () => ({
|
|
21
|
-
fetchProductsById: jest.fn()
|
|
22
|
-
}));
|
|
23
|
-
jest.mock('@shopgate/pwa-common/providers', () => ({
|
|
24
|
-
LoadingProvider: {
|
|
25
|
-
setLoading: jest.fn(),
|
|
26
|
-
unsetLoading: jest.fn()
|
|
27
|
-
}
|
|
28
|
-
}));
|
|
29
|
-
const mockedDefaultListId = 'DEFAULT';
|
|
30
|
-
jest.mock("../actions/fetchFavorites", () => jest.fn().mockReturnValue('fetchFavoritesResult'));
|
|
31
|
-
jest.mock("../actions/fetchFavoritesList", () => jest.fn().mockResolvedValue([{
|
|
32
|
-
id: 'DEFAULT',
|
|
33
|
-
name: 'Wish List'
|
|
34
|
-
}]));
|
|
35
|
-
jest.mock("../actions/fetchFavoritesListsWithItems", () => {
|
|
36
|
-
const original = jest.requireActual("../actions/fetchFavoritesListsWithItems");
|
|
37
|
-
return {
|
|
38
|
-
__esModule: true,
|
|
39
|
-
default: jest.fn(original.default)
|
|
40
|
-
};
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
// Mock all used selectors to avoid mocking the store
|
|
44
|
-
let mockedGetFavoritesProductsIdsReturnValue;
|
|
45
|
-
let mockedGetFavoritesCountReturnValue;
|
|
46
|
-
let mockedGetFavoritesCountByListReturnValue;
|
|
47
|
-
let mockedGetFavoritesProductsReturnValue;
|
|
48
|
-
let mockedGetProductRelativesOnFavoritesReturnValue;
|
|
49
|
-
let mockedMakeGetFavoritesReturnValue;
|
|
50
|
-
const mockedMakeGetFavoritesCountByList = jest.fn(() => mockedGetFavoritesCountByListReturnValue || 0);
|
|
51
|
-
jest.mock("../selectors", () => ({
|
|
52
|
-
getFavoritesProductsIds: jest.fn(() => mockedGetFavoritesProductsIdsReturnValue),
|
|
53
|
-
getFavoritesProducts: jest.fn(() => mockedGetFavoritesProductsReturnValue),
|
|
54
|
-
getFavoritesCount: jest.fn(() => mockedGetFavoritesCountReturnValue),
|
|
55
|
-
makeGetFavoritesCountByList: jest.fn(() => mockedMakeGetFavoritesCountByList),
|
|
56
|
-
makeGetFavorites: jest.fn(() => mockedMakeGetFavoritesReturnValue),
|
|
57
|
-
makeGetProductRelativesOnFavorites: jest.fn(() => jest.fn().mockReturnValue(mockedGetProductRelativesOnFavoritesReturnValue)),
|
|
58
|
-
getUseGetFavoriteIdsPipeline: jest.fn().mockReturnValue(false)
|
|
59
|
-
}));
|
|
60
|
-
jest.mock("../actions/addFavorites", () => jest.fn().mockReturnValue('addFavoritesResult'));
|
|
61
|
-
jest.mock("../actions/removeFavorites", () => jest.fn().mockReturnValue('removeFavoritesResult'));
|
|
62
|
-
jest.mock("../actions/updateFavorites", () => jest.fn().mockReturnValue('updateFavoritesResult'));
|
|
63
|
-
let mockedHasFavorites = true;
|
|
64
|
-
let mockedFavoritesLimit = 100;
|
|
65
|
-
jest.mock('@shopgate/pwa-common/helpers/config', () => ({
|
|
66
|
-
get hasFavorites() {
|
|
67
|
-
return mockedHasFavorites;
|
|
68
|
-
},
|
|
69
|
-
get favorites() {
|
|
70
|
-
return {
|
|
71
|
-
limit: mockedFavoritesLimit
|
|
72
|
-
};
|
|
73
|
-
},
|
|
74
|
-
get themeConfig() {
|
|
75
|
-
return {
|
|
76
|
-
colors: {}
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
}));
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Flushes the promise queue.
|
|
83
|
-
* @returns {Promise}
|
|
84
|
-
*/
|
|
85
|
-
const flushPromises = () => new Promise(resolve => queueMicrotask(resolve));
|
|
86
|
-
describe('Favorites - subscriptions', () => {
|
|
87
|
-
describe('Favorites enabled', () => {
|
|
88
|
-
const pipelineDependenciesSet = pipelineDependencies.set;
|
|
89
|
-
beforeAll(() => {
|
|
90
|
-
// Make sure no conflicting subscriptions exist
|
|
91
|
-
resetSubscriptions();
|
|
92
|
-
|
|
93
|
-
// Replace singleton object property with a mock
|
|
94
|
-
pipelineDependencies.set = jest.fn();
|
|
95
|
-
|
|
96
|
-
// Subscribe all streams
|
|
97
|
-
favorites(subscribe);
|
|
98
|
-
});
|
|
99
|
-
afterAll(() => {
|
|
100
|
-
// Clean up subscriptions
|
|
101
|
-
resetSubscriptions();
|
|
102
|
-
|
|
103
|
-
// Restore singleton
|
|
104
|
-
pipelineDependencies.set = pipelineDependenciesSet;
|
|
105
|
-
});
|
|
106
|
-
const getState = jest.fn().mockReturnValue(() => {});
|
|
107
|
-
// Dispatch always resolves it's promise by default
|
|
108
|
-
const dispatch = jest.fn(result => {
|
|
109
|
-
if (typeof result === 'function') {
|
|
110
|
-
return result(dispatch, getState);
|
|
111
|
-
}
|
|
112
|
-
return result;
|
|
113
|
-
});
|
|
114
|
-
const productIds = ['prod1', 'prod2'];
|
|
115
|
-
const defaultListItems = [{
|
|
116
|
-
quantity: 1,
|
|
117
|
-
notes: null,
|
|
118
|
-
productId: productIds[0]
|
|
119
|
-
}, {
|
|
120
|
-
quantity: 1,
|
|
121
|
-
notes: null,
|
|
122
|
-
productId: productIds[1]
|
|
123
|
-
}];
|
|
124
|
-
beforeEach(() => {
|
|
125
|
-
jest.clearAllMocks();
|
|
126
|
-
|
|
127
|
-
// Reset selector return values
|
|
128
|
-
mockedGetFavoritesProductsIdsReturnValue = productIds;
|
|
129
|
-
mockedGetFavoritesCountReturnValue = productIds.length;
|
|
130
|
-
mockedGetProductRelativesOnFavoritesReturnValue = [];
|
|
131
|
-
mockedGetFavoritesProductsReturnValue = {
|
|
132
|
-
byList: {
|
|
133
|
-
DEFAULT: {
|
|
134
|
-
items: defaultListItems,
|
|
135
|
-
isFetching: false
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
mockedMakeGetFavoritesReturnValue = jest.fn().mockReturnValue(defaultListItems);
|
|
140
|
-
});
|
|
141
|
-
describe('appDidStart$', () => {
|
|
142
|
-
it('should subscribe to the stream', () => {
|
|
143
|
-
expect(getSubscriptionCount(appDidStart$)).toBe(1);
|
|
144
|
-
});
|
|
145
|
-
it('should not return any value', async () => {
|
|
146
|
-
await expect(invoke(appDidStart$, {
|
|
147
|
-
dispatch,
|
|
148
|
-
getState
|
|
149
|
-
})).resolves.toBeUndefined();
|
|
150
|
-
});
|
|
151
|
-
it('should set up pipeline dependencies correctly', () => {
|
|
152
|
-
invoke(appDidStart$, {
|
|
153
|
-
dispatch,
|
|
154
|
-
getState
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
// Expect pipeline dependencies to be set correctly
|
|
158
|
-
expect(pipelineDependencies.set).toHaveBeenCalledTimes(2);
|
|
159
|
-
expect(pipelineDependencies.set.mock.calls[0][0]).toBe(SHOPGATE_USER_ADD_FAVORITES);
|
|
160
|
-
expect(pipelineDependencies.set.mock.calls[0][1]).toEqual([SHOPGATE_USER_ADD_FAVORITES, SHOPGATE_USER_DELETE_FAVORITES]);
|
|
161
|
-
expect(pipelineDependencies.set.mock.calls[1][0]).toBe(SHOPGATE_USER_DELETE_FAVORITES);
|
|
162
|
-
expect(pipelineDependencies.set.mock.calls[1][1]).toEqual([SHOPGATE_USER_ADD_FAVORITES, SHOPGATE_USER_DELETE_FAVORITES]);
|
|
163
|
-
});
|
|
164
|
-
it('should fetch favorites', async () => {
|
|
165
|
-
await invoke(appDidStart$, {
|
|
166
|
-
dispatch,
|
|
167
|
-
getState
|
|
168
|
-
});
|
|
169
|
-
expect(fetchFavoritesListsWithItems).toHaveBeenCalledTimes(1);
|
|
170
|
-
expect(fetchFavoritesListsWithItems).toHaveBeenCalledWith(false);
|
|
171
|
-
expect(dispatch).toHaveBeenCalledTimes(3);
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
describe('favoritesWillEnter$', () => {
|
|
175
|
-
it('should subscribe to the stream', () => {
|
|
176
|
-
expect(getSubscriptionCount(favoritesWillEnter$)).toBe(1);
|
|
177
|
-
});
|
|
178
|
-
it('should not return any value', async () => {
|
|
179
|
-
expect(await invoke(favoritesWillEnter$, {
|
|
180
|
-
dispatch,
|
|
181
|
-
getState
|
|
182
|
-
})).toBeUndefined();
|
|
183
|
-
});
|
|
184
|
-
it('should handle fetch and map favorites', async () => {
|
|
185
|
-
// eslint-disable-next-line extra-rules/no-single-line-objects
|
|
186
|
-
await invoke(favoritesWillEnter$, {
|
|
187
|
-
dispatch,
|
|
188
|
-
getState
|
|
189
|
-
});
|
|
190
|
-
expect(fetchFavoritesListsWithItems).toHaveBeenCalledTimes(1);
|
|
191
|
-
expect(fetchFavoritesListsWithItems).toHaveBeenCalledWith(true);
|
|
192
|
-
expect(dispatch).toHaveBeenCalledTimes(3);
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
describe('shouldFetchFreshFavorites$', () => {
|
|
196
|
-
it('should subscribe to the stream', () => {
|
|
197
|
-
expect(getSubscriptionCount(shouldFetchFreshFavorites$)).toBe(1);
|
|
198
|
-
});
|
|
199
|
-
it('should not return any value', async () => {
|
|
200
|
-
await expect(invoke(shouldFetchFreshFavorites$, {
|
|
201
|
-
dispatch
|
|
202
|
-
})).resolves.toBeUndefined();
|
|
203
|
-
});
|
|
204
|
-
it('should fetch fresh favorites without using the cache', async () => {
|
|
205
|
-
await invoke(shouldFetchFreshFavorites$, {
|
|
206
|
-
dispatch,
|
|
207
|
-
getState
|
|
208
|
-
});
|
|
209
|
-
expect(fetchFavoritesListsWithItems).toHaveBeenCalledTimes(1);
|
|
210
|
-
expect(fetchFavoritesListsWithItems).toHaveBeenCalledWith(true);
|
|
211
|
-
expect(dispatch).toHaveBeenCalledTimes(3);
|
|
212
|
-
});
|
|
213
|
-
});
|
|
214
|
-
describe('addProductToFavoritesDebounced$', () => {
|
|
215
|
-
it('should subscribe to the stream', () => {
|
|
216
|
-
expect(getSubscriptionCount(addProductToFavoritesDebounced$)).toBe(1);
|
|
217
|
-
});
|
|
218
|
-
it('should not return any value', () => {
|
|
219
|
-
expect(invoke(addProductToFavoritesDebounced$, {
|
|
220
|
-
action: addProductToFavorites('prod3'),
|
|
221
|
-
dispatch,
|
|
222
|
-
getState
|
|
223
|
-
})).toBeUndefined();
|
|
224
|
-
});
|
|
225
|
-
it('should cancel the request when the product is already there', () => {
|
|
226
|
-
invoke(addProductToFavoritesDebounced$, {
|
|
227
|
-
action: addProductToFavorites('prod1', mockedDefaultListId),
|
|
228
|
-
dispatch,
|
|
229
|
-
getState
|
|
230
|
-
});
|
|
231
|
-
expect(getState).toHaveBeenCalledTimes(1);
|
|
232
|
-
expect(getFavoritesProducts).toHaveBeenCalledWith(getState());
|
|
233
|
-
expect(getFavoritesProducts).toHaveBeenCalledTimes(1);
|
|
234
|
-
expect(dispatch).toHaveBeenCalledWith(cancelRequestSyncFavorites(0, mockedDefaultListId));
|
|
235
|
-
expect(dispatch).toHaveBeenCalledTimes(1);
|
|
236
|
-
});
|
|
237
|
-
it('should proceed and dispatch an error if the product is not yet on the list and the limit is reached', () => {
|
|
238
|
-
const favoritesLimit = mockedFavoritesLimit;
|
|
239
|
-
const productId = 'prod3';
|
|
240
|
-
mockedFavoritesLimit = 2;
|
|
241
|
-
mockedGetFavoritesCountByListReturnValue = 2;
|
|
242
|
-
invoke(addProductToFavoritesDebounced$, {
|
|
243
|
-
action: addProductToFavorites(productId, 'DEFAULT'),
|
|
244
|
-
dispatch,
|
|
245
|
-
getState
|
|
246
|
-
});
|
|
247
|
-
expect(getState).toHaveBeenCalledTimes(1);
|
|
248
|
-
expect(getFavoritesProducts).toHaveBeenCalledWith(getState());
|
|
249
|
-
expect(getFavoritesProducts).toHaveBeenCalledTimes(1);
|
|
250
|
-
expect(mockedMakeGetFavoritesCountByList).toHaveBeenCalledWith(getState());
|
|
251
|
-
expect(mockedMakeGetFavoritesCountByList).toHaveBeenCalledTimes(1);
|
|
252
|
-
expect(mockedMakeGetFavoritesCountByList).toHaveReturnedWith(mockedGetFavoritesCountByListReturnValue);
|
|
253
|
-
const error = new Error('Limit exceeded');
|
|
254
|
-
error.code = FAVORITES_LIMIT_ERROR;
|
|
255
|
-
expect(dispatch).toHaveBeenCalledWith(errorFavorites(productId, error));
|
|
256
|
-
expect(dispatch).toHaveBeenCalledTimes(1);
|
|
257
|
-
mockedFavoritesLimit = favoritesLimit;
|
|
258
|
-
});
|
|
259
|
-
it('should proceed and dispatch an add request if all is good', () => {
|
|
260
|
-
const productId = 'prod3';
|
|
261
|
-
invoke(addProductToFavoritesDebounced$, {
|
|
262
|
-
action: addProductToFavorites(productId),
|
|
263
|
-
dispatch,
|
|
264
|
-
getState
|
|
265
|
-
});
|
|
266
|
-
expect(getState).toHaveBeenCalledTimes(1);
|
|
267
|
-
expect(getFavoritesProducts).toHaveBeenCalledWith(getState());
|
|
268
|
-
expect(getFavoritesProducts).toHaveBeenCalledTimes(1);
|
|
269
|
-
expect(mockedMakeGetFavoritesCountByList).toHaveBeenCalledWith(getState());
|
|
270
|
-
expect(mockedMakeGetFavoritesCountByList).toHaveBeenCalledTimes(1);
|
|
271
|
-
expect(dispatch).toHaveBeenCalledWith(requestAddFavorites(productId));
|
|
272
|
-
expect(dispatch).toHaveBeenCalledTimes(1);
|
|
273
|
-
});
|
|
274
|
-
});
|
|
275
|
-
describe('updateProductInFavoritesDebounced$', () => {
|
|
276
|
-
it('should subscribe to the stream', () => {
|
|
277
|
-
expect(getSubscriptionCount(updateProductInFavoritesDebounced$)).toBe(1);
|
|
278
|
-
});
|
|
279
|
-
it('should not return any value', () => {
|
|
280
|
-
expect(invoke(updateProductInFavoritesDebounced$, {
|
|
281
|
-
action: updateProductInFavorites('prod3'),
|
|
282
|
-
dispatch,
|
|
283
|
-
getState
|
|
284
|
-
})).toBeUndefined();
|
|
285
|
-
});
|
|
286
|
-
it('should proceed and dispatch an add request if all is good', () => {
|
|
287
|
-
const productId = 'prod3';
|
|
288
|
-
invoke(updateProductInFavoritesDebounced$, {
|
|
289
|
-
action: updateProductInFavorites(productId),
|
|
290
|
-
dispatch,
|
|
291
|
-
getState
|
|
292
|
-
});
|
|
293
|
-
expect(dispatch).toHaveBeenCalledWith(requestUpdateFavorites(productId));
|
|
294
|
-
expect(dispatch).toHaveBeenCalledTimes(1);
|
|
295
|
-
});
|
|
296
|
-
});
|
|
297
|
-
describe('removeProductFromFavoritesDebounced$', () => {
|
|
298
|
-
it('should subscribe to the stream', () => {
|
|
299
|
-
expect(getSubscriptionCount(removeProductFromFavoritesDebounced$)).toBe(1);
|
|
300
|
-
});
|
|
301
|
-
it('should not return any value', () => {
|
|
302
|
-
expect(invoke(removeProductFromFavoritesDebounced$, {
|
|
303
|
-
action: removeProductFromFavorites('prod1', true, mockedDefaultListId),
|
|
304
|
-
dispatch,
|
|
305
|
-
getState
|
|
306
|
-
})).toBeUndefined();
|
|
307
|
-
expect(invoke(removeProductFromFavoritesDebounced$, {
|
|
308
|
-
action: removeProductFromFavorites('prod1', false, mockedDefaultListId),
|
|
309
|
-
dispatch,
|
|
310
|
-
getState
|
|
311
|
-
})).toBeUndefined();
|
|
312
|
-
});
|
|
313
|
-
it('should not do anything if no products are on the list and currently fetching', () => {
|
|
314
|
-
mockedGetFavoritesCountReturnValue = 0;
|
|
315
|
-
mockedGetFavoritesProductsReturnValue.isFetching = true;
|
|
316
|
-
invoke(removeProductFromFavoritesDebounced$, {
|
|
317
|
-
action: removeProductFromFavorites('prod1', false, mockedDefaultListId),
|
|
318
|
-
dispatch,
|
|
319
|
-
getState
|
|
320
|
-
});
|
|
321
|
-
expect(getFavoritesCount).toHaveBeenCalledTimes(1);
|
|
322
|
-
expect(makeGetProductRelativesOnFavorites).toHaveBeenCalledTimes(0);
|
|
323
|
-
expect(getFavoritesProducts).toHaveBeenCalledTimes(1);
|
|
324
|
-
expect(getState).toHaveBeenCalledTimes(2);
|
|
325
|
-
expect(dispatch).toHaveBeenCalledTimes(1);
|
|
326
|
-
});
|
|
327
|
-
it('should idle-sync when no products are on the list and not fetching', () => {
|
|
328
|
-
mockedGetFavoritesCountReturnValue = 0;
|
|
329
|
-
invoke(removeProductFromFavoritesDebounced$, {
|
|
330
|
-
action: removeProductFromFavorites('prod1', false, mockedDefaultListId),
|
|
331
|
-
dispatch,
|
|
332
|
-
getState
|
|
333
|
-
});
|
|
334
|
-
expect(getFavoritesCount).toHaveBeenCalledTimes(1);
|
|
335
|
-
expect(makeGetProductRelativesOnFavorites).toHaveBeenCalledTimes(0);
|
|
336
|
-
expect(getFavoritesProducts).toHaveBeenCalledTimes(1);
|
|
337
|
-
expect(getState).toHaveBeenCalledTimes(2);
|
|
338
|
-
expect(dispatch).toHaveBeenCalledTimes(1);
|
|
339
|
-
expect(dispatch).toHaveBeenCalledWith(idleSyncFavorites(mockedDefaultListId));
|
|
340
|
-
});
|
|
341
|
-
it('should dispatch a remove request for each relative', () => {
|
|
342
|
-
const productId = 'prod0';
|
|
343
|
-
const mock = jest.fn(() => productIds);
|
|
344
|
-
makeGetProductRelativesOnFavorites.mockReturnValueOnce(mock);
|
|
345
|
-
invoke(removeProductFromFavoritesDebounced$, {
|
|
346
|
-
action: removeProductFromFavorites(productId, true, mockedDefaultListId),
|
|
347
|
-
dispatch,
|
|
348
|
-
getState
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
// Expect multiple remove requests to be dispatched
|
|
352
|
-
expect(makeGetProductRelativesOnFavorites).toHaveBeenCalledTimes(1);
|
|
353
|
-
expect(dispatch).toHaveBeenCalledTimes(4);
|
|
354
|
-
expect(dispatch.mock.calls[1][0]).toEqual(requestRemoveFavorites(productIds[0], mockedDefaultListId)(dispatch, getState));
|
|
355
|
-
expect(dispatch.mock.calls[3][0]).toEqual(requestRemoveFavorites(productIds[1], mockedDefaultListId)(dispatch, getState));
|
|
356
|
-
});
|
|
357
|
-
it('should cancel the remove request if the product is not on the list', () => {
|
|
358
|
-
const productId = 'prod0';
|
|
359
|
-
mockedGetProductRelativesOnFavoritesReturnValue = productIds;
|
|
360
|
-
invoke(removeProductFromFavoritesDebounced$, {
|
|
361
|
-
action: removeProductFromFavorites(productId, false, mockedDefaultListId),
|
|
362
|
-
dispatch,
|
|
363
|
-
getState
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
// Don't expect any remove requests to be triggered
|
|
367
|
-
expect(makeGetProductRelativesOnFavorites).toHaveBeenCalledTimes(0);
|
|
368
|
-
expect(dispatch).toHaveBeenCalledTimes(1);
|
|
369
|
-
expect(dispatch).toHaveBeenCalledWith(cancelRequestSyncFavorites(0, mockedDefaultListId));
|
|
370
|
-
});
|
|
371
|
-
it('should request the removal of the single favorite item', () => {
|
|
372
|
-
const productId = 'prod0';
|
|
373
|
-
mockedGetFavoritesProductsReturnValue = {
|
|
374
|
-
byList: {
|
|
375
|
-
DEFAULT: {
|
|
376
|
-
items: [].concat(mockedGetFavoritesProductsReturnValue.byList.DEFAULT.items, [{
|
|
377
|
-
productId,
|
|
378
|
-
quantity: 1,
|
|
379
|
-
notes: null
|
|
380
|
-
}])
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
};
|
|
384
|
-
const mock = jest.fn(() => productIds);
|
|
385
|
-
makeGetProductRelativesOnFavorites.mockReturnValueOnce(mock);
|
|
386
|
-
invoke(removeProductFromFavoritesDebounced$, {
|
|
387
|
-
action: removeProductFromFavorites(productId, false, mockedDefaultListId),
|
|
388
|
-
dispatch,
|
|
389
|
-
getState
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
// Only one removal request is expected
|
|
393
|
-
expect(makeGetProductRelativesOnFavorites).toHaveBeenCalledTimes(0);
|
|
394
|
-
expect(dispatch).toHaveBeenCalledTimes(2);
|
|
395
|
-
expect(dispatch.mock.calls[1][0]).toEqual(requestRemoveFavorites(productId, mockedDefaultListId)(dispatch, getState));
|
|
396
|
-
});
|
|
397
|
-
});
|
|
398
|
-
describe('errorFavoritesLimit$', () => {
|
|
399
|
-
it('should subscribe to the stream', () => {
|
|
400
|
-
expect(getSubscriptionCount(errorFavoritesLimit$)).toBe(1);
|
|
401
|
-
});
|
|
402
|
-
it('should not return any value', () => {
|
|
403
|
-
expect(invoke(errorFavoritesLimit$, {
|
|
404
|
-
dispatch
|
|
405
|
-
})).toBeUndefined();
|
|
406
|
-
});
|
|
407
|
-
it('should dispatch an action to show a modal', () => {
|
|
408
|
-
invoke(errorFavoritesLimit$, {
|
|
409
|
-
dispatch
|
|
410
|
-
});
|
|
411
|
-
expect(showModal).toHaveBeenCalledTimes(1);
|
|
412
|
-
expect(dispatch).toHaveBeenCalledTimes(1);
|
|
413
|
-
expect(dispatch).toHaveBeenCalledWith(showModal({
|
|
414
|
-
confirm: null,
|
|
415
|
-
dismiss: 'modal.ok',
|
|
416
|
-
title: 'modal.title_error',
|
|
417
|
-
message: 'favorites.error_limit'
|
|
418
|
-
}));
|
|
419
|
-
});
|
|
420
|
-
});
|
|
421
|
-
describe('refreshFavorites$', () => {
|
|
422
|
-
it('should subscribe to the stream', () => {
|
|
423
|
-
expect(getSubscriptionCount(refreshFavorites$)).toBe(1);
|
|
424
|
-
});
|
|
425
|
-
it('should not return any value', async () => {
|
|
426
|
-
await expect(invoke(refreshFavorites$, {
|
|
427
|
-
dispatch,
|
|
428
|
-
action: {
|
|
429
|
-
listId: mockedDefaultListId
|
|
430
|
-
},
|
|
431
|
-
getState
|
|
432
|
-
})).resolves.toBeUndefined();
|
|
433
|
-
});
|
|
434
|
-
it('should refresh favorites by fetching them without using the cache', async () => {
|
|
435
|
-
await invoke(refreshFavorites$, {
|
|
436
|
-
dispatch,
|
|
437
|
-
action: {
|
|
438
|
-
listId: mockedDefaultListId
|
|
439
|
-
},
|
|
440
|
-
getState
|
|
441
|
-
});
|
|
442
|
-
expect(fetchFavorites).toHaveBeenCalledTimes(1);
|
|
443
|
-
expect(dispatch).toHaveBeenCalledTimes(1);
|
|
444
|
-
expect(dispatch).toHaveBeenCalledWith(fetchFavorites(true));
|
|
445
|
-
});
|
|
446
|
-
});
|
|
447
|
-
describe('didReceiveFlushFavoritesBuffer$', () => {
|
|
448
|
-
it('should subscribe to the stream', () => {
|
|
449
|
-
expect(getSubscriptionCount(didReceiveFlushFavoritesBuffer$)).toBe(1);
|
|
450
|
-
});
|
|
451
|
-
it('should not return any value', async () => {
|
|
452
|
-
const productId = 'prod1';
|
|
453
|
-
expect(await invoke(didReceiveFlushFavoritesBuffer$, null)).toBeUndefined();
|
|
454
|
-
expect(await invoke(didReceiveFlushFavoritesBuffer$, [])).toBeUndefined();
|
|
455
|
-
expect(await invoke(didReceiveFlushFavoritesBuffer$, [{
|
|
456
|
-
action: requestAddFavorites(productId, mockedDefaultListId),
|
|
457
|
-
dispatch,
|
|
458
|
-
getState
|
|
459
|
-
}])).toBeUndefined();
|
|
460
|
-
expect(await invoke(didReceiveFlushFavoritesBuffer$, [{
|
|
461
|
-
action: requestAddFavorites(productId, mockedDefaultListId),
|
|
462
|
-
dispatch,
|
|
463
|
-
getState
|
|
464
|
-
}, {
|
|
465
|
-
action: requestUpdateFavorites(productId, mockedDefaultListId),
|
|
466
|
-
dispatch,
|
|
467
|
-
getState
|
|
468
|
-
}, {
|
|
469
|
-
action: requestRemoveFavorites(productId, mockedDefaultListId)(dispatch, getState),
|
|
470
|
-
dispatch,
|
|
471
|
-
getState
|
|
472
|
-
}])).toBeUndefined();
|
|
473
|
-
});
|
|
474
|
-
it('should cancel all redundant requests', async () => {
|
|
475
|
-
const productId = 'prod1';
|
|
476
|
-
|
|
477
|
-
// Add and remove the same product to make both redundant
|
|
478
|
-
await invoke(didReceiveFlushFavoritesBuffer$, [{
|
|
479
|
-
action: requestAddFavorites(productId, mockedDefaultListId),
|
|
480
|
-
dispatch,
|
|
481
|
-
getState
|
|
482
|
-
}, {
|
|
483
|
-
action: requestRemoveFavorites(productId, mockedDefaultListId)(dispatch, getState),
|
|
484
|
-
dispatch,
|
|
485
|
-
getState
|
|
486
|
-
}]);
|
|
487
|
-
expect(dispatch).toHaveBeenCalledTimes(2);
|
|
488
|
-
expect(dispatch).toHaveBeenCalledWith(cancelRequestSyncFavorites(2, mockedDefaultListId));
|
|
489
|
-
});
|
|
490
|
-
it('should filter out duplicated add requests', async () => {
|
|
491
|
-
const productId = 'prod1';
|
|
492
|
-
|
|
493
|
-
// Add the same product twice
|
|
494
|
-
await invoke(didReceiveFlushFavoritesBuffer$, [{
|
|
495
|
-
action: requestAddFavorites(productId, mockedDefaultListId),
|
|
496
|
-
dispatch,
|
|
497
|
-
getState
|
|
498
|
-
}, {
|
|
499
|
-
action: requestAddFavorites(productId, mockedDefaultListId),
|
|
500
|
-
dispatch,
|
|
501
|
-
getState
|
|
502
|
-
}]);
|
|
503
|
-
await flushPromises();
|
|
504
|
-
|
|
505
|
-
// One cancel and one add action call as well as one idle-sync afterwards
|
|
506
|
-
expect(addFavorites).toHaveBeenCalledTimes(1);
|
|
507
|
-
expect(addFavorites.mock.calls[0][0]).toBe(productId);
|
|
508
|
-
expect(dispatch).toHaveBeenCalledTimes(2);
|
|
509
|
-
expect(dispatch.mock.calls[0][0]).toEqual(addFavorites());
|
|
510
|
-
expect(dispatch.mock.calls[1][0]).toEqual(idleSyncFavorites(mockedDefaultListId));
|
|
511
|
-
});
|
|
512
|
-
it('should filter out duplicated remove requests', async () => {
|
|
513
|
-
const productId = 'prod1';
|
|
514
|
-
|
|
515
|
-
// Remove the same product twice
|
|
516
|
-
await invoke(didReceiveFlushFavoritesBuffer$, [{
|
|
517
|
-
action: requestRemoveFavorites(productId, mockedDefaultListId)(dispatch, getState),
|
|
518
|
-
dispatch,
|
|
519
|
-
getState
|
|
520
|
-
}, {
|
|
521
|
-
action: requestRemoveFavorites(productId, mockedDefaultListId)(dispatch, getState),
|
|
522
|
-
dispatch,
|
|
523
|
-
getState
|
|
524
|
-
}]);
|
|
525
|
-
await flushPromises();
|
|
526
|
-
|
|
527
|
-
// One cancel and one add action call as well as one idle-sync afterwards
|
|
528
|
-
expect(removeFavorites).toHaveBeenCalledTimes(1);
|
|
529
|
-
expect(removeFavorites.mock.calls[0][0]).toBe(productId);
|
|
530
|
-
expect(dispatch).toHaveBeenCalledTimes(4);
|
|
531
|
-
expect(dispatch.mock.calls[2][0]).toEqual(removeFavorites());
|
|
532
|
-
expect(dispatch.mock.calls[3][0]).toEqual(idleSyncFavorites(mockedDefaultListId));
|
|
533
|
-
});
|
|
534
|
-
it('should not filter out unique add or remove requests', async () => {
|
|
535
|
-
// Remove the same product twice
|
|
536
|
-
await invoke(didReceiveFlushFavoritesBuffer$, [{
|
|
537
|
-
action: requestAddFavorites('prod3', mockedDefaultListId),
|
|
538
|
-
dispatch,
|
|
539
|
-
getState
|
|
540
|
-
}, {
|
|
541
|
-
action: requestAddFavorites('prod4', mockedDefaultListId),
|
|
542
|
-
dispatch,
|
|
543
|
-
getState
|
|
544
|
-
}, {
|
|
545
|
-
action: requestRemoveFavorites('prod1', mockedDefaultListId)(dispatch, getState),
|
|
546
|
-
dispatch,
|
|
547
|
-
getState
|
|
548
|
-
}, {
|
|
549
|
-
action: requestRemoveFavorites('prod2', mockedDefaultListId)(dispatch, getState),
|
|
550
|
-
dispatch,
|
|
551
|
-
getState
|
|
552
|
-
}]);
|
|
553
|
-
await flushPromises();
|
|
554
|
-
|
|
555
|
-
// Only dispatch add and remove actions, no cancellation
|
|
556
|
-
expect(addFavorites).toHaveBeenCalledTimes(2);
|
|
557
|
-
expect(addFavorites.mock.calls[0][0]).toBe('prod3');
|
|
558
|
-
expect(addFavorites.mock.calls[1][0]).toBe('prod4');
|
|
559
|
-
expect(removeFavorites).toHaveBeenCalledTimes(2);
|
|
560
|
-
expect(removeFavorites.mock.calls[0][0]).toBe('prod1');
|
|
561
|
-
expect(removeFavorites.mock.calls[1][0]).toBe('prod2');
|
|
562
|
-
expect(dispatch).toHaveBeenCalledTimes(7);
|
|
563
|
-
expect(dispatch.mock.calls[2][0]).toEqual(addFavorites());
|
|
564
|
-
expect(dispatch.mock.calls[3][0]).toEqual(addFavorites());
|
|
565
|
-
expect(dispatch.mock.calls[4][0]).toEqual(removeFavorites());
|
|
566
|
-
expect(dispatch.mock.calls[5][0]).toEqual(removeFavorites());
|
|
567
|
-
expect(dispatch.mock.calls[6][0]).toEqual(idleSyncFavorites(mockedDefaultListId));
|
|
568
|
-
});
|
|
569
|
-
it('should filter out duplicated update requests', async () => {
|
|
570
|
-
const productId = 'prod1';
|
|
571
|
-
|
|
572
|
-
// Add the same product twice
|
|
573
|
-
await invoke(didReceiveFlushFavoritesBuffer$, [{
|
|
574
|
-
action: requestUpdateFavorites(productId, mockedDefaultListId, 2),
|
|
575
|
-
dispatch,
|
|
576
|
-
getState
|
|
577
|
-
}, {
|
|
578
|
-
action: requestUpdateFavorites(productId, mockedDefaultListId, 3),
|
|
579
|
-
dispatch,
|
|
580
|
-
getState
|
|
581
|
-
}]);
|
|
582
|
-
await flushPromises();
|
|
583
|
-
|
|
584
|
-
// One cancel and one add action call as well as one idle-sync afterwards
|
|
585
|
-
expect(updateFavorites).toHaveBeenCalledTimes(1);
|
|
586
|
-
expect(updateFavorites.mock.calls[0][0]).toBe(productId);
|
|
587
|
-
expect(updateFavorites.mock.calls[0][1]).toBe(mockedDefaultListId);
|
|
588
|
-
expect(updateFavorites.mock.calls[0][2]).toBe(3);
|
|
589
|
-
expect(dispatch).toHaveBeenCalledTimes(2);
|
|
590
|
-
expect(dispatch.mock.calls[0][0]).toEqual(updateFavorites());
|
|
591
|
-
expect(dispatch.mock.calls[1][0]).toEqual(idleSyncFavorites(mockedDefaultListId));
|
|
592
|
-
});
|
|
593
|
-
it('should properly handle conflicts and duplicates when they occur at once', async () => {
|
|
594
|
-
// Remove the same product twice
|
|
595
|
-
await invoke(didReceiveFlushFavoritesBuffer$, [{
|
|
596
|
-
action: requestAddFavorites('prod3', mockedDefaultListId),
|
|
597
|
-
dispatch,
|
|
598
|
-
getState
|
|
599
|
-
}, {
|
|
600
|
-
action: requestAddFavorites('prod4', mockedDefaultListId),
|
|
601
|
-
dispatch,
|
|
602
|
-
getState
|
|
603
|
-
}, {
|
|
604
|
-
action: requestAddFavorites('prod4', mockedDefaultListId),
|
|
605
|
-
// duplicated
|
|
606
|
-
dispatch,
|
|
607
|
-
getState
|
|
608
|
-
}, {
|
|
609
|
-
action: requestRemoveFavorites('prod1', mockedDefaultListId)(dispatch, getState),
|
|
610
|
-
dispatch,
|
|
611
|
-
getState
|
|
612
|
-
}, {
|
|
613
|
-
action: requestAddFavorites('prod1', mockedDefaultListId),
|
|
614
|
-
// conflict
|
|
615
|
-
dispatch,
|
|
616
|
-
getState
|
|
617
|
-
}, {
|
|
618
|
-
action: requestRemoveFavorites('prod2', mockedDefaultListId)(dispatch, getState),
|
|
619
|
-
dispatch,
|
|
620
|
-
getState
|
|
621
|
-
}]);
|
|
622
|
-
await flushPromises();
|
|
623
|
-
|
|
624
|
-
// Cancel three calls (conflict -> 2 + duplicate -> 1 => 3), handle the rest
|
|
625
|
-
expect(addFavorites).toHaveBeenCalledTimes(2);
|
|
626
|
-
expect(addFavorites.mock.calls[0][0]).toBe('prod3');
|
|
627
|
-
expect(addFavorites.mock.calls[1][0]).toBe('prod4');
|
|
628
|
-
expect(removeFavorites).toHaveBeenCalledTimes(1);
|
|
629
|
-
expect(removeFavorites.mock.calls[0][0]).toBe('prod2');
|
|
630
|
-
expect(dispatch).toHaveBeenCalledTimes(7);
|
|
631
|
-
expect(dispatch.mock.calls[2][0]).toEqual(addFavorites());
|
|
632
|
-
expect(dispatch.mock.calls[3][0]).toEqual(addFavorites());
|
|
633
|
-
expect(dispatch.mock.calls[4][0]).toEqual(cancelRequestSyncFavorites(2, mockedDefaultListId));
|
|
634
|
-
expect(dispatch.mock.calls[5][0]).toEqual(removeFavorites());
|
|
635
|
-
expect(dispatch.mock.calls[6][0]).toEqual(idleSyncFavorites(mockedDefaultListId));
|
|
636
|
-
});
|
|
637
|
-
it('should not break on any failing request', async () => {
|
|
638
|
-
dispatch.mockImplementation(async action => {
|
|
639
|
-
if (action === addFavorites() || action === removeFavorites() || action === updateFavorites()) {
|
|
640
|
-
throw new Error('Failed to add/remove favorite');
|
|
641
|
-
}
|
|
642
|
-
});
|
|
643
|
-
|
|
644
|
-
// Remove the same product twice
|
|
645
|
-
await expect(invoke(didReceiveFlushFavoritesBuffer$, [{
|
|
646
|
-
action: requestAddFavorites('prod3'),
|
|
647
|
-
dispatch,
|
|
648
|
-
getState
|
|
649
|
-
}, {
|
|
650
|
-
action: requestUpdateFavorites('prod3'),
|
|
651
|
-
dispatch,
|
|
652
|
-
getState
|
|
653
|
-
}, {
|
|
654
|
-
action: requestRemoveFavorites('prod1')(dispatch, getState),
|
|
655
|
-
dispatch,
|
|
656
|
-
getState
|
|
657
|
-
}])).resolves.toBeUndefined();
|
|
658
|
-
});
|
|
659
|
-
it('should dispatch only the requests and one idle-sync if any error occurs', async () => {
|
|
660
|
-
dispatch.mockImplementation(async action => {
|
|
661
|
-
if (action === addFavorites() || action === updateFavorites() || action === removeFavorites()) {
|
|
662
|
-
throw new Error('Failed to add/remove favorite');
|
|
663
|
-
}
|
|
664
|
-
if (typeof action === 'function') {
|
|
665
|
-
return action(dispatch, getState);
|
|
666
|
-
}
|
|
667
|
-
return action;
|
|
668
|
-
});
|
|
669
|
-
|
|
670
|
-
// Remove the same product twice
|
|
671
|
-
await invoke(didReceiveFlushFavoritesBuffer$, [{
|
|
672
|
-
action: requestAddFavorites('prod3', mockedDefaultListId),
|
|
673
|
-
dispatch,
|
|
674
|
-
getState
|
|
675
|
-
}, {
|
|
676
|
-
action: requestUpdateFavorites('prod2', mockedDefaultListId, 3),
|
|
677
|
-
dispatch,
|
|
678
|
-
getState
|
|
679
|
-
}, {
|
|
680
|
-
action: await requestRemoveFavorites('prod1', mockedDefaultListId)(dispatch, getState),
|
|
681
|
-
dispatch,
|
|
682
|
-
getState
|
|
683
|
-
}]);
|
|
684
|
-
await flushPromises();
|
|
685
|
-
expect(dispatch).toHaveBeenCalledTimes(5);
|
|
686
|
-
expect(dispatch.mock.calls[1][0]).toEqual(addFavorites());
|
|
687
|
-
expect(dispatch.mock.calls[2][0]).toEqual(updateFavorites());
|
|
688
|
-
expect(dispatch.mock.calls[3][0]).toEqual(removeFavorites());
|
|
689
|
-
expect(dispatch.mock.calls[4][0]).toEqual(idleSyncFavorites(mockedDefaultListId));
|
|
690
|
-
});
|
|
691
|
-
});
|
|
692
|
-
});
|
|
693
|
-
describe('Favorites disabled', () => {
|
|
694
|
-
it('should not subscribe to anything', () => {
|
|
695
|
-
const hasFavorites = mockedHasFavorites;
|
|
696
|
-
mockedHasFavorites = false;
|
|
697
|
-
favorites(subscribe);
|
|
698
|
-
expect(getSubscriptionCount()).toBe(0);
|
|
699
|
-
mockedHasFavorites = hasFavorites;
|
|
700
|
-
});
|
|
701
|
-
});
|
|
702
|
-
});
|