/** * Advanced Logger Tests * * Tests for advanced logger functionality including complex metadata handling, * child loggers, and advanced error scenarios. */ import { afterEach, beforeEach, describe, expect, it } from 'bun:test'; import { Logger, shutdownLoggers } from '../src'; import { loggerTestHelpers } from './setup'; describe('Advanced Logger Features', () => { let logger: Logger; let testLoggerInstance: ReturnType; beforeEach(() => { testLoggerInstance = loggerTestHelpers.createTestLogger('advanced-features'); logger = testLoggerInstance.logger; }); afterEach(async () => { testLoggerInstance.clearCapturedLogs(); // Clear any global logger cache await shutdownLoggers(); }); describe('Complex Metadata Handling', () => { it('should handle nested metadata objects', () => { const complexMetadata = { user: { id: '123', name: 'John Doe' }, session: { id: 'sess-456', timeout: 3600 }, request: { method: 'POST', path: '/api/test' }, }; logger.info('Complex operation', complexMetadata); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(1); expect(logs[0].user).toEqual({ id: '123', name: 'John Doe' }); expect(logs[0].session).toEqual({ id: 'sess-456', timeout: 3600 }); expect(logs[0].request).toEqual({ method: 'POST', path: '/api/test' }); }); it('should handle arrays in metadata', () => { const arrayMetadata = { tags: ['user', 'authentication', 'success'], ids: [1, 2, 3, 4], }; logger.info('Array metadata test', arrayMetadata); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(1); expect(logs[0].tags).toEqual(['user', 'authentication', 'success']); expect(logs[0].ids).toEqual([1, 2, 3, 4]); }); it('should handle null and undefined metadata values', () => { const nullMetadata = { nullValue: null, undefinedValue: undefined, emptyString: '', zeroValue: 0, }; logger.info('Null metadata test', nullMetadata); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(1); expect(logs[0].nullValue).toBe(null); expect(logs[0].emptyString).toBe(''); expect(logs[0].zeroValue).toBe(0); }); }); describe('Child Logger Functionality', () => { it('should create child logger with additional context', () => { const childLogger = logger.child({ component: 'auth-service', version: '1.2.3', }); childLogger.info('Child logger message'); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(1); expect(logs[0].component).toBe('auth-service'); expect(logs[0].version).toBe('1.2.3'); expect(logs[0].msg).toBe('Child logger message'); }); it('should support nested child loggers', () => { const childLogger = logger.child({ level1: 'parent' }); const grandChildLogger = childLogger.child({ level2: 'child' }); grandChildLogger.warn('Nested child message'); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(1); expect(logs[0].level1).toBe('parent'); expect(logs[0].level2).toBe('child'); expect(logs[0].level).toBe('warn'); }); it('should merge child context with log metadata', () => { const childLogger = logger.child({ service: 'api' }); childLogger.info('Request processed', { requestId: 'req-789', duration: 150, }); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(1); expect(logs[0].service).toBe('api'); expect(logs[0].requestId).toBe('req-789'); expect(logs[0].duration).toBe(150); }); }); describe('Advanced Error Handling', () => { it('should handle Error objects with custom properties', () => { const customError = new Error('Custom error message'); (customError as any).code = 'ERR_CUSTOM'; (customError as any).statusCode = 500; logger.error('Custom error occurred', { error: customError }); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(1); expect(logs[0].level).toBe('error'); expect(logs[0].msg).toBe('Custom error occurred'); }); it('should handle multiple errors in metadata', () => { const error1 = new Error('First error'); const error2 = new Error('Second error'); logger.error('Multiple errors', { primaryError: error1, secondaryError: error2, context: 'batch processing', }); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(1); expect(logs[0].context).toBe('batch processing'); }); it('should handle error objects with circular references', () => { const errorWithCircular: any = { name: 'CircularError', message: 'Circular reference error' }; // Create a simple circular reference errorWithCircular.self = errorWithCircular; // Should not throw when logging circular references expect(() => { logger.error('Circular error test', { error: errorWithCircular }); }).not.toThrow(); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(1); expect(logs[0].level).toBe('error'); // Clean up circular reference to prevent memory issues delete errorWithCircular.self; }); }); describe('Performance and Edge Cases', () => { it('should handle moderate metadata objects', () => { const moderateMetadata: any = {}; for (let i = 0; i < 10; i++) { moderateMetadata[`key${i}`] = `value${i}`; } logger.debug('Moderate metadata test', moderateMetadata); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(1); expect(logs[0].key0).toBe('value0'); expect(logs[0].key9).toBe('value9'); }); it('should handle special characters in messages', () => { const specialMessage = 'Special chars: 🚀 ñ ü'; logger.info(specialMessage); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(1); expect(logs[0].msg).toBe(specialMessage); }); it('should handle empty and whitespace-only messages', () => { logger.info(''); logger.info(' '); const logs = testLoggerInstance.getCapturedLogs(); expect(logs.length).toBe(2); expect(logs[0].msg).toBe(''); expect(logs[1].msg).toBe(' '); }); }); });