/** * Tests for logger-utils.js * Created: 2026-03-21 */ const { sanitizeForLog, redactCredential, safeLog, SENSITIVE_FIELDS } = require('../logger-utils'); describe('logger-utils', () => { describe('sanitizeForLog', () => { test('should redact sensitive field names', () => { const input = { username: 'admin', password: 'secret123', apiKey: 'abc-def-ghi', token: 'xyz123' }; const result = sanitizeForLog(input); expect(result.username).toBe('admin'); expect(result.password).toBe('[REDACTED]'); expect(result.apiKey).toBe('[REDACTED]'); expect(result.token).toBe('[REDACTED]'); }); test('should handle nested objects', () => { const input = { user: { name: 'Alice', credentials: { password: 'secret', token: 'abc123' } } }; const result = sanitizeForLog(input); expect(result.user.name).toBe('Alice'); expect(result.user.credentials.password).toBe('[REDACTED]'); expect(result.user.credentials.token).toBe('[REDACTED]'); }); test('should handle arrays', () => { const input = [ { name: 'user1', password: 'pass1' }, { name: 'user2', secret: 'pass2' } ]; const result = sanitizeForLog(input); expect(result[0].name).toBe('user1'); expect(result[0].password).toBe('[REDACTED]'); expect(result[1].name).toBe('user2'); expect(result[1].secret).toBe('[REDACTED]'); }); test('should handle null and undefined', () => { expect(sanitizeForLog(null)).toBeNull(); expect(sanitizeForLog(undefined)).toBeUndefined(); }); test('should support additional sensitive keys', () => { const input = { email: 'user@example.com', ssn: '123-45-6789' }; const result = sanitizeForLog(input, ['ssn']); expect(result.email).toBe('user@example.com'); expect(result.ssn).toBe('[REDACTED]'); }); test('should be case-insensitive for field matching', () => { const input = { PASSWORD: 'secret', ApiKey: 'key123', Bearer_Token: 'token456' }; const result = sanitizeForLog(input); expect(result.PASSWORD).toBe('[REDACTED]'); expect(result.ApiKey).toBe('[REDACTED]'); expect(result.Bearer_Token).toBe('[REDACTED]'); }); }); describe('redactCredential', () => { test('should show first and last 4 characters for long strings', () => { const input = 'abcdefghijklmnop'; const result = redactCredential(input); expect(result).toMatch(/^abcd.*mnop$/); expect(result).toContain('*'); }); test('should fully redact short strings', () => { expect(redactCredential('short')).toBe('[REDACTED]'); expect(redactCredential('12345678')).toBe('[REDACTED]'); }); test('should handle null/undefined', () => { expect(redactCredential(null)).toBe('[REDACTED]'); expect(redactCredential(undefined)).toBe('[REDACTED]'); }); test('should handle non-string input', () => { expect(redactCredential(12345)).toBe('[REDACTED]'); expect(redactCredential({})).toBe('[REDACTED]'); }); test('should limit middle asterisks to 10', () => { const input = 'a'.repeat(100); const result = redactCredential(input); const asteriskMatch = result.match(/\*/g); expect(asteriskMatch).toBeTruthy(); expect(asteriskMatch.length).toBe(10); }); }); describe('safeLog', () => { test('should create safe log object with message and sanitized data', () => { const result = safeLog('User login', { username: 'alice', password: 'secret123' }); expect(result).toHaveProperty('message', 'User login'); expect(result).toHaveProperty('timestamp'); expect(result.data.username).toBe('alice'); expect(result.data.password).toBe('[REDACTED]'); }); test('should include timestamp in ISO format', () => { const result = safeLog('Test message'); expect(result.timestamp).toMatch(/^\d{4}-\d{2}-\d{2}T/); }); test('should handle empty data', () => { const result = safeLog('Test message'); expect(result.message).toBe('Test message'); expect(result.data).toEqual({}); }); }); describe('SENSITIVE_FIELDS constant', () => { test('should include common sensitive field names', () => { expect(SENSITIVE_FIELDS).toContain('password'); expect(SENSITIVE_FIELDS).toContain('token'); expect(SENSITIVE_FIELDS).toContain('secret'); expect(SENSITIVE_FIELDS).toContain('apiKey'); expect(SENSITIVE_FIELDS).toContain('privateKey'); }); test('should have reasonable length', () => { expect(SENSITIVE_FIELDS.length).toBeGreaterThan(10); }); }); });