import winston from 'winston'; export interface LogEntry { level: string; message: string; meta: Record; timestamp: string; } export function createMockLogger(): winston.Logger & { logs: LogEntry[] } { const logs: LogEntry[] = []; const logger = winston.createLogger({ level: 'debug', format: winston.format.combine( winston.format.timestamp(), winston.format.json() ), transports: [ new winston.transports.Console({ format: winston.format.printf(({ level, message, timestamp, ...meta }) => { logs.push({ level: String(level), message: String(message), meta, timestamp: String(timestamp) }); return ''; }), }), ], }) as winston.Logger & { logs: LogEntry[] }; // Override all log levels to capture const levels = ['error', 'warn', 'info', 'http', 'debug'] as const; for (const level of levels) { const original = logger[level]; logger[level] = ((message: unknown, ...meta: unknown[]) => { logs.push({ level, message: String(message), meta: meta[0] as Record || {}, timestamp: new Date().toISOString(), }); return logger; }) as any; } (logger as any).logs = logs; logger.logs = logs; return logger as winston.Logger & { logs: LogEntry[] }; } export function getLogsByLevel(logger: winston.Logger & { logs: LogEntry[] }, level: string): LogEntry[] { return logger.logs.filter(l => l.level === level); } export function hasLog(logger: winston.Logger & { logs: LogEntry[] }, level: string, messageContains: string): boolean { return logger.logs.some(l => l.level === level && l.message.includes(messageContains)); }