smyld-lib-common
Version:
SMYLD Javascript Core Library, contains several core APIs that benefit the developers working on SPA applications
456 lines (357 loc) • 17.5 kB
text/typescript
import MainLogger, { Logger } from '../src/logging/Logger';
import { LogManager } from '../src/logging/LogManager';
import { LogLevel } from '../src/logging/LogSettings';
import { Type } from '../src/logging/LogMessage';
// Helper function to spy on console methods
function setupConsoleSpy(method: 'log' | 'info' | 'warn' | 'error' | 'debug') {
const originalMethod = console[method];
const spy = jest.spyOn(console, method).mockImplementation(() => {});
return {
spy,
restore: () => {
spy.mockRestore();
console[method] = originalMethod;
}
};
}
describe('Logger', () => {
beforeEach(()=>{
LogManager.getInstance().clearAll();
});
// Reset console spies after each test
afterEach(() => {
jest.restoreAllMocks();
});
describe('MainLogger', () => {
test('should be a singleton instance of Logger', () => {
expect(MainLogger).toBeInstanceOf(Logger);
expect(MainLogger.source).toBe('MainLogger');
});
test('should log messages with different levels', () => {
// Setup spies for all console methods
const infoSpy = setupConsoleSpy('info');
const warnSpy = setupConsoleSpy('warn');
const errorSpy = setupConsoleSpy('error');
const debugSpy = setupConsoleSpy('debug');
// Log messages with different levels
MainLogger.info('Info message');
MainLogger.warn('Warning message');
MainLogger.error('Error message');
MainLogger.debug('Debug message');
// Verify that console methods were called
expect(infoSpy.spy).toHaveBeenCalled();
expect(warnSpy.spy).toHaveBeenCalled();
expect(errorSpy.spy).toHaveBeenCalled();
expect(debugSpy.spy).toHaveBeenCalled();
// Restore console methods
infoSpy.restore();
warnSpy.restore();
errorSpy.restore();
debugSpy.restore();
});
test('should handle different input types', () => {
const infoSpy = setupConsoleSpy('info');
// Test with string
MainLogger.info('String message');
expect(infoSpy.spy).toHaveBeenCalled();
infoSpy.spy.mockClear();
// Test with object
const testObj = { id: 'myObject', text: 'This is an object' };
MainLogger.info(testObj);
expect(infoSpy.spy).toHaveBeenCalled();
infoSpy.spy.mockClear();
// Test with object in compact mode
MainLogger.info(testObj, true);
expect(infoSpy.spy).toHaveBeenCalled();
infoSpy.restore();
});
test('should cache logs when enabled', () => {
const testLogger:Logger = new Logger({source:'testCachedLogs'})
// Clear existing logs
MainLogger.deleteCachedLogs();
// Log some messages
testLogger.info('Test message 1');
testLogger.warn('Test message 2');
// Check that logs were cached
const cachedLogs = MainLogger.getCachedLogs();
expect(cachedLogs.length).toBeGreaterThan(0);
// Test getting logs as blob
const logsBlob = MainLogger.getCachedLogsAsBlob();
expect(logsBlob).toBeInstanceOf(Blob);
expect(logsBlob.type).toBe('text/plain');
});
test('Cached logs should not be duplicated', () => {
const testLogger:Logger = new Logger({source:'testDuplicateCachedLogs'})
// Clear existing logs
MainLogger.deleteCachedLogs();
MainLogger.setLogSettings({ cacheLogs: true });
// Log some messages
testLogger.info('Test message 1');
testLogger.warn('Test message 2');
// Check that logs were cached
const cachedLogs = MainLogger.getCachedLogs();
console.log('Cached Logs :', cachedLogs);
expect(cachedLogs.filter(log =>log.indexOf('Test message 1') !== -1).length).toBe(1);
});
test('should delete cached logs when requested', () => {
// Clear existing logs
MainLogger.logs = [];
// Log some messages
MainLogger.info('Test message for deletion 1');
MainLogger.warn('Test message for deletion 2');
// Verify logs were cached
expect(MainLogger.getCachedLogs().length).toBeGreaterThan(0);
// Delete cached logs
MainLogger.deleteCachedLogs();
// Verify logs were deleted
expect(MainLogger.getCachedLogs().length).toBe(0);
});
});
describe('Custom Logger', () => {
test('should create a custom logger with specified source', () => {
const customLogger = new Logger({ source: 'TestLogger' });
expect(customLogger.source).toBe('TestLogger');
const infoSpy = setupConsoleSpy('info');
customLogger.info('Custom logger message');
expect(infoSpy.spy).toHaveBeenCalled();
infoSpy.restore();
});
test('Should have a special source Log for nested Source names', () => {
const customLogger = new Logger({ source: 'application.components.gui.TestField' });
expect(customLogger.source).toBe('application.components.gui.TestField');
expect(customLogger.sourceLog).toBe('a.c.g.TestField');
const infoSpy = setupConsoleSpy('info');
customLogger.info('Custom logger message');
expect(infoSpy.spy).toHaveBeenCalled();
infoSpy.restore();
});
test('should register with LogManager', () => {
const loggerName = 'RegisteredLogger';
const customLogger = new Logger({ source: loggerName });
// Check that logger was registered
const logManager = LogManager.getInstance();
expect(logManager.hasLogger(loggerName)).toBe(true);
expect(logManager.getLogger(loggerName)).toBe(customLogger);
});
test('should retrieve the same logger instance in case created twice with pooled loggers set to true', () => {
const loggerName = 'ManagedLogger';
// Create a logger
const logger1 = new Logger({ source: loggerName });
// Get the logger from LogManager
const logManager = LogManager.getInstance();
const retrievedLogger1 = logManager.getLogger(loggerName);
const logger2 = new Logger({ source: loggerName });
// It should be the same instance
expect(retrievedLogger1).toBe(logger1);
const retrievedLogger2 = logManager.getLogger(loggerName);
expect(retrievedLogger2).toBe(logger2);
//
expect(logManager.getLogger(loggerName)).toBe(logger1);
expect(logManager.getLogger(loggerName)).toBe(logger2);
});
test('should retrieve different logger instance in case created twice with the same source with pooled loggers set to false', () => {
console.log("***************************************** Testing different instances ");
LogManager.getInstance().logSettings.pooledLoggers= false;
const loggerName = 'ManagedLogger';
// Create a logger
const logger1 = new Logger({ source: loggerName });
// Get the logger from LogManager
const logManager = LogManager.getInstance();
const retrievedLogger1 = logManager.getLogger(loggerName);
const logger2 = new Logger({ source: loggerName });
// It should be the same instance
expect(retrievedLogger1).toBe(logger1);
const retrievedLogger2 = logManager.getLogger(loggerName);
expect(retrievedLogger2).toBe(logger2);
//
expect(logManager.getLogger(loggerName)).not.toBe(logger1);
expect(logManager.getLogger(loggerName)).toBe(logger2);
});
test('should retrieve the same logger instance from LogManager', () => {
const loggerName = 'ManagedLogger';
// Create a logger
const logger1 = new Logger({ source: loggerName });
// Get the logger from LogManager
const logManager = LogManager.getInstance();
const retrievedLogger = logManager.getLogger(loggerName);
// It should be the same instance
expect(retrievedLogger).toBe(logger1);
// Create a logger with a different source
const differentLogger = new Logger({ source: 'DifferentLogger' });
// It should be a different instance
expect(logManager.getLogger('DifferentLogger')).toBe(differentLogger);
expect(logManager.getLogger('DifferentLogger')).not.toBe(logger1);
});
test('should respect log level settings', () => {
// Create logger with ERROR level
const restrictedLogger = new Logger({
source: 'RestrictedLogger',
logLevel: LogLevel.ERROR
});
// Setup spies
const infoSpy = setupConsoleSpy('info');
const errorSpy = setupConsoleSpy('error');
// Info should not be logged (below ERROR level)
restrictedLogger.info('This should not be logged');
expect(infoSpy.spy).not.toHaveBeenCalled();
// Error should be logged
restrictedLogger.error('This should be logged');
expect(errorSpy.spy).toHaveBeenCalled();
infoSpy.restore();
errorSpy.restore();
});
test('should update log level dynamically', () => {
const dynamicLogger = new Logger({
source: 'DynamicLogger',
logLevel: LogLevel.ERROR // Start with ERROR level
});
const infoSpy = setupConsoleSpy('info');
// Info should not be logged initially
dynamicLogger.info('This should not be logged');
expect(infoSpy.spy).not.toHaveBeenCalled();
infoSpy.spy.mockClear();
// Change log level to INFO
dynamicLogger.logLevel = LogLevel.INFO;
// Now info should be logged
dynamicLogger.info('This should be logged');
expect(infoSpy.spy).toHaveBeenCalled();
infoSpy.restore();
});
test('should initialize with LogManager log level when not specified', () => {
// Set LogManager log level
const logManager = LogManager.getInstance();
logManager.setGeneralLogLevel(LogLevel.WARN);
// Create logger without specifying log level
const logger = new Logger({ source: 'LogManagerLevelLogger' });
// Logger should have LogManager's log level
expect(logger.logLevel).toBe(LogLevel.WARN);
// Test that it respects this level
const debugSpy = setupConsoleSpy('debug');
const warnSpy = setupConsoleSpy('warn');
// Debug should not be logged (below WARN level)
logger.debug('This should not be logged');
expect(debugSpy.spy).not.toHaveBeenCalled();
// Warn should be logged
logger.warn('This should be logged');
expect(warnSpy.spy).toHaveBeenCalled();
debugSpy.restore();
warnSpy.restore();
// Reset LogManager log level for other tests
logManager.setGeneralLogLevel(LogLevel.DEBUG);
});
});
describe('LogManager', () => {
test('should be a singleton', () => {
const instance1 = LogManager.getInstance();
const instance2 = LogManager.getInstance();
expect(instance1).toBe(instance2);
});
test('should store and retrieve log level via getter', () => {
const logManager = LogManager.getInstance();
// Store the initial log level
const initialLogLevel = logManager.logLevel;
// Set a different log level
logManager.setGeneralLogLevel(LogLevel.WARN);
// Check that logLevel getter returns the new value
expect(logManager.logLevel).toBe(LogLevel.WARN);
// Reset to initial log level for other tests
logManager.setGeneralLogLevel(initialLogLevel);
});
test('should set log level for all loggers', () => {
// Create multiple loggers
const logger1 = new Logger({ source: 'Logger1' });
const logger2 = new Logger({ source: 'Logger2' });
// Set global log level
const logManager = LogManager.getInstance();
logManager.setGeneralLogLevel(LogLevel.ERROR);
// Check that all loggers have the new log level
expect(logger1.logLevel).toBe(LogLevel.ERROR);
expect(logger2.logLevel).toBe(LogLevel.ERROR);
// Check that logManager's logLevel is also updated
expect(logManager.logLevel).toBe(LogLevel.ERROR);
});
test('should set log level for specific logger', () => {
// Create multiple loggers
const logger1 = new Logger({ source: 'SpecificLogger1' });
const logger2 = new Logger({ source: 'SpecificLogger2' });
// Set log level for specific logger
const logManager = LogManager.getInstance();
logManager.setLogLevel('SpecificLogger1', LogLevel.DEBUG);
// Check that only the specified logger has the new log level
expect(logger1.logLevel).toBe(LogLevel.DEBUG);
expect(logger2.logLevel).not.toBe(LogLevel.DEBUG);
});
test('should set log level for specific loggers group', () => {
// Create multiple loggers
const logger1 = new Logger({ source: 'app.components.SpecificLogger1' });
const logger2 = new Logger({ source: 'app.components.SpecificLogger2' });
const logger3 = new Logger({ source: 'app.service.SpecificLogger3' });
const logger4 = new Logger({ source: 'app.service.SpecificLogger4' });
// Set log level for specific logger
const logManager = LogManager.getInstance();
logManager.setLogLevel('app.components', LogLevel.DEBUG);
logManager.setLogLevel('app.service', LogLevel.ALL);
// Check that only the specified logger has the new log level
expect(logger1.logLevel).toBe(LogLevel.DEBUG);
expect(logger2.logLevel).not.toBe(LogLevel.ALL);
expect(logger3.logLevel).toBe(LogLevel.ALL);
});
test('should set log level for loggers containing a specific string', () => {
// Create multiple loggers with different naming patterns
const logger1 = new Logger({ source: 'UserService' });
const logger2 = new Logger({ source: 'AdminUserService' });
const logger3 = new Logger({ source: 'ProductService' });
// Set log level for loggers containing 'User'
const logManager = LogManager.getInstance();
logManager.setLogLevelContaining('User', LogLevel.WARN);
// Check that only loggers with 'User' in their source have the new log level
expect(logger1.logLevel).toBe(LogLevel.WARN);
expect(logger2.logLevel).toBe(LogLevel.WARN);
expect(logger3.logLevel).not.toBe(LogLevel.WARN);
});
test('should set log level for loggers matching a regex pattern', () => {
// Create multiple loggers with different naming patterns
const logger1 = new Logger({ source: 'api.v1.UserController', logLevel: LogLevel.DEBUG });
const logger2 = new Logger({ source: 'api.v2.UserController', logLevel: LogLevel.DEBUG });
const logger3 = new Logger({ source: 'service.UserService', logLevel: LogLevel.DEBUG });
// Set log level for loggers matching the regex pattern
const logManager = LogManager.getInstance();
logManager.setLogLevelByRegex(/^api\.v\d+\..+$/, LogLevel.ERROR);
// Check that only loggers matching the regex have the new log level
expect(logger1.logLevel).toBe(LogLevel.ERROR);
expect(logger2.logLevel).toBe(LogLevel.ERROR);
expect(logger3.logLevel).toBe(LogLevel.DEBUG); // Should still be DEBUG, not ERROR
});
test('should retrieve loggers matching a regex pattern', () => {
// Create multiple loggers with different naming patterns
const logger1 = new Logger({ source: 'component.Button' });
const logger2 = new Logger({ source: 'component.Form' });
const logger3 = new Logger({ source: 'service.AuthService' });
// Get loggers matching the regex pattern
const logManager = LogManager.getInstance();
const matchingLoggers = logManager.getLoggersByRegex(/^component\..+$/);
// Check that only matching loggers are returned
expect(matchingLoggers.length).toBe(2);
expect(matchingLoggers).toContainEqual(logger1);
expect(matchingLoggers).toContainEqual(logger2);
expect(matchingLoggers).not.toContainEqual(logger3);
});
test('should retrieve all registered loggers', () => {
// Clear existing loggers by creating a new instance
const logManager = LogManager.getInstance();
// Create a set of test loggers
const logger1 = new Logger({ source: 'TestLogger1' });
const logger2 = new Logger({ source: 'TestLogger2' });
const logger3 = new Logger({ source: 'TestLogger3' });
// Get all loggers
const allLoggers = logManager.getAllLoggers();
// Check that all our test loggers are included
expect(allLoggers).toContainEqual(logger1);
expect(allLoggers).toContainEqual(logger2);
expect(allLoggers).toContainEqual(logger3);
// Check that the length is at least the number of loggers we created
// (there might be other loggers from previous tests)
expect(allLoggers.length).toBeGreaterThanOrEqual(3);
});
});
});