Merge branch 'fix-typo-drive' into 'main'
[ProtonMail-WebClient.git] / packages / utils / logs.test.ts
blob16ef5c814c90b68a505b0ac7dba3e63739cef81b
1 /* eslint-disable no-console */
2 import { traceError } from '@proton/shared/lib/helpers/sentry';
4 import { Logger } from './logs';
6 jest.mock('@proton/shared/lib/helpers/sentry', () => ({
7     traceError: jest.fn(),
8 }));
10 const mockTraceError = jest.mocked(traceError);
12 describe('Logger', () => {
13     let logger: Logger;
15     beforeEach(() => {
16         logger = new Logger('test-logger');
17         console.log = jest.fn();
18         console.warn = jest.fn();
19         console.error = jest.fn();
20     });
22     afterEach(() => {
23         jest.clearAllMocks();
24         localStorage.removeItem('test-logger-debug');
25     });
27     test('should log debug messages if verbose is true', () => {
28         localStorage.setItem('test-logger-debug', 'true');
29         logger = new Logger('test-logger', 'test-logger-debug');
30         logger.debug('This is a debug message');
32         expect(console.log).toHaveBeenCalledTimes(1);
33         expect(logger.getLogs()).toContain('This is a debug message');
34     });
36     test('should not log debug messages if verbose is false', () => {
37         localStorage.setItem('test-logger-debug', 'false');
38         logger = new Logger('test-logger', 'test-logger-debug');
39         logger.debug('This is a debug message');
41         expect(console.log).toHaveBeenCalledTimes(0);
42         expect(logger.getLogs()).not.toContain('This is a debug message');
43     });
45     test('should log info messages', () => {
46         logger.info('This is an info message');
48         expect(console.log).toHaveBeenCalledTimes(1);
49         expect(logger.getLogs()).toContain('This is an info message');
50     });
52     test('should log warn messages', () => {
53         logger.warn('This is a warn message');
55         expect(console.warn).toHaveBeenCalledWith('This is a warn message');
56         expect(logger.getLogs()).toContain('This is a warn message');
57     });
59     test('should log error messages', () => {
60         const error = new Error('This is an error message');
61         logger.error(error);
63         expect(console.error).toHaveBeenCalledWith(error);
64         expect(logger.getLogs()).toContain('This is an error message');
65     });
67     test('should log error messages with no Error object', () => {
68         logger.error('This is an error message');
70         expect(console.error).toHaveBeenCalledWith('This is an error message');
71         expect(logger.getLogs()).toContain('This is an error message');
72         expect(mockTraceError).toHaveBeenCalledWith(expect.any(Error), {
73             tags: {
74                 tag: 'test-logger',
75             },
76         });
77     });
79     test('should log error messages with Error and extras', () => {
80         const error = new Error('This is an error message');
81         logger.error(error, 'extra', 123);
83         expect(console.error).toHaveBeenCalledWith(error, 'extra', 123);
84         expect(logger.getLogs()).toContain('This is an error message');
85         expect(mockTraceError).toHaveBeenCalledWith(expect.any(Error), {
86             tags: {
87                 tag: 'test-logger',
88             },
89             extra: {
90                 0: 'extra',
91                 1: 123,
92             },
93         });
94     });
96     test('should not log if enabled is false', () => {
97         logger.setEnabled(false);
98         logger.info('This is an info message');
100         expect(console.log).not.toHaveBeenCalled();
101         expect(logger.getLogs()).not.toContain('This is an info message');
102     });
104     test('should not warn if enabled is false', () => {
105         logger.setEnabled(false);
106         logger.warn('This is a warn message');
108         expect(console.warn).not.toHaveBeenCalled();
109         expect(logger.getLogs()).not.toContain('This is a warn message');
110     });
112     test('should not error if enabled is false', () => {
113         logger.setEnabled(false);
114         logger.error('This is an error message');
116         expect(console.error).not.toHaveBeenCalled();
117         expect(logger.getLogs()).not.toContain('This is an error message');
118     });
120     test('should save logs', () => {
121         logger.info('First message');
122         logger.info('Second message');
124         const logs = logger.getLogs();
125         expect(logs).toContain('First message');
126         expect(logs).toContain('Second message');
127     });
129     test('should save logs until limit is reached', () => {
130         logger = new Logger('test-logger', undefined, 2);
131         logger.info('First message');
132         logger.info('Second message');
133         logger.info('Third message');
135         const logs = logger.getLogs();
136         expect(logs).not.toContain('First message');
137         expect(logs).toContain('Second message');
138         expect(logs).toContain('Third message');
139     });
141     test('should save logs with objects', () => {
142         const obj = { hello: 'world', test: true, docs: 123 };
143         logger.info('First message');
144         logger.info('Second message', obj);
146         const logs = logger.getLogs();
147         expect(logs).toContain('First message');
148         expect(logs).toContain(`Second message hello:world test:true docs:123`);
149     });
151     test('should clear logs', () => {
152         logger.info('First message');
153         logger.clearLogs();
155         expect(logger.getLogs()).toBe('');
156     });
158     test('should not add duplicate messages but increase times', () => {
159         logger.info('Repeated message');
160         logger.info('Repeated message');
162         const logs = logger.getLogs();
163         expect(logs).toContain('Repeated message');
164         expect(
165             logs.indexOf(new Date().getFullYear().toString()) !== logs.lastIndexOf(new Date().getFullYear().toString())
166         ).toEqual(true);
167     });
169     test('should download logs', () => {
170         const createElementSpy = jest.spyOn(document, 'createElement');
172         logger.info('Message to download');
173         logger.downloadLogs();
175         expect(createElementSpy).toHaveBeenCalled();
176         createElementSpy.mockRestore();
177     });
179     test('should not download logs if not logs', () => {
180         const createElementSpy = jest.spyOn(document, 'createElement');
182         logger.downloadLogs();
184         expect(createElementSpy).not.toHaveBeenCalled();
185         createElementSpy.mockRestore();
186     });
188     test('should call downloadLogs on Ctrl+Shift+H in main frame', () => {
189         const createElementSpy = jest.spyOn(document, 'createElement');
190         // Simulate Ctrl+Shift+H keydown event
191         const event = new KeyboardEvent('keydown', {
192             key: 'H',
193             ctrlKey: true,
194             shiftKey: true,
195         });
196         window.dispatchEvent(event);
198         // Assert that downloadLogs has been called
199         expect(createElementSpy).toHaveBeenCalled();
200     });
202     test('should call downloadLogs on message event in main frame', () => {
203         const createElementSpy = jest.spyOn(document, 'createElement');
204         // Simulate a message event from a child frame
205         const event = new MessageEvent('message', {
206             data: { type: '@proton/utils/logs:downloadLogs' },
207         });
208         window.dispatchEvent(event);
210         // Assert that downloadLogs has been called
211         expect(createElementSpy).toHaveBeenCalled();
212     });
214     test('should log report on main frame when receiving message from child frames', () => {
215         const err = new Error('test');
216         const tag = 'test';
217         const event = new MessageEvent('message', {
218             data: { type: '@proton/utils/logs:report', tag, args: [err] },
219         });
220         window.dispatchEvent(event);
221         expect(mockTraceError).toHaveBeenCalledWith(err, {
222             tags: {
223                 tag,
224             },
225             extra: {},
226         });
227     });
229     test('should log report on main frame when receiving message from child frames in the wrong format', () => {
230         const err = new Error('test');
231         const event = new MessageEvent('message', {
232             data: { type: '@proton/utils/logs:report', not: 'good format', args: [err] },
233         });
234         window.dispatchEvent(event);
235         expect(mockTraceError).toHaveBeenCalledWith(
236             new Error('@proton/utils/logs:report message does not contain args or is not spreadable'),
237             {
238                 tags: {
239                     tag: 'test-logger',
240                 },
241                 extra: {},
242             }
243         );
244     });