forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {beforeAll, describe, expect, jest, test} from '@jest/globals'
2import * as Sentry from '@sentry/react-native'
3import {nanoid} from 'nanoid/non-secure'
4
5import {Logger} from '#/logger'
6import {sentryTransport} from '#/logger/transports/sentry'
7import {LogLevel} from '#/logger/types'
8
9jest.mock('@sentry/react-native', () => ({
10 addBreadcrumb: jest.fn(),
11 captureException: jest.fn(),
12 captureMessage: jest.fn(),
13}))
14
15beforeAll(() => {
16 jest.useFakeTimers()
17})
18
19describe('general functionality', () => {
20 test('default params', () => {
21 const logger = new Logger()
22 expect(logger.level).toEqual(LogLevel.Info)
23 })
24
25 test('can override default params', () => {
26 const logger = new Logger({
27 level: LogLevel.Debug,
28 })
29 expect(logger.level).toEqual(LogLevel.Debug)
30 })
31
32 test('contextFilter overrides level', () => {
33 const logger = new Logger({
34 level: LogLevel.Info,
35 contextFilter: 'test',
36 })
37 expect(logger.level).toEqual(LogLevel.Debug)
38 })
39
40 test('supports extra metadata', () => {
41 const timestamp = Date.now()
42 const logger = new Logger({})
43
44 const mockTransport = jest.fn()
45
46 logger.addTransport(mockTransport)
47
48 const extra = {foo: true, __metadata__: {}}
49 logger.warn('message', extra)
50
51 expect(mockTransport).toHaveBeenCalledWith(
52 LogLevel.Warn,
53 undefined,
54 'message',
55 extra,
56 timestamp,
57 )
58 })
59
60 test('supports inherited metadata', () => {
61 const timestamp = Date.now()
62 const logger = new Logger({
63 metadata: {bar: true},
64 })
65
66 const mockTransport = jest.fn()
67
68 logger.addTransport(mockTransport)
69
70 const extra = {foo: true, __metadata__: {bar: true}}
71 logger.warn('message', extra)
72
73 expect(mockTransport).toHaveBeenCalledWith(
74 LogLevel.Warn,
75 undefined,
76 'message',
77 extra,
78 timestamp,
79 )
80 })
81
82 test('supports nullish/falsy metadata', () => {
83 const timestamp = Date.now()
84 const logger = new Logger({})
85
86 const mockTransport = jest.fn()
87
88 const remove = logger.addTransport(mockTransport)
89
90 // @ts-expect-error testing the JS case
91 logger.warn('a', null)
92 expect(mockTransport).toHaveBeenCalledWith(
93 LogLevel.Warn,
94 undefined,
95 'a',
96 {__metadata__: {}},
97 timestamp,
98 )
99
100 // @ts-expect-error testing the JS case
101 logger.warn('b', false)
102 expect(mockTransport).toHaveBeenCalledWith(
103 LogLevel.Warn,
104 undefined,
105 'b',
106 {__metadata__: {}},
107 timestamp,
108 )
109
110 // @ts-expect-error testing the JS case
111 logger.warn('c', 0)
112 expect(mockTransport).toHaveBeenCalledWith(
113 LogLevel.Warn,
114 undefined,
115 'c',
116 {__metadata__: {}},
117 timestamp,
118 )
119
120 remove()
121
122 logger.addTransport((level, context, message, metadata) => {
123 expect(typeof metadata).toEqual('object')
124 })
125
126 // @ts-expect-error testing the JS case
127 logger.warn('message', null)
128 })
129
130 test('sentryTransport', () => {
131 const message = 'message'
132 const timestamp = Date.now()
133 const sentryTimestamp = timestamp / 1000
134
135 /*
136 sentryTransport(
137 LogLevel.Debug,
138 Logger.Context.Default,
139 message,
140 {},
141 timestamp,
142 )
143 expect(Sentry.addBreadcrumb).toHaveBeenCalledWith({
144 category: Logger.Context.Default,
145 message,
146 data: {__context__: 'logger'},
147 type: 'default',
148 level: LogLevel.Debug,
149 timestamp: sentryTimestamp,
150 })
151 */
152
153 sentryTransport(
154 LogLevel.Info,
155 Logger.Context.Default,
156 message,
157 {type: 'info', prop: true},
158 timestamp,
159 )
160 expect(Sentry.addBreadcrumb).toHaveBeenCalledWith({
161 category: Logger.Context.Default,
162 message,
163 data: {prop: true, __context__: 'logger'},
164 type: 'info',
165 level: LogLevel.Info,
166 timestamp: sentryTimestamp,
167 })
168
169 sentryTransport(
170 LogLevel.Log,
171 Logger.Context.Default,
172 message,
173 {},
174 timestamp,
175 )
176 expect(Sentry.addBreadcrumb).toHaveBeenCalledWith({
177 category: Logger.Context.Default,
178 message,
179 data: {__context__: 'logger'},
180 type: 'default',
181 level: 'log',
182 timestamp: sentryTimestamp,
183 })
184 jest.runAllTimers()
185 expect(Sentry.captureMessage).toHaveBeenCalledWith(message, {
186 level: 'log',
187 tags: {category: 'logger'},
188 extra: {__context__: 'logger'},
189 })
190
191 sentryTransport(
192 LogLevel.Warn,
193 Logger.Context.Default,
194 message,
195 {},
196 timestamp,
197 )
198 expect(Sentry.addBreadcrumb).toHaveBeenCalledWith({
199 category: Logger.Context.Default,
200 message,
201 data: {__context__: 'logger'},
202 type: 'default',
203 level: 'warning',
204 timestamp: sentryTimestamp,
205 })
206 jest.runAllTimers()
207 expect(Sentry.captureMessage).toHaveBeenCalledWith(message, {
208 level: 'warning',
209 tags: {category: 'logger'},
210 extra: {__context__: 'logger'},
211 })
212
213 const e = new Error('error')
214 const tags = {
215 prop: 'prop',
216 }
217
218 sentryTransport(
219 LogLevel.Error,
220 Logger.Context.Default,
221 e,
222 {
223 tags,
224 prop: true,
225 },
226 timestamp,
227 )
228
229 expect(Sentry.captureException).toHaveBeenCalledWith(e, {
230 tags: {
231 ...tags,
232 category: 'logger',
233 },
234 extra: {
235 prop: true,
236 __context__: 'logger',
237 },
238 })
239 })
240
241 test('sentryTransport serializes errors', () => {
242 const message = 'message'
243 const timestamp = Date.now()
244 const sentryTimestamp = timestamp / 1000
245
246 sentryTransport(
247 LogLevel.Info,
248 undefined,
249 message,
250 {error: new Error('foo')},
251 timestamp,
252 )
253 expect(Sentry.addBreadcrumb).toHaveBeenCalledWith({
254 message,
255 data: {error: 'Error: foo'},
256 type: 'default',
257 level: LogLevel.Info,
258 timestamp: sentryTimestamp,
259 })
260 })
261
262 test('add/remove transport', () => {
263 const timestamp = Date.now()
264 const logger = new Logger({})
265 const mockTransport = jest.fn()
266
267 const remove = logger.addTransport(mockTransport)
268
269 logger.warn('warn')
270
271 remove()
272
273 logger.warn('warn')
274
275 // only called once bc it was removed
276 expect(mockTransport).toHaveBeenNthCalledWith(
277 1,
278 LogLevel.Warn,
279 undefined,
280 'warn',
281 {__metadata__: {}},
282 timestamp,
283 )
284 })
285})
286
287describe('create', () => {
288 test('create', () => {
289 const mockTransport = jest.fn()
290 const timestamp = Date.now()
291 const message = nanoid()
292 const logger = Logger.create(Logger.Context.Default)
293
294 logger.addTransport(mockTransport)
295 logger.info(message, {})
296
297 expect(mockTransport).toHaveBeenCalledWith(
298 LogLevel.Info,
299 Logger.Context.Default,
300 message,
301 {__metadata__: {}},
302 timestamp,
303 )
304 })
305})
306
307describe('debug contexts', () => {
308 test('specific', () => {
309 const mockTransport = jest.fn()
310 const timestamp = Date.now()
311 const message = nanoid()
312 const logger = new Logger({
313 // @ts-ignore
314 context: 'specific',
315 level: LogLevel.Debug,
316 })
317
318 logger.addTransport(mockTransport)
319 logger.debug(message, {})
320
321 expect(mockTransport).toHaveBeenCalledWith(
322 LogLevel.Debug,
323 'specific',
324 message,
325 {__metadata__: {}},
326 timestamp,
327 )
328 })
329
330 test('namespaced', () => {
331 const mockTransport = jest.fn()
332 const timestamp = Date.now()
333 const message = nanoid()
334 const logger = new Logger({
335 // @ts-ignore
336 context: 'namespace:foo',
337 contextFilter: 'namespace:*',
338 level: LogLevel.Debug,
339 })
340
341 logger.addTransport(mockTransport)
342 logger.debug(message, {})
343
344 expect(mockTransport).toHaveBeenCalledWith(
345 LogLevel.Debug,
346 'namespace:foo',
347 message,
348 {__metadata__: {}},
349 timestamp,
350 )
351 })
352
353 test('ignores inactive', () => {
354 const mockTransport = jest.fn()
355 const timestamp = Date.now()
356 const message = nanoid()
357 const logger = new Logger({
358 // @ts-ignore
359 context: 'namespace:bar:baz',
360 contextFilter: 'namespace:foo:*',
361 })
362
363 logger.addTransport(mockTransport)
364 logger.debug(message, {})
365
366 expect(mockTransport).not.toHaveBeenCalledWith(
367 LogLevel.Debug,
368 'namespace:bar:baz',
369 message,
370 {__metadata__: {}},
371 timestamp,
372 )
373 })
374})
375
376describe('supports levels', () => {
377 test('debug', () => {
378 const timestamp = Date.now()
379 const logger = new Logger({
380 level: LogLevel.Debug,
381 })
382 const message = nanoid()
383 const mockTransport = jest.fn()
384
385 logger.addTransport(mockTransport)
386
387 logger.debug(message)
388 expect(mockTransport).toHaveBeenCalledWith(
389 LogLevel.Debug,
390 undefined,
391 message,
392 {__metadata__: {}},
393 timestamp,
394 )
395
396 logger.info(message)
397 expect(mockTransport).toHaveBeenCalledWith(
398 LogLevel.Info,
399 undefined,
400 message,
401 {__metadata__: {}},
402 timestamp,
403 )
404
405 logger.warn(message)
406 expect(mockTransport).toHaveBeenCalledWith(
407 LogLevel.Warn,
408 undefined,
409 message,
410 {__metadata__: {}},
411 timestamp,
412 )
413
414 const e = new Error(message)
415 logger.error(e)
416 expect(mockTransport).toHaveBeenCalledWith(
417 LogLevel.Error,
418 undefined,
419 e,
420 {__metadata__: {}},
421 timestamp,
422 )
423 })
424
425 test('info', () => {
426 const timestamp = Date.now()
427 const logger = new Logger({
428 level: LogLevel.Info,
429 })
430 const message = nanoid()
431 const mockTransport = jest.fn()
432
433 logger.addTransport(mockTransport)
434
435 logger.debug(message)
436 expect(mockTransport).not.toHaveBeenCalled()
437
438 logger.info(message)
439 expect(mockTransport).toHaveBeenCalledWith(
440 LogLevel.Info,
441 undefined,
442 message,
443 {__metadata__: {}},
444 timestamp,
445 )
446 })
447
448 test('warn', () => {
449 const timestamp = Date.now()
450 const logger = new Logger({
451 level: LogLevel.Warn,
452 })
453 const message = nanoid()
454 const mockTransport = jest.fn()
455
456 logger.addTransport(mockTransport)
457
458 logger.debug(message)
459 expect(mockTransport).not.toHaveBeenCalled()
460
461 logger.info(message)
462 expect(mockTransport).not.toHaveBeenCalled()
463
464 logger.warn(message)
465 expect(mockTransport).toHaveBeenCalledWith(
466 LogLevel.Warn,
467 undefined,
468 message,
469 {__metadata__: {}},
470 timestamp,
471 )
472 })
473
474 test('error', () => {
475 const timestamp = Date.now()
476 const logger = new Logger({
477 level: LogLevel.Error,
478 })
479 const message = nanoid()
480 const mockTransport = jest.fn()
481
482 logger.addTransport(mockTransport)
483
484 logger.debug(message)
485 expect(mockTransport).not.toHaveBeenCalled()
486
487 logger.info(message)
488 expect(mockTransport).not.toHaveBeenCalled()
489
490 logger.warn(message)
491 expect(mockTransport).not.toHaveBeenCalled()
492
493 const e = new Error('original message')
494 logger.error(e)
495 expect(mockTransport).toHaveBeenCalledWith(
496 LogLevel.Error,
497 undefined,
498 e,
499 {__metadata__: {}},
500 timestamp,
501 )
502 })
503})