import { beforeEach, describe, expect, it } from 'bun:test'; import { Logger, getLogger, setLoggerConfig, shutdownLoggers } from '../src/logger'; describe('Logger', () => { beforeEach(async () => { // Reset logger state await shutdownLoggers(); }); it('should create a logger instance', () => { const logger = getLogger('test'); expect(logger).toBeDefined(); expect(logger).toBeInstanceOf(Logger); }); it('should use same pino instance for same name', async () => { await shutdownLoggers(); // Reset first const logger1 = getLogger('test'); const logger2 = getLogger('test'); // While Logger instances are different, they should share the same pino instance expect(logger1).not.toBe(logger2); // Different Logger instances // But they have the same service name expect((logger1 as any).serviceName).toBe((logger2 as any).serviceName); }); it('should create different instances for different names', () => { const logger1 = getLogger('test1'); const logger2 = getLogger('test2'); expect(logger1).not.toBe(logger2); }); it('should have logging methods', () => { const logger = getLogger('test'); expect(typeof logger.info).toBe('function'); expect(typeof logger.error).toBe('function'); expect(typeof logger.warn).toBe('function'); expect(typeof logger.debug).toBe('function'); expect(typeof logger.trace).toBe('function'); }); it('should create child logger', () => { const logger = getLogger('parent'); const child = logger.child('child'); expect(child).toBeDefined(); expect(child).toBeInstanceOf(Logger); }); it('should accept metadata in log methods', () => { const logger = getLogger('test'); // These should not throw logger.info('Test message'); logger.info('Test message', { key: 'value' }); logger.error('Error message', { error: new Error('test') }); logger.warn('Warning', { count: 5 }); logger.debug('Debug info', { data: [1, 2, 3] }); logger.trace('Trace details', { nested: { value: true } }); }); it('should format log messages', () => { const logger = getLogger('test'); // Just verify the logger can log without errors // The actual format is handled by pino-pretty which outputs to stdout expect(() => { logger.info('Test message'); logger.warn('Warning message'); logger.error('Error message'); }).not.toThrow(); }); it('should set logger config', () => { setLoggerConfig({ logLevel: 'debug', }); const logger = getLogger('test'); expect(logger).toBeDefined(); }); it('should handle shutdown', async () => { await shutdownLoggers(); // Reset first const logger1 = getLogger('test1'); const _logger2 = getLogger('test2'); // not used, just to ensure multiple loggers can be created // Store references const logger1Ref = logger1; await shutdownLoggers(); // Should create new instances after shutdown const logger3 = getLogger('test1'); expect(logger3).not.toBe(logger1Ref); }); it('should handle log levels', async () => { await shutdownLoggers(); // Reset first setLoggerConfig({ logLevel: 'warn' }); const logger = getLogger('test'); // Just verify that log methods exist and don't throw // The actual level filtering is handled by pino expect(() => { logger.trace('Trace'); // Should not log logger.debug('Debug'); // Should not log logger.info('Info'); // Should not log logger.warn('Warn'); // Should log logger.error('Error'); // Should log }).not.toThrow(); // Clean up await shutdownLoggers(); }); });