/** * Basic Logger Tests * * Tests for the core logger functionality and utilities. */ import { afterEach, beforeEach, describe, expect, it } from 'bun:test'; import { getLogger, Logger, shutdownLoggers } from '../src'; import { loggerTestHelpers } from './setup'; describe('Basic Logger Tests', () => { let logger: Logger; let testLoggerInstance: ReturnType; beforeEach(() => { testLoggerInstance = loggerTestHelpers.createTestLogger('utils-test'); logger = testLoggerInstance.logger; }); afterEach(async () => { testLoggerInstance.clearCapturedLogs(); // Clear any global logger cache await shutdownLoggers(); }); describe('Logger Factory Functions', () => { it('should create logger with getLogger', () => { expect(typeof getLogger).toBe('function'); // Test that getLogger doesn't throw expect(() => { const anotherTestLoggerInstance = loggerTestHelpers.createTestLogger('factory-test'); anotherTestLoggerInstance.logger.info('Factory test'); }).not.toThrow(); }); }); describe('Logger Methods', () => { it('should have all required logging methods', () => { expect(typeof logger.debug).toBe('function'); expect(typeof logger.info).toBe('function'); expect(typeof logger.warn).toBe('function'); expect(typeof logger.error).toBe('function'); expect(typeof logger.child).toBe('function'); }); it('should log with different message types', () => { // String message logger.info('String message'); // Object message logger.info({ event: 'object_message', data: 'test' }); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(2); expect(logs[0].msg).toBe('String message'); expect(logs[1].level).toBe('info'); }); it('should handle metadata correctly', () => { const metadata = { userId: 'user123', sessionId: 'session456', requestId: 'req789', }; logger.info('Request processed', metadata); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(1); expect(logs[0].userId).toBe('user123'); expect(logs[0].sessionId).toBe('session456'); expect(logs[0].requestId).toBe('req789'); }); }); describe('Child Logger Functionality', () => { it('should create child loggers with additional context', () => { const childLogger = logger.child({ module: 'payment', version: '1.0.0', }); childLogger.info('Payment processed'); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(1); expect(logs[0].msg).toBe('Payment processed'); }); it('should inherit service name in child loggers', () => { const childLogger = logger.child({ operation: 'test' }); childLogger.info('Child operation'); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(1); expect(logs[0].service).toBe('utils-test'); }); }); describe('Error Normalization', () => { it('should handle Error objects', () => { const error = new Error('Test error'); error.stack = 'Error stack trace'; logger.error('Error test', error); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(1); expect(logs[0].level).toBe('error'); }); it('should handle error-like objects', () => { const errorLike = { name: 'ValidationError', message: 'Invalid input', code: 'VALIDATION_FAILED', }; logger.error('Validation failed', { error: errorLike }); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(1); expect(logs[0].level).toBe('error'); }); it('should handle primitive error values', () => { logger.error('Simple error', { error: 'Error string' }); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(1); expect(logs[0].level).toBe('error'); }); }); describe('Service Context', () => { it('should include service name in all logs', () => { logger.debug('Debug message'); logger.info('Info message'); logger.warn('Warn message'); logger.error('Error message'); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(4); logs.forEach(log => { expect(log.service).toBe('utils-test'); }); }); it('should support different service names', () => { const logger1Instance = loggerTestHelpers.createTestLogger('service-one'); const logger2Instance = loggerTestHelpers.createTestLogger('service-two'); logger1Instance.logger.info('Message from service one'); logger2Instance.logger.info('Message from service two'); // Since each logger instance has its own capture, we check them separately // or combine them if that's the desired test logic. // For this test, it seems we want to ensure they are separate. const logs1 = logger1Instance.getCapturedLogs(); expect(logs1.length).toBe(1); expect(logs1[0].service).toBe('service-one'); const logs2 = logger2Instance.getCapturedLogs(); expect(logs2.length).toBe(1); expect(logs2[0].service).toBe('service-two'); }); }); });