UNPKG

@rollercoaster-dev/rd-logger

Version:

A neurodivergent-friendly logger for Rollercoaster.dev projects

109 lines (108 loc) 4.58 kB
/// <reference types="jest" /> // Mock chalk to disable color codes in tests for easier string matching jest.mock('chalk', () => { const chalkMock = { gray: (msg) => msg, whiteBright: (msg) => msg, blue: (msg) => msg, green: (msg) => msg, yellow: (msg) => msg, red: (msg) => msg, magenta: (msg) => msg, dim: (msg) => msg, cyan: (msg) => msg, }; return Object.assign({ __esModule: true, default: chalkMock }, chalkMock); }); import { Logger } from '../logger.service'; import { SensitiveValue } from '../sensitive'; describe('Sensitive Logging', () => { let logger; let consoleSpy; beforeEach(() => { jest.clearAllMocks(); logger = new Logger(); consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => { }); }); afterEach(() => { consoleSpy.mockRestore(); }); it('should log sensitive data with approval', () => { const apiKey = 'secret-api-key-12345'; const approval = { reason: 'Testing sensitive data logging', approvedBy: 'Test Team' }; logger.logWithSensitiveData('info', 'API key debug', { key: apiKey }, approval); expect(consoleSpy).toHaveBeenCalled(); const logOutput = consoleSpy.mock.calls[0][0]; // Should include warning prefix expect(logOutput).toContain('SENSITIVE DATA'); // Should include the actual sensitive data expect(logOutput).toContain(apiKey); // Should include approval information expect(logOutput).toContain('Testing sensitive data logging'); expect(logOutput).toContain('Test Team'); }); it('should not log sensitive data without proper approval', () => { const apiKey = 'secret-api-key-12345'; const approval = { reason: '', // Empty reason approvedBy: 'Test Team' }; logger.logWithSensitiveData('info', 'API key debug', { key: apiKey }, approval); expect(consoleSpy).toHaveBeenCalled(); const logOutput = consoleSpy.mock.calls[0][0]; // Should not include the sensitive data expect(logOutput).not.toContain(apiKey); // Should include warning about missing approval expect(logOutput).toContain('without proper approval'); }); it('should not log sensitive data with expired approval', () => { const apiKey = 'secret-api-key-12345'; const yesterday = new Date(); yesterday.setDate(yesterday.getDate() - 1); const approval = { reason: 'Testing sensitive data logging', approvedBy: 'Test Team', expiresAt: yesterday // Expired }; logger.logWithSensitiveData('info', 'API key debug', { key: apiKey }, approval); expect(consoleSpy).toHaveBeenCalled(); const logOutput = consoleSpy.mock.calls[0][0]; // Should not include the sensitive data expect(logOutput).not.toContain(apiKey); // Should include warning about expired approval expect(logOutput).toContain('expired approval'); }); it('should provide convenience methods for common log levels', () => { const apiKey = 'secret-api-key-12345'; const approval = { reason: 'Testing sensitive data logging', approvedBy: 'Test Team' }; // Test info level logger.infoWithSensitiveData('Info with sensitive data', { key: apiKey }, approval); expect(consoleSpy).toHaveBeenCalled(); let logOutput = consoleSpy.mock.calls[0][0]; expect(logOutput).toContain('INFO'); expect(logOutput).toContain(apiKey); consoleSpy.mockClear(); // Test error level logger.errorWithSensitiveData('Error with sensitive data', { key: apiKey }, approval); expect(consoleSpy).toHaveBeenCalled(); logOutput = consoleSpy.mock.calls[0][0]; expect(logOutput).toContain('ERROR'); expect(logOutput).toContain(apiKey); }); it('should redact SensitiveValue instances in normal logging', () => { const apiKey = new SensitiveValue('secret-api-key-12345'); logger.info('API key created', { key: apiKey }); expect(consoleSpy).toHaveBeenCalled(); const logOutput = consoleSpy.mock.calls[0][0]; // Should not include the actual sensitive data expect(logOutput).not.toContain('secret-api-key-12345'); // Should include the redacted value expect(logOutput).toContain('[REDACTED]'); }); });