trying to figure out the issue with logger tests

This commit is contained in:
Bojan Kucera 2025-06-07 12:18:41 -04:00
parent 6aa63a8b59
commit d836e766d5
5 changed files with 127 additions and 93 deletions

View file

@ -11,7 +11,7 @@ export const loggingConfig = cleanEnv(process.env, {
// Basic Logging Settings
LOG_LEVEL: str({
default: 'info',
choices: ['error', 'warn', 'info', 'http', 'verbose', 'debug', 'silly'],
choices: ['debug' , 'info' , 'warn' , 'error'],
desc: 'Logging level'
}),
LOG_FORMAT: str({

View file

@ -11,13 +11,15 @@ import { loggerTestHelpers } from './setup';
describe('Advanced Logger Features', () => {
let logger: Logger;
let testLoggerInstance: ReturnType<typeof loggerTestHelpers.createTestLogger>;
beforeEach(() => {
loggerTestHelpers.clearCapturedLogs();
logger = loggerTestHelpers.createTestLogger('advanced-features');
testLoggerInstance = loggerTestHelpers.createTestLogger('advanced-features');
logger = testLoggerInstance.logger;
});
afterEach(() => {
loggerTestHelpers.clearCapturedLogs();
testLoggerInstance.clearCapturedLogs();
// Force garbage collection to clean up any potential circular references
if (global.gc) {
global.gc();
@ -34,7 +36,7 @@ describe('Advanced Logger Features', () => {
logger.info('Complex operation', complexMetadata);
const logs = loggerTestHelpers.getCapturedLogs();
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 });
@ -49,7 +51,7 @@ describe('Advanced Logger Features', () => {
logger.info('Array metadata test', arrayMetadata);
const logs = loggerTestHelpers.getCapturedLogs();
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]);
@ -65,7 +67,7 @@ describe('Advanced Logger Features', () => {
logger.info('Null metadata test', nullMetadata);
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].nullValue).toBe(null);
expect(logs[0].emptyString).toBe('');
@ -82,7 +84,7 @@ describe('Advanced Logger Features', () => {
childLogger.info('Child logger message');
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].component).toBe('auth-service');
expect(logs[0].version).toBe('1.2.3');
@ -95,7 +97,7 @@ describe('Advanced Logger Features', () => {
grandChildLogger.warn('Nested child message');
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].level1).toBe('parent');
expect(logs[0].level2).toBe('child');
@ -110,7 +112,7 @@ describe('Advanced Logger Features', () => {
duration: 150
});
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].service).toBe('api');
expect(logs[0].requestId).toBe('req-789');
@ -126,7 +128,7 @@ describe('Advanced Logger Features', () => {
logger.error('Custom error occurred', { error: customError });
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].level).toBe('error');
expect(logs[0].msg).toBe('Custom error occurred');
@ -142,7 +144,7 @@ describe('Advanced Logger Features', () => {
context: 'batch processing'
});
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].context).toBe('batch processing');
});
@ -157,7 +159,7 @@ describe('Advanced Logger Features', () => {
logger.error('Circular error test', { error: errorWithCircular });
}).not.toThrow();
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].level).toBe('error');
});
@ -171,7 +173,7 @@ describe('Advanced Logger Features', () => {
logger.debug('Moderate metadata test', moderateMetadata);
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].key0).toBe('value0');
expect(logs[0].key9).toBe('value9');
@ -182,7 +184,7 @@ describe('Advanced Logger Features', () => {
logger.info(specialMessage);
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].msg).toBe(specialMessage);
});
@ -191,7 +193,7 @@ describe('Advanced Logger Features', () => {
logger.info('');
logger.info(' ');
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(2);
expect(logs[0].msg).toBe('');
expect(logs[1].msg).toBe(' ');

View file

@ -10,14 +10,15 @@ import { loggerTestHelpers } from './setup';
describe('Basic Logger Tests', () => {
let logger: Logger;
let testLoggerInstance: ReturnType<typeof loggerTestHelpers.createTestLogger>;
beforeEach(() => {
loggerTestHelpers.clearCapturedLogs();
logger = loggerTestHelpers.createTestLogger('utils-test');
testLoggerInstance = loggerTestHelpers.createTestLogger('utils-test');
logger = testLoggerInstance.logger;
});
afterEach(() => {
loggerTestHelpers.clearCapturedLogs();
testLoggerInstance.clearCapturedLogs();
});
describe('Logger Factory Functions', () => {
@ -26,8 +27,8 @@ describe('Basic Logger Tests', () => {
// Test that getLogger doesn't throw
expect(() => {
const testLogger = loggerTestHelpers.createTestLogger('factory-test');
testLogger.info('Factory test');
const anotherTestLoggerInstance = loggerTestHelpers.createTestLogger('factory-test');
anotherTestLoggerInstance.logger.info('Factory test');
}).not.toThrow();
});
@ -55,7 +56,7 @@ describe('Basic Logger Tests', () => {
// Object message
logger.info({ event: 'object_message', data: 'test' });
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(2);
expect(logs[0].msg).toBe('String message');
expect(logs[1].level).toBe('info');
@ -70,7 +71,7 @@ describe('Basic Logger Tests', () => {
logger.info('Request processed', metadata);
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].userId).toBe('user123');
expect(logs[0].sessionId).toBe('session456');
@ -87,7 +88,7 @@ describe('Basic Logger Tests', () => {
childLogger.info('Payment processed');
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].msg).toBe('Payment processed');
});
@ -96,7 +97,7 @@ describe('Basic Logger Tests', () => {
const childLogger = logger.child({ operation: 'test' });
childLogger.info('Child operation');
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].service).toBe('utils-test');
});
@ -109,7 +110,7 @@ describe('Basic Logger Tests', () => {
logger.error('Error test', error);
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].level).toBe('error');
});
@ -123,7 +124,7 @@ describe('Basic Logger Tests', () => {
logger.error('Validation failed', { error: errorLike });
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].level).toBe('error');
});
@ -131,7 +132,7 @@ describe('Basic Logger Tests', () => {
it('should handle primitive error values', () => {
logger.error('Simple error', { error: 'Error string' });
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].level).toBe('error');
});
@ -144,7 +145,7 @@ describe('Basic Logger Tests', () => {
logger.warn('Warn message');
logger.error('Error message');
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(4);
logs.forEach(log => {
@ -153,16 +154,22 @@ describe('Basic Logger Tests', () => {
});
it('should support different service names', () => {
const logger1 = loggerTestHelpers.createTestLogger('service-one');
const logger2 = loggerTestHelpers.createTestLogger('service-two');
const logger1Instance = loggerTestHelpers.createTestLogger('service-one');
const logger2Instance = loggerTestHelpers.createTestLogger('service-two');
logger1.info('Message from service one');
logger2.info('Message from service two');
logger1Instance.logger.info('Message from service one');
logger2Instance.logger.info('Message from service two');
const logs = loggerTestHelpers.getCapturedLogs();
expect(logs.length).toBe(2);
expect(logs[0].service).toBe('service-one');
expect(logs[1].service).toBe('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');
});
});
});

View file

@ -14,15 +14,15 @@ import { loggerTestHelpers } from './setup';
describe('Logger Integration Tests', () => {
let logger: Logger;
let testLoggerInstance: ReturnType<typeof loggerTestHelpers.createTestLogger>;
beforeEach(() => {
// Create a new test logger before each test
loggerTestHelpers.clearCapturedLogs();
logger = loggerTestHelpers.createTestLogger('integration-test');
testLoggerInstance = loggerTestHelpers.createTestLogger('integration-test');
logger = testLoggerInstance.logger;
});
afterEach(() => {
loggerTestHelpers.clearCapturedLogs();
testLoggerInstance.clearCapturedLogs();
});
describe('Core Logger Functionality', () => {
@ -34,7 +34,7 @@ describe('Logger Integration Tests', () => {
logger.error('Error message');
// Get captured logs
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
// Verify logs were captured
expect(logs.length).toBe(4);
@ -53,7 +53,7 @@ describe('Logger Integration Tests', () => {
logger.info('User logged in', { userId: '123', action: 'login' });
// Get captured logs
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
// Verify structured log
expect(logs.length).toBe(1);
@ -69,7 +69,7 @@ describe('Logger Integration Tests', () => {
logger.error('Something went wrong', { error: testError });
// Get captured logs
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
// Verify error was logged
expect(logs.length).toBe(1);
@ -88,7 +88,7 @@ describe('Logger Integration Tests', () => {
childLogger.info('Child logger test');
// Get captured logs
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
// Verify child logger logged something
expect(logs.length).toBe(1);
@ -104,17 +104,19 @@ describe('Logger Integration Tests', () => {
});
it('should create different logger instances', () => {
const logger1 = loggerTestHelpers.createTestLogger('service-1');
const logger2 = loggerTestHelpers.createTestLogger('service-2');
const logger1Instance = loggerTestHelpers.createTestLogger('service-1');
const logger2Instance = loggerTestHelpers.createTestLogger('service-2');
logger1.info('Message from service 1');
logger2.info('Message from service 2');
logger1Instance.logger.info('Message from service 1');
logger2Instance.logger.info('Message from service 2');
const logs = loggerTestHelpers.getCapturedLogs();
expect(logs.length).toBe(2);
expect(logs[0].service).toBe('service-1');
expect(logs[1].service).toBe('service-2');
const logs1 = logger1Instance.getCapturedLogs();
expect(logs1.length).toBe(1);
expect(logs1[0].service).toBe('service-1');
const logs2 = logger2Instance.getCapturedLogs();
expect(logs2.length).toBe(1);
expect(logs2[0].service).toBe('service-2');
});
});
@ -125,7 +127,7 @@ describe('Logger Integration Tests', () => {
logger.error('Error occurred', error);
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].level).toBe('error');
expect(logs[0].msg).toBe('Error occurred');
@ -140,7 +142,7 @@ describe('Logger Integration Tests', () => {
logger.error('Custom error occurred', { error: errorLike });
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].level).toBe('error');
expect(logs[0].msg).toBe('Custom error occurred');
@ -149,7 +151,7 @@ describe('Logger Integration Tests', () => {
it('should handle primitive error values', () => {
logger.error('String error occurred', { error: 'Simple string error' });
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].level).toBe('error');
expect(logs[0].msg).toBe('String error occurred');
@ -166,7 +168,7 @@ describe('Logger Integration Tests', () => {
logger.info('Operation completed', metadata);
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].requestId).toBe('req-123');
expect(logs[0].userId).toBe('user-456');
@ -182,7 +184,7 @@ describe('Logger Integration Tests', () => {
logger.info(objectMessage);
const logs = loggerTestHelpers.getCapturedLogs();
const logs = testLoggerInstance.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].level).toBe('info');
});

View file

@ -5,7 +5,7 @@
* Provides utilities and mocks for testing logging operations.
*/
import { Logger } from '../src';
import { Logger, LogMetadata } from '../src';
import { afterAll, afterEach, beforeAll, beforeEach } from 'bun:test';
// Store original console methods
@ -17,43 +17,66 @@ const originalConsole = {
debug: console.debug
};
// Storage for captured logs
let capturedLogs: any[] = [];
// Create a test logger helper
export const loggerTestHelpers = { /**
* Create a test logger instance that captures logs instead of outputting them
*/ 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, ...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) => {
return loggerTestHelpers.createTestLogger(serviceName, { ...context, ...childContext });
export const loggerTestHelpers = {
/**
* Create a test logger instance that captures logs locally.
*/
createTestLogger: (serviceName: string = 'test-service', initialContext: any = {}) => {
const capturedLogsArray: any[] = [];
const createLoggerMockInstance = (currentContext: any): Logger => {
const buildLogEntry = (level: string, messageOrObject: string | object, metadata?: any) => {
const logObject: any = { level, service: serviceName, ...currentContext };
if (typeof messageOrObject === 'string') {
logObject.msg = messageOrObject;
if (metadata) {
Object.assign(logObject, metadata);
}
} else { // messageOrObject is an object
Object.assign(logObject, messageOrObject); // Merge fields from the message object
if (metadata) { // If metadata is also provided (e.g. logger.error({code: 1}, {extra: 'data'}))
Object.assign(logObject, metadata);
}
// Ensure 'msg' field exists, defaulting if necessary
if (typeof logObject.msg === 'undefined') {
// If the second arg was a string, it might have been intended as the message
if (typeof metadata === 'string') {
logObject.msg = metadata;
} else {
logObject.msg = 'Object logged';
}
}
}
capturedLogsArray.push(logObject);
};
return {
// serviceName, // For inspection if needed, though logs capture it
context: currentContext, // For inspection
debug: (msgOrObj: string | object, meta?: any) => buildLogEntry('debug', msgOrObj, meta),
info: (msgOrObj: string | object, meta?: any) => buildLogEntry('info', msgOrObj, meta),
warn: (msgOrObj: string | object, meta?: any) => buildLogEntry('warn', msgOrObj, meta),
error: (msgOrObj: string | object, metaOrMsg?: any) => buildLogEntry('error', msgOrObj, metaOrMsg),
child: (childContext: any): Logger => {
// Children will log to the same capturedLogsArray
return createLoggerMockInstance({ ...currentContext, ...childContext });
}
} as any; // Cast to Logger, assuming it fulfills the interface for testing purposes
};
const loggerInstance = createLoggerMockInstance(initialContext);
return {
logger: loggerInstance,
getCapturedLogs: () => [...capturedLogsArray],
clearCapturedLogs: () => {
capturedLogsArray.length = 0;
}
};
return logger as unknown as Logger;
},
/**
* Get the captured logs
*/
getCapturedLogs: () => [...capturedLogs],
/**
* Clear captured logs
*/
clearCapturedLogs: () => {
capturedLogs = [];
},
/**
* Mock Loki transport
*/
@ -156,7 +179,7 @@ beforeAll(() => {
// Clean up after each test
afterEach(() => {
loggerTestHelpers.clearCapturedLogs();
// loggerTestHelpers.clearCapturedLogs(); // REMOVE this if it targeted a global array
});
// Restore everything after tests