dyo-tools 0.1.0-rc1

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 (78) hide show
  1. package/.c8rc.json +4 -0
  2. package/.eslintignore +2 -0
  3. package/.eslintrc.json +41 -0
  4. package/Makefile +34 -0
  5. package/README.md +0 -0
  6. package/TODO.md +18 -0
  7. package/babel.config.js +1 -0
  8. package/dist/core/DTBunch.d.ts +32 -0
  9. package/dist/core/DTBunch.js +283 -0
  10. package/dist/core/DTBunch.js.map +1 -0
  11. package/dist/core/DTComponent.d.ts +20 -0
  12. package/dist/core/DTComponent.js +41 -0
  13. package/dist/core/DTComponent.js.map +1 -0
  14. package/dist/core/DTComponentWithMeta.d.ts +9 -0
  15. package/dist/core/DTComponentWithMeta.js +32 -0
  16. package/dist/core/DTComponentWithMeta.js.map +1 -0
  17. package/dist/core/DTElement.d.ts +13 -0
  18. package/dist/core/DTElement.js +46 -0
  19. package/dist/core/DTElement.js.map +1 -0
  20. package/dist/core/DTError.d.ts +13 -0
  21. package/dist/core/DTError.js +28 -0
  22. package/dist/core/DTError.js.map +1 -0
  23. package/dist/core/DTPlayer.d.ts +8 -0
  24. package/dist/core/DTPlayer.js +30 -0
  25. package/dist/core/DTPlayer.js.map +1 -0
  26. package/dist/index.d.ts +6 -0
  27. package/dist/index.js +16 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/tsconfig.tsbuildinfo +1321 -0
  30. package/dist/types/index.d.ts +58 -0
  31. package/dist/types/index.js +15 -0
  32. package/dist/types/index.js.map +1 -0
  33. package/dist/utils/filters.d.ts +6 -0
  34. package/dist/utils/filters.js +39 -0
  35. package/dist/utils/filters.js.map +1 -0
  36. package/docs/.nojekyll +1 -0
  37. package/docs/assets/highlight.css +22 -0
  38. package/docs/assets/icons.css +1043 -0
  39. package/docs/assets/icons.png +0 -0
  40. package/docs/assets/icons@2x.png +0 -0
  41. package/docs/assets/main.js +52 -0
  42. package/docs/assets/search.js +1 -0
  43. package/docs/assets/style.css +1388 -0
  44. package/docs/assets/widgets.png +0 -0
  45. package/docs/assets/widgets@2x.png +0 -0
  46. package/docs/classes/DTBunch.html +265 -0
  47. package/docs/classes/DTComponent.html +49 -0
  48. package/docs/classes/DTComponentWithMeta.html +73 -0
  49. package/docs/classes/DTElement.html +95 -0
  50. package/docs/classes/DTError.html +32 -0
  51. package/docs/classes/DTPlayer.html +86 -0
  52. package/docs/index.html +1 -0
  53. package/docs/modules.html +1 -0
  54. package/jest.config.js +6 -0
  55. package/package.json +41 -0
  56. package/src/core/DTBunch.ts +600 -0
  57. package/src/core/DTComponent.ts +135 -0
  58. package/src/core/DTComponentWithMeta.ts +62 -0
  59. package/src/core/DTElement.ts +96 -0
  60. package/src/core/DTError.ts +78 -0
  61. package/src/core/DTPlayer.ts +57 -0
  62. package/src/index.ts +7 -0
  63. package/src/types/index.ts +76 -0
  64. package/src/utils/filters.ts +64 -0
  65. package/test/core/DTBunch.double.ts +150 -0
  66. package/test/core/DTBunch.spec.ts +1374 -0
  67. package/test/core/DTComponent.double.ts +69 -0
  68. package/test/core/DTComponent.spec.ts +182 -0
  69. package/test/core/DTComponentWithMeta.double.ts +88 -0
  70. package/test/core/DTComponentWithMeta.spec.ts +112 -0
  71. package/test/core/DTElement.double.ts +27 -0
  72. package/test/core/DTElement.spec.ts +181 -0
  73. package/test/core/DTError.double.ts +43 -0
  74. package/test/core/DTError.spec.ts +106 -0
  75. package/test/core/DTPlayer.double.ts +49 -0
  76. package/test/core/DTPlayer.spec.ts +102 -0
  77. package/test/utils/filters.spec.ts +109 -0
  78. package/tsconfig.json +21 -0
@@ -0,0 +1,1374 @@
1
+ import {
2
+ afterAll, afterEach, beforeAll, beforeEach, describe, expect, jest, test,
3
+ } from '@jest/globals';
4
+ import {
5
+ defaultOptions,
6
+ DTBunchMock,
7
+ generateMockedElements,
8
+ HaileiIdTest,
9
+ HaileiKeyTest,
10
+ HaileiToObjectTest,
11
+ IDTest,
12
+ IldressIdTest,
13
+ IldressKeyTest,
14
+ IldressToObjectTest,
15
+ KeyTest,
16
+ MaydenaIdTest,
17
+ MaydenaKeyTest,
18
+ MaydenaToObjectTest,
19
+ MeldrineIdTest,
20
+ MeldrineKeyTest,
21
+ MeldrineToObjectTest,
22
+ YssaliaIdTest,
23
+ YssaliaKeyTest,
24
+ YssaliaToObjectTest,
25
+ } from './DTBunch.double';
26
+ import { DTBunch, DTError } from '../../src';
27
+ import DYOToolsElement from '../../src/core/DTElement';
28
+ import { BunchMetaData, IMetaDataTest } from './DTComponentWithMeta.double';
29
+ import { DTAcceptedMetaDataValue, DTBunchOptionsConstructor } from '../../src/types';
30
+ import {
31
+ DTPlayerStub,
32
+ IDTest as IDPlayerTest,
33
+ KeyTest as KeyPlayerTest,
34
+ toStringTest as toStringPlayerTest,
35
+ } from './DTPlayer.double';
36
+ import { DTErrorStub } from './DTError.double';
37
+ import { validFiltersForItem } from '../../src/utils/filters';
38
+ import { DTComponentTestMock, IDTest as IDContextTest } from './DTComponent.double';
39
+ import Mocked = jest.Mocked;
40
+ import MockedFunction = jest.MockedFunction;
41
+
42
+ describe('class DYOToolsBunch', () => {
43
+ let bunchMock: DTBunchMock;
44
+
45
+ beforeEach(() => {
46
+ bunchMock = new DTBunchMock();
47
+ });
48
+
49
+ afterEach(() => {
50
+ jest.restoreAllMocks();
51
+ });
52
+
53
+ describe('constructor()', () => {
54
+ let mockedAddMany; let
55
+ originalAddMany;
56
+
57
+ beforeAll(() => {
58
+ originalAddMany = DTBunch.prototype.addMany;
59
+ DTBunch.prototype.addMany = jest.fn();
60
+ mockedAddMany = DTBunch.prototype.addMany as MockedFunction<(items: Array<Mocked<DYOToolsElement<IMetaDataTest>>>) => void>;
61
+ });
62
+
63
+ afterAll(() => {
64
+ DTBunch.prototype.addMany = originalAddMany;
65
+ });
66
+
67
+ test('creation simple with key', () => {
68
+ const newBunch = new DTBunch(KeyTest);
69
+ jest.spyOn(newBunch, 'getId').mockImplementation(function () {
70
+ return this._id;
71
+ });
72
+ jest.spyOn(newBunch, 'getKey').mockImplementation(function () {
73
+ return this._key;
74
+ });
75
+ jest.spyOn(newBunch, 'getErrors').mockImplementation(function () {
76
+ return this._errors;
77
+ });
78
+ jest.spyOn(newBunch, 'get').mockImplementation(function (key) {
79
+ return key === 'options' ? this._globalOptions : undefined;
80
+ });
81
+ jest.spyOn(newBunch, 'getAll').mockImplementation(function () {
82
+ return this._items;
83
+ });
84
+
85
+ expect(newBunch.getId()).toBeDefined();
86
+ expect(newBunch.getKey()).toBe(KeyTest);
87
+ expect(newBunch.getErrors()).toStrictEqual([]);
88
+ expect(newBunch.get('options')).toStrictEqual(defaultOptions);
89
+ expect(newBunch.getAll()).toStrictEqual([]);
90
+ });
91
+
92
+ test('creation with items', () => {
93
+ const newBunch = new DTBunch<Mocked<DYOToolsElement<IMetaDataTest>>, {}>(KeyTest, generateMockedElements(3));
94
+ jest.spyOn(newBunch, 'getKey').mockImplementation(function () {
95
+ return this._key;
96
+ });
97
+ jest.spyOn(newBunch, 'getErrors').mockImplementation(function () {
98
+ return this._errors;
99
+ });
100
+ jest.spyOn(newBunch, 'getAll').mockImplementation(function () {
101
+ return this._items;
102
+ });
103
+
104
+ expect(newBunch.getKey()).toBe(KeyTest);
105
+ expect(newBunch.getErrors()).toStrictEqual([]);
106
+ expect(newBunch.getAll()).toStrictEqual([]);
107
+ expect(mockedAddMany.mock.calls.length).toBe(1);
108
+ expect(mockedAddMany.mock.calls[0][0].length).toBe(3);
109
+ expect(mockedAddMany.mock.calls[0][0][0].getKey()).toBe(HaileiKeyTest);
110
+ expect(mockedAddMany.mock.calls[0][0][1].getKey()).toBe(MeldrineKeyTest);
111
+ expect(mockedAddMany.mock.calls[0][0][2].getKey()).toBe(MaydenaKeyTest);
112
+ });
113
+
114
+ test('creations with options', () => {
115
+ const testOptions: Partial<DTBunchOptionsConstructor> = {
116
+ errors: true,
117
+ uniqueKey: true,
118
+ inheritOwner: true,
119
+ };
120
+ const newBunch = new DTBunch<Mocked<DYOToolsElement<IMetaDataTest>>, {}>(KeyTest, [], testOptions);
121
+ jest.spyOn(newBunch, 'get').mockImplementation(function (key) {
122
+ return key === 'options' ? this._globalOptions : undefined;
123
+ });
124
+ jest.spyOn(newBunch, 'getAll').mockImplementation(function () {
125
+ return this._items;
126
+ });
127
+ jest.spyOn(newBunch, 'getKey').mockImplementation(function () {
128
+ return this._key;
129
+ });
130
+ jest.spyOn(newBunch, 'getErrors').mockImplementation(function () {
131
+ return this._errors;
132
+ });
133
+
134
+ expect(newBunch.getKey()).toBe(KeyTest);
135
+ expect(newBunch.getErrors()).toStrictEqual([]);
136
+ expect(newBunch.get('options')).toStrictEqual({
137
+ errors: true,
138
+ uniqueKey: true,
139
+ inheritOwner: true,
140
+ replaceIndex: false,
141
+ virtualContext: false,
142
+ });
143
+ expect(newBunch.getAll()).toStrictEqual([]);
144
+ });
145
+ });
146
+
147
+ describe('_componentType', () => {
148
+ test('componentType must be "bunch"', () => {
149
+ expect(bunchMock.getComponentType()).toBe('bunch');
150
+ });
151
+ });
152
+
153
+ describe('getOwner()', () => {
154
+ test('return empty owner by default', () => {
155
+ expect(bunchMock.getOwner()).toBeUndefined();
156
+ });
157
+
158
+ test('return owner when set', () => {
159
+ const owner = new DTPlayerStub();
160
+ jest.spyOn(bunchMock, 'setOwner').mockImplementation(function (owner) {
161
+ this._owner = owner;
162
+ });
163
+ bunchMock.setOwner(owner);
164
+
165
+ expect(bunchMock.getOwner().getId()).toBe(IDPlayerTest);
166
+ });
167
+ });
168
+
169
+ describe('setOwner()', () => {
170
+ beforeEach(() => {
171
+ jest.spyOn(bunchMock, 'getOwner').mockImplementation(function () {
172
+ return this._owner;
173
+ });
174
+ });
175
+
176
+ test('add a new owner', () => {
177
+ const owner = new DTPlayerStub();
178
+ bunchMock.setOwner(owner);
179
+
180
+ expect(bunchMock.getOwner().getId()).toBe(IDPlayerTest);
181
+ });
182
+
183
+ test('add a new owner - not updating elements owner when inheritOwner = false', () => {
184
+ bunchMock.mockDefineOptions({ inheritOwner: false });
185
+ bunchMock.mockDefineItems(3);
186
+
187
+ const owner = new DTPlayerStub();
188
+ bunchMock.setOwner(owner);
189
+
190
+ expect(bunchMock.getOwner().getId()).toBe(IDPlayerTest);
191
+ expect(bunchMock.mockItemGetter(0).setOwner.mock.calls.length).toBe(0);
192
+ expect(bunchMock.mockItemGetter(1).setOwner.mock.calls.length).toBe(0);
193
+ expect(bunchMock.mockItemGetter(2).setOwner.mock.calls.length).toBe(0);
194
+ });
195
+
196
+ test('add a new owner - updating elements owner when inheritOwner = true', () => {
197
+ bunchMock.mockDefineOptions({ inheritOwner: true });
198
+ bunchMock.mockDefineItems(3);
199
+
200
+ const owner = new DTPlayerStub();
201
+ bunchMock.setOwner(owner);
202
+
203
+ expect(bunchMock.getOwner().getId()).toBe(IDPlayerTest);
204
+ expect(bunchMock.mockItemGetter(0).setOwner.mock.calls.length).toBe(1);
205
+ expect(bunchMock.mockItemGetter(0).setOwner.mock.calls[0][0].getId()).toBe(IDPlayerTest);
206
+ expect(bunchMock.mockItemGetter(1).setOwner.mock.calls.length).toBe(1);
207
+ expect(bunchMock.mockItemGetter(1).setOwner.mock.calls[0][0].getId()).toBe(IDPlayerTest);
208
+ expect(bunchMock.mockItemGetter(2).setOwner.mock.calls.length).toBe(1);
209
+ expect(bunchMock.mockItemGetter(2).setOwner.mock.calls[0][0].getId()).toBe(IDPlayerTest);
210
+ });
211
+ });
212
+
213
+ describe('removeOwner()', () => {
214
+ beforeEach(() => {
215
+ jest.spyOn(bunchMock, 'getOwner').mockImplementation(function () {
216
+ return this._owner;
217
+ });
218
+ jest.spyOn(bunchMock, 'setOwner').mockImplementation(function (owner) {
219
+ this._owner = owner;
220
+ });
221
+ });
222
+
223
+ test('remove current Owner', () => {
224
+ const owner = new DTPlayerStub();
225
+ bunchMock.setOwner(owner);
226
+ bunchMock.removeOwner();
227
+
228
+ expect(bunchMock.getOwner()).toBeUndefined();
229
+ });
230
+
231
+ test('remove current Owner - not updating elements owner when inheritOwner = false', () => {
232
+ bunchMock.mockDefineOptions({ inheritOwner: true });
233
+ bunchMock.mockDefineItems(2);
234
+
235
+ const owner = new DTPlayerStub();
236
+ bunchMock.setOwner(owner);
237
+
238
+ bunchMock.mockDefineOptions({ inheritOwner: false });
239
+ bunchMock.removeOwner();
240
+
241
+ expect(bunchMock.getOwner()).toBeUndefined();
242
+ expect(bunchMock.mockItemGetter(0).removeOwner.mock.calls.length).toBe(0);
243
+ expect(bunchMock.mockItemGetter(1).removeOwner.mock.calls.length).toBe(0);
244
+ });
245
+
246
+ test('remove current Owner - updating elements owner when inheritOwner = true', () => {
247
+ bunchMock.mockDefineOptions({ inheritOwner: true });
248
+ bunchMock.mockDefineItems(2);
249
+
250
+ const owner = new DTPlayerStub();
251
+ bunchMock.setOwner(owner);
252
+
253
+ bunchMock.removeOwner();
254
+
255
+ expect(bunchMock.getOwner()).toBeUndefined();
256
+ expect(bunchMock.mockItemGetter(0).removeOwner.mock.calls.length).toBe(1);
257
+ expect(bunchMock.mockItemGetter(1).removeOwner.mock.calls.length).toBe(1);
258
+ });
259
+ });
260
+
261
+ describe('getErrors()', () => {
262
+ test('return empty errors by default', () => {
263
+ expect(bunchMock.getErrors()).toStrictEqual([]);
264
+ });
265
+
266
+ test('return array of errors if defined', () => {
267
+ const errors = [new DTErrorStub(), new DTErrorStub()];
268
+ bunchMock.mockDefineErrors(errors);
269
+
270
+ expect(bunchMock.getErrors()).toStrictEqual(errors);
271
+ });
272
+ });
273
+
274
+ describe('getLastError()', () => {
275
+ test('return undefined if the bunch has no errors', () => {
276
+ expect(bunchMock.getLastError()).toBeUndefined();
277
+ });
278
+
279
+ test('return the last error', () => {
280
+ const lastError = new DTErrorStub();
281
+ const errors = [new DTErrorStub(), new DTErrorStub(), lastError];
282
+ bunchMock.mockDefineErrors(errors);
283
+
284
+ expect(bunchMock.getLastError().getTimestamp().toString()).toStrictEqual(lastError.getTimestamp().toString());
285
+ });
286
+ });
287
+
288
+ describe('get()', () => {
289
+ beforeEach(() => {
290
+ bunchMock.mockDefineItems(5);
291
+ });
292
+
293
+ test('return an item by its id', () => {
294
+ expect(bunchMock.get(`${MaydenaIdTest}-2`).getKey()).toBe(MaydenaKeyTest);
295
+ expect(bunchMock.get(`${YssaliaIdTest}-4`).getKey()).toBe(YssaliaKeyTest);
296
+ });
297
+
298
+ test('return an item by its index', () => {
299
+ expect(bunchMock.get(2).getKey()).toBe(MaydenaKeyTest);
300
+ expect(bunchMock.get(4).getKey()).toBe(YssaliaKeyTest);
301
+ });
302
+
303
+ test('return undefined if item not found by id', () => {
304
+ expect(bunchMock.get('id-123456')).toBeUndefined();
305
+ });
306
+
307
+ test('return undefined if item not found by index', () => {
308
+ expect(bunchMock.get(11)).toBeUndefined();
309
+ });
310
+
311
+ test('return undefined if item not found by index - incoherent index', () => {
312
+ expect(bunchMock.get(-11)).toBeUndefined();
313
+ });
314
+ });
315
+
316
+ describe('getAll()', () => {
317
+ test('return empty array if no items', () => {
318
+ expect(bunchMock.getAll()).toStrictEqual([]);
319
+ });
320
+
321
+ test('return all items array', () => {
322
+ bunchMock.mockDefineItems(5);
323
+
324
+ expect(bunchMock.getAll()[0].getKey()).toBe(HaileiKeyTest);
325
+ expect(bunchMock.getAll()[1].getKey()).toBe(MeldrineKeyTest);
326
+ expect(bunchMock.getAll()[2].getKey()).toBe(MaydenaKeyTest);
327
+ expect(bunchMock.getAll()[3].getKey()).toBe(IldressKeyTest);
328
+ expect(bunchMock.getAll()[4].getKey()).toBe(YssaliaKeyTest);
329
+ });
330
+ });
331
+
332
+ describe('indexOf()', () => {
333
+ beforeEach(() => {
334
+ bunchMock.mockDefineItems(5);
335
+ });
336
+
337
+ test('return index of an item by id', () => {
338
+ expect(bunchMock.indexOf(`${MaydenaIdTest}-2`)).toBe(2);
339
+ expect(bunchMock.indexOf(`${YssaliaIdTest}-4`)).toBe(4);
340
+ });
341
+
342
+ test('return -1 if id is not found', () => {
343
+ expect(bunchMock.indexOf('id-123456')).toBe(-1);
344
+ });
345
+ });
346
+
347
+ describe('addAtIndex()', () => {
348
+ let objectToAdd;
349
+ let objectsToAdd;
350
+
351
+ const checkErrorCall = (code, message, initiatorId, convictedId) => {
352
+ expect(DTError).toHaveBeenCalled();
353
+ expect((DTError as any).mock.calls.length).toBe(1);
354
+ expect((DTError as any).mock.calls[0][0]).toBe(code);
355
+ expect((DTError as any).mock.calls[0][1]).toBe(message);
356
+ expect((DTError as any).mock.calls[0][2].getId()).toBe(initiatorId);
357
+ expect((DTError as any).mock.calls[0][3].getId()).toBe(convictedId);
358
+ };
359
+
360
+ beforeEach(() => {
361
+ (DTError as any).mockReset();
362
+ jest.spyOn(bunchMock, 'getErrors').mockImplementation(function () {
363
+ return this._errors;
364
+ });
365
+ jest.spyOn(bunchMock, 'getOwner').mockImplementation(function () {
366
+ return this._owner;
367
+ });
368
+ jest.spyOn(bunchMock, 'setOwner').mockImplementation(function (owner) {
369
+ this._owner = owner;
370
+ });
371
+
372
+ bunchMock.mockDefineItems(5);
373
+ bunchMock.mockDefineOptions({
374
+ replaceIndex: false,
375
+ errors: false,
376
+ uniqueKey: false,
377
+ virtualContext: false,
378
+ inheritOwner: false,
379
+ });
380
+
381
+ objectsToAdd = generateMockedElements(6);
382
+ objectToAdd = objectsToAdd[5];
383
+ jest.spyOn(bunchMock, 'find').mockReturnValue([objectToAdd]);
384
+ });
385
+
386
+ test('add a new item at last index - simple case', () => {
387
+ bunchMock.addAtIndex(objectToAdd, 5);
388
+ expect(bunchMock.mockItemGetter(5).getId()).toBe(objectToAdd.getId());
389
+ });
390
+
391
+ test('add a new item at specified index and reindex - default case', () => {
392
+ bunchMock.addAtIndex(objectToAdd, 2);
393
+
394
+ expect(bunchMock.mockItemGetter(2).getId()).toBe(objectToAdd.getId());
395
+ expect(bunchMock.mockItemGetter(3).getId()).toBe(`${MaydenaIdTest}-2`);
396
+ expect(bunchMock.mockItemGetter(4).getId()).toBe(`${IldressIdTest}-3`);
397
+ expect(bunchMock.mockItemGetter(5).getId()).toBe(`${YssaliaIdTest}-4`);
398
+ });
399
+
400
+ test('add a new item at specified index and replace - replace option', () => {
401
+ bunchMock.addAtIndex(objectToAdd, 2, { replaceIndex: true });
402
+ expect(bunchMock.mockItemGetter(2).getId()).toBe(objectToAdd.getId());
403
+ expect(bunchMock.mockItemGetter(3).getId()).toBe(`${IldressIdTest}-3`);
404
+ expect(bunchMock.mockItemGetter(4).getId()).toBe(`${YssaliaIdTest}-4`);
405
+ expect(bunchMock.mockItemGetter(5)).toBeUndefined();
406
+ });
407
+
408
+ test('add a new item at lower index', () => {
409
+ bunchMock.addAtIndex(objectToAdd, -11);
410
+ expect(bunchMock.mockItemGetter(0).getId()).toBe(objectToAdd.getId());
411
+ expect(bunchMock.mockItemGetter(1).getId()).toBe(`${HaileiIdTest}-0`);
412
+ });
413
+
414
+ test('add a new item at greater index', () => {
415
+ bunchMock.addAtIndex(objectToAdd, 11);
416
+ expect(bunchMock.mockItemGetter(5).getId()).toBe(objectToAdd.getId());
417
+ expect(bunchMock.mockItemGetter(6)).toBeUndefined();
418
+ });
419
+
420
+ test('trigger conflict when adding two same ids - default exception errors', () => {
421
+ let errorThrown;
422
+ try {
423
+ bunchMock.addAtIndex(objectsToAdd[0], 2);
424
+ } catch (error) {
425
+ errorThrown = error;
426
+ }
427
+
428
+ expect(errorThrown).toBeDefined();
429
+ checkErrorCall(
430
+ 'id_conflict',
431
+ 'Element with same id already exists in the bunch',
432
+ IDTest,
433
+ objectsToAdd[0].getId(),
434
+ );
435
+ expect(bunchMock.mockItemGetter(2).getId()).toBe(`${MaydenaIdTest}-2`);
436
+ });
437
+
438
+ test('trigger conflict when adding two same ids - stack errors', () => {
439
+ jest.spyOn(bunchMock, 'getErrors').mockImplementation(function () {
440
+ return this._errors;
441
+ });
442
+
443
+ bunchMock.addAtIndex(objectsToAdd[0], 2, { errors: true });
444
+ const errors = bunchMock.getErrors();
445
+
446
+ expect(errors.length).toBe(1);
447
+ checkErrorCall(
448
+ 'id_conflict',
449
+ 'Element with same id already exists in the bunch',
450
+ IDTest,
451
+ objectsToAdd[0].getId(),
452
+ );
453
+ expect(bunchMock.mockItemGetter(2).getId()).toBe(`${MaydenaIdTest}-2`);
454
+ });
455
+
456
+ test('no conflict when adding two same keys - default case', () => {
457
+ let errorThrown;
458
+ try {
459
+ bunchMock.addAtIndex(objectToAdd, 2);
460
+ } catch (error) {
461
+ errorThrown = error;
462
+ }
463
+
464
+ expect(errorThrown).toBeUndefined();
465
+ expect((bunchMock.find as any).mock.calls.length).toBe(0);
466
+ expect(bunchMock.mockItemGetter(0).getKey()).toBe(HaileiKeyTest);
467
+ expect(bunchMock.mockItemGetter(2).getKey()).toBe(HaileiKeyTest);
468
+ });
469
+
470
+ test('trigger conflict when adding two same keys - uniqueKey option and exception errors', () => {
471
+ let errorThrown;
472
+ try {
473
+ bunchMock.addAtIndex(objectToAdd, 2, { uniqueKey: true });
474
+ } catch (error) {
475
+ errorThrown = error;
476
+ }
477
+
478
+ expect(errorThrown).toBeDefined();
479
+ checkErrorCall(
480
+ 'key_conflict',
481
+ 'Element with same key already exists in the bunch',
482
+ IDTest,
483
+ objectToAdd.getId(),
484
+ );
485
+ expect((bunchMock.find as any).mock.calls.length).toBe(1);
486
+ expect((bunchMock.find as any).mock.calls[0][0]).toStrictEqual({ key: { $eq: objectToAdd.getKey() } });
487
+ expect(bunchMock.mockItemGetter(2).getId()).toBe(`${MaydenaIdTest}-2`);
488
+ });
489
+
490
+ test('trigger conflict when adding two same keys - uniqueKey option and stack errors', () => {
491
+ bunchMock.addAtIndex(objectToAdd, 2, { errors: true, uniqueKey: true });
492
+ jest.spyOn(bunchMock, 'getErrors').mockImplementation(function () {
493
+ return this._errors;
494
+ });
495
+
496
+ const errors = bunchMock.getErrors();
497
+
498
+ expect(errors.length).toBe(1);
499
+ checkErrorCall(
500
+ 'key_conflict',
501
+ 'Element with same key already exists in the bunch',
502
+ IDTest,
503
+ objectToAdd.getId(),
504
+ );
505
+ expect(bunchMock.mockItemGetter(2).getId()).toBe(`${MaydenaIdTest}-2`);
506
+ });
507
+
508
+ test('not inherit owner when adding an item - default case', () => {
509
+ const owner = new DTPlayerStub();
510
+ bunchMock.setOwner(owner);
511
+ bunchMock.addAtIndex(objectToAdd, 2);
512
+
513
+ expect(bunchMock.getOwner().getId()).toBe(IDPlayerTest);
514
+ expect(objectToAdd.setOwner.mock.calls.length).toBe(0);
515
+ });
516
+
517
+ test('inherit owner when adding an item - inheritOwner option', () => {
518
+ const owner = new DTPlayerStub();
519
+ bunchMock.setOwner(owner);
520
+ bunchMock.addAtIndex(objectToAdd, 2, { inheritOwner: true });
521
+
522
+ expect(bunchMock.getOwner().getId()).toBe(IDPlayerTest);
523
+ expect(objectToAdd.setOwner.mock.calls.length).toBe(1);
524
+ expect(objectToAdd.setOwner.mock.calls[0][0].getId()).toBe(IDPlayerTest);
525
+ });
526
+
527
+ test('set context when adding an item - default case', () => {
528
+ bunchMock.addAtIndex(objectToAdd, 2);
529
+
530
+ expect(bunchMock.mockItemGetter(2).setContext.mock.calls.length).toBe(1);
531
+ expect(bunchMock.mockItemGetter(2).setContext.mock.calls[0][0].getId()).toBe(IDTest);
532
+ });
533
+
534
+ test('not set context when adding an item - virtualContext option', () => {
535
+ bunchMock.mockDefineOptions({ virtualContext: true });
536
+ bunchMock.addAtIndex(objectToAdd, 2);
537
+
538
+ expect(bunchMock.mockItemGetter(2).setContext.mock.calls.length).toBe(0);
539
+ });
540
+
541
+ test('set context when adding an item - remove from old bunch', () => {
542
+ const bunchMockOld = new DTBunchMock();
543
+ bunchMockOld.mockDefineItems(6);
544
+ objectToAdd = bunchMockOld.mockItemGetter(5);
545
+ objectToAdd.setContext(bunchMockOld);
546
+ objectToAdd.setContext.mockClear();
547
+ jest.spyOn(bunchMockOld, 'remove').mockImplementation(() => {});
548
+
549
+ bunchMock.addAtIndex(objectToAdd, 2);
550
+
551
+ expect(bunchMock.mockItemGetter(2).setContext.mock.calls.length).toBe(1);
552
+ expect(bunchMock.mockItemGetter(2).setContext.mock.calls[0][0].getId()).toBe(IDTest);
553
+ expect((bunchMockOld.remove as any).mock.calls.length).toBe(1);
554
+ expect((bunchMockOld.remove as any).mock.calls[0][0]).toBe(objectToAdd.getId());
555
+ });
556
+
557
+ test('set context when adding an item - dont remove if virtualContext option', () => {
558
+ const bunchMockOld = new DTBunchMock();
559
+ bunchMockOld.mockDefineItems(6);
560
+ objectToAdd = bunchMockOld.mockItemGetter(5);
561
+ jest.spyOn(bunchMockOld, 'remove').mockImplementation(() => {});
562
+
563
+ bunchMock.mockDefineOptions({ virtualContext: true });
564
+ bunchMock.addAtIndex(objectToAdd, 2);
565
+
566
+ expect(bunchMock.mockItemGetter(2).setContext.mock.calls.length).toBe(0);
567
+ expect((bunchMockOld.remove as any).mock.calls.length).toBe(0);
568
+ });
569
+ });
570
+
571
+ describe('add()', () => {
572
+ let objectsToAdd;
573
+ let objectToAdd;
574
+
575
+ beforeEach(() => {
576
+ jest.spyOn(bunchMock, 'addAtIndex').mockImplementation(() => {});
577
+
578
+ bunchMock.mockDefineItems(5);
579
+
580
+ objectsToAdd = generateMockedElements(6);
581
+ objectToAdd = objectsToAdd[5];
582
+ });
583
+
584
+ test('add as last item using addAtIndex', () => {
585
+ const testBunchOptions = {
586
+ replaceIndex: true,
587
+ inheritOwner: true,
588
+ };
589
+ bunchMock.add(objectToAdd, testBunchOptions);
590
+
591
+ expect((bunchMock.addAtIndex as any).mock.calls.length).toBe(1);
592
+ expect((bunchMock.addAtIndex as any).mock.calls[0][0].getId()).toBe(objectToAdd.getId());
593
+ expect((bunchMock.addAtIndex as any).mock.calls[0][1]).toBe(5);
594
+ expect((bunchMock.addAtIndex as any).mock.calls[0][2]).toStrictEqual(testBunchOptions);
595
+ });
596
+ });
597
+
598
+ describe('addManyAtIndex()', () => {
599
+ let itemsToAdd;
600
+ let itemLibrary;
601
+
602
+ beforeEach(() => {
603
+ (DTError as any).mockReset();
604
+ jest.spyOn(bunchMock, 'addAtIndex').mockImplementation(() => {});
605
+
606
+ bunchMock.mockDefineItems(5);
607
+
608
+ itemLibrary = generateMockedElements(8);
609
+ itemsToAdd = [itemLibrary[5], itemLibrary[6], itemLibrary[7]];
610
+ });
611
+
612
+ test('add many items at index using addAtIndex - simple case', () => {
613
+ const testBunchOptions = {
614
+ replaceIndex: true,
615
+ inheritOwner: true,
616
+ };
617
+ const indexToAdd = 2;
618
+ bunchMock.addManyAtIndex(itemsToAdd, indexToAdd, testBunchOptions);
619
+
620
+ expect((bunchMock.addAtIndex as any).mock.calls.length).toBe(3);
621
+ for (let i = 0; i < 3; i++) {
622
+ expect((bunchMock.addAtIndex as any).mock.calls[i][0].getId()).toBe(itemsToAdd[i].getId());
623
+ expect((bunchMock.addAtIndex as any).mock.calls[i][1]).toBe(i + indexToAdd);
624
+ expect((bunchMock.addAtIndex as any).mock.calls[i][2]).toStrictEqual(testBunchOptions);
625
+ }
626
+ });
627
+
628
+ test('add many items at index using addAtIndex - index lower than 0', () => {
629
+ const indexToAdd = -11;
630
+ bunchMock.addManyAtIndex(itemsToAdd, indexToAdd);
631
+
632
+ expect((bunchMock.addAtIndex as any).mock.calls.length).toBe(3);
633
+ for (let i = 0; i < 3; i++) {
634
+ expect((bunchMock.addAtIndex as any).mock.calls[i][0].getId()).toBe(itemsToAdd[i].getId());
635
+ expect((bunchMock.addAtIndex as any).mock.calls[i][1]).toBe(i);
636
+ }
637
+ });
638
+
639
+ test('errors when adding many items at index - default case - add no items and throw error', () => {
640
+ const indexToAdd = 2;
641
+ let errorThrown;
642
+ jest.spyOn(bunchMock, 'addAtIndex').mockImplementation(function (item, index, options) {
643
+ if (item.getKey() !== MeldrineKeyTest) {
644
+ throw new DTError('test_error', `Item ${item.getId()}`);
645
+ } else {
646
+ this._items[index] = item;
647
+ }
648
+ });
649
+
650
+ try {
651
+ bunchMock.addManyAtIndex(itemsToAdd, indexToAdd);
652
+ } catch (error) {
653
+ errorThrown = error;
654
+ }
655
+
656
+ expect(errorThrown).toBeDefined();
657
+ expect(DTError).toHaveBeenCalled();
658
+ expect((DTError as any).mock.calls.length).toBe(1);
659
+ expect((DTError as any).mock.calls[0][0]).toBe('test_error');
660
+ expect((DTError as any).mock.calls[0][1]).toBe(`Item ${itemsToAdd[0].getId()}`);
661
+ expect((bunchMock.addAtIndex as any).mock.calls.length).toBe(1);
662
+ expect((bunchMock.addAtIndex as any).mock.calls[0][0].getId()).toBe(itemsToAdd[0].getId());
663
+ expect((bunchMock.addAtIndex as any).mock.calls[0][1]).toBe(indexToAdd);
664
+ expect(bunchMock.mockItemGetter(2).getKey()).not.toBe(MeldrineKeyTest);
665
+ });
666
+
667
+ test('errors when adding many items at index - errors case - add success items and stack errors for others', () => {
668
+ const indexToAdd = 2;
669
+ jest.spyOn(bunchMock, 'addAtIndex').mockImplementation(function (item, index, options) {
670
+ if (item.getKey() !== MeldrineKeyTest) {
671
+ this._errors.push(new DTError('test_error', `Item ${item.getId()}`));
672
+ }
673
+ });
674
+ jest.spyOn(bunchMock, 'getErrors').mockImplementation(function () {
675
+ return this._errors;
676
+ });
677
+
678
+ bunchMock.addManyAtIndex(itemsToAdd, indexToAdd, { errors: true });
679
+ const errors = bunchMock.getErrors();
680
+
681
+ expect(errors.length).toBe(2);
682
+ expect(DTError).toHaveBeenCalled();
683
+ expect((DTError as any).mock.calls.length).toBe(2);
684
+ expect((DTError as any).mock.calls[0][0]).toBe('test_error');
685
+ expect((DTError as any).mock.calls[0][1]).toBe(`Item ${itemsToAdd[0].getId()}`);
686
+ expect((DTError as any).mock.calls[1][0]).toBe('test_error');
687
+ expect((DTError as any).mock.calls[1][1]).toBe(`Item ${itemsToAdd[2].getId()}`);
688
+ expect((bunchMock.addAtIndex as any).mock.calls.length).toBe(3);
689
+ });
690
+ });
691
+
692
+ describe('addMany()', () => {
693
+ let itemsToAdd;
694
+ let itemLibrary;
695
+
696
+ beforeEach(() => {
697
+ jest.spyOn(bunchMock, 'addManyAtIndex').mockImplementation(() => {});
698
+
699
+ bunchMock.mockDefineItems(5);
700
+
701
+ itemLibrary = generateMockedElements(8);
702
+ itemsToAdd = [itemLibrary[5], itemLibrary[6], itemLibrary[7]];
703
+ });
704
+
705
+ test('add many items as last item using addManyAtIndex', () => {
706
+ const testBunchOptions = {
707
+ replaceIndex: true,
708
+ inheritOwner: true,
709
+ };
710
+ bunchMock.addMany(itemsToAdd, testBunchOptions);
711
+
712
+ expect((bunchMock.addManyAtIndex as any).mock.calls.length).toBe(1);
713
+ expect((bunchMock.addManyAtIndex as any).mock.calls[0][0].length).toBe(3);
714
+ expect((bunchMock.addManyAtIndex as any).mock.calls[0][0][0].getId()).toBe(`${HaileiIdTest}-5`);
715
+ expect((bunchMock.addManyAtIndex as any).mock.calls[0][0][1].getId()).toBe(`${MeldrineIdTest}-6`);
716
+ expect((bunchMock.addManyAtIndex as any).mock.calls[0][0][2].getId()).toBe(`${MaydenaIdTest}-7`);
717
+ expect((bunchMock.addManyAtIndex as any).mock.calls[0][1]).toBe(5);
718
+ expect((bunchMock.addManyAtIndex as any).mock.calls[0][2]).toStrictEqual(testBunchOptions);
719
+ });
720
+ });
721
+
722
+ describe('removeMany()', () => {
723
+ const checkAllItemsInBunch = (bunch: DTBunchMock, itemRemoved = 3) => {
724
+ const sup = itemRemoved;
725
+ expect(bunchMock.getAll().length).toBe(5 - sup);
726
+ expect(bunchMock.mockItemGetter(0).getId()).toBe(`${HaileiIdTest}-0`);
727
+ itemRemoved < 1 && expect(bunchMock.mockItemGetter(1 - sup).getId()).toBe(`${MeldrineIdTest}-1`);
728
+ itemRemoved < 2 && expect(bunchMock.mockItemGetter(2 - sup).getId()).toBe(`${MaydenaIdTest}-2`);
729
+ itemRemoved < 3 && expect(bunchMock.mockItemGetter(3 - sup).getId()).toBe(`${IldressIdTest}-3`);
730
+ expect(bunchMock.mockItemGetter(4 - sup).getId()).toBe(`${YssaliaIdTest}-4`);
731
+ };
732
+
733
+ beforeEach(() => {
734
+ jest.spyOn(bunchMock, 'getAll').mockImplementation(function () {
735
+ return this._items;
736
+ });
737
+ jest.spyOn(bunchMock, 'removeContext').mockImplementation(() => {});
738
+
739
+ bunchMock.mockDefineItems(5);
740
+ });
741
+
742
+ test('remove many items by ids', () => {
743
+ bunchMock.removeMany([`${MeldrineIdTest}-1`, `${MaydenaIdTest}-2`, `${IldressIdTest}-3`]);
744
+
745
+ checkAllItemsInBunch(bunchMock);
746
+ });
747
+
748
+ test('remove many items by indexes', () => {
749
+ bunchMock.removeMany([1, 2, 3]);
750
+
751
+ checkAllItemsInBunch(bunchMock);
752
+ });
753
+
754
+ test('remove only item with corresponding ids', () => {
755
+ bunchMock.removeMany([`${MeldrineIdTest}-1`, `${MaydenaIdTest}-2`, 'id-12345']);
756
+
757
+ checkAllItemsInBunch(bunchMock, 2);
758
+ });
759
+
760
+ test('remove only item with corresponding indexes', () => {
761
+ bunchMock.removeMany([1, 2, 11]);
762
+
763
+ checkAllItemsInBunch(bunchMock, 2);
764
+ });
765
+
766
+ test('remove only item with corresponding indexes - incoherent index', () => {
767
+ bunchMock.removeMany([-11, 2, 1, -13]);
768
+
769
+ checkAllItemsInBunch(bunchMock, 2);
770
+ });
771
+
772
+ test('define context at undefined for removed items - default case', () => {
773
+ const items = [
774
+ bunchMock.mockItemGetter(1),
775
+ bunchMock.mockItemGetter(2),
776
+ ];
777
+
778
+ bunchMock.removeMany([`${MeldrineIdTest}-1`, `${MaydenaIdTest}-2`]);
779
+ items.push(bunchMock.mockItemGetter(0));
780
+ items.push(bunchMock.mockItemGetter(1));
781
+ bunchMock.removeMany([0, 1]);
782
+
783
+ expect(items[0].removeContext.mock.calls.length).toBe(1);
784
+ expect(items[1].removeContext.mock.calls.length).toBe(1);
785
+ expect(items[2].removeContext.mock.calls.length).toBe(1);
786
+ expect(items[3].removeContext.mock.calls.length).toBe(1);
787
+ });
788
+
789
+ test('not change context for removed items - virtual context option', () => {
790
+ const items = [
791
+ bunchMock.mockItemGetter(1),
792
+ bunchMock.mockItemGetter(2),
793
+ ];
794
+ bunchMock.mockDefineOptions({ virtualContext: true });
795
+ bunchMock.removeMany([`${MeldrineIdTest}-1`, `${MaydenaIdTest}-2`]);
796
+ items.push(bunchMock.mockItemGetter(0));
797
+ items.push(bunchMock.mockItemGetter(1));
798
+ bunchMock.removeMany([0, 1]);
799
+
800
+ expect(items[0].removeContext.mock.calls.length).toBe(0);
801
+ expect(items[1].removeContext.mock.calls.length).toBe(0);
802
+ expect(items[2].removeContext.mock.calls.length).toBe(0);
803
+ expect(items[3].removeContext.mock.calls.length).toBe(0);
804
+ });
805
+ });
806
+
807
+ describe('remove()', () => {
808
+ beforeEach(() => {
809
+ jest.spyOn(bunchMock, 'removeMany').mockImplementation(() => {
810
+ });
811
+
812
+ bunchMock.mockDefineItems(5);
813
+ });
814
+
815
+ test('remove one item by id using removeMany', () => {
816
+ bunchMock.remove(`${MaydenaIdTest}-2`);
817
+
818
+ expect((bunchMock.removeMany as any).mock.calls.length).toBe(1);
819
+ expect((bunchMock.removeMany as any).mock.calls[0][0]).toStrictEqual([`${MaydenaIdTest}-2`]);
820
+ });
821
+
822
+ test('remove one item by index using removeMany', () => {
823
+ bunchMock.remove(2);
824
+
825
+ expect((bunchMock.removeMany as any).mock.calls.length).toBe(1);
826
+ expect((bunchMock.removeMany as any).mock.calls[0][0]).toStrictEqual([2]);
827
+ });
828
+ });
829
+
830
+ describe('removeAll()', () => {
831
+ beforeEach(() => {
832
+ jest.spyOn(bunchMock, 'removeMany').mockImplementation(() => {
833
+ });
834
+
835
+ bunchMock.mockDefineItems(5);
836
+ });
837
+
838
+ test('remove all items using removeMany', () => {
839
+ bunchMock.removeAll();
840
+
841
+ expect((bunchMock.removeMany as any).mock.calls.length).toBe(1);
842
+ expect((bunchMock.removeMany as any).mock.calls[0][0]).toStrictEqual([0, 1, 2, 3, 4]);
843
+ });
844
+ });
845
+
846
+ describe('find()', () => {
847
+ const validFiltersForItemMockFn = validFiltersForItem as MockedFunction<typeof validFiltersForItem>;
848
+ const checkItemFound = (items) => {
849
+ expect(items.length).toBe(3);
850
+ expect(items[0].getId()).toBe(`${HaileiIdTest}-0`);
851
+ expect(items[1].getId()).toBe(`${MaydenaIdTest}-2`);
852
+ expect(items[2].getId()).toBe(`${YssaliaIdTest}-4`);
853
+ };
854
+ const generateFiltersCallsResponse = (filters): any => {
855
+ const items = generateMockedElements(5);
856
+ let nbCalls = 0;
857
+ let itemCount = 0;
858
+ let inversion = false;
859
+ const response = { nbCalls: 0, callsData: [] };
860
+ validFiltersForItemMockFn.mockReturnValue(true);
861
+
862
+ for (const item of items) {
863
+ for (const prop of Object.keys(filters)) {
864
+ let itemProp: DTAcceptedMetaDataValue = '';
865
+ let operators = { fake: filters[prop] };
866
+ if (prop === 'id') {
867
+ itemProp = item.getId();
868
+ } else if (prop === 'key') {
869
+ itemProp = item.getKey();
870
+ } else if (prop === 'owner') {
871
+ itemProp = itemCount % 2 ? null : IDPlayerTest;
872
+ } else if (prop === 'context') {
873
+ itemProp = itemCount % 2 ? IDContextTest : null;
874
+ } else if (prop === 'meta') {
875
+ operators = filters[prop];
876
+ }
877
+
878
+ let metaBreakerLoop = false;
879
+ for (const metaKey of Object.keys(operators)) {
880
+ if (prop === 'meta') {
881
+ itemProp = item.getManyMeta()[metaKey];
882
+ }
883
+ if (metaBreakerLoop) {
884
+ break;
885
+ }
886
+
887
+ for (const operator of Object.keys(operators[metaKey])) {
888
+ response.callsData.push([
889
+ itemProp, filters[prop][operator], operator,
890
+ ]);
891
+
892
+ if (!(itemCount % 2)) {
893
+ validFiltersForItemMockFn.mockReturnValueOnce(true);
894
+ } else {
895
+ validFiltersForItemMockFn.mockReturnValueOnce(inversion);
896
+ if (inversion === false) {
897
+ if (prop === 'meta') {
898
+ metaBreakerLoop = true;
899
+ }
900
+ break;
901
+ }
902
+ inversion = !inversion;
903
+ }
904
+ nbCalls++;
905
+ }
906
+ }
907
+ }
908
+
909
+ itemCount++;
910
+ inversion = false;
911
+ }
912
+
913
+ response.nbCalls = nbCalls;
914
+ return response;
915
+ };
916
+
917
+ beforeEach(() => {
918
+ bunchMock.mockDefineItems(5);
919
+
920
+ bunchMock.mockItemGetter(0).setOwner(new DTPlayerStub());
921
+ bunchMock.mockItemGetter(1).setContext(new DTComponentTestMock());
922
+ bunchMock.mockItemGetter(2).setOwner(new DTPlayerStub());
923
+ bunchMock.mockItemGetter(3).setContext(new DTComponentTestMock());
924
+ bunchMock.mockItemGetter(4).setOwner(new DTPlayerStub());
925
+ });
926
+
927
+ afterEach(() => {
928
+ validFiltersForItemMockFn.mockReset();
929
+ });
930
+
931
+ test('find items by id - $eq case', () => {
932
+ const filters = { id: { $eq: 'filter-id' } };
933
+ const expectedResponseCalls = generateFiltersCallsResponse(filters);
934
+ const itemsFound = bunchMock.find(filters);
935
+
936
+ expect(expectedResponseCalls).toStrictEqual(expectedResponseCalls);
937
+ checkItemFound(itemsFound);
938
+ });
939
+
940
+ test('find items by id - all valid operators', () => {
941
+ const filters = {
942
+ id: {
943
+ $eq: 'filter-id',
944
+ $in: ['filter-id', '12345'],
945
+ $nin: [false, 12345],
946
+ $ne: 'filter-id',
947
+ },
948
+ };
949
+ const expectedResponseCalls = generateFiltersCallsResponse(filters);
950
+ const itemsFound = bunchMock.find(filters);
951
+
952
+ expect(expectedResponseCalls).toStrictEqual(expectedResponseCalls);
953
+ checkItemFound(itemsFound);
954
+ });
955
+
956
+ test('find items by key - one operator $eq', () => {
957
+ const filters = { key: { $eq: 'filter-key' } };
958
+ const expectedResponseCalls = generateFiltersCallsResponse(filters);
959
+ const itemsFound = bunchMock.find(filters);
960
+
961
+ expect(expectedResponseCalls).toStrictEqual(expectedResponseCalls);
962
+ checkItemFound(itemsFound);
963
+ });
964
+
965
+ test('find items by key - all valid operators', () => {
966
+ const filters = {
967
+ key: {
968
+ $eq: 'filter-key',
969
+ $in: ['filter-key', '12345'],
970
+ $nin: [false, 12345],
971
+ $ne: 'filter-key',
972
+ },
973
+ };
974
+ const expectedResponseCalls = generateFiltersCallsResponse(filters);
975
+ const itemsFound = bunchMock.find(filters);
976
+
977
+ expect(expectedResponseCalls).toStrictEqual(expectedResponseCalls);
978
+ checkItemFound(itemsFound);
979
+ });
980
+
981
+ test('find items by owner - $eq case', () => {
982
+ const filters = { owner: { $eq: 'filter-owner-id' } };
983
+ const expectedResponseCalls = generateFiltersCallsResponse(filters);
984
+ const itemsFound = bunchMock.find(filters);
985
+
986
+ expect(expectedResponseCalls).toStrictEqual(expectedResponseCalls);
987
+ checkItemFound(itemsFound);
988
+ });
989
+
990
+ test('find items by owner - all valid operators', () => {
991
+ const filters = {
992
+ owner: {
993
+ $eq: 'filter-owner-id',
994
+ $in: ['filter-owner-id', '12345'],
995
+ $nin: [null, 12345],
996
+ $ne: 'filter-owner-id',
997
+ },
998
+ };
999
+ const expectedResponseCalls = generateFiltersCallsResponse(filters);
1000
+ const itemsFound = bunchMock.find(filters);
1001
+
1002
+ expect(expectedResponseCalls).toStrictEqual(expectedResponseCalls);
1003
+ checkItemFound(itemsFound);
1004
+ });
1005
+
1006
+ test('find items by context - $eq case', () => {
1007
+ const filters = { id: { $eq: 'filter-context-id' } };
1008
+ const expectedResponseCalls = generateFiltersCallsResponse(filters);
1009
+ const itemsFound = bunchMock.find(filters);
1010
+
1011
+ expect(expectedResponseCalls).toStrictEqual(expectedResponseCalls);
1012
+ checkItemFound(itemsFound);
1013
+ });
1014
+
1015
+ test('find items by context - all valid operators', () => {
1016
+ const filters = {
1017
+ context: {
1018
+ $eq: 'filter-context-id',
1019
+ $in: ['filter-context-id', '12345'],
1020
+ $nin: [null, 12345],
1021
+ $ne: 'filter-context-id',
1022
+ },
1023
+ };
1024
+ const expectedResponseCalls = generateFiltersCallsResponse(filters);
1025
+ const itemsFound = bunchMock.find(filters);
1026
+
1027
+ expect(expectedResponseCalls).toStrictEqual(expectedResponseCalls);
1028
+ checkItemFound(itemsFound);
1029
+ });
1030
+
1031
+ test('find items by meta - one meta with one operator $eq', () => {
1032
+ const filters = { meta: { name: { $eq: 'filter-meta-name' } } };
1033
+ const expectedResponseCalls = generateFiltersCallsResponse(filters);
1034
+ const itemsFound = bunchMock.find(filters);
1035
+
1036
+ expect(expectedResponseCalls).toStrictEqual(expectedResponseCalls);
1037
+ checkItemFound(itemsFound);
1038
+ });
1039
+
1040
+ test('find items by meta - several meta with one operator $eq', () => {
1041
+ const filters = {
1042
+ meta: {
1043
+ name: { $eq: 'filter-meta-name' },
1044
+ queen: { $eq: false },
1045
+ rank: { $eq: 13 },
1046
+ },
1047
+ };
1048
+ const expectedResponseCalls = generateFiltersCallsResponse(filters);
1049
+ const itemsFound = bunchMock.find(filters);
1050
+
1051
+ expect(expectedResponseCalls).toStrictEqual(expectedResponseCalls);
1052
+ checkItemFound(itemsFound);
1053
+ });
1054
+
1055
+ test('find items by meta - one meta with all valid operators', () => {
1056
+ const filters = {
1057
+ meta: {
1058
+ rank: {
1059
+ $eq: 5,
1060
+ $in: [5, 11],
1061
+ $nin: [2, 3],
1062
+ $ne: 11,
1063
+ $lte: 17,
1064
+ $gte: 3,
1065
+ $contains: 5,
1066
+ $ncontains: 11,
1067
+ },
1068
+ },
1069
+ };
1070
+ const expectedResponseCalls = generateFiltersCallsResponse(filters);
1071
+ const itemsFound = bunchMock.find(filters);
1072
+
1073
+ expect(expectedResponseCalls).toStrictEqual(expectedResponseCalls);
1074
+ checkItemFound(itemsFound);
1075
+ });
1076
+
1077
+ test('find items by meta - several meta with several operators', () => {
1078
+ const filters = {
1079
+ meta: {
1080
+ name: {
1081
+ $eq: 'filter-meta-name',
1082
+ $in: ['filter-meta-name', '12345'],
1083
+ $ne: null,
1084
+ },
1085
+ kd: {
1086
+ $contains: 0,
1087
+ $ncontains: 53,
1088
+ },
1089
+ rank: {
1090
+ $lte: 17,
1091
+ $gte: 3,
1092
+ },
1093
+ },
1094
+ };
1095
+ const expectedResponseCalls = generateFiltersCallsResponse(filters);
1096
+ const itemsFound = bunchMock.find(filters);
1097
+
1098
+ expect(expectedResponseCalls).toStrictEqual(expectedResponseCalls);
1099
+ checkItemFound(itemsFound);
1100
+ });
1101
+
1102
+ test('find items by meta - all props with several operators', () => {
1103
+ const filters = {
1104
+ id: {
1105
+ $eq: 'filter-id',
1106
+ },
1107
+ key: {
1108
+ $eq: 'filter-key',
1109
+ $in: ['filter-key', '12345'],
1110
+ },
1111
+ owner: {
1112
+ $nin: [null, 12345],
1113
+ $ne: 'filter-owner-id',
1114
+ },
1115
+ context: {
1116
+ $in: ['filter-context-id', '12345'],
1117
+ $nin: [null, 12345],
1118
+ $ne: 'filter-context-id',
1119
+ },
1120
+ meta: {
1121
+ name: {
1122
+ $eq: 'filter-meta-name',
1123
+ $in: ['filter-meta-name', '12345'],
1124
+ $ne: null,
1125
+ },
1126
+ kd: {
1127
+ $contains: 0,
1128
+ $ncontains: 53,
1129
+ },
1130
+ rank: {
1131
+ $lte: 17,
1132
+ $gte: 3,
1133
+ },
1134
+ },
1135
+ };
1136
+ const expectedResponseCalls = generateFiltersCallsResponse(filters);
1137
+ const itemsFound = bunchMock.find(filters);
1138
+
1139
+ expect(expectedResponseCalls).toStrictEqual(expectedResponseCalls);
1140
+ checkItemFound(itemsFound);
1141
+ });
1142
+
1143
+ test('find items by meta - empty filters (return empty array)', () => {
1144
+ const filters = {};
1145
+ const itemsFound = bunchMock.find(filters);
1146
+
1147
+ expect(itemsFound.length).toBe(0);
1148
+ expect(validFiltersForItemMockFn.mock.calls.length).toBe(0);
1149
+
1150
+ validFiltersForItemMockFn.mockReset();
1151
+ const filters2 = {
1152
+ id: {},
1153
+ key: {},
1154
+ owner: {},
1155
+ context: {},
1156
+ meta: {},
1157
+ };
1158
+ const itemsFound2 = bunchMock.find(filters2);
1159
+
1160
+ expect(itemsFound2.length).toBe(0);
1161
+ expect(validFiltersForItemMockFn.mock.calls.length).toBe(0);
1162
+ });
1163
+ });
1164
+
1165
+ describe('copy()', () => {
1166
+ test('copy a bunch - simple case with id and key', () => {
1167
+ // This test doesn't mock the DOC (Depended-on Component) correctly
1168
+ // Need to change implementation to implement correct testing
1169
+ const bunchMockCopy = bunchMock.copy();
1170
+ jest.spyOn(bunchMock, 'getId').mockImplementation(function () {
1171
+ return this._id;
1172
+ });
1173
+ jest.spyOn(bunchMockCopy, 'getId').mockImplementation(function () {
1174
+ return this._id;
1175
+ });
1176
+ jest.spyOn(bunchMock, 'getKey').mockImplementation(function () {
1177
+ return this._key;
1178
+ });
1179
+ jest.spyOn(bunchMockCopy, 'getKey').mockImplementation(function () {
1180
+ return this._key;
1181
+ });
1182
+
1183
+ expect(bunchMock.getId() === bunchMockCopy.getId()).toBeFalsy();
1184
+ expect(bunchMock.getKey() === bunchMockCopy.getKey()).toBeTruthy();
1185
+ });
1186
+
1187
+ test('copy a bunch - not copy owner and context', () => {
1188
+ // This test doesn't mock the DOC (Depended-on Component) correctly
1189
+ // Need to change implementation to implement correct testing
1190
+ jest.spyOn(bunchMock, 'setContext').mockImplementation(function (context) {
1191
+ this._context = context;
1192
+ });
1193
+ jest.spyOn(bunchMock, 'setOwner').mockImplementation(function (owner) {
1194
+ this._owner = owner;
1195
+ });
1196
+
1197
+ bunchMock.setContext(new DTComponentTestMock());
1198
+ bunchMock.setOwner(new DTPlayerStub());
1199
+
1200
+ const bunchMockCopy = bunchMock.copy();
1201
+ jest.spyOn(bunchMockCopy, 'getContext').mockImplementation(function () {
1202
+ return this._context;
1203
+ });
1204
+ jest.spyOn(bunchMockCopy, 'getOwner').mockImplementation(function () {
1205
+ return this._owner;
1206
+ });
1207
+
1208
+ expect(bunchMockCopy.getContext()).toBeUndefined();
1209
+ expect(bunchMockCopy.getOwner()).toBeUndefined();
1210
+ });
1211
+
1212
+ test('copy a bunch - copy meta-data and globalOptions', () => {
1213
+ // This test doesn't mock the DOC (Depended-on Component) correctly
1214
+ // Need to change implementation to implement correct testing
1215
+ bunchMock.setManyMeta({});
1216
+ const copiedOptions: Partial<DTBunchOptionsConstructor> = {
1217
+ inheritOwner: true,
1218
+ replaceIndex: true,
1219
+ virtualContext: true,
1220
+ };
1221
+ bunchMock.mockDefineOptions(copiedOptions);
1222
+
1223
+ const bunchMockCopy = bunchMock.copy();
1224
+ jest.spyOn(bunchMockCopy, 'getManyMeta').mockImplementation(function () {
1225
+ return this._meta;
1226
+ });
1227
+ jest.spyOn(bunchMockCopy, 'get').mockImplementation(function (key) {
1228
+ return key === 'options' ? this._globalOptions : undefined;
1229
+ });
1230
+
1231
+ expect(bunchMockCopy.getManyMeta()).toStrictEqual(BunchMetaData);
1232
+ expect(bunchMockCopy.get('options')).toStrictEqual({
1233
+ ...defaultOptions,
1234
+ ...copiedOptions,
1235
+ });
1236
+ });
1237
+
1238
+ test('copy a bunch - empty errors', () => {
1239
+ // This test doesn't mock the DOC (Depended-on Component) correctly
1240
+ // Need to change implementation to implement correct testing
1241
+ const errors = [new DTErrorStub(), new DTErrorStub()];
1242
+ bunchMock.mockDefineErrors(errors);
1243
+
1244
+ const bunchMockCopy = bunchMock.copy();
1245
+ jest.spyOn(bunchMockCopy, 'getErrors').mockImplementation(function () {
1246
+ return this._errors;
1247
+ });
1248
+
1249
+ expect(bunchMockCopy.getErrors().length).toBe(0);
1250
+ });
1251
+
1252
+ test('copy a bunch with items - default case', () => {
1253
+ // This test doesn't mock the DOC (Depended-on Component) correctly
1254
+ // Need to change implementation to implement correct testing
1255
+ bunchMock.mockDefineItems(5);
1256
+
1257
+ const bunchMockCopy = bunchMock.copy();
1258
+ jest.spyOn(bunchMockCopy, 'getAll').mockImplementation(function () {
1259
+ return this._items;
1260
+ });
1261
+
1262
+ const items = bunchMockCopy.getAll();
1263
+
1264
+ expect(items.length).toBe(5);
1265
+ expect(bunchMock.mockItemGetter(0).copy.mock.calls.length).toBe(1);
1266
+ expect(bunchMock.mockItemGetter(1).copy.mock.calls.length).toBe(1);
1267
+ expect(bunchMock.mockItemGetter(2).copy.mock.calls.length).toBe(1);
1268
+ expect(bunchMock.mockItemGetter(3).copy.mock.calls.length).toBe(1);
1269
+ expect(bunchMock.mockItemGetter(4).copy.mock.calls.length).toBe(1);
1270
+ });
1271
+
1272
+ test('copy a bunch with items - virtual context case', () => {
1273
+ // This test doesn't mock the DOC (Depended-on Component) correctly
1274
+ // Need to change implementation to implement correct testing
1275
+ bunchMock.mockDefineItems(5);
1276
+ bunchMock.mockDefineOptions({ virtualContext: true });
1277
+
1278
+ const bunchMockCopy = bunchMock.copy();
1279
+ jest.spyOn(bunchMockCopy, 'getAll').mockImplementation(function () {
1280
+ return this._items;
1281
+ });
1282
+
1283
+ const items = bunchMockCopy.getAll();
1284
+
1285
+ expect(items.length).toBe(5);
1286
+ expect(bunchMock.mockItemGetter(0).copy.mock.calls.length).toBe(0);
1287
+ expect(bunchMock.mockItemGetter(1).copy.mock.calls.length).toBe(0);
1288
+ expect(bunchMock.mockItemGetter(2).copy.mock.calls.length).toBe(0);
1289
+ expect(bunchMock.mockItemGetter(3).copy.mock.calls.length).toBe(0);
1290
+ expect(bunchMock.mockItemGetter(4).copy.mock.calls.length).toBe(0);
1291
+ });
1292
+ });
1293
+
1294
+ describe('toObject()', () => {
1295
+ test('toObject output standard', () => {
1296
+ const toObjectBunch = bunchMock.toObject();
1297
+
1298
+ expect(Object.keys(toObjectBunch)).toStrictEqual(['id', 'key', 'type', 'items']);
1299
+ expect(toObjectBunch.id).toBe(IDTest);
1300
+ expect(toObjectBunch.key).toBe(KeyTest);
1301
+ expect(toObjectBunch.type).toBe('bunch');
1302
+ expect(toObjectBunch.items.length).toBe(0);
1303
+ });
1304
+
1305
+ test('toObject output standard with owner', () => {
1306
+ jest.spyOn(bunchMock, 'setOwner').mockImplementation(function (owner) {
1307
+ this._owner = owner;
1308
+ });
1309
+ bunchMock.setOwner(new DTPlayerStub());
1310
+
1311
+ const toObjectBunch = bunchMock.toObject();
1312
+ expect(Object.keys(toObjectBunch)).toStrictEqual(['id', 'key', 'type', 'items', 'owner']);
1313
+ expect(toObjectBunch.owner.toString()).toBe(toStringPlayerTest);
1314
+ });
1315
+
1316
+ test('toObject output standard with owner and meta', () => {
1317
+ jest.spyOn(bunchMock, 'setOwner').mockImplementation(function (owner) {
1318
+ this._owner = owner;
1319
+ });
1320
+ jest.spyOn(bunchMock, 'getManyMeta').mockImplementation(function () {
1321
+ return this._meta;
1322
+ });
1323
+
1324
+ bunchMock.setOwner(new DTPlayerStub());
1325
+ bunchMock.setManyMeta({});
1326
+
1327
+ const toObjectBunch = bunchMock.toObject();
1328
+ expect(Object.keys(toObjectBunch)).toStrictEqual(['id', 'key', 'type', 'items', 'owner', 'meta']);
1329
+ expect(toObjectBunch.meta).toStrictEqual(BunchMetaData);
1330
+ });
1331
+
1332
+ test('toObject output standard with items', () => {
1333
+ bunchMock.mockDefineItems(5);
1334
+ const toObjectBunch = bunchMock.toObject();
1335
+
1336
+ expect(Object.keys(toObjectBunch)).toStrictEqual(['id', 'key', 'type', 'items']);
1337
+ expect(toObjectBunch.items.length).toBe(5);
1338
+ expect(toObjectBunch.items).toStrictEqual([
1339
+ HaileiToObjectTest,
1340
+ MeldrineToObjectTest,
1341
+ MaydenaToObjectTest,
1342
+ IldressToObjectTest,
1343
+ YssaliaToObjectTest,
1344
+ ]);
1345
+ });
1346
+ });
1347
+
1348
+ describe('toString()', () => {
1349
+ test('string output standard', () => {
1350
+ const toStringBunch = bunchMock.toString();
1351
+
1352
+ expect(toStringBunch).toBe(`Component ${KeyTest} - Type: Bunch - Items: 0`);
1353
+ });
1354
+
1355
+ test('string output standard with items', () => {
1356
+ bunchMock.mockDefineItems(5);
1357
+ const toStringBunch = bunchMock.toString();
1358
+
1359
+ expect(toStringBunch).toBe(`Component ${KeyTest} - Type: Bunch - Items: 5`);
1360
+ });
1361
+
1362
+ test('string output standard with items and owner', () => {
1363
+ bunchMock.mockDefineItems(5);
1364
+ jest.spyOn(bunchMock, 'setOwner').mockImplementation(function (owner) {
1365
+ this._owner = owner;
1366
+ });
1367
+
1368
+ bunchMock.setOwner(new DTPlayerStub());
1369
+
1370
+ const toStringBunch = bunchMock.toString();
1371
+ expect(toStringBunch).toBe(`Component ${KeyTest} - Type: Bunch - Owner: ${KeyPlayerTest} - Items: 5`);
1372
+ });
1373
+ });
1374
+ });