updating logger tests

This commit is contained in:
Bojan Kucera 2025-06-07 10:59:21 -04:00
parent b52765ecd8
commit e76489e8f3
6 changed files with 358 additions and 1089 deletions

View file

@ -1,21 +1,14 @@
/**
* Logger Integration Tests
*
* Tests the complete functionality of the @stock-bot/logger package,
* verifying that all components work together correctly.
* Tests the core functionality of the simplified @stock-bot/logger package.
*/
import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
import { describe, it, expect, beforeEach } from 'bun:test';
import {
Logger,
createLogger,
getLogger,
createTimer,
formatError,
sanitizeMetadata,
generateCorrelationId,
calculateLogSize,
LogThrottle
getLogger
} from '../src';
import { loggerTestHelpers } from './setup';
@ -63,35 +56,24 @@ describe('Logger Integration Tests', () => {
expect(logs[0].userId).toBe('123');
expect(logs[0].action).toBe('login');
expect(logs[0].msg).toBe('User logged in');
}); it('should maintain context across log calls', () => {
// Create a custom logger with context
const contextLogger = loggerTestHelpers.createTestLogger('context-test');
(contextLogger as any).context = {
requestId: 'req-123',
userId: 'user-456'
};
});
it('should handle error objects in error logs', () => {
const testError = new Error('Test error message');
// Log with context
contextLogger.info('Context test');
// Log error with error object
logger.error('Something went wrong', { error: testError });
// Get captured logs
const logs = loggerTestHelpers.getCapturedLogs();
// Verify context is included (implementation dependent)
// Verify error was logged
expect(logs.length).toBe(1);
expect(logs[0].msg).toBe('Context test');
// Context might be included in different ways
if (logs[0].context) {
expect(logs[0].context.requestId).toBe('req-123');
expect(logs[0].context.userId).toBe('user-456');
} else if (logs[0].requestId) {
expect(logs[0].requestId).toBe('req-123');
expect(logs[0].userId).toBe('user-456');
}
expect(logs[0].level).toBe('error');
expect(logs[0].msg).toBe('Something went wrong');
});
it('should create child loggers with additional context', () => {
it('should create child loggers with additional context', () => {
// Create a child logger with additional context
const childLogger = logger.child({
transactionId: 'tx-789',
@ -107,180 +89,98 @@ describe('Logger Integration Tests', () => {
// Verify child logger logged something
expect(logs.length).toBe(1);
expect(logs[0].msg).toBe('Child logger test');
// Check if context is preserved (implementation specific)
if (logs[0].context) {
expect(logs[0].context.transactionId).toBe('tx-789');
expect(logs[0].context.operation).toBe('payment');
} else if (logs[0].transactionId) {
expect(logs[0].transactionId).toBe('tx-789');
expect(logs[0].operation).toBe('payment');
}
});
}); describe('Factory Functions Integration', () => {
it('should create logger instances', () => {
// Since we're fully mocking the logger for tests,
// we'll just verify that the factory function doesn't throw
try {
// We don't actually call the real createLogger here to avoid Pino errors
// Instead just verify we have exported the function
expect(typeof createLogger).toBe('function');
expect(typeof getLogger).toBe('function');
} catch (error) {
// Should not throw
fail('Factory functions should be defined');
}
});
});
describe('Utility Function Integration', () => {
it('should create performance timers', async () => {
// Create and use timer
const timer = createTimer('test-operation');
// Wait a bit to measure time
await new Promise(resolve => setTimeout(resolve, 10));
// End timer
const result = timer.end();
// Log timer result
logger.info('Operation completed', { performance: result });
// Get captured logs
const logs = loggerTestHelpers.getCapturedLogs();
// Verify timer data in log
expect(logs.length).toBe(1);
expect(logs[0].performance.operation).toBe('test-operation');
expect(logs[0].performance.duration).toBeGreaterThan(0);
expect(logs[0].msg).toBe('Operation completed');
describe('Factory Functions', () => {
it('should export factory functions', () => {
// Verify that the factory functions are exported and callable
expect(typeof createLogger).toBe('function');
expect(typeof getLogger).toBe('function');
});
it('should format errors for logging', () => {
// Create error
it('should create different logger instances', () => {
const logger1 = loggerTestHelpers.createTestLogger('service-1');
const logger2 = loggerTestHelpers.createTestLogger('service-2');
logger1.info('Message from service 1');
logger2.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');
});
});
describe('Error Handling', () => {
it('should normalize Error objects', () => {
const error = new Error('Test error');
error.name = 'TestError';
error.stack = 'Error stack trace';
// Format error
const formattedError = formatError(error);
logger.error('Error occurred', { error });
// Log error with differently formatted object to match our mock
logger.error('An error occurred', { error: formattedError });
// Get captured logs
const logs = loggerTestHelpers.getCapturedLogs();
// Verify error format
expect(logs.length).toBe(1);
expect(logs[0].error.name).toBe('TestError');
expect(logs[0].error.message).toBe('Test error');
expect(logs[0].error.stack).toBeDefined();
}); it('should sanitize metadata', () => {
// Create metadata with sensitive info
const metadata = {
user: 'testuser',
password: 'secret123',
creditCard: '1234-5678-9012-3456',
ssn: '123-45-6789',
nested: {
password: 'another-secret',
token: 'sensitive-token'
}
};
// Sanitize metadata
const sanitized = sanitizeMetadata(metadata);
// Log sanitized data
logger.info('User data', { ...sanitized });
// Get captured logs
const logs = loggerTestHelpers.getCapturedLogs();
// Verify sanitized data
expect(logs.length).toBe(1);
// Based on actual implementation, 'user' is considered sensitive
expect(logs[0].user).toBe('[REDACTED]');
expect(logs[0].password).toBe('[REDACTED]');
expect(logs[0].creditCard).toBe('[REDACTED]');
expect(logs[0].ssn).toBe('[REDACTED]');
expect(logs[0].nested.password).toBe('[REDACTED]');
expect(logs[0].nested.token).toBe('[REDACTED]');
}); it('should generate correlation IDs', () => {
// Generate correlation ID
const correlationId = generateCorrelationId();
// Log with correlation ID
logger.info('Correlated event', { correlationId });
// Get captured logs
const logs = loggerTestHelpers.getCapturedLogs();
// Verify correlation ID format (timestamp-random format)
expect(logs.length).toBe(1);
expect(logs[0].correlationId).toBe(correlationId);
// The actual implementation uses timestamp-random format, not UUID
expect(correlationId).toMatch(/^\d+-[a-z0-9]+$/);
});
it('should calculate log size', () => {
// Create a log object
const logObj = {
message: 'Test message',
user: { id: 1234, name: 'Test User' },
tags: ['test', 'calculation'],
timestamp: new Date().toISOString()
};
// Calculate size
const size = calculateLogSize(logObj);
// Size should be greater than zero
expect(size).toBeGreaterThan(0);
// Double check with JSON.stringify
const jsonSize = JSON.stringify(logObj).length;
expect(size).toBe(jsonSize);
}); it('should throttle logs correctly', () => {
// Create throttle with small window
const throttle = new LogThrottle(3, 1000);
// First 3 should pass for same key
const sameKey = 'test-key';
expect(throttle.shouldLog(sameKey)).toBe(true);
expect(throttle.shouldLog(sameKey)).toBe(true);
expect(throttle.shouldLog(sameKey)).toBe(true);
// 4th should be throttled for same key
expect(throttle.shouldLog(sameKey)).toBe(false);
// Reset throttle
throttle.reset();
// Should allow logs again
expect(throttle.shouldLog('key4')).toBe(true);
});
});
describe('Error Handling Integration', () => {
it('should log caught exceptions properly', () => {
try {
// Throw an error
throw new Error('Test exception');
} catch (error) {
// Log the error
logger.error('Caught an exception', { error: formatError(error) });
}
// Get captured logs
const logs = loggerTestHelpers.getCapturedLogs();
// Verify error log
expect(logs.length).toBe(1);
expect(logs[0].level).toBe('error');
expect(logs[0].error.message).toBe('Test exception');
expect(logs[0].msg).toBe('Caught an exception');
expect(logs[0].msg).toBe('Error occurred');
});
it('should handle error-like objects', () => {
const errorLike = {
name: 'CustomError',
message: 'Custom error message',
code: 'ERR_CUSTOM'
};
logger.error('Custom error occurred', { error: errorLike });
const logs = loggerTestHelpers.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].level).toBe('error');
expect(logs[0].msg).toBe('Custom error occurred');
});
it('should handle primitive error values', () => {
logger.error('String error occurred', { error: 'Simple string error' });
const logs = loggerTestHelpers.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].level).toBe('error');
expect(logs[0].msg).toBe('String error occurred');
});
});
describe('Metadata Handling', () => {
it('should include metadata in logs', () => {
const metadata = {
requestId: 'req-123',
userId: 'user-456',
operation: 'data-fetch'
};
logger.info('Operation completed', metadata);
const logs = loggerTestHelpers.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].requestId).toBe('req-123');
expect(logs[0].userId).toBe('user-456');
expect(logs[0].operation).toBe('data-fetch');
});
it('should handle object messages', () => {
const objectMessage = {
event: 'user_action',
action: 'login',
timestamp: Date.now()
};
logger.info(objectMessage);
const logs = loggerTestHelpers.getCapturedLogs();
expect(logs.length).toBe(1);
expect(logs[0].level).toBe('info');
});
});
});