Skip to main content
Glama
enhanced-file-output-manager.test.ts20.1 kB
/** * Tests for EnhancedFileOutputManager */ import { EnhancedFileOutputManager } from '../../src/utils/enhanced-file-output-manager'; import { fileOutputManager } from '../../src/utils/file-output-manager'; // Mock the file output manager jest.mock('../../src/utils/file-output-manager', () => ({ fileOutputManager: { initialize: jest.fn(), saveFile: jest.fn(), getDirectoryStats: jest.fn(), cleanup: jest.fn(), deleteFile: jest.fn(), getFileInfo: jest.fn(), }, })); describe('EnhancedFileOutputManager', () => { let manager: EnhancedFileOutputManager; const mockFileOutputManager = fileOutputManager as jest.Mocked< typeof fileOutputManager >; beforeEach(() => { manager = EnhancedFileOutputManager.getInstance(); jest.clearAllMocks(); }); describe('Singleton pattern', () => { test('should return the same instance', () => { const instance1 = EnhancedFileOutputManager.getInstance(); const instance2 = EnhancedFileOutputManager.getInstance(); expect(instance1).toBe(instance2); }); }); describe('initialize', () => { test('should initialize file output manager', async () => { mockFileOutputManager.initialize.mockResolvedValue(); await manager.initialize(); expect(mockFileOutputManager.initialize).toHaveBeenCalledTimes(1); }); }); describe('saveHTMLVisualization', () => { test('should save HTML visualization with basic options', async () => { const mockMetadata = { path: '/test/path/file.html', filename: 'file.html', size: 1024, createdAt: new Date('2024-01-01T00:00:00Z'), type: 'html' as const, description: 'Test HTML visualization', }; mockFileOutputManager.saveFile.mockResolvedValue(mockMetadata); const result = await manager.saveHTMLVisualization('<html></html>', { toolName: 'test-tool', }); expect(mockFileOutputManager.saveFile).toHaveBeenCalledWith( '<html></html>', 'html', { description: 'test-tool HTML visualization', } ); expect(result).toEqual({ html_file: { file_path: '/test/path/file.html', filename: 'file.html', size: 1024, created_at: '2024-01-01T00:00:00.000Z', type: 'html', description: 'Test HTML visualization', }, }); }); test('should save HTML visualization with custom options', async () => { const mockMetadata = { path: '/test/path/custom-file.html', filename: 'custom-file.html', size: 2048, createdAt: new Date('2024-01-01T00:00:00Z'), type: 'html' as const, description: 'Custom description', }; mockFileOutputManager.saveFile.mockResolvedValue(mockMetadata); const result = await manager.saveHTMLVisualization('<html></html>', { toolName: 'test-tool', description: 'Custom description', customName: 'custom-file', subdirectory: 'custom-dir', }); expect(mockFileOutputManager.saveFile).toHaveBeenCalledWith( '<html></html>', 'html', { description: 'Custom description', customName: 'custom-file', subdirectory: 'custom-dir', } ); expect(result.html_file?.description).toBe('Custom description'); }); test('should handle save errors', async () => { const error = new Error('Save failed'); mockFileOutputManager.saveFile.mockRejectedValue(error); await expect( manager.saveHTMLVisualization('<html></html>', { toolName: 'test-tool', }) ).rejects.toThrow('Save failed'); }); }); describe('saveDualPNGVisualization', () => { test('should return base64 in test environment', async () => { const lightBuffer = Buffer.from('light-png-data'); const darkBuffer = Buffer.from('dark-png-data'); const result = await manager.saveDualPNGVisualization( lightBuffer, darkBuffer, { toolName: 'test-tool', dimensions: [800, 600], resolution: 150, } ); expect(result).toEqual({ png_base64: lightBuffer.toString('base64'), }); // Should not call file output manager in test environment expect(mockFileOutputManager.saveFile).not.toHaveBeenCalled(); }); }); describe('savePNGVisualization', () => { test('should return base64 in test environment', async () => { const buffer = Buffer.from('png-data'); const result = await manager.savePNGVisualization(buffer, { toolName: 'test-tool', }); expect(result).toEqual({ png_base64: buffer.toString('base64'), }); // Should not call file output manager in test environment expect(mockFileOutputManager.saveFile).not.toHaveBeenCalled(); }); }); describe('saveSVGVisualization', () => { test('should save SVG visualization with basic options', async () => { const mockMetadata = { path: '/test/path/file.svg', filename: 'file.svg', size: 512, createdAt: new Date('2024-01-01T00:00:00Z'), type: 'svg' as const, description: 'Test SVG visualization', }; mockFileOutputManager.saveFile.mockResolvedValue(mockMetadata); const result = await manager.saveSVGVisualization('<svg></svg>', { toolName: 'test-tool', }); expect(mockFileOutputManager.saveFile).toHaveBeenCalledWith( '<svg></svg>', 'svg', { description: 'test-tool SVG visualization', } ); expect(result).toEqual({ svg_file: { file_path: '/test/path/file.svg', filename: 'file.svg', size: 512, created_at: '2024-01-01T00:00:00.000Z', type: 'svg', description: 'Test SVG visualization', }, }); }); test('should save SVG visualization with custom options', async () => { const mockMetadata = { path: '/test/path/custom.svg', filename: 'custom.svg', size: 1024, createdAt: new Date('2024-01-01T00:00:00Z'), type: 'svg' as const, description: 'Custom SVG', }; mockFileOutputManager.saveFile.mockResolvedValue(mockMetadata); const result = await manager.saveSVGVisualization('<svg></svg>', { toolName: 'test-tool', description: 'Custom SVG', customName: 'custom', subdirectory: 'svg-dir', }); expect(mockFileOutputManager.saveFile).toHaveBeenCalledWith( '<svg></svg>', 'svg', { description: 'Custom SVG', customName: 'custom', subdirectory: 'svg-dir', } ); expect(result.svg_file?.description).toBe('Custom SVG'); }); test('should handle SVG save errors', async () => { const error = new Error('SVG save failed'); mockFileOutputManager.saveFile.mockRejectedValue(error); await expect( manager.saveSVGVisualization('<svg></svg>', { toolName: 'test-tool', }) ).rejects.toThrow('SVG save failed'); }); }); describe('saveCombinedVisualization', () => { test('should save both HTML and PNG', async () => { const htmlMetadata = { path: '/test/path/file.html', filename: 'file.html', size: 1024, createdAt: new Date('2024-01-01T00:00:00Z'), type: 'html' as const, description: 'Test HTML', }; mockFileOutputManager.saveFile.mockResolvedValueOnce(htmlMetadata); const result = await manager.saveCombinedVisualization( '<html></html>', Buffer.from('png-data'), { toolName: 'test-tool', } ); expect(result.html_file).toBeDefined(); expect(result.png_base64).toBeDefined(); // In test environment }); test('should handle combined save errors', async () => { const error = new Error('Combined save failed'); mockFileOutputManager.saveFile.mockRejectedValue(error); await expect( manager.saveCombinedVisualization( '<html></html>', Buffer.from('png-data'), { toolName: 'test-tool', } ) ).rejects.toThrow('Combined save failed'); }); }); describe('saveCompleteVisualization', () => { test('should save HTML and dual PNG', async () => { const htmlMetadata = { path: '/test/path/file.html', filename: 'file.html', size: 1024, createdAt: new Date('2024-01-01T00:00:00Z'), type: 'html' as const, description: 'Test HTML', }; mockFileOutputManager.saveFile.mockResolvedValueOnce(htmlMetadata); const result = await manager.saveCompleteVisualization( '<html></html>', Buffer.from('light-png'), Buffer.from('dark-png'), { toolName: 'test-tool', dimensions: [800, 600], resolution: 150, } ); expect(result.html_file).toBeDefined(); expect(result.png_base64).toBeDefined(); // In test environment }); test('should handle complete save errors', async () => { const error = new Error('Complete save failed'); mockFileOutputManager.saveFile.mockRejectedValue(error); await expect( manager.saveCompleteVisualization( '<html></html>', Buffer.from('light-png'), Buffer.from('dark-png'), { toolName: 'test-tool', dimensions: [800, 600], resolution: 150, } ) ).rejects.toThrow('Complete save failed'); }); }); describe('createPNGVisualizationResult', () => { test('should create structured PNG result', () => { const lightFile = { file_path: '/test/light.png', filename: 'light.png', size: 1024, created_at: '2024-01-01T00:00:00.000Z', type: 'png' as const, description: 'Light background', }; const darkFile = { file_path: '/test/dark.png', filename: 'dark.png', size: 1536, created_at: '2024-01-01T00:00:00.000Z', type: 'png' as const, description: 'Dark background', }; const options = { toolName: 'test-tool', dimensions: [800, 600] as [number, number], resolution: 150, colorSpace: 'sRGB', }; const result = manager.createPNGVisualizationResult( lightFile, darkFile, options ); expect(result).toEqual({ light_background: lightFile, dark_background: darkFile, metadata: { dimensions: [800, 600], resolution: 150, color_space: 'sRGB', total_size: 2560, }, }); }); test('should use default color space', () => { const lightFile = { file_path: '/test/light.png', filename: 'light.png', size: 1024, created_at: '2024-01-01T00:00:00.000Z', type: 'png' as const, description: 'Light background', }; const darkFile = { file_path: '/test/dark.png', filename: 'dark.png', size: 1024, created_at: '2024-01-01T00:00:00.000Z', type: 'png' as const, description: 'Dark background', }; const options = { toolName: 'test-tool', dimensions: [800, 600] as [number, number], resolution: 150, }; const result = manager.createPNGVisualizationResult( lightFile, darkFile, options ); expect(result.metadata.color_space).toBe('sRGB'); }); }); describe('getVisualizationStats', () => { test('should return directory stats', async () => { const mockStats = { totalFiles: 10, totalSize: 1024000, filesByType: { html: 5, png: 3, svg: 2 }, }; mockFileOutputManager.getDirectoryStats.mockResolvedValue(mockStats); const result = await manager.getVisualizationStats(); expect(result).toEqual(mockStats); expect(mockFileOutputManager.getDirectoryStats).toHaveBeenCalledTimes(1); }); }); describe('cleanupVisualizations', () => { test('should cleanup with default force=false', async () => { const mockResult = { filesRemoved: 5, bytesFreed: 512000, errors: [] }; mockFileOutputManager.cleanup.mockResolvedValue(mockResult); const result = await manager.cleanupVisualizations(); expect(result).toEqual(mockResult); expect(mockFileOutputManager.cleanup).toHaveBeenCalledWith(false); }); test('should cleanup with force=true', async () => { const mockResult = { filesRemoved: 10, bytesFreed: 1024000, errors: [] }; mockFileOutputManager.cleanup.mockResolvedValue(mockResult); const result = await manager.cleanupVisualizations(true); expect(result).toEqual(mockResult); expect(mockFileOutputManager.cleanup).toHaveBeenCalledWith(true); }); }); describe('deleteVisualization', () => { test('should delete specific file', async () => { mockFileOutputManager.deleteFile.mockResolvedValue(); await manager.deleteVisualization('/test/file.html'); expect(mockFileOutputManager.deleteFile).toHaveBeenCalledWith( '/test/file.html' ); }); }); describe('getVisualizationInfo', () => { test('should return file info', async () => { const mockInfo = { path: '/test/file.html', filename: 'file.html', size: 1024, createdAt: new Date('2024-01-01T00:00:00Z'), type: 'html' as const, description: 'Test file', }; mockFileOutputManager.getFileInfo.mockResolvedValue(mockInfo); const result = await manager.getVisualizationInfo('/test/file.html'); expect(result).toEqual(mockInfo); expect(mockFileOutputManager.getFileInfo).toHaveBeenCalledWith( '/test/file.html' ); }); test('should return null for non-existent file', async () => { mockFileOutputManager.getFileInfo.mockResolvedValue(null); const result = await manager.getVisualizationInfo('/test/missing.html'); expect(result).toBeNull(); }); }); describe('validateVisualizationFile', () => { test('should validate supported file types', async () => { const mockInfo = { path: '/test/file.html', filename: 'file.html', size: 1024, createdAt: new Date('2024-01-01T00:00:00Z'), type: 'html' as const, description: 'Test file', }; mockFileOutputManager.getFileInfo.mockResolvedValue(mockInfo); const result = await manager.validateVisualizationFile('/test/file.html'); expect(result).toBe(true); }); test('should reject unsupported file types', async () => { const mockInfo = { path: '/test/file.txt', filename: 'file.txt', size: 1024, createdAt: new Date('2024-01-01T00:00:00Z'), type: 'txt' as any, description: 'Text file', }; mockFileOutputManager.getFileInfo.mockResolvedValue(mockInfo); const result = await manager.validateVisualizationFile('/test/file.txt'); expect(result).toBe(false); }); test('should return false for non-existent files', async () => { mockFileOutputManager.getFileInfo.mockResolvedValue(null); const result = await manager.validateVisualizationFile('/test/missing.html'); expect(result).toBe(false); }); test('should handle validation errors', async () => { mockFileOutputManager.getFileInfo.mockRejectedValue( new Error('Access denied') ); const result = await manager.validateVisualizationFile('/test/file.html'); expect(result).toBe(false); }); }); describe('generatePreviewURL', () => { test('should generate preview URL with base URL', () => { const fileResult = { file_path: '/test/file.html', filename: 'file.html', size: 1024, created_at: '2024-01-01T00:00:00.000Z', type: 'html' as const, description: 'Test file', }; const result = manager.generatePreviewURL( fileResult, 'http://localhost:3000' ); expect(result).toBe('http://localhost:3000/visualizations/file.html'); }); test('should handle base URL with trailing slash', () => { const fileResult = { file_path: '/test/file.html', filename: 'file.html', size: 1024, created_at: '2024-01-01T00:00:00.000Z', type: 'html' as const, description: 'Test file', }; const result = manager.generatePreviewURL( fileResult, 'http://localhost:3000/' ); expect(result).toBe('http://localhost:3000/visualizations/file.html'); }); test('should return undefined without base URL', () => { const fileResult = { file_path: '/test/file.html', filename: 'file.html', size: 1024, created_at: '2024-01-01T00:00:00.000Z', type: 'html' as const, description: 'Test file', }; const result = manager.generatePreviewURL(fileResult); expect(result).toBeUndefined(); }); }); describe('createVisualizationManifest', () => { test('should create manifest with all file types', () => { const result = { html_file: { file_path: '/test/file.html', filename: 'file.html', size: 1024, created_at: '2024-01-01T00:00:00.000Z', type: 'html' as const, description: 'HTML file', }, png_files: [ { file_path: '/test/file.png', filename: 'file.png', size: 2048, created_at: '2024-01-01T00:00:00.000Z', type: 'png' as const, description: 'PNG file', }, ], svg_file: { file_path: '/test/file.svg', filename: 'file.svg', size: 512, created_at: '2024-01-01T00:00:00.000Z', type: 'svg' as const, description: 'SVG file', }, }; const options = { toolName: 'test-tool', parameters: { color: '#FF0000' }, description: 'Test visualization', }; const manifest = manager.createVisualizationManifest(result, options); expect(manifest).toMatchObject({ tool: 'test-tool', parameters: { color: '#FF0000' }, description: 'Test visualization', files: { html: result.html_file, png: result.png_files, svg: result.svg_file, }, }); expect(manifest['created_at']).toMatch( /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/ ); }); test('should create manifest with minimal data', () => { const result = { html_file: { file_path: '/test/file.html', filename: 'file.html', size: 1024, created_at: '2024-01-01T00:00:00.000Z', type: 'html' as const, description: 'HTML file', }, }; const options = { toolName: 'test-tool', }; const manifest = manager.createVisualizationManifest(result, options); expect(manifest).toMatchObject({ tool: 'test-tool', parameters: {}, files: { html: result.html_file, }, }); expect(manifest['description']).toBeUndefined(); }); }); describe('Error handling', () => { test('should handle HTML save errors gracefully', async () => { const error = new Error('Disk full'); mockFileOutputManager.saveFile.mockRejectedValue(error); await expect( manager.saveHTMLVisualization('<html></html>', { toolName: 'test-tool', }) ).rejects.toThrow('Disk full'); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/keyurgolani/ColorMcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server