trying to fix tests

This commit is contained in:
Bojan Kucera 2025-06-07 11:44:45 -04:00
parent 6b4d4ea29f
commit db66687f48
3 changed files with 159 additions and 64 deletions

View file

@ -176,12 +176,14 @@ export class Logger {
message: String(error)
};
}
/**
* Create child logger with additional context
*/
child(context: LogContext): Logger {
return new Logger((this.pino.bindings() as any).service, { ...this.context, ...context });
const childLogger = new Logger((this.pino.bindings() as any).service, { ...this.context, ...context });
// Use the pino child logger to properly propagate context
childLogger.pino = this.pino.child(context);
return childLogger;
}
}

View file

@ -1,102 +1,198 @@
/**
* Advanced Logger Tests
*
* Tests for advanced logger functionality.
* 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, getLogger } from '../src';
import { Logger } from '../src';
import { loggerTestHelpers } from './setup';
describe('Advanced Logger Tests', () => {
describe('Advanced Logger Features', () => {
let logger: Logger;
beforeEach(() => {
loggerTestHelpers.clearCapturedLogs();
logger = loggerTestHelpers.createTestLogger('advanced-test');
logger = loggerTestHelpers.createTestLogger('advanced-features');
});
afterEach(() => {
loggerTestHelpers.clearCapturedLogs();
// Force garbage collection to clean up any potential circular references
if (global.gc) {
global.gc();
}
});
describe('Basic Logging', () => {
it('should create logger instances', () => {
expect(logger).toBeDefined();
expect(typeof logger.info).toBe('function');
expect(typeof logger.error).toBe('function');
expect(typeof logger.warn).toBe('function');
expect(typeof logger.debug).toBe('function');
});
it('should log simple messages', () => {
logger.info('Test message');
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 = loggerTestHelpers.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].msg).toBe('Test message');
expect(logs[0].level).toBe('info');
}); it('should include service name in logs', () => {
logger.info('Service test');
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 = loggerTestHelpers.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].service).toBe('advanced-test');
expect(logs[0].tags).toEqual(['user', 'authentication', 'success']);
expect(logs[0].ids).toEqual([1, 2, 3, 4]);
});
it('should handle multiple log levels', () => {
logger.debug('Debug level');
logger.info('Info level');
logger.warn('Warn level');
logger.error('Error level');
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 = loggerTestHelpers.getCapturedLogs();
expect(logs.length).toBe(4);
const levels = logs.map(log => log.level);
expect(levels).toEqual(['debug', 'info', 'warn', 'error']);
expect(logs.length).toBe(1);
expect(logs[0].nullValue).toBe(null);
expect(logs[0].emptyString).toBe('');
expect(logs[0].zeroValue).toBe(0);
});
});
describe('Context and Metadata', () => {
it('should include metadata in logs', () => {
const metadata = { userId: '123', action: 'test' };
logger.info('User action', metadata);
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 = loggerTestHelpers.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].userId).toBe('123');
expect(logs[0].action).toBe('test');
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 child loggers', () => {
const childLogger = logger.child({ requestId: 'req-456' });
childLogger.info('Child log 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 = loggerTestHelpers.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].msg).toBe('Child log message');
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 = loggerTestHelpers.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('Error Logging', () => {
it('should log errors with error metadata', () => {
const error = new Error('Test error');
logger.error('Error occurred', { error });
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 = loggerTestHelpers.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].level).toBe('error');
expect(logs[0].msg).toBe('Error occurred');
expect(logs[0].msg).toBe('Custom error occurred');
});
it('should handle error-like objects', () => {
const errorLike = { name: 'CustomError', message: 'Custom message' };
logger.error('Custom error', { error: errorLike });
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 = loggerTestHelpers.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 = loggerTestHelpers.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].level).toBe('error');
});
});
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 = loggerTestHelpers.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 = loggerTestHelpers.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 = loggerTestHelpers.getCapturedLogs();
expect(logs.length).toBe(2);
expect(logs[0].msg).toBe('');
expect(logs[1].msg).toBe(' ');
});
});
});

View file

@ -21,25 +21,22 @@ const originalConsole = {
let capturedLogs: any[] = [];
// Create a test logger helper
export const loggerTestHelpers = {
/**
export const loggerTestHelpers = { /**
* Create a test logger instance that captures logs instead of outputting them
*/ createTestLogger: (serviceName: string = 'test-service') => {
*/ createTestLogger: (serviceName: string = 'test-service', context: any = {}) => {
// Create a fully mocked Logger instance without using the real Logger class
const logger = {
serviceName,
context: {},
debug: (msg: string, metadata?: any) => capturedLogs.push({ level: 'debug', msg, service: serviceName, ...metadata }),
info: (msg: string, metadata?: any) => capturedLogs.push({ level: 'info', msg, service: serviceName, ...metadata }),
warn: (msg: string, metadata?: any) => capturedLogs.push({ level: 'warn', msg, service: serviceName, ...metadata }),
error: (msg: string, metadata?: any) => capturedLogs.push({ level: 'error', msg, service: serviceName, ...metadata }),
http: (msg: string, metadata?: any) => capturedLogs.push({ level: 'http', msg, service: serviceName, ...metadata }),
verbose: (msg: string, metadata?: any) => capturedLogs.push({ level: 'verbose', msg, service: serviceName, ...metadata }),
silly: (msg: string, metadata?: any) => capturedLogs.push({ level: 'silly', msg, service: serviceName, ...metadata }),
context,
debug: (msg: string, metadata?: any) => capturedLogs.push({ level: 'debug', msg, service: serviceName, ...context, ...metadata }),
info: (msg: string, metadata?: any) => capturedLogs.push({ level: 'info', msg, service: serviceName, ...context, ...metadata }),
warn: (msg: string, metadata?: any) => capturedLogs.push({ level: 'warn', msg, service: serviceName, ...context, ...metadata }),
error: (msg: string, metadata?: any) => capturedLogs.push({ level: 'error', msg, service: serviceName, ...context, ...metadata }),
http: (msg: string, metadata?: any) => capturedLogs.push({ level: 'http', msg, service: serviceName, ...context, ...metadata }),
verbose: (msg: string, metadata?: any) => capturedLogs.push({ level: 'verbose', msg, service: serviceName, ...context, ...metadata }),
silly: (msg: string, metadata?: any) => capturedLogs.push({ level: 'silly', msg, service: serviceName, ...context, ...metadata }),
child: (childContext: any) => {
const childLogger = loggerTestHelpers.createTestLogger(serviceName);
(childLogger as any).context = { ...(childLogger as any).context, ...childContext };
return childLogger;
return loggerTestHelpers.createTestLogger(serviceName, { ...context, ...childContext });
}
};