Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / applications / drive / src / app / store / _links / useLinksState.test.tsx
blob6a1fd365cc5c2063b5b964e84d8b4cf89a21df4a
1 import { act, renderHook } from '@testing-library/react-hooks';
3 import { EVENT_TYPES } from '@proton/shared/lib/drive/constants';
5 import type { DriveEvents } from '../_events';
6 import type { DecryptedLink, EncryptedLink, LinkShareUrl } from './interface';
7 import type { Link, LinksState } from './useLinksState';
8 import {
9     addOrUpdate,
10     deleteLinks,
11     setCachedThumbnailUrl,
12     setLock,
13     updateByEvents,
14     useLinksStateProvider,
15 } from './useLinksState';
17 jest.mock('../_events/useDriveEventManager', () => {
18     const useDriveEventManager = () => {
19         return {
20             eventHandlers: {
21                 register: () => 'id',
22                 unregister: () => false,
23             },
24         };
25     };
26     return {
27         useDriveEventManager,
28     };
29 });
31 function generateTestLink({
32     id,
33     parentId,
34     decrypted,
35     shareId,
36     rootShareId = 'defaultShareId',
37 }: {
38     id: string;
39     parentId: string | undefined;
40     decrypted?: boolean;
41     shareId?: string;
42     rootShareId?: string;
43 }): Link {
44     return {
45         encrypted: {
46             linkId: id,
47             name: id,
48             parentLinkId: parentId,
49             sharingDetails: {
50                 shareId,
51             },
52             rootShareId,
53         },
54         decrypted: decrypted
55             ? {
56                   linkId: id,
57                   name: id,
58                   parentLinkId: parentId,
59                   sharingDetails: {
60                       shareId,
61                   },
62                   rootShareId,
63               }
64             : undefined,
65     } as Link;
68 function getLockedIds(state: LinksState): string[] {
69     return Object.values(state.shareId.links)
70         .filter(({ decrypted }) => decrypted?.isLocked)
71         .map(({ encrypted }) => encrypted.linkId);
74 function generateEvents(events: any[]): DriveEvents {
75     return {
76         eventId: 'eventId',
77         events: events.map(([eventType, encryptedLink]) => ({ eventType, encryptedLink })),
78         refresh: false,
79     };
82 describe('useLinksState', () => {
83     let state: LinksState;
85     beforeEach(() => {
86         state = {
87             shareId: {
88                 links: {
89                     linkId0: generateTestLink({ id: 'linkId0', parentId: undefined }),
90                     linkId1: generateTestLink({ id: 'linkId1', parentId: 'linkId0' }),
91                     linkId2: generateTestLink({ id: 'linkId2', parentId: 'linkId1' }),
92                     linkId3: generateTestLink({ id: 'linkId3', parentId: 'linkId1' }),
93                     linkId4: generateTestLink({ id: 'linkId4', parentId: 'linkId0' }),
94                     linkId5: generateTestLink({
95                         id: 'linkId5',
96                         parentId: 'linkId4',
97                         shareId: 'shareId1',
98                         rootShareId: 'shareId0',
99                     }),
100                     linkId6: generateTestLink({
101                         id: 'linkId6',
102                         parentId: 'linkId4',
103                         shareId: 'shareId2',
104                         rootShareId: 'shareId2',
105                     }),
106                     linkId7: generateTestLink({ id: 'linkId7', parentId: 'linkId0', decrypted: true }),
107                     linkId8: generateTestLink({ id: 'linkId8', parentId: 'linkId7', decrypted: true }),
108                     linkId9: generateTestLink({ id: 'linkId9', parentId: 'linkId7', decrypted: true }),
109                 },
110                 tree: {
111                     linkId0: ['linkId1', 'linkId4', 'linkId7'],
112                     linkId1: ['linkId2', 'linkId3'],
113                     linkId4: ['linkId5', 'linkId6'],
114                     linkId7: ['linkId8', 'linkId9'],
115                 },
116             },
117         };
118     });
120     it('deletes links', () => {
121         const result = deleteLinks(state, 'shareId', ['linkId1', 'linkId2', 'linkId6', 'linkId8', 'linkId9']);
122         // Removed links from links.
123         expect(Object.keys(result.shareId.links)).toMatchObject(['linkId0', 'linkId4', 'linkId5', 'linkId7']);
124         // Removed parent from tree.
125         expect(Object.keys(result.shareId.tree)).toMatchObject(['linkId0', 'linkId4', 'linkId7']);
126         // Removed children from tree.
127         expect(result.shareId.tree.linkId4).toMatchObject(['linkId5']);
128     });
130     it('adds new encrypted link', () => {
131         const result = addOrUpdate(state, 'shareId', [
132             {
133                 encrypted: {
134                     linkId: 'newLink',
135                     name: 'newLink',
136                     parentLinkId: 'linkId1',
137                 } as EncryptedLink,
138             },
139         ]);
140         // Added to links.
141         expect(result.shareId.links.newLink).toMatchObject({
142             encrypted: { linkId: 'newLink' },
143         });
144         // Added to tree as child to its parent.
145         expect(result.shareId.tree.linkId1).toMatchObject(['linkId2', 'linkId3', 'newLink']);
146     });
148     it('adds link to new share', () => {
149         const result = addOrUpdate(state, 'shareId2', [
150             {
151                 encrypted: {
152                     linkId: 'newLink',
153                     name: 'newLink',
154                     parentLinkId: 'linkId1',
155                 } as EncryptedLink,
156             },
157         ]);
158         // Added new link to links.
159         expect(result.shareId2.links.newLink).toMatchObject({
160             encrypted: { linkId: 'newLink' },
161         });
162         // Added parent to tree.
163         expect(Object.keys(result.shareId2.tree)).toMatchObject(['linkId1']);
164         expect(result.shareId2.tree.linkId1).toMatchObject(['newLink']);
165     });
167     it('updates encrypted link', () => {
168         const result = addOrUpdate(state, 'shareId', [
169             {
170                 encrypted: {
171                     linkId: 'linkId7',
172                     name: 'new name',
173                     parentLinkId: 'linkId0',
174                 } as EncryptedLink,
175             },
176         ]);
177         expect(result.shareId.links.linkId7).toMatchObject({
178             decrypted: { linkId: 'linkId7', name: 'linkId7', isStale: true },
179             encrypted: { linkId: 'linkId7' },
180         });
181     });
183     it('updates encrypted link without need to re-decrypt', () => {
184         const result = addOrUpdate(state, 'shareId', [
185             {
186                 encrypted: {
187                     linkId: 'linkId7',
188                     name: 'linkId7',
189                     parentLinkId: 'linkId0',
190                 } as EncryptedLink,
191             },
192         ]);
193         expect(result.shareId.links.linkId7).toMatchObject({
194             decrypted: { linkId: 'linkId7', name: 'linkId7', isStale: false },
195             encrypted: { linkId: 'linkId7' },
196         });
197     });
199     it('updates encrypted link with different parent', () => {
200         const result = addOrUpdate(state, 'shareId', [
201             {
202                 encrypted: {
203                     linkId: 'linkId7',
204                     name: 'linkId7',
205                     parentLinkId: 'linkId6',
206                 } as EncryptedLink,
207             },
208         ]);
209         // Updated link in links.
210         expect(result.shareId.links.linkId7).toMatchObject({
211             decrypted: { linkId: 'linkId7', isStale: true }, // Changing parent requires to re-decrypt again.
212             encrypted: { linkId: 'linkId7' },
213         });
214         // Updated original parent tree.
215         expect(result.shareId.tree.linkId0).toMatchObject(['linkId1', 'linkId4']);
216         // Updated new parent tree.
217         expect(result.shareId.tree.linkId6).toMatchObject(['linkId7']);
218     });
220     it('updates decrypted link', () => {
221         const result = addOrUpdate(state, 'shareId', [
222             {
223                 encrypted: {
224                     linkId: 'linkId7',
225                     name: 'new name',
226                     parentLinkId: 'linkId0',
227                 } as EncryptedLink,
228                 decrypted: {
229                     linkId: 'linkId7',
230                     name: 'new name',
231                     parentLinkId: 'linkId0',
232                 } as DecryptedLink,
233             },
234         ]);
235         expect(result.shareId.links.linkId7).toMatchObject({
236             decrypted: { linkId: 'linkId7', name: 'new name' },
237             encrypted: { linkId: 'linkId7' },
238         });
239     });
241     it('updates trashed link', () => {
242         const result1 = addOrUpdate(state, 'shareId', [
243             {
244                 encrypted: {
245                     linkId: 'linkId7',
246                     name: 'linkId7',
247                     parentLinkId: 'linkId0',
248                     trashed: 12345678,
249                 } as EncryptedLink,
250             },
251             {
252                 encrypted: {
253                     linkId: 'linkId8',
254                     name: 'linkId8',
255                     parentLinkId: 'linkId7',
256                     trashed: 123456789,
257                 } as EncryptedLink,
258             },
259         ]);
260         expect(result1.shareId.links.linkId7).toMatchObject({
261             decrypted: { linkId: 'linkId7', name: 'linkId7', isStale: false },
262             encrypted: { linkId: 'linkId7' },
263         });
264         // Trashed link is removed from the parent.
265         expect(result1.shareId.tree.linkId0).toMatchObject(['linkId1', 'linkId4']);
266         // Trashed parent trashes automatically also children.
267         expect(result1.shareId.links.linkId7.encrypted.trashed).toBe(12345678);
268         expect(result1.shareId.links.linkId7.encrypted.trashedByParent).toBeFalsy();
269         expect(result1.shareId.links.linkId8.encrypted.trashed).toBe(123456789);
270         expect(result1.shareId.links.linkId8.encrypted.trashedByParent).toBeFalsy();
271         expect(result1.shareId.links.linkId9.encrypted.trashed).toBe(12345678);
272         expect(result1.shareId.links.linkId9.encrypted.trashedByParent).toBeTruthy();
274         // Restoring from trash re-adds link back to its parent.
275         const result2 = addOrUpdate(result1, 'shareId', [
276             {
277                 encrypted: {
278                     linkId: 'linkId7',
279                     name: 'linkId7',
280                     parentLinkId: 'linkId0',
281                     trashed: null,
282                 } as EncryptedLink,
283             },
284         ]);
285         expect(result2.shareId.tree.linkId0).toMatchObject(['linkId1', 'linkId4', 'linkId7']);
286         // Restoring from trash removes also trashed flag to its children which were trashed with it.
287         expect(result1.shareId.links.linkId7.encrypted.trashed).toBe(null);
288         expect(result1.shareId.links.linkId7.encrypted.trashedByParent).toBeFalsy();
289         expect(result1.shareId.links.linkId8.encrypted.trashed).toBe(123456789);
290         expect(result1.shareId.links.linkId8.encrypted.trashedByParent).toBeFalsy();
291         expect(result1.shareId.links.linkId9.encrypted.trashed).toBe(null);
292         expect(result1.shareId.links.linkId9.encrypted.trashedByParent).toBeFalsy();
293     });
295     it('updates trashed folder and adds files to it', () => {
296         const result1 = addOrUpdate(state, 'shareId', [
297             {
298                 encrypted: {
299                     linkId: 'linkId7',
300                     name: 'linkId7',
301                     parentLinkId: 'linkId0',
302                     trashed: 12345678,
303                 } as EncryptedLink,
304             },
305             {
306                 encrypted: {
307                     linkId: 'linkId7a',
308                     name: 'linkId7a',
309                     parentLinkId: 'linkId7',
310                 } as EncryptedLink,
311             },
312         ]);
313         // Children of trashed parent is added to tree structure.
314         expect(result1.shareId.tree.linkId7).toMatchObject(['linkId8', 'linkId9', 'linkId7a']);
315         // Trashed parent trashes automatically also children.
316         expect(result1.shareId.links.linkId7.encrypted.trashed).toBe(12345678);
317         expect(result1.shareId.links.linkId7.encrypted.trashedByParent).toBeFalsy();
318         expect(result1.shareId.links.linkId7a.encrypted.trashed).toBe(12345678);
319         expect(result1.shareId.links.linkId7a.encrypted.trashedByParent).toBeTruthy();
321         // Restoring from trash re-adds link back to its parent.
322         const result2 = addOrUpdate(result1, 'shareId', [
323             {
324                 encrypted: {
325                     linkId: 'linkId7',
326                     name: 'linkId7',
327                     parentLinkId: 'linkId0',
328                     trashed: null,
329                 } as EncryptedLink,
330             },
331         ]);
332         // Trashed parent trashes automatically also children.
333         expect(result2.shareId.links.linkId7.encrypted.trashed).toBe(null);
334         expect(result2.shareId.links.linkId7.encrypted.trashedByParent).toBeFalsy();
335         expect(result2.shareId.links.linkId7a.encrypted.trashed).toBe(null);
336         expect(result2.shareId.links.linkId7a.encrypted.trashedByParent).toBeFalsy();
337     });
339     it('updates encrypted link with signature issue', () => {
340         // First, it sets signature issue.
341         const result1 = addOrUpdate(state, 'shareId', [
342             {
343                 encrypted: {
344                     linkId: 'linkId7',
345                     name: 'linkId7',
346                     parentLinkId: 'linkId0',
347                     signatureIssues: { name: 2 },
348                 } as unknown as EncryptedLink,
349             },
350         ]);
351         expect(result1.shareId.links.linkId7).toMatchObject({
352             decrypted: { linkId: 'linkId7', signatureIssues: { name: 2 } },
353             encrypted: { linkId: 'linkId7', signatureIssues: { name: 2 } },
354         });
355         // Second, it keeps it even if we do another update which doesnt change
356         // how the link is encrypted (keys and encrypted data are the same).
357         const result2 = addOrUpdate(result1, 'shareId', [
358             {
359                 encrypted: {
360                     linkId: 'linkId7',
361                     name: 'linkId7',
362                     parentLinkId: 'linkId0',
363                 } as unknown as EncryptedLink,
364             },
365         ]);
366         expect(result2.shareId.links.linkId7).toMatchObject({
367             decrypted: { linkId: 'linkId7', signatureIssues: { name: 2 } },
368             encrypted: { linkId: 'linkId7', signatureIssues: { name: 2 } },
369         });
370         // Third, signature issue is cleared if keys or encrypted data is changed.
371         const result3 = addOrUpdate(result2, 'shareId', [
372             {
373                 encrypted: {
374                     linkId: 'linkId7',
375                     name: 'linkId7',
376                     parentLinkId: 'linkId0',
377                     nodeKey: 'anotherKey',
378                 } as unknown as EncryptedLink,
379             },
380         ]);
381         expect(result3.shareId.links.linkId7).toMatchObject({
382             decrypted: { linkId: 'linkId7', signatureIssues: undefined },
383             encrypted: { linkId: 'linkId7', signatureIssues: undefined },
384         });
385     });
387     it('updates decrypted link with signature issue', () => {
388         const result = addOrUpdate(state, 'shareId', [
389             {
390                 encrypted: {
391                     linkId: 'linkId7',
392                     name: 'linkId7',
393                     parentLinkId: 'linkId0',
394                 } as unknown as EncryptedLink,
395                 decrypted: {
396                     linkId: 'linkId7',
397                     name: 'linkId7',
398                     parentLinkId: 'linkId0',
399                     signatureIssues: { name: 2 },
400                 } as unknown as DecryptedLink,
401             },
402         ]);
403         expect(result.shareId.links.linkId7).toMatchObject({
404             decrypted: { linkId: 'linkId7', signatureIssues: { name: 2 } },
405             encrypted: { linkId: 'linkId7', signatureIssues: { name: 2 } },
406         });
407     });
409     it('locks and unlocks links', () => {
410         const result1 = setLock(state, 'shareId', ['linkId7', 'linkId8'], true);
411         expect(getLockedIds(result1)).toMatchObject(['linkId7', 'linkId8']);
412         const result2 = setLock(state, 'shareId', ['linkId8'], false);
413         expect(getLockedIds(result2)).toMatchObject(['linkId7']);
414     });
416     it('locks and unlocks trashed links', () => {
417         (state.shareId.links.linkId7.decrypted as DecryptedLink).trashed = 1234;
418         (state.shareId.links.linkId8.decrypted as DecryptedLink).trashed = 5678;
419         const result1 = setLock(state, 'shareId', 'trash', true);
420         expect(getLockedIds(result1)).toMatchObject(['linkId7', 'linkId8']);
421         const result2 = setLock(state, 'shareId', 'trash', false);
422         expect(getLockedIds(result2)).toMatchObject([]);
423     });
425     it('preserves lock for newly added trashed link', () => {
426         const result1 = setLock(state, 'shareId', 'trash', true);
427         const result2 = addOrUpdate(result1, 'shareId', [
428             {
429                 encrypted: {
430                     linkId: 'linkId100',
431                     name: 'linkId100',
432                     parentLinkId: 'linkId0',
433                     trashed: 12345678,
434                 } as EncryptedLink,
435                 decrypted: {
436                     linkId: 'linkId100',
437                     name: 'linkId100',
438                     parentLinkId: 'linkId0',
439                     trashed: 12345678,
440                 } as DecryptedLink,
441             },
442             {
443                 encrypted: {
444                     linkId: 'linkId101',
445                     name: 'linkId101',
446                     parentLinkId: 'linkId0',
447                     trashed: 12345678900, // Way in future after setLock was called.
448                 } as EncryptedLink,
449                 decrypted: {
450                     linkId: 'linkId101',
451                     name: 'linkId101',
452                     parentLinkId: 'linkId0',
453                     trashed: 12345678900,
454                 } as DecryptedLink,
455             },
456         ]);
457         // linkId101 was deleted after our empty action, so is not locked.
458         expect(getLockedIds(result2)).toMatchObject(['linkId100']);
459     });
461     it('sets cached thumbnail', () => {
462         const result = setCachedThumbnailUrl(state, 'shareId', 'linkId7', 'cachedurl');
463         expect(result.shareId.links.linkId7.decrypted).toMatchObject({ cachedThumbnailUrl: 'cachedurl' });
464     });
466     it('preserves cached lock flag', () => {
467         const state2 = setLock(state, 'shareId', ['linkId7'], true);
468         const link = {
469             linkId: 'linkId7',
470             name: 'new name',
471             parentLinkId: 'linkId0',
472         };
473         const result = addOrUpdate(state2, 'shareId', [
474             {
475                 encrypted: link as EncryptedLink,
476                 decrypted: link as DecryptedLink,
477             },
478         ]);
479         expect(result.shareId.links.linkId7.decrypted).toMatchObject({ isLocked: true });
480     });
482     it('preserves cached thumbnail', () => {
483         const state2 = setCachedThumbnailUrl(state, 'shareId', 'linkId7', 'cachedurl');
484         const link = {
485             linkId: 'linkId7',
486             name: 'new name',
487             parentLinkId: 'linkId0',
488         };
489         const result = addOrUpdate(state2, 'shareId', [
490             {
491                 encrypted: link as EncryptedLink,
492                 decrypted: link as DecryptedLink,
493             },
494         ]);
495         expect(result.shareId.links.linkId7.decrypted).toMatchObject({ cachedThumbnailUrl: 'cachedurl' });
496     });
498     it('does not preserve cached thumbnail when revision changed', () => {
499         const state2 = setCachedThumbnailUrl(state, 'shareId', 'linkId7', 'cachedurl');
500         const link = {
501             linkId: 'linkId7',
502             name: 'new name',
503             parentLinkId: 'linkId0',
504             activeRevision: { id: 'newId' },
505         };
506         const result = addOrUpdate(state2, 'shareId', [
507             {
508                 encrypted: link as EncryptedLink,
509                 decrypted: link as DecryptedLink,
510             },
511         ]);
512         expect(result.shareId.links.linkId7.decrypted).toMatchObject({ cachedThumbnailUrl: undefined });
513     });
515     it('preserves latest share url num accesses', () => {
516         expect(state.shareId.links.linkId7.decrypted?.shareUrl?.numAccesses).toBe(undefined);
518         // First set the numAccesses and check its set.
519         const linkWithAccesses = {
520             linkId: 'linkId7',
521             name: 'new name',
522             parentLinkId: 'linkId0',
523             shareUrl: {
524                 id: 'shareUrlId',
525                 numAccesses: 0, // Test with zero to make sure zero is also well handled.
526             },
527         };
528         const result1 = addOrUpdate(state, 'shareId', [
529             {
530                 encrypted: linkWithAccesses as EncryptedLink,
531                 decrypted: linkWithAccesses as DecryptedLink,
532             },
533         ]);
534         expect(result1.shareId.links.linkId7.decrypted?.shareUrl?.numAccesses).toBe(0);
536         // Then set newer link without numAccesses which stil preserves the previous value.
537         const linkWithoutAccesses = {
538             linkId: 'linkId7',
539             name: 'newer name',
540             parentLinkId: 'linkId0',
541             shareUrl: {
542                 id: 'shareUrlId',
543             },
544         };
545         const result2 = addOrUpdate(state, 'shareId', [
546             {
547                 encrypted: linkWithoutAccesses as EncryptedLink,
548                 decrypted: linkWithoutAccesses as DecryptedLink,
549             },
550         ]);
551         expect(result2.shareId.links.linkId7.decrypted?.shareUrl?.numAccesses).toBe(0);
552     });
554     it('sets zero num accesses for fresh new share url', () => {
555         (state.shareId.links.linkId7.decrypted as DecryptedLink).shareUrl = undefined;
556         (state.shareId.links.linkId8.decrypted as DecryptedLink).shareUrl = {
557             id: 'shareUrlId',
558         } as LinkShareUrl;
559         const link7 = {
560             linkId: 'linkId7',
561             name: 'new name',
562             parentLinkId: 'linkId0',
563             shareUrl: {
564                 id: 'shareUrlId1',
565             },
566         };
567         const link8 = {
568             linkId: 'linkId8',
569             name: 'new name',
570             parentLinkId: 'linkId7',
571             shareUrl: {
572                 id: 'shareUrlId2',
573             },
574         };
575         const result = addOrUpdate(state, 'shareId', [
576             {
577                 encrypted: link7 as EncryptedLink,
578                 decrypted: link7 as DecryptedLink,
579             },
580             {
581                 encrypted: link8 as EncryptedLink,
582                 decrypted: link8 as DecryptedLink,
583             },
584         ]);
585         // Link 7 had no shareUrl before, that means it is freshly created, so set to 0.
586         expect(result.shareId.links.linkId7.decrypted?.shareUrl?.numAccesses).toBe(0);
587         // Whereas link 8 had shareUrl before, so the update is about something else, and we need to keep undefined.
588         expect(result.shareId.links.linkId8.decrypted?.shareUrl?.numAccesses).toBe(undefined);
589     });
591     it('processes events', () => {
592         const result = updateByEvents(
593             state,
594             generateEvents([
595                 [
596                     EVENT_TYPES.CREATE,
597                     { linkId: 'newLink', name: 'newLink', parentLinkId: 'linkId0', rootShareId: 'shareId' },
598                 ],
599                 [EVENT_TYPES.DELETE, { linkId: 'linkId1' }],
600                 [EVENT_TYPES.DELETE, { linkId: 'linkId4' }],
601                 [
602                     EVENT_TYPES.UPDATE,
603                     { linkId: 'linkId7', name: 'new name', parentLinkId: 'linkId0', rootShareId: 'shareId' },
604                 ],
605             ]),
606             jest.fn()
607         );
609         expect(Object.keys(result.shareId.links)).toMatchObject([
610             'linkId0',
611             'linkId7',
612             'linkId8',
613             'linkId9',
614             'newLink',
615         ]);
616         expect(Object.keys(result.shareId.tree)).toMatchObject(['linkId0', 'linkId7']);
617         expect(result.shareId.links.linkId7).toMatchObject({
618             decrypted: { linkId: 'linkId7', name: 'linkId7', isStale: true },
619             encrypted: { linkId: 'linkId7' },
620         });
621     });
623     it('skips events from non-present share', () => {
624         const result = updateByEvents(
625             state,
626             generateEvents([
627                 [
628                     EVENT_TYPES.CREATE,
629                     { linkId: 'newLink', name: 'newLink', parentLinkId: 'linkId0', rootShareId: 'shareId2' },
630                 ],
631             ]),
632             jest.fn()
633         );
635         expect(Object.keys(result)).toMatchObject(['shareId']);
636     });
638     describe('hook', () => {
639         let hook: {
640             current: ReturnType<typeof useLinksStateProvider>;
641         };
643         beforeEach(() => {
644             const { result } = renderHook(() => useLinksStateProvider());
645             hook = result;
647             act(() => {
648                 state.shareId.links.linkId6.encrypted.shareUrl = {
649                     id: 'shareUrlId',
650                     token: 'token',
651                     isExpired: false,
652                     createTime: 12345,
653                     expireTime: null,
654                 };
655                 state.shareId.links.linkId7.encrypted.trashed = 12345;
656                 state.shareId.links.linkId8.encrypted.trashed = 12345;
657                 state.shareId.links.linkId8.encrypted.trashedByParent = true;
658                 state.shareId.links.linkId9.encrypted.trashed = 12345;
659                 state.shareId.links.linkId9.encrypted.trashedByParent = true;
660                 hook.current.setLinks('shareId', Object.values(state.shareId.links));
661             });
662         });
664         it('returns children of the parent', () => {
665             const links = hook.current.getChildren('shareId', 'linkId1');
666             expect(links.map((link) => link.encrypted.linkId)).toMatchObject(['linkId2', 'linkId3']);
667         });
669         it('returns trashed links', () => {
670             const links = hook.current.getTrashed('shareId');
671             expect(links.map((link) => link.encrypted.linkId)).toMatchObject(['linkId7']);
672         });
674         it('returns shared links', () => {
675             const links = hook.current.getSharedByLink('shareId');
676             expect(links.map((link) => link.encrypted.linkId)).toMatchObject(['linkId5']);
677         });
679         it('returns shared with me links', () => {
680             const links = hook.current.getSharedWithMeByLink('shareId');
681             expect(links.map((link) => link.encrypted.linkId)).toMatchObject(['linkId6']);
682         });
683     });