200 lines
6.9 KiB
TypeScript
200 lines
6.9 KiB
TypeScript
/**
|
|
* Advanced Logger Tests
|
|
*
|
|
* Tests for advanced logger functionality including complex metadata handling,
|
|
* child loggers, and advanced error scenarios.
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
|
|
import { Logger, shutdownLoggers } from '../src';
|
|
import { loggerTestHelpers } from './setup';
|
|
|
|
describe('Advanced Logger Features', () => {
|
|
let logger: Logger;
|
|
let testLoggerInstance: ReturnType<typeof loggerTestHelpers.createTestLogger>;
|
|
|
|
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(' ');
|
|
});
|
|
});
|
|
});
|