import { describe, it, expect, vi } from 'vitest'; import * as fs from 'fs/promises'; import * as path from 'path'; import { FileLogger } from '@d8d/shared-utils'; // 直接测试文件日志器,不依赖外部模块 describe('文件日志功能测试', () => { // 模拟 fs 模块 vi.mock('fs/promises', () => ({ mkdir: vi.fn().mockResolvedValue(undefined), appendFile: vi.fn().mockResolvedValue(undefined) })); vi.mock('path', () => ({ join: (...args: string[]) => args.join('/'), dirname: (filePath: string) => filePath.split('/').slice(0, -1).join('/') })); beforeEach(() => { vi.clearAllMocks(); // 设置环境变量 process.env.LOG_DIR = './test-logs'; }); afterEach(() => { delete process.env.LOG_DIR; }); it('应该正确创建日志器实例', () => { const logger = new FileLogger('test-service'); expect(logger).toBeDefined(); expect(logger).toHaveProperty('info'); expect(logger).toHaveProperty('warn'); expect(logger).toHaveProperty('error'); expect(logger).toHaveProperty('debug'); }); it('应该正确格式化日志消息', async () => { const logger = new FileLogger('test-service'); // 测试私有方法需要一些技巧,这里我们测试公开方法 const testMessage = '测试消息'; const testMetadata = { key: 'value' }; // 直接调用方法 await logger.info(testMessage, testMetadata); // 验证 fs.appendFile 被调用 expect(fs.appendFile).toHaveBeenCalled(); const callArgs = (fs.appendFile as any).mock.calls[0]; const filePath = callArgs[0]; const message = callArgs[1]; expect(filePath).toContain('test-service.log'); expect(message).toContain('[INFO]'); expect(message).toContain(testMessage); expect(message).toContain(JSON.stringify(testMetadata, null, 2)); }); it('应该支持不同的日志级别', async () => { const logger = new FileLogger('test-service'); await logger.info('信息日志'); await logger.warn('警告日志'); await logger.error('错误日志'); await logger.debug('调试日志'); expect(fs.appendFile).toHaveBeenCalledTimes(4); // 验证不同级别的日志格式 const calls = (fs.appendFile as any).mock.calls; expect(calls[0][1]).toContain('[INFO]'); expect(calls[1][1]).toContain('[WARN]'); expect(calls[2][1]).toContain('[ERROR]'); expect(calls[3][1]).toContain('[DEBUG]'); }); it('应该正确处理没有元数据的日志', async () => { const logger = new FileLogger('test-service'); await logger.info('简单日志'); const callArgs = (fs.appendFile as any).mock.calls[0]; const message = callArgs[1]; expect(message).toContain('[INFO]'); expect(message).toContain('简单日志'); // 不应该包含额外的换行和空对象 expect(message.split('\n').length).toBe(2); // 消息 + 空行 }); it('应该使用自定义日志目录', async () => { const customLogDir = '/custom/logs'; const logger = new FileLogger('test-service', customLogDir); await logger.info('测试自定义目录'); const callArgs = (fs.appendFile as any).mock.calls[0]; const filePath = callArgs[0]; expect(filePath).toContain(customLogDir); }); it('应该在写入失败时不抛出错误', async () => { const logger = new FileLogger('test-service'); // 模拟写入失败 (fs.appendFile as any).mockRejectedValue(new Error('磁盘已满')); // 不应该抛出错误 await expect(logger.info('测试错误处理')).resolves.not.toThrow(); }); });