Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / applications / drive / src / app / store / _links / useLinksQueue.test.tsx
blob1c9e9401b97faade367683217988943cdb52d7eb
1 import { act, renderHook } from '@testing-library/react-hooks';
3 import { useLinksQueue } from './useLinksQueue';
5 const mockedLoadLinksMeta = jest.fn();
6 jest.mock('./useLinksListing', () => ({
7     useLinksListing: () => ({
8         loadLinksMeta: mockedLoadLinksMeta,
9     }),
10 }));
12 const mockedGetLink = jest.fn();
13 jest.mock('./useLinksState', () => ({
14     __esModule: true,
15     default: () => ({
16         getLink: mockedGetLink,
17     }),
18 }));
20 jest.useFakeTimers();
21 jest.spyOn(global, 'setTimeout');
23 const mockedAbort = jest.fn();
24 let mockedAbortSignal = { aborted: false };
25 // @ts-ignore - not mocking the entire AbortSignal, sorry =)
26 global.AbortController = jest.fn(() => ({
27     signal: mockedAbortSignal,
28     abort: mockedAbort,
29 }));
31 const SHARE_ID = 'shareId';
33 const getLinkIds = (count: number) => [...Array(count).keys()].map((id) => `linkId-${id}`);
34 const getFakeRef: <T>(value: T) => React.MutableRefObject<T> = (value) => ({ current: value });
36 describe('useLinksQueue', () => {
37     let hook: {
38         current: ReturnType<typeof useLinksQueue>;
39     };
40     let unmountHook: () => void;
42     beforeEach(() => {
43         const { result, unmount } = renderHook(() => useLinksQueue());
45         hook = result;
46         unmountHook = unmount;
48         jest.clearAllTimers();
49         jest.clearAllMocks();
50         mockedGetLink.mockReset();
51         mockedLoadLinksMeta.mockReset();
53         mockedAbort.mockReset();
54         mockedAbortSignal.aborted = false;
56         mockedGetLink.mockImplementation(() => undefined);
57     });
59     it('should not add to queue if link is already in state', async () => {
60         mockedGetLink.mockImplementation((shareId, linkId) => ({
61             shareId,
62             linkId,
63         }));
65         await act(async () => {
66             hook.current.addToQueue(SHARE_ID, 'linkId');
67         });
69         expect(setTimeout).not.toHaveBeenCalled();
70     });
72     it('should not add to queue if linkId is already in queue', async () => {
73         await act(async () => {
74             hook.current.addToQueue(SHARE_ID, 'linkId');
75             hook.current.addToQueue(SHARE_ID, 'linkId');
76         });
78         expect(setTimeout).toHaveBeenCalledTimes(1);
79     });
81     it('should debounce processing to wait for the queue to fill up', async () => {
82         const items = getLinkIds(7);
84         await act(async () => {
85             items.forEach((item) => hook.current.addToQueue(SHARE_ID, item));
86         });
88         jest.runAllTimers();
90         expect(setTimeout).toHaveBeenCalledTimes(items.length);
91         expect(mockedLoadLinksMeta).toHaveBeenCalledTimes(1);
92     });
94     it('should not load links if the domRef is null', async () => {
95         await act(async () => {
96             hook.current.addToQueue(SHARE_ID, 'linkId', getFakeRef(null));
97         });
99         jest.runAllTimers();
101         expect(setTimeout).toHaveBeenCalledTimes(1);
102         expect(mockedLoadLinksMeta).not.toHaveBeenCalled();
103     });
105     it('should abort when the hook is unmounted', async () => {
106         await act(async () => {
107             hook.current.addToQueue(SHARE_ID, 'linkId');
108         });
110         jest.runAllTimers();
111         unmountHook();
113         expect(mockedAbort).toHaveBeenCalled();
114     });
116     it('should not load links if aborted', async () => {
117         mockedAbortSignal.aborted = true;
119         await act(async () => {
120             hook.current.addToQueue(SHARE_ID, 'linkId');
121         });
123         jest.runAllTimers();
125         expect(setTimeout).toHaveBeenCalledTimes(1);
126         expect(mockedLoadLinksMeta).not.toHaveBeenCalled();
127     });
129     it('should not infinite loop if loadLinksMeta fails', async () => {
130         // Silence console errors
131         const consoleErrorMock = jest.spyOn(console, 'error').mockImplementation(() => {});
133         mockedLoadLinksMeta.mockRejectedValue(new Error('oh no'));
135         await act(async () => {
136             hook.current.addToQueue(SHARE_ID, 'linkId');
137         });
139         await jest.runAllTimersAsync();
141         expect(setTimeout).toHaveBeenCalledTimes(1);
142         expect(mockedLoadLinksMeta).toHaveBeenCalledTimes(1);
143         expect(consoleErrorMock).toHaveBeenCalledTimes(1);
145         consoleErrorMock.mockRestore();
146     }, 1000);