import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' import { info, error, warn, debug, setContext, clearContext, runWithContext } from '../../server/utils/logger.js' describe('logger', () => { const testState = { originalLog: null, originalError: null, originalWarn: null, originalDebug: null, logCalls: [], errorCalls: [], warnCalls: [], debugCalls: [], } beforeEach(() => { testState.logCalls = [] testState.errorCalls = [] testState.warnCalls = [] testState.debugCalls = [] testState.originalLog = console.log testState.originalError = console.error testState.originalWarn = console.warn testState.originalDebug = console.debug console.log = vi.fn((...args) => testState.logCalls.push(args)) console.error = vi.fn((...args) => testState.errorCalls.push(args)) console.warn = vi.fn((...args) => testState.warnCalls.push(args)) console.debug = vi.fn((...args) => testState.debugCalls.push(args)) }) afterEach(() => { console.log = testState.originalLog console.error = testState.originalError console.warn = testState.originalWarn console.debug = testState.originalDebug }) it('logs info message', () => { info('Test message') expect(testState.logCalls.length).toBe(1) const logMsg = testState.logCalls[0][0] expect(logMsg).toContain('[INFO]') expect(logMsg).toContain('Test message') }) it('includes request context when set', async () => { await runWithContext('req-123', 'user-456', async () => { info('Test message') const logMsg = testState.logCalls[0][0] expect(logMsg).toContain('req-123') expect(logMsg).toContain('user-456') }) }) it('includes additional context', () => { info('Test message', { key: 'value', count: 42 }) const logMsg = testState.logCalls[0][0] expect(logMsg).toContain('key') expect(logMsg).toContain('value') expect(logMsg).toContain('42') }) it('logs error with stack trace', () => { const err = new Error('Test error') error('Failed', { error: err }) expect(testState.errorCalls.length).toBe(1) const errorMsg = testState.errorCalls[0][0] expect(errorMsg).toContain('[ERROR]') expect(errorMsg).toContain('Failed') expect(errorMsg).toContain('stack') }) it('logs warning', () => { warn('Warning message') expect(testState.warnCalls.length).toBe(1) const warnMsg = testState.warnCalls[0][0] expect(warnMsg).toContain('[WARN]') }) it('logs debug only in development', () => { const originalEnv = process.env.NODE_ENV process.env.NODE_ENV = 'development' debug('Debug message') expect(testState.debugCalls.length).toBe(1) process.env.NODE_ENV = originalEnv }) it('does not log debug in production', () => { const originalEnv = process.env.NODE_ENV process.env.NODE_ENV = 'production' debug('Debug message') expect(testState.debugCalls.length).toBe(0) process.env.NODE_ENV = originalEnv }) it('clears context', async () => { await runWithContext('req-123', 'user-456', async () => { info('Test with context') const logMsg = testState.logCalls[0][0] expect(logMsg).toContain('req-123') }) // Context should be cleared after runWithContext completes info('Test without context') const logMsg = testState.logCalls[testState.logCalls.length - 1][0] expect(logMsg).not.toContain('req-123') }) it('supports deprecated setContext/clearContext API', async () => { await runWithContext(null, null, async () => { setContext('req-123', 'user-456') info('Test message') const logMsg = testState.logCalls[0][0] expect(logMsg).toContain('req-123') expect(logMsg).toContain('user-456') clearContext() info('Test after clear') const logMsg2 = testState.logCalls[1][0] expect(logMsg2).not.toContain('req-123') }) }) })