@iterable/react-native-sdk
Version:
Iterable SDK for React Native.
399 lines (340 loc) • 13.6 kB
text/typescript
import { IterableLogLevel } from '../enums/IterableLogLevel';
import { IterableLogger, DEFAULT_LOG_LEVEL, DEFAULT_LOGGING_ENABLED } from './IterableLogger';
// Mock console.log to capture log output
const mockConsoleLog = jest.fn();
const originalConsoleLog = console.log;
describe('IterableLogger', () => {
beforeEach(() => {
// Reset to default values before each test
IterableLogger.loggingEnabled = DEFAULT_LOGGING_ENABLED;
IterableLogger.logLevel = DEFAULT_LOG_LEVEL;
// Mock console.log
console.log = mockConsoleLog;
mockConsoleLog.mockClear();
});
afterEach(() => {
// Restore original console.log
console.log = originalConsoleLog;
});
describe('Static Properties', () => {
test('should have default logging enabled', () => {
expect(IterableLogger.loggingEnabled).toBe(true);
});
test('should have default log level as debug', () => {
expect(IterableLogger.logLevel).toBe(IterableLogLevel.debug);
});
test('should allow setting loggingEnabled directly', () => {
IterableLogger.loggingEnabled = false;
expect(IterableLogger.loggingEnabled).toBe(false);
});
test('should allow setting logLevel directly', () => {
IterableLogger.logLevel = IterableLogLevel.error;
expect(IterableLogger.logLevel).toBe(IterableLogLevel.error);
});
});
describe('setLoggingEnabled', () => {
test('should set logging enabled to true when passed true', () => {
IterableLogger.setLoggingEnabled(true);
expect(IterableLogger.loggingEnabled).toBe(true);
});
test('should set logging enabled to false when passed false', () => {
IterableLogger.setLoggingEnabled(false);
expect(IterableLogger.loggingEnabled).toBe(false);
});
test('should default to true when passed non-boolean value', () => {
IterableLogger.setLoggingEnabled(undefined);
expect(IterableLogger.loggingEnabled).toBe(true);
});
test('should default to true when passed null', () => {
// @ts-expect-error - null is not a valid value for loggingEnabled
IterableLogger.setLoggingEnabled(null);
expect(IterableLogger.loggingEnabled).toBe(true);
});
test('should default to true when passed string', () => {
// @ts-expect-error - string is not a valid value for loggingEnabled
IterableLogger.setLoggingEnabled('true');
expect(IterableLogger.loggingEnabled).toBe(true);
});
});
describe('setLogLevel', () => {
test('should set log level to error when passed error', () => {
IterableLogger.setLogLevel(IterableLogLevel.error);
expect(IterableLogger.logLevel).toBe(IterableLogLevel.error);
});
test('should set log level to debug when passed debug', () => {
IterableLogger.setLogLevel(IterableLogLevel.debug);
expect(IterableLogger.logLevel).toBe(IterableLogLevel.debug);
});
test('should set log level to info when passed info', () => {
IterableLogger.setLogLevel(IterableLogLevel.info);
expect(IterableLogger.logLevel).toBe(IterableLogLevel.info);
});
test('should default to debug when passed undefined', () => {
IterableLogger.setLogLevel(undefined);
expect(IterableLogger.logLevel).toBe(IterableLogLevel.debug);
});
});
describe('log method', () => {
test('should log message when logging is enabled', () => {
IterableLogger.log('Test message');
expect(mockConsoleLog).toHaveBeenCalledWith('Test message');
});
test('should log message with optional parameters when logging is enabled', () => {
IterableLogger.log('Test message', 'param1', 'param2');
expect(mockConsoleLog).toHaveBeenCalledWith(
'Test message',
'param1',
'param2'
);
});
test('should not log when logging is disabled', () => {
IterableLogger.loggingEnabled = false;
IterableLogger.log('Test message');
expect(mockConsoleLog).not.toHaveBeenCalled();
});
test('should log undefined message when no message provided', () => {
IterableLogger.log();
expect(mockConsoleLog).toHaveBeenCalledWith(undefined);
});
test('should log object when object is passed', () => {
const testObj = { key: 'value' };
IterableLogger.log(testObj);
expect(mockConsoleLog).toHaveBeenCalledWith(testObj);
});
});
describe('error method', () => {
test('should log error message when logging is enabled and log level is error', () => {
IterableLogger.logLevel = IterableLogLevel.error;
IterableLogger.error('Error message');
expect(mockConsoleLog).toHaveBeenCalledWith('ERROR:', 'Error message');
});
test('should log error message with optional parameters', () => {
IterableLogger.logLevel = IterableLogLevel.error;
IterableLogger.error('Error message', 'param1', 'param2');
expect(mockConsoleLog).toHaveBeenCalledWith(
'ERROR:',
'Error message',
'param1',
'param2'
);
});
test('should not log when logging is disabled', () => {
IterableLogger.loggingEnabled = false;
IterableLogger.logLevel = IterableLogLevel.error;
IterableLogger.error('Error message');
expect(mockConsoleLog).not.toHaveBeenCalled();
});
test('should not log when log level is not error', () => {
IterableLogger.logLevel = IterableLogLevel.debug;
IterableLogger.error('Error message');
expect(mockConsoleLog).not.toHaveBeenCalled();
});
test('should not log when log level is info', () => {
IterableLogger.logLevel = IterableLogLevel.info;
IterableLogger.error('Error message');
expect(mockConsoleLog).not.toHaveBeenCalled();
});
});
describe('debug method', () => {
test('should log debug message when logging is enabled and log level is debug', () => {
IterableLogger.logLevel = IterableLogLevel.debug;
IterableLogger.debug('Debug message');
expect(mockConsoleLog).toHaveBeenCalledWith('DEBUG:', 'Debug message');
});
test('should log debug message when logging is enabled and log level is error', () => {
IterableLogger.logLevel = IterableLogLevel.error;
IterableLogger.debug('Debug message');
expect(mockConsoleLog).toHaveBeenCalledWith('DEBUG:', 'Debug message');
});
test('should log debug message with optional parameters', () => {
IterableLogger.logLevel = IterableLogLevel.debug;
IterableLogger.debug('Debug message', 'param1', 'param2');
expect(mockConsoleLog).toHaveBeenCalledWith(
'DEBUG:',
'Debug message',
'param1',
'param2'
);
});
test('should not log when logging is disabled', () => {
IterableLogger.loggingEnabled = false;
IterableLogger.logLevel = IterableLogLevel.debug;
IterableLogger.debug('Debug message');
expect(mockConsoleLog).not.toHaveBeenCalled();
});
test('should not log when log level is info', () => {
IterableLogger.logLevel = IterableLogLevel.info;
IterableLogger.debug('Debug message');
expect(mockConsoleLog).not.toHaveBeenCalled();
});
});
describe('info method', () => {
test('should log info message when logging is enabled and log level is info', () => {
IterableLogger.logLevel = IterableLogLevel.info;
IterableLogger.info('Info message');
expect(mockConsoleLog).toHaveBeenCalledWith('INFO:', 'Info message');
});
test('should log info message when logging is enabled and log level is debug', () => {
IterableLogger.logLevel = IterableLogLevel.debug;
IterableLogger.info('Info message');
expect(mockConsoleLog).toHaveBeenCalledWith('INFO:', 'Info message');
});
test('should log info message when logging is enabled and log level is error', () => {
IterableLogger.logLevel = IterableLogLevel.error;
IterableLogger.info('Info message');
expect(mockConsoleLog).toHaveBeenCalledWith('INFO:', 'Info message');
});
test('should log info message with optional parameters', () => {
IterableLogger.logLevel = IterableLogLevel.info;
IterableLogger.info('Info message', 'param1', 'param2');
expect(mockConsoleLog).toHaveBeenCalledWith(
'INFO:',
'Info message',
'param1',
'param2'
);
});
test('should not log when logging is disabled', () => {
IterableLogger.loggingEnabled = false;
IterableLogger.logLevel = IterableLogLevel.info;
IterableLogger.info('Info message');
expect(mockConsoleLog).not.toHaveBeenCalled();
});
});
describe('Log Level Hierarchy', () => {
test('should respect log level hierarchy for error level', () => {
IterableLogger.logLevel = IterableLogLevel.error;
IterableLogger.error('Error message');
IterableLogger.debug('Debug message');
IterableLogger.info('Info message');
// When logLevel is error (3), all messages should log
// Note: There's a bug in the error method - it only logs when logLevel is exactly error
// It should log when logLevel is error OR higher (debug, info)
expect(mockConsoleLog).toHaveBeenCalledTimes(3);
expect(mockConsoleLog).toHaveBeenNthCalledWith(
1,
'ERROR:',
'Error message'
);
expect(mockConsoleLog).toHaveBeenNthCalledWith(
2,
'DEBUG:',
'Debug message'
);
expect(mockConsoleLog).toHaveBeenNthCalledWith(
3,
'INFO:',
'Info message'
);
});
test('should respect log level hierarchy for debug level', () => {
IterableLogger.logLevel = IterableLogLevel.debug;
IterableLogger.error('Error message');
IterableLogger.debug('Debug message');
IterableLogger.info('Info message');
// When logLevel is debug (1), debug and info should log
// Note: There's a bug in the error method - it doesn't log when logLevel is debug
// It should log when logLevel is debug OR higher (info)
expect(mockConsoleLog).toHaveBeenCalledTimes(2);
expect(mockConsoleLog).toHaveBeenNthCalledWith(
1,
'DEBUG:',
'Debug message'
);
expect(mockConsoleLog).toHaveBeenNthCalledWith(
2,
'INFO:',
'Info message'
);
});
test('should respect log level hierarchy for info level', () => {
IterableLogger.logLevel = IterableLogLevel.info;
IterableLogger.error('Error message');
IterableLogger.debug('Debug message');
IterableLogger.info('Info message');
// When logLevel is info (2), only info should log
// Note: There's a bug in the error method - it doesn't log when logLevel is info
// It should log when logLevel is info (highest level)
expect(mockConsoleLog).toHaveBeenCalledTimes(1);
expect(mockConsoleLog).toHaveBeenNthCalledWith(
1,
'INFO:',
'Info message'
);
});
});
describe('Edge Cases', () => {
test('should handle empty string messages', () => {
IterableLogger.log('');
expect(mockConsoleLog).toHaveBeenCalledWith('');
});
test('should handle null messages', () => {
IterableLogger.log(null);
expect(mockConsoleLog).toHaveBeenCalledWith(null);
});
test('should handle zero as message', () => {
IterableLogger.log(0);
expect(mockConsoleLog).toHaveBeenCalledWith(0);
});
test('should handle false as message', () => {
IterableLogger.log(false);
expect(mockConsoleLog).toHaveBeenCalledWith(false);
});
test('should handle complex objects as messages', () => {
const complexObj = {
nested: { value: 'test' },
array: [1, 2, 3],
func: () => 'test',
};
IterableLogger.log(complexObj);
expect(mockConsoleLog).toHaveBeenCalledWith(complexObj);
});
test('should handle multiple optional parameters of different types', () => {
IterableLogger.log('Message', 123, true, { key: 'value' }, [1, 2, 3]);
expect(mockConsoleLog).toHaveBeenCalledWith(
'Message',
123,
true,
{ key: 'value' },
[1, 2, 3]
);
});
});
describe('Integration Tests', () => {
test('should work with real-world usage patterns', () => {
// Simulate typical usage
IterableLogger.setLoggingEnabled(true);
IterableLogger.setLogLevel(IterableLogLevel.info);
IterableLogger.info('SDK initialized');
IterableLogger.debug('Debug info', { userId: '123' });
IterableLogger.error('API error', { status: 500 });
// Note: Due to bug in error method, only info logs when logLevel is info
expect(mockConsoleLog).toHaveBeenCalledTimes(1);
expect(mockConsoleLog).toHaveBeenNthCalledWith(
1,
'INFO:',
'SDK initialized'
);
});
test('should handle rapid state changes', () => {
// Test rapid state changes
IterableLogger.setLoggingEnabled(false);
IterableLogger.log('Should not appear');
IterableLogger.setLoggingEnabled(true);
IterableLogger.setLogLevel(IterableLogLevel.error);
IterableLogger.info('Should appear'); // info logs when logLevel is error
IterableLogger.error('Should appear');
expect(mockConsoleLog).toHaveBeenCalledTimes(2);
expect(mockConsoleLog).toHaveBeenNthCalledWith(
1,
'INFO:',
'Should appear'
);
expect(mockConsoleLog).toHaveBeenNthCalledWith(
2,
'ERROR:',
'Should appear'
);
});
});
});