dyo-tools 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/.c8rc.json +4 -0
  2. package/.eslintignore +2 -0
  3. package/.eslintrc.json +47 -0
  4. package/LICENSE +21 -0
  5. package/Makefile +34 -0
  6. package/README.md +0 -7
  7. package/babel.config.js +1 -0
  8. package/cucumber-report.html +48 -0
  9. package/cucumber.js +9 -0
  10. package/dist/constants.d.ts +6 -0
  11. package/dist/constants.js +63 -0
  12. package/dist/constants.js.map +1 -0
  13. package/dist/core/DTBunch.d.ts +11 -15
  14. package/dist/core/DTBunch.js +27 -106
  15. package/dist/core/DTBunch.js.map +1 -1
  16. package/dist/core/DTComponent.d.ts +13 -5
  17. package/dist/core/DTComponent.js +39 -1
  18. package/dist/core/DTComponent.js.map +1 -1
  19. package/dist/core/DTComponentPhysical.d.ts +10 -0
  20. package/dist/core/DTComponentPhysical.js +16 -0
  21. package/dist/core/DTComponentPhysical.js.map +1 -0
  22. package/dist/core/DTComponentWithMeta.d.ts +2 -2
  23. package/dist/core/DTComponentWithMeta.js.map +1 -1
  24. package/dist/core/DTElement.d.ts +2 -7
  25. package/dist/core/DTElement.js +3 -12
  26. package/dist/core/DTElement.js.map +1 -1
  27. package/dist/core/DTManager.d.ts +31 -0
  28. package/dist/core/DTManager.js +180 -0
  29. package/dist/core/DTManager.js.map +1 -0
  30. package/dist/core/DTPlayer.js +1 -1
  31. package/dist/core/DTPlayer.js.map +1 -1
  32. package/dist/index.d.ts +2 -0
  33. package/dist/index.js +5 -1
  34. package/dist/index.js.map +1 -1
  35. package/dist/libs/DYOFinder.d.ts +10 -0
  36. package/dist/libs/DYOFinder.js +96 -0
  37. package/dist/libs/DYOFinder.js.map +1 -0
  38. package/dist/tsconfig.tsbuildinfo +1 -1321
  39. package/dist/types/index.d.ts +64 -24
  40. package/dist/types/index.js.map +1 -1
  41. package/docs/.nojekyll +1 -0
  42. package/docs/assets/highlight.css +29 -0
  43. package/docs/assets/main.js +58 -0
  44. package/docs/assets/search.js +1 -0
  45. package/docs/assets/style.css +1367 -0
  46. package/docs/index.html +46 -0
  47. package/e2e/0.2.0/epic1.feature +29 -0
  48. package/e2e/0.2.0/epic2.feature +22 -0
  49. package/e2e/0.2.0/epic3.feature +25 -0
  50. package/e2e/0.2.0/resources/dominion.js +195 -0
  51. package/e2e/0.2.0/resources/utils.js +27 -0
  52. package/e2e/0.2.0/support/steps.js +108 -0
  53. package/e2e/future/epic4.feature +39 -0
  54. package/e2e/future/resources/dominion.js +238 -0
  55. package/e2e/future/resources/utils.js +27 -0
  56. package/jest.config.js +6 -0
  57. package/package.json +33 -23
  58. package/src/constants.ts +85 -0
  59. package/src/core/DTBunch.ts +461 -0
  60. package/src/core/DTComponent.ts +225 -0
  61. package/src/core/DTComponentPhysical.ts +39 -0
  62. package/src/core/DTComponentWithMeta.ts +65 -0
  63. package/src/core/DTElement.ts +69 -0
  64. package/src/core/DTError.ts +78 -0
  65. package/src/core/DTManager.ts +446 -0
  66. package/src/core/DTPlayer.ts +57 -0
  67. package/src/index.ts +9 -0
  68. package/src/libs/DYOFinder.ts +175 -0
  69. package/src/types/index.ts +162 -0
  70. package/test/core/DTBunch.double.ts +253 -0
  71. package/test/core/DTBunch.spec.ts +895 -0
  72. package/test/core/DTComponent.double.ts +164 -0
  73. package/test/core/DTComponent.spec.ts +295 -0
  74. package/test/core/DTComponentPhysical.double.ts +76 -0
  75. package/test/core/DTComponentPhysical.spec.ts +64 -0
  76. package/test/core/DTComponentWithMeta.double.ts +115 -0
  77. package/test/core/DTComponentWithMeta.spec.ts +124 -0
  78. package/test/core/DTElement.double.ts +147 -0
  79. package/test/core/DTElement.spec.ts +102 -0
  80. package/test/core/DTError.double.ts +92 -0
  81. package/test/core/DTError.spec.ts +89 -0
  82. package/test/core/DTManager.double.ts +192 -0
  83. package/test/core/DTManager.spec.ts +902 -0
  84. package/test/core/DTPlayer.double.ts +64 -0
  85. package/test/core/DTPlayer.spec.ts +80 -0
  86. package/test/core/copy.spec.ts +227 -0
  87. package/test/libs/DYOFinder.double.ts +152 -0
  88. package/test/libs/DYOFinder.spec.ts +194 -0
  89. package/tsconfig.dev.json +22 -0
  90. package/tsconfig.json +21 -0
  91. package/dist/utils/filters.d.ts +0 -6
  92. package/dist/utils/filters.js +0 -39
  93. package/dist/utils/filters.js.map +0 -1
@@ -0,0 +1,902 @@
1
+ import { afterEach, beforeEach, describe, expect, jest, test, } from '@jest/globals';
2
+ import {
3
+ checkManagerItem,
4
+ DomainTest,
5
+ DTManagerStubDomain,
6
+ DTManagerTest,
7
+ IDTest,
8
+ KeyTest,
9
+ populateManager,
10
+ ScopesTest,
11
+ } from './DTManager.double';
12
+ import DTManager from '../../src/core/DTManager';
13
+ import {
14
+ bunch1IdTest,
15
+ bunch1toObjectTest,
16
+ bunch2IdTest,
17
+ bunch2toObjectTest,
18
+ bunch3toObjectTest,
19
+ DTBunchStub,
20
+ DTBunchStubLibrary, DTBunchTest,
21
+ generateMockedElements,
22
+ IDTest as IDTestBunch,
23
+ IDTestLibrary,
24
+ KeyTest as KeyTestBunch,
25
+ } from './DTBunch.double';
26
+ import { mockOverriddenMethods } from './DTComponent.double';
27
+ import { DTComponent, DTComponentPhysical, DTElement } from '../../src';
28
+ import DYOToolsError from '../../src/core/DTError';
29
+ import { checkCallForMockedDTError, DTErrorStub } from './DTError.double';
30
+ import { BunchMetaData, IMetaDataTest } from './DTComponentWithMeta.double';
31
+ import { componentManagerDefaultFinderConfiguration, managerDefaultOptions } from '../../src/constants';
32
+ import { FilterOperatorType } from '../../src/types';
33
+ import { DTPlayerStub, IDTest as IDTestPlayer } from './DTPlayer.double';
34
+ import MockedFunction = jest.MockedFunction;
35
+
36
+ /** ****************** MOCK DEPENDENCIES
37
+ * Dependencies used by the component are mocked with Jest
38
+ * **** */
39
+ jest.mock('../../src/core/DTElement');
40
+ jest.mock('../../src/core/DTBunch');
41
+ jest.mock('../../src/core/DTComponent');
42
+ jest.mock('../../src/core/DTError');
43
+ jest.mock('../../src/libs/DYOFinder');
44
+ // Add specific mock for inherited methods to have a basic implementation
45
+ mockOverriddenMethods(DTComponent);
46
+
47
+ /** *********************** TESTS SUITES ****************************** */
48
+ describe('class DYOToolsManager', () => {
49
+ let managerTest: DTManagerTest;
50
+
51
+ beforeEach(() => {
52
+ managerTest = new DTManagerTest();
53
+ });
54
+
55
+ afterEach(() => {
56
+ jest.resetAllMocks();
57
+ });
58
+
59
+ describe('inheritance', () => {
60
+ test('check good inheritance for class', () => {
61
+ expect(DTManager.prototype instanceof DTComponent).toBeTruthy();
62
+ });
63
+ });
64
+
65
+ describe('_componentType', () => {
66
+ test('componentType must be "bunch"', () => {
67
+ expect(managerTest.th_get_componentType()).toBe('manager');
68
+ });
69
+ });
70
+
71
+ describe('constructor()', () => {
72
+ beforeEach(() => {
73
+ jest.resetAllMocks();
74
+ });
75
+
76
+ test('creation simple with key', () => {
77
+ const newManager = new DTManagerTest(KeyTest);
78
+ const parentConstructorMock = (DTComponentPhysical.prototype.constructor as MockedFunction<(key: string, options: any) => void>).mock;
79
+
80
+ expect(parentConstructorMock.calls.length).toBe(1);
81
+ expect(parentConstructorMock.calls[0][0]).toBe(KeyTest);
82
+ expect(parentConstructorMock.calls[0][1]).toStrictEqual(managerDefaultOptions);
83
+
84
+ expect(newManager.th_get_items()).toStrictEqual({});
85
+ expect(newManager.th_get_scopes()).toStrictEqual(['default', 'virtual']);
86
+
87
+ // Library tests
88
+ expect(newManager.th_get_library().constructor.mock.calls.length).toBe(1);
89
+ expect(newManager.th_get_library().constructor.mock.calls[0][0]).toBe('library');
90
+ expect(newManager.th_get_library().constructor.mock.calls[0][1]).toStrictEqual([]);
91
+ expect(newManager.th_get_library().constructor.mock.calls[0][2].virtualContext).toBe(true);
92
+
93
+ // Finder initialization
94
+ expect((newManager.th_get_finder() as any).constructor.mock.calls.length).toBe(1);
95
+ expect((newManager.th_get_finder() as any).constructor.mock.calls[0][0]).toStrictEqual(newManager);
96
+ expect((newManager.th_get_finder() as any).constructor.mock.calls[0][1]).toStrictEqual(componentManagerDefaultFinderConfiguration);
97
+ });
98
+
99
+ test('creation simple without key - use domain if defined', () => {
100
+ const newManager = new DTManager();
101
+ const newManagerWithDomain = new DTManagerStubDomain();
102
+ const newManagerWithDomain2 = new DTManagerStubDomain(null);
103
+
104
+ jest.spyOn(newManager, 'getKey').mockImplementation(function () {
105
+ return this._key;
106
+ });
107
+ jest.spyOn(newManagerWithDomain, 'getKey').mockImplementation(function () {
108
+ return this._key;
109
+ });
110
+ jest.spyOn(newManagerWithDomain2, 'getKey').mockImplementation(function () {
111
+ return this._key;
112
+ });
113
+
114
+ expect(newManager.getKey() === DomainTest).toBe(false);
115
+ expect(newManagerWithDomain.getKey() === DomainTest).toStrictEqual(true);
116
+ expect(newManagerWithDomain2.getKey() === DomainTest).toStrictEqual(true);
117
+ });
118
+
119
+ test('creation with elements for library', () => {
120
+ const mockedElements = generateMockedElements(5);
121
+ const newManager = new DTManagerTest(KeyTest, mockedElements);
122
+
123
+ expect(newManager.th_get_items()).toStrictEqual({});
124
+ expect(newManager.th_get_scopes()).toStrictEqual(['default', 'virtual']);
125
+
126
+ // Library tests
127
+ expect(newManager.th_get_library().constructor.mock.calls.length).toBe(1);
128
+ expect(newManager.th_get_library().constructor.mock.calls[0][0]).toBe('library');
129
+ expect(newManager.th_get_library().constructor.mock.calls[0][1].length).toStrictEqual(5);
130
+ expect(newManager.th_get_library().constructor.mock.calls[0][1].map((item) => item.getId()))
131
+ .toStrictEqual(mockedElements.map((item) => item.getId()));
132
+ expect(newManager.th_get_library().constructor.mock.calls[0][2].virtualContext).toBe(true);
133
+ });
134
+
135
+ test('creation with extended scopes', () => {
136
+ const mockedElements = generateMockedElements(5);
137
+ const newManager = new DTManagerTest(null, mockedElements, ScopesTest);
138
+
139
+ expect(newManager.th_get_items()).toStrictEqual({});
140
+ expect(newManager.th_get_scopes()).toStrictEqual([
141
+ 'default',
142
+ 'virtual',
143
+ ...ScopesTest,
144
+ ]);
145
+ });
146
+
147
+ test('creation with specific options', () => {
148
+ const mockedElements = generateMockedElements(5);
149
+ const options = { errors: true, libraryDeletion: true };
150
+ const parentConstructorMock = (DTComponentPhysical.prototype.constructor as MockedFunction<(key: string, options: any) => void>).mock;
151
+
152
+ const newManager = new DTManagerTest(null, mockedElements, ScopesTest, options);
153
+
154
+ expect(parentConstructorMock.calls.length).toBe(1);
155
+ expect(parentConstructorMock.calls[0][0]).toBe(null);
156
+ expect(parentConstructorMock.calls[0][1]).toStrictEqual(options);
157
+ });
158
+ });
159
+
160
+ describe('getFinderConfiguration()', () => {
161
+ const baseOperators = [
162
+ FilterOperatorType.EQ,
163
+ FilterOperatorType.IN,
164
+ FilterOperatorType.NIN,
165
+ FilterOperatorType.NE,
166
+ ];
167
+ const advancedOperators = [
168
+ ...baseOperators,
169
+ FilterOperatorType.GTE,
170
+ FilterOperatorType.LTE,
171
+ FilterOperatorType.CONTAINS,
172
+ FilterOperatorType.NCONTAINS,
173
+ ];
174
+
175
+ test('check finder configuration for id attribute', () => {
176
+ const finderConfigurationToCheck = managerTest.getFinderConfiguration().id;
177
+
178
+ expect(finderConfigurationToCheck.operators).toStrictEqual(baseOperators);
179
+ expect(finderConfigurationToCheck.getValue(new DTBunchStub())).toBe(IDTestBunch);
180
+ expect(finderConfigurationToCheck.objectSearch).toBe(false);
181
+ });
182
+
183
+ test('check finder configuration for key attribute', () => {
184
+ const finderConfigurationToCheck = managerTest.getFinderConfiguration().key;
185
+
186
+ expect(finderConfigurationToCheck.operators).toStrictEqual(baseOperators);
187
+ expect(finderConfigurationToCheck.getValue(new DTBunchStub())).toBe(KeyTestBunch);
188
+ expect(finderConfigurationToCheck.objectSearch).toBe(false);
189
+ });
190
+
191
+ test('check finder configuration for owner attribute - empty owner', () => {
192
+ const bunch = new DTBunchStub();
193
+ jest.spyOn(bunch, 'getOwner').mockImplementation(() => undefined);
194
+
195
+ const finderConfigurationToCheck = managerTest.getFinderConfiguration().owner;
196
+
197
+ expect(finderConfigurationToCheck.operators).toStrictEqual(baseOperators);
198
+ expect(finderConfigurationToCheck.getValue(bunch)).toBeNull();
199
+ expect(finderConfigurationToCheck.objectSearch).toBe(false);
200
+ });
201
+
202
+ test('check finder configuration for owner attribute - with owner', () => {
203
+ const bunch = new DTBunchStub();
204
+ jest.spyOn(bunch, 'getOwner').mockImplementation(() => new DTPlayerStub());
205
+
206
+ const finderConfigurationToCheck = managerTest.getFinderConfiguration().owner;
207
+
208
+ expect(finderConfigurationToCheck.operators).toStrictEqual(baseOperators);
209
+ expect(finderConfigurationToCheck.getValue(bunch)).toBe(IDTestPlayer);
210
+ expect(finderConfigurationToCheck.objectSearch).toBe(false);
211
+ });
212
+
213
+ test('check finder configuration for meta attribute', () => {
214
+ const bunch = new DTBunchStub();
215
+ jest.spyOn(bunch, 'getManyMeta').mockImplementation(() => BunchMetaData);
216
+
217
+ const finderConfigurationToCheck = managerTest.getFinderConfiguration().meta;
218
+
219
+ expect(finderConfigurationToCheck.operators).toStrictEqual(advancedOperators);
220
+ expect(finderConfigurationToCheck.getValue(bunch)).toStrictEqual(BunchMetaData);
221
+ expect(finderConfigurationToCheck.objectSearch).toBe(true);
222
+ });
223
+
224
+ test('check finder configuration for scope attribute', () => {
225
+ const bunch = new DTBunchStub();
226
+ jest.spyOn(managerTest, 'getScope').mockImplementation(() => ScopesTest[0]);
227
+
228
+ const finderConfigurationToCheck = managerTest.getFinderConfiguration().scope;
229
+
230
+ expect(finderConfigurationToCheck.operators).toStrictEqual(baseOperators);
231
+ expect(finderConfigurationToCheck.getValue(bunch, managerTest)).toStrictEqual(ScopesTest[0]);
232
+ expect(finderConfigurationToCheck.objectSearch).toBe(false);
233
+ });
234
+ });
235
+
236
+ describe('getLibrary()', () => {
237
+ test('return current manager Library', () => {
238
+ managerTest.th_set_library(new DTBunchStubLibrary());
239
+
240
+ const library: DTBunchStubLibrary = managerTest.getLibrary() as DTBunchStubLibrary;
241
+ expect(library).toBeTruthy();
242
+ expect(library.getId()).toBe(IDTestLibrary);
243
+ });
244
+ });
245
+
246
+ describe('getScopes()', () => {
247
+ test('return manager scopes', () => {
248
+ managerTest.th_set_scopes(ScopesTest);
249
+
250
+ expect(managerTest.getScopes()).toStrictEqual(ScopesTest);
251
+ });
252
+ });
253
+
254
+ describe('isValidScope()', () => {
255
+ beforeEach(() => {
256
+ managerTest.th_set_scopes(ScopesTest);
257
+ });
258
+
259
+ test('return true if scope exists', () => {
260
+ expect(managerTest.isValidScope(ScopesTest[0])).toBe(true);
261
+ });
262
+
263
+ test('return false if scope doesn\'t exist', () => {
264
+ expect(managerTest.isValidScope('invalid_scope')).toBe(false);
265
+ });
266
+ });
267
+
268
+ describe('add()', () => {
269
+ let bunchToAdd: DTBunchStub;
270
+
271
+ beforeEach(() => {
272
+ jest.spyOn(managerTest, 'getId').mockReturnValue(IDTest);
273
+ jest.spyOn(managerTest, 'isValidScope').mockReturnValue(true);
274
+
275
+ // Bunch to add
276
+ bunchToAdd = new DTBunchStub();
277
+ jest.spyOn(bunchToAdd, 'getAll').mockImplementation(function () {
278
+ return this._items;
279
+ });
280
+ jest.spyOn(bunchToAdd, 'getOptions').mockImplementation(function () {
281
+ return this._options;
282
+ });
283
+ jest.spyOn(bunchToAdd, 'getContext').mockImplementation(function () {
284
+ return this._context;
285
+ });
286
+
287
+ // Add tests scopes
288
+ managerTest.th_set_scopes([...managerTest.th_get_scopes(), ...ScopesTest]);
289
+ });
290
+
291
+ test('add a new item - empty bunch in default scope', () => {
292
+ managerTest.add(bunchToAdd);
293
+
294
+ expect(Object.keys(managerTest.th_get_items()).length).toBe(1);
295
+ checkManagerItem(managerTest, IDTestBunch, 'default');
296
+ });
297
+
298
+ test('add a new item - empty bunch in specific scope', () => {
299
+ managerTest.add(bunchToAdd, ScopesTest[0]);
300
+
301
+ expect(Object.keys(managerTest.th_get_items()).length).toBe(1);
302
+ checkManagerItem(managerTest, IDTestBunch, ScopesTest[0]);
303
+ });
304
+
305
+ test('add a new item - virtual bunch in virtual scope', () => {
306
+ bunchToAdd.th_set_options({ virtualContext: true });
307
+
308
+ managerTest.add(bunchToAdd);
309
+
310
+ expect(Object.keys(managerTest.th_get_items()).length).toBe(1);
311
+ checkManagerItem(managerTest, IDTestBunch, 'virtual');
312
+ });
313
+
314
+ test('trigger error if not existing scope for bunch', () => {
315
+ const errorScope = 'not-existing-scope';
316
+ const mockedTriggerError = DTManager.prototype.triggerError as MockedFunction<(error: DYOToolsError) => void>;
317
+ jest.spyOn(managerTest, 'isValidScope').mockReturnValue(false);
318
+
319
+ managerTest.add(bunchToAdd, errorScope);
320
+
321
+ expect(Object.keys(managerTest.th_get_items()).length).toBe(0);
322
+ expect((managerTest.isValidScope as any).mock.calls.length).toBe(1);
323
+ expect((managerTest.isValidScope as any).mock.calls[0][0]).toBe(errorScope);
324
+ expect(mockedTriggerError.mock.calls.length).toBe(1);
325
+ checkCallForMockedDTError(
326
+ 'invalid_scope',
327
+ "Scope provided doesn't exist in the manager",
328
+ IDTest,
329
+ bunchToAdd.getId(),
330
+ );
331
+ });
332
+
333
+ test('trigger error if invalid scope for virtual bunch', () => {
334
+ bunchToAdd.th_set_options({ virtualContext: true });
335
+ const mockedTriggerError = DTManager.prototype.triggerError as MockedFunction<(error: DYOToolsError) => void>;
336
+
337
+ managerTest.add(bunchToAdd, ScopesTest[0]);
338
+
339
+ expect(Object.keys(managerTest.th_get_items()).length).toBe(0);
340
+ expect(mockedTriggerError.mock.calls.length).toBe(1);
341
+ checkCallForMockedDTError(
342
+ 'forbidden_scope',
343
+ 'Scope provided cannot be associated to a virtual bunch',
344
+ IDTest,
345
+ bunchToAdd.getId(),
346
+ );
347
+ });
348
+
349
+ test('trigger error if invalid virtual scope for bunch', () => {
350
+ const mockedTriggerError = DTManager.prototype.triggerError as MockedFunction<(error: DYOToolsError) => void>;
351
+
352
+ managerTest.add(bunchToAdd, 'virtual');
353
+
354
+ expect(Object.keys(managerTest.th_get_items()).length).toBe(0);
355
+ expect(mockedTriggerError.mock.calls.length).toBe(1);
356
+ checkCallForMockedDTError(
357
+ 'forbidden_virtual_scope',
358
+ 'Virtual Scope provided cannot be associated to a physical bunch',
359
+ IDTest,
360
+ bunchToAdd.getId(),
361
+ );
362
+ });
363
+
364
+ test('trigger conflict error when adding two same bunch ids', () => {
365
+ const mockedTriggerError = DTManager.prototype.triggerError as MockedFunction<(error: DYOToolsError) => void>;
366
+
367
+ managerTest.add(bunchToAdd);
368
+ managerTest.add(bunchToAdd);
369
+
370
+ expect(Object.keys(managerTest.th_get_items()).length).toBe(1);
371
+ expect(mockedTriggerError.mock.calls.length).toBe(1);
372
+ checkCallForMockedDTError(
373
+ 'id_conflict',
374
+ 'Bunch with same id already exists in the manager',
375
+ IDTest,
376
+ bunchToAdd.getId(),
377
+ );
378
+ });
379
+
380
+ test('add bunch elements into library - simple case', () => {
381
+ const bunchElements = generateMockedElements(5);
382
+ const bunchElementsKeys = bunchElements.map((item: DTElement<IMetaDataTest>) => item.getKey());
383
+ bunchToAdd.th_set_items(bunchElements);
384
+
385
+ managerTest.add(bunchToAdd);
386
+
387
+ expect(managerTest.th_get_single_item(IDTestBunch).item.getAllKeys()).toStrictEqual(bunchElementsKeys);
388
+ expect(managerTest.th_get_library().add.mock.calls.length).toBe(5);
389
+ let itemCount = 0;
390
+ for (const addCalls of managerTest.th_get_library().add.mock.calls) {
391
+ expect(addCalls[0].getKey()).toBe(bunchElements[itemCount].getKey());
392
+ expect(addCalls[1]).toBeUndefined();
393
+ itemCount += 1;
394
+ }
395
+ });
396
+
397
+ test('add bunch elements into library - not adding existing elements in library', () => {
398
+ const bunchElements = generateMockedElements(5);
399
+ const bunchElementsInLibrary = generateMockedElements(2);
400
+ const bunchElementsKeys = bunchElements.map((item: DTElement<IMetaDataTest>) => item.getKey());
401
+ bunchToAdd.th_set_items(bunchElements);
402
+ managerTest.th_set_library(new DTBunchStubLibrary(bunchElementsInLibrary));
403
+
404
+ managerTest.add(bunchToAdd);
405
+
406
+ expect(managerTest.th_get_single_item(IDTestBunch).item.getAllKeys()).toStrictEqual(bunchElementsKeys);
407
+ expect(managerTest.th_get_library().add.mock.calls.length).toBe(3);
408
+ let itemCount = 2;
409
+ for (const addCalls of managerTest.th_get_library().add.mock.calls) {
410
+ expect(addCalls[0].getKey()).toBe(bunchElements[itemCount].getKey());
411
+ expect(addCalls[1]).toBeUndefined();
412
+ itemCount += 1;
413
+ }
414
+ });
415
+
416
+ test('set context when adding an item - default case', () => {
417
+ managerTest.th_set_id(IDTest);
418
+
419
+ managerTest.add(bunchToAdd);
420
+
421
+ expect((bunchToAdd.setContext as any).mock.calls.length).toBe(1);
422
+ expect((bunchToAdd.setContext as any).mock.calls[0][0].th_get_id()).toBe(IDTest);
423
+ });
424
+
425
+ test('set context when adding an item - remove from old manager', () => {
426
+ const oldManagerTest = new DTManagerTest();
427
+ bunchToAdd.th_set_context(oldManagerTest);
428
+ oldManagerTest.th_set_items({ [bunchToAdd.getId()]: { scope: 'default', item: bunchToAdd } });
429
+ managerTest.th_set_id(IDTest);
430
+ oldManagerTest.th_set_id(`${IDTest}-old`);
431
+ jest.spyOn(oldManagerTest, 'remove');
432
+ jest.spyOn(oldManagerTest, 'getComponentType').mockImplementation(() => 'manager');
433
+
434
+ managerTest.add(bunchToAdd);
435
+
436
+ expect((oldManagerTest.remove as any).mock.calls.length).toBe(1);
437
+ expect((oldManagerTest.remove as any).mock.calls[0][0]).toBe(bunchToAdd.getId());
438
+ expect(Object.keys(managerTest.th_get_items()).length).toBe(1);
439
+ checkManagerItem(managerTest, IDTestBunch, 'default');
440
+ });
441
+ });
442
+
443
+ describe('addMany()', () => {
444
+ let mockedAdd: MockedFunction<(item: any, scope?: string) => void>;
445
+ let bunchesToAdd: DTBunchStub[];
446
+
447
+ beforeEach(() => {
448
+ jest.spyOn(managerTest, 'add').mockImplementation(() => {});
449
+ mockedAdd = managerTest.add as MockedFunction<(item: any, scope?: string) => void>;
450
+
451
+ // Bunches to add
452
+ const bunchToAdd1 = new DTBunchStub();
453
+ bunchToAdd1.th_set_id(`${IDTestBunch}_1`);
454
+ const bunchToAdd2 = new DTBunchStub();
455
+ bunchToAdd2.th_set_id(`${IDTestBunch}_2`);
456
+ const bunchToAdd3 = new DTBunchStub();
457
+ bunchToAdd3.th_set_id(`${IDTestBunch}_3`);
458
+ bunchesToAdd = [bunchToAdd1, bunchToAdd2, bunchToAdd3];
459
+
460
+ // Add tests scopes and options
461
+ managerTest.th_set_scopes([...managerTest.th_get_scopes(), ...ScopesTest]);
462
+ managerTest.th_set_options({ errors: false });
463
+ });
464
+
465
+ test('add many items - use add method - default case', () => {
466
+ managerTest.addMany(bunchesToAdd);
467
+
468
+ expect(mockedAdd.mock.calls.length).toBe(3);
469
+ let itemCount = 0;
470
+ for (const addCalls of mockedAdd.mock.calls) {
471
+ expect(addCalls[0].th_get_id()).toBe(bunchesToAdd[itemCount].th_get_id());
472
+ expect(addCalls[1]).toBeUndefined();
473
+ itemCount += 1;
474
+ }
475
+ });
476
+
477
+ test('add many items - use add method - with scope case', () => {
478
+ managerTest.addMany(bunchesToAdd, ScopesTest[0]);
479
+
480
+ expect(mockedAdd.mock.calls.length).toBe(3);
481
+ let itemCount = 0;
482
+ for (const addCalls of mockedAdd.mock.calls) {
483
+ expect(addCalls[0].th_get_id()).toBe(bunchesToAdd[itemCount].th_get_id());
484
+ expect(addCalls[1]).toBe(ScopesTest[0]);
485
+ itemCount += 1;
486
+ }
487
+ });
488
+
489
+ test('errors when adding many items at index - default case - add no items and throw error', () => {
490
+ jest.spyOn(managerTest, 'add')
491
+ .mockImplementationOnce(function (item) {
492
+ this._items[`${IDTestBunch}_1`] = {
493
+ scope: 'default',
494
+ item,
495
+ };
496
+ })
497
+ .mockImplementationOnce(() => {
498
+ throw new DTErrorStub();
499
+ })
500
+ .mockImplementationOnce(function (item) {
501
+ this._items[`${IDTestBunch}_3`] = {
502
+ scope: 'default',
503
+ item,
504
+ };
505
+ });
506
+
507
+ expect(() => { managerTest.addMany(bunchesToAdd); }).toThrow();
508
+ expect(mockedAdd.mock.calls.length).toBe(2);
509
+ expect(Object.keys(managerTest.th_get_items()).length).toBe(0);
510
+ });
511
+
512
+ test('errors when adding many items at index - errors case - add success items and stack errors for others', () => {
513
+ managerTest.th_set_options({ errors: true });
514
+ jest.spyOn(managerTest, 'add')
515
+ .mockImplementationOnce(function (item) {
516
+ this._items[`${IDTestBunch}_1`] = {
517
+ scope: 'default',
518
+ item,
519
+ };
520
+ })
521
+ .mockImplementationOnce(function () {
522
+ this._errors = [new DTErrorStub()];
523
+ })
524
+ .mockImplementationOnce(function (item) {
525
+ this._items[`${IDTestBunch}_3`] = {
526
+ scope: 'default',
527
+ item,
528
+ };
529
+ });
530
+
531
+ managerTest.addMany(bunchesToAdd);
532
+
533
+ expect(mockedAdd.mock.calls.length).toBe(3);
534
+ expect(Object.keys(managerTest.th_get_items()).length).toBe(2);
535
+ });
536
+ });
537
+
538
+ describe('moveToScope()', () => {
539
+ beforeEach(() => {
540
+ populateManager(managerTest);
541
+
542
+ jest.spyOn(managerTest, 'getId').mockReturnValue(IDTest);
543
+ jest.spyOn(managerTest, 'isValidScope').mockReturnValue(true);
544
+ });
545
+
546
+ test('move to default scope', () => {
547
+ managerTest.moveToScope(`${IDTestBunch}_2`, 'default');
548
+
549
+ expect(Object.keys(managerTest.th_get_items()).length).toBe(3);
550
+ checkManagerItem(managerTest, `${IDTestBunch}_2`, 'default');
551
+ });
552
+
553
+ test('move to existing scope', () => {
554
+ managerTest.moveToScope(`${IDTestBunch}_2`, ScopesTest[1]);
555
+
556
+ expect(Object.keys(managerTest.th_get_items()).length).toBe(3);
557
+ checkManagerItem(managerTest, `${IDTestBunch}_2`, ScopesTest[1]);
558
+ });
559
+
560
+ test('move to non-existing scope - trigger invalid_scope error', () => {
561
+ const mockedTriggerError = DTManager.prototype.triggerError as MockedFunction<(error: DYOToolsError) => void>;
562
+ jest.spyOn(managerTest, 'isValidScope').mockReturnValue(false);
563
+
564
+ managerTest.moveToScope(`${IDTestBunch}_2`, 'invalid_scope');
565
+
566
+ expect(Object.keys(managerTest.th_get_items()).length).toBe(3);
567
+ expect(mockedTriggerError.mock.calls.length).toBe(1);
568
+ checkCallForMockedDTError(
569
+ 'invalid_scope',
570
+ "Scope provided doesn't exist in the manager",
571
+ IDTest,
572
+ `${IDTestBunch}_2`,
573
+ );
574
+ });
575
+
576
+ test('move non-virtual bunch to virtual scope - trigger forbidden_virtual_scope error', () => {
577
+ const mockedTriggerError = DTManager.prototype.triggerError as MockedFunction<(error: DYOToolsError) => void>;
578
+
579
+ managerTest.moveToScope(`${IDTestBunch}_2`, 'virtual');
580
+
581
+ expect(Object.keys(managerTest.th_get_items()).length).toBe(3);
582
+ expect(mockedTriggerError.mock.calls.length).toBe(1);
583
+ checkCallForMockedDTError(
584
+ 'forbidden_virtual_scope',
585
+ 'Virtual Scope provided cannot be associated to a physical bunch',
586
+ IDTest,
587
+ `${IDTestBunch}_2`,
588
+ );
589
+ });
590
+
591
+ test('move virtual bunch to non-virtual scope - trigger forbidden_scope error', () => {
592
+ const mockedTriggerError = DTManager.prototype.triggerError as MockedFunction<(error: DYOToolsError) => void>;
593
+
594
+ managerTest.moveToScope(`${IDTestBunch}_3`, ScopesTest[0]);
595
+
596
+ expect(Object.keys(managerTest.th_get_items()).length).toBe(3);
597
+ expect(mockedTriggerError.mock.calls.length).toBe(1);
598
+ checkCallForMockedDTError(
599
+ 'forbidden_scope',
600
+ 'Scope provided cannot be associated to a virtual bunch',
601
+ IDTest,
602
+ `${IDTestBunch}_3`,
603
+ );
604
+ });
605
+
606
+ test('move to same scope - nothing append', () => {
607
+ managerTest.moveToScope(`${IDTestBunch}_1`, 'default');
608
+
609
+ expect(Object.keys(managerTest.th_get_items()).length).toBe(3);
610
+ checkManagerItem(managerTest, `${IDTestBunch}_1`, 'default');
611
+ });
612
+
613
+ test('move an non-existing bunch id - trigger invalid_id error', () => {
614
+ const mockedTriggerError = DTManager.prototype.triggerError as MockedFunction<(error: DYOToolsError) => void>;
615
+
616
+ managerTest.moveToScope(`${IDTestBunch}_5`, ScopesTest[0]);
617
+
618
+ expect(Object.keys(managerTest.th_get_items()).length).toBe(3);
619
+ expect(mockedTriggerError.mock.calls.length).toBe(1);
620
+ checkCallForMockedDTError(
621
+ 'invalid_id',
622
+ 'Bunch id provided doesn\'t exist in the manager',
623
+ IDTest,
624
+ );
625
+ });
626
+ });
627
+
628
+ describe('get()', () => {
629
+ beforeEach(() => {
630
+ populateManager(managerTest);
631
+ });
632
+
633
+ test('return a bunch by its id', () => {
634
+ const bunch = managerTest.get(`${IDTestBunch}_1`) as DTBunchTest;
635
+
636
+ expect(bunch).toBeDefined();
637
+ expect(bunch.th_get_id()).toBe(`${IDTestBunch}_1`);
638
+ });
639
+
640
+ test('return undefined if bunch is not found', () => {
641
+ const bunch = managerTest.get(`${IDTestBunch}_5`);
642
+
643
+ expect(bunch).toBeUndefined();
644
+ });
645
+ });
646
+
647
+ describe('getAll()', () => {
648
+ beforeEach(() => {
649
+ populateManager(managerTest);
650
+ });
651
+
652
+ test('return all bunch items', () => {
653
+ const bunches = managerTest.getAll() as DTBunchTest[];
654
+
655
+ const bunchesIds = bunches.map((bunch) => bunch.th_get_id());
656
+ expect(bunchesIds.length).toBe(3);
657
+ expect(bunchesIds.includes(`${IDTestBunch}_1`)).toBeTruthy();
658
+ expect(bunchesIds.includes(`${IDTestBunch}_2`)).toBeTruthy();
659
+ expect(bunchesIds.includes(`${IDTestBunch}_3`)).toBeTruthy();
660
+ });
661
+
662
+ test('return empty array if no bunch', () => {
663
+ managerTest.th_set_items({});
664
+
665
+ const bunches = managerTest.getAll();
666
+
667
+ expect(bunches.length).toBe(0);
668
+ });
669
+
670
+ test('scope argument : return only bunches into the scope', () => {
671
+ const bunches = managerTest.getAll(ScopesTest[0]) as DTBunchTest[];
672
+
673
+ const bunchesIds = bunches.map((bunch) => bunch.th_get_id());
674
+ expect(bunchesIds.length).toBe(1);
675
+ expect(bunchesIds.includes(`${IDTestBunch}_2`)).toBeTruthy();
676
+ });
677
+
678
+ test('scope argument : return empty array if no bunch into the scope', () => {
679
+ const bunches = managerTest.getAll(ScopesTest[1]);
680
+
681
+ expect(bunches.length).toBe(0);
682
+ });
683
+
684
+ test('scope argument : return empty array if invalid scope is passed', () => {
685
+ const bunches = managerTest.getAll('invalid_scope');
686
+
687
+ expect(bunches.length).toBe(0);
688
+ });
689
+ });
690
+
691
+ describe('getScope()', () => {
692
+ beforeEach(() => {
693
+ populateManager(managerTest);
694
+ });
695
+
696
+ test('get scope for an existing bunch id', () => {
697
+ const scope1 = managerTest.getScope(`${IDTestBunch}_1`);
698
+ const scope2 = managerTest.getScope(`${IDTestBunch}_2`);
699
+ const scope3 = managerTest.getScope(`${IDTestBunch}_3`);
700
+
701
+ expect(scope1).toBe('default');
702
+ expect(scope2).toBe(ScopesTest[0]);
703
+ expect(scope3).toBe('virtual');
704
+ });
705
+
706
+ test('get undefined scope for an non-existing bunch id', () => {
707
+ const scope = managerTest.getScope(`${IDTestBunch}_5`);
708
+
709
+ expect(scope).toBeUndefined();
710
+ });
711
+ });
712
+
713
+ describe('remove()', () => {
714
+ beforeEach(() => {
715
+ populateManager(managerTest);
716
+
717
+ jest.spyOn(managerTest, 'removeMany');
718
+ });
719
+
720
+ test('remove one item using removeMany', () => {
721
+ managerTest.remove(`${IDTestBunch}_2`);
722
+
723
+ expect((managerTest.removeMany as any).mock.calls.length).toBe(1);
724
+ expect((managerTest.removeMany as any).mock.calls[0][0]).toStrictEqual([`${IDTestBunch}_2`]);
725
+ });
726
+ });
727
+
728
+ describe('removeMany()', () => {
729
+ beforeEach(() => {
730
+ populateManager(managerTest);
731
+ });
732
+
733
+ test('remove multiple bunches from manager', () => {
734
+ managerTest.removeMany([`${IDTestBunch}_1`, `${IDTestBunch}_2`]);
735
+
736
+ const newItems = managerTest.th_get_items();
737
+ expect(Object.keys(newItems).length).toBe(1);
738
+ expect(Object.keys(newItems)).toStrictEqual([`${IDTestBunch}_3`]);
739
+ });
740
+
741
+ test('remove non-existing bunches - nothing happen', () => {
742
+ managerTest.removeMany([`${IDTestBunch}_5`, `${IDTestBunch}_7`]);
743
+
744
+ const newItems = managerTest.th_get_items();
745
+ expect(Object.keys(newItems).length).toBe(3);
746
+ expect(Object.keys(newItems)).toStrictEqual([`${IDTestBunch}_1`, `${IDTestBunch}_2`, `${IDTestBunch}_3`]);
747
+ });
748
+
749
+ test('remove multiple bunches from manager - no removal from library by default', () => {
750
+ managerTest.removeMany([`${IDTestBunch}_1`, `${IDTestBunch}_2`]);
751
+
752
+ expect(managerTest.th_get_library().remove.mock.calls.length).toBe(0);
753
+ });
754
+
755
+ test('remove multiple bunches from manager - libraryDeletion option', () => {
756
+ const libraryElementsIdToRemove = managerTest.th_get_library().th_get_items().map((item: any) => item.getId());
757
+ managerTest.removeMany([`${IDTestBunch}_1`, `${IDTestBunch}_2`], { libraryDeletion: true });
758
+
759
+ expect(managerTest.th_get_library().remove.mock.calls.length).toBe(5);
760
+ expect(managerTest.th_get_library().remove.mock.calls.map((call: any) => call[0])).toEqual(libraryElementsIdToRemove);
761
+ });
762
+ });
763
+
764
+ describe('removeAll()', () => {
765
+ beforeEach(() => {
766
+ populateManager(managerTest);
767
+
768
+ jest.spyOn(managerTest, 'removeMany');
769
+ });
770
+
771
+ test('remove all items using removeMany', () => {
772
+ const bunchesIdToRemove = Object.keys(managerTest.th_get_items());
773
+ managerTest.removeAll();
774
+
775
+ expect((managerTest.removeMany as any).mock.calls.length).toBe(1);
776
+ expect((managerTest.removeMany as any).mock.calls[0][0]).toStrictEqual(bunchesIdToRemove);
777
+ });
778
+ });
779
+
780
+ describe('find()', () => {
781
+ test('find items using DYOFinder - empty case', () => {
782
+ managerTest.find({});
783
+
784
+ expect((managerTest.th_get_finder() as any).execute.mock.calls.length).toBe(1);
785
+ expect((managerTest.th_get_finder() as any).execute.mock.calls[0][0]).toStrictEqual({});
786
+ });
787
+
788
+ test('find items using DYOFinder', () => {
789
+ const testFilters = { id: { $eq: 'id_bunch' }, key: { $ne: 'key_test' } };
790
+ managerTest.find(testFilters);
791
+
792
+ expect((managerTest.th_get_finder() as any).execute.mock.calls.length).toBe(1);
793
+ expect((managerTest.th_get_finder() as any).execute.mock.calls[0][0]).toStrictEqual(testFilters);
794
+ });
795
+ });
796
+
797
+ describe('reloadLibrary()', () => {
798
+ beforeEach(() => {
799
+ populateManager(managerTest);
800
+ });
801
+
802
+ const extractIdsFromLibraryAddCalls = () => (managerTest.th_get_library().add as any).mock.calls.map((call) => call[0].getId());
803
+
804
+ test('synchronize bunches items into an empty library - one bunch with items', () => {
805
+ const items = managerTest.th_get_library().th_get_items();
806
+ managerTest.th_get_library().th_set_items([]);
807
+ const expectedAddedItemIds = items.map((item: any) => item.getId());
808
+
809
+ managerTest.reloadLibrary();
810
+
811
+ expect(extractIdsFromLibraryAddCalls()).toEqual(expectedAddedItemIds);
812
+ });
813
+
814
+ test('synchronize bunches items into an empty library - multiple bunches with items', () => {
815
+ const items = managerTest.th_get_library().th_get_items();
816
+ managerTest.th_get_library().th_set_items([]);
817
+ managerTest.th_get_single_item(bunch1IdTest).item.th_set_items([items[0], items[1], items[2]]);
818
+ managerTest.th_get_single_item(bunch2IdTest).item.th_set_items([items[3], items[4]]);
819
+ const expectedAddedItemIds = items.map((item: any) => item.getId());
820
+
821
+ managerTest.reloadLibrary();
822
+
823
+ expect(extractIdsFromLibraryAddCalls()).toEqual(expectedAddedItemIds);
824
+ });
825
+
826
+ test('synchronize bunches items into an empty library - pass already existing ids', () => {
827
+ jest.spyOn(managerTest.th_get_library(), 'removeAll').mockImplementation(function () {
828
+ this._items = [];
829
+ });
830
+ const items = managerTest.th_get_library().th_get_items();
831
+ managerTest.th_get_library().th_set_items([items[0], items[1], items[2]]);
832
+ managerTest.th_get_single_item(bunch1IdTest).item.th_set_items(items);
833
+ const expectedAddedItemIds = items.map((item: any) => item.getId());
834
+
835
+ managerTest.reloadLibrary();
836
+
837
+ expect(extractIdsFromLibraryAddCalls()).toEqual(expectedAddedItemIds);
838
+ });
839
+ });
840
+
841
+ describe('toObject()', () => {
842
+ beforeEach(() => {
843
+ managerTest.th_set_id(IDTest);
844
+ managerTest.th_set_key(KeyTest);
845
+ });
846
+
847
+ test('toObject output standard', () => {
848
+ const toObjectManager = managerTest.toObject();
849
+
850
+ expect(Object.keys(toObjectManager)).toStrictEqual(['id', 'key', 'type', 'items']);
851
+ expect(toObjectManager.id).toBe(IDTest);
852
+ expect(toObjectManager.key).toBe(KeyTest);
853
+ expect(toObjectManager.type).toBe('manager');
854
+ expect(toObjectManager.items.length).toBe(0);
855
+ });
856
+
857
+ test('toObject output with items', () => {
858
+ populateManager(managerTest);
859
+
860
+ const toObjectManager = managerTest.toObject();
861
+
862
+ expect(Object.keys(toObjectManager)).toStrictEqual(['id', 'key', 'type', 'items']);
863
+ expect(toObjectManager.items.length).toBe(3);
864
+ expect(toObjectManager.items).toStrictEqual([
865
+ { scope: 'default', ...bunch1toObjectTest },
866
+ { scope: ScopesTest[0], ...bunch2toObjectTest },
867
+ { scope: 'virtual', ...bunch3toObjectTest },
868
+ ]);
869
+ });
870
+ });
871
+
872
+ describe('toString()', () => {
873
+ beforeEach(() => {
874
+ managerTest.th_set_key(KeyTest);
875
+ });
876
+
877
+ test('string output standard', () => {
878
+ managerTest.th_set_library(new DTBunchStubLibrary());
879
+
880
+ const toStringManager = managerTest.toString();
881
+
882
+ expect(toStringManager).toBe(`Component ${KeyTest} - Type: Manager - Library: 0 - Items: 0`);
883
+ });
884
+
885
+ test('string output with library', () => {
886
+ populateManager(managerTest);
887
+ managerTest.th_set_items({});
888
+
889
+ const toStringManager = managerTest.toString();
890
+
891
+ expect(toStringManager).toBe(`Component ${KeyTest} - Type: Manager - Library: 5 - Items: 0`);
892
+ });
893
+
894
+ test('string output with library and items', () => {
895
+ populateManager(managerTest);
896
+
897
+ const toStringManager = managerTest.toString();
898
+
899
+ expect(toStringManager).toBe(`Component ${KeyTest} - Type: Manager - Library: 5 - Items: 3`);
900
+ });
901
+ });
902
+ });