Skip to main content
Glama
cleanup-manager.test.ts13.3 kB
import { describe, it, expect, beforeEach } from '@jest/globals'; import { CleanupManager } from '../utils/cleanup-manager.js'; import type { CleanupMode } from '../utils/cleanup-manager.js'; describe('CleanupManager', () => { let cleanupManager: CleanupManager; beforeEach(() => { cleanupManager = new CleanupManager(); }); describe('constructor', () => { it('should create instance successfully', () => { expect(cleanupManager).toBeInstanceOf(CleanupManager); }); it('should initialize without errors', () => { expect(() => new CleanupManager()).not.toThrow(); }); }); describe('formatBytes', () => { it('should format 0 bytes', () => { const result = cleanupManager.formatBytes(0); expect(result).toBe('0 Bytes'); }); it('should format bytes', () => { const result = cleanupManager.formatBytes(512); expect(result).toBe('512 Bytes'); }); it('should format kilobytes', () => { const result = cleanupManager.formatBytes(1024); expect(result).toBe('1 KB'); }); it('should format kilobytes with decimals', () => { const result = cleanupManager.formatBytes(1536); expect(result).toBe('1.5 KB'); }); it('should format megabytes', () => { const result = cleanupManager.formatBytes(1024 * 1024); expect(result).toBe('1 MB'); }); it('should format megabytes with decimals', () => { const result = cleanupManager.formatBytes(1024 * 1024 * 2.5); expect(result).toBe('2.5 MB'); }); it('should format gigabytes', () => { const result = cleanupManager.formatBytes(1024 * 1024 * 1024); expect(result).toBe('1 GB'); }); it('should format gigabytes with decimals', () => { const result = cleanupManager.formatBytes(1024 * 1024 * 1024 * 1.75); expect(result).toBe('1.75 GB'); }); it('should round to 2 decimal places', () => { const result = cleanupManager.formatBytes(1024 * 1.666); expect(result).toMatch(/^\d+\.\d{1,2} KB$/); }); it('should handle large byte values', () => { const result = cleanupManager.formatBytes(1024 * 1024 * 1024 * 100); expect(result).toBe('100 GB'); }); it('should handle small fractional bytes', () => { const result = cleanupManager.formatBytes(100); expect(result).toBe('100 Bytes'); }); it('should handle edge case of 1 byte', () => { const result = cleanupManager.formatBytes(1); expect(result).toBe('1 Bytes'); }); }); describe('getPlatformInfo', () => { it('should return platform information', () => { const info = cleanupManager.getPlatformInfo(); expect(info).toBeDefined(); expect(info).toHaveProperty('platform'); expect(info).toHaveProperty('legacyBasePath'); expect(info).toHaveProperty('currentBasePath'); expect(info).toHaveProperty('npmCachePath'); expect(info).toHaveProperty('claudeCliCachePath'); expect(info).toHaveProperty('claudeProjectsPath'); }); it('should have valid platform name', () => { const info = cleanupManager.getPlatformInfo(); expect(['Windows', 'macOS', 'Linux', 'Unknown']).toContain(info.platform); }); it('should have string paths', () => { const info = cleanupManager.getPlatformInfo(); expect(typeof info.legacyBasePath).toBe('string'); expect(typeof info.currentBasePath).toBe('string'); expect(typeof info.npmCachePath).toBe('string'); expect(typeof info.claudeCliCachePath).toBe('string'); expect(typeof info.claudeProjectsPath).toBe('string'); }); it('should have non-empty paths', () => { const info = cleanupManager.getPlatformInfo(); expect(info.legacyBasePath.length).toBeGreaterThan(0); expect(info.currentBasePath.length).toBeGreaterThan(0); expect(info.npmCachePath.length).toBeGreaterThan(0); expect(info.claudeCliCachePath.length).toBeGreaterThan(0); expect(info.claudeProjectsPath.length).toBeGreaterThan(0); }); it('should have different legacy and current paths', () => { const info = cleanupManager.getPlatformInfo(); // Legacy path should have -nodejs suffix, current should not expect(info.legacyBasePath).not.toBe(info.currentBasePath); }); it('should contain notebooklm-mcp in paths', () => { const info = cleanupManager.getPlatformInfo(); expect(info.legacyBasePath.toLowerCase()).toContain('notebooklm-mcp'); expect(info.currentBasePath.toLowerCase()).toContain('notebooklm-mcp'); }); it('should return consistent results', () => { const info1 = cleanupManager.getPlatformInfo(); const info2 = cleanupManager.getPlatformInfo(); expect(info1.platform).toBe(info2.platform); expect(info1.legacyBasePath).toBe(info2.legacyBasePath); expect(info1.currentBasePath).toBe(info2.currentBasePath); }); }); describe('CleanupMode types', () => { it('should support legacy mode', () => { const mode: CleanupMode = 'legacy'; expect(mode).toBe('legacy'); }); it('should support all mode', () => { const mode: CleanupMode = 'all'; expect(mode).toBe('all'); }); it('should support deep mode', () => { const mode: CleanupMode = 'deep'; expect(mode).toBe('deep'); }); it('should have valid mode values', () => { const validModes: CleanupMode[] = ['legacy', 'all', 'deep']; expect(validModes.length).toBe(3); }); }); describe('cleanup result structure', () => { it('should have expected properties', () => { const mockResult = { success: true, mode: 'legacy' as CleanupMode, deletedPaths: [], failedPaths: [], totalSizeBytes: 0, categorySummary: {}, }; expect(mockResult).toHaveProperty('success'); expect(mockResult).toHaveProperty('mode'); expect(mockResult).toHaveProperty('deletedPaths'); expect(mockResult).toHaveProperty('failedPaths'); expect(mockResult).toHaveProperty('totalSizeBytes'); expect(mockResult).toHaveProperty('categorySummary'); }); it('should have correct property types', () => { const mockResult = { success: true, mode: 'all' as CleanupMode, deletedPaths: ['/path/1', '/path/2'], failedPaths: ['/path/3'], totalSizeBytes: 1024, categorySummary: { 'Category 1': { count: 2, bytes: 512 }, 'Category 2': { count: 1, bytes: 512 }, }, }; expect(typeof mockResult.success).toBe('boolean'); expect(typeof mockResult.mode).toBe('string'); expect(Array.isArray(mockResult.deletedPaths)).toBe(true); expect(Array.isArray(mockResult.failedPaths)).toBe(true); expect(typeof mockResult.totalSizeBytes).toBe('number'); expect(typeof mockResult.categorySummary).toBe('object'); }); }); describe('cleanup category structure', () => { it('should have expected properties', () => { const mockCategory = { name: 'Test Category', description: 'Test description', paths: ['/path/1', '/path/2'], totalBytes: 1024, optional: false, }; expect(mockCategory).toHaveProperty('name'); expect(mockCategory).toHaveProperty('description'); expect(mockCategory).toHaveProperty('paths'); expect(mockCategory).toHaveProperty('totalBytes'); expect(mockCategory).toHaveProperty('optional'); }); it('should support optional categories', () => { const optionalCategory = { name: 'Optional Category', description: 'Optional files', paths: [], totalBytes: 0, optional: true, }; expect(optionalCategory.optional).toBe(true); }); it('should support required categories', () => { const requiredCategory = { name: 'Required Category', description: 'Required files', paths: [], totalBytes: 0, optional: false, }; expect(requiredCategory.optional).toBe(false); }); }); describe('byte size calculations', () => { it('should calculate KB correctly', () => { const bytes = 1024; const kb = bytes / 1024; expect(kb).toBe(1); }); it('should calculate MB correctly', () => { const bytes = 1024 * 1024; const mb = bytes / (1024 * 1024); expect(mb).toBe(1); }); it('should calculate GB correctly', () => { const bytes = 1024 * 1024 * 1024; const gb = bytes / (1024 * 1024 * 1024); expect(gb).toBe(1); }); it('should handle fractional values', () => { const bytes = 1536; // 1.5 KB const kb = bytes / 1024; expect(kb).toBe(1.5); }); it('should handle zero bytes', () => { const bytes = 0; const kb = bytes / 1024; expect(kb).toBe(0); }); }); describe('path validation logic', () => { it('should validate absolute paths', () => { const isAbsolute = (p: string) => { return p.startsWith('/') || /^[A-Z]:\\/.test(p); }; expect(isAbsolute('/home/user/file')).toBe(true); expect(isAbsolute('C:\\Users\\file')).toBe(true); expect(isAbsolute('relative/path')).toBe(false); }); it('should identify relative paths', () => { const isRelative = (p: string) => { return !p.startsWith('/') && !/^[A-Z]:\\/.test(p); }; expect(isRelative('relative/path')).toBe(true); expect(isRelative('./relative')).toBe(true); expect(isRelative('../parent')).toBe(true); expect(isRelative('/absolute')).toBe(false); }); it('should handle empty paths', () => { const path = ''; expect(path.length).toBe(0); }); it('should detect path separators', () => { const unixPath = '/home/user/file'; const windowsPath = 'C:\\Users\\file'; expect(unixPath).toContain('/'); expect(windowsPath).toContain('\\'); }); }); describe('category summary calculations', () => { it('should sum bytes correctly', () => { const files = [{ size: 1024 }, { size: 2048 }, { size: 512 }]; const total = files.reduce((sum, f) => sum + f.size, 0); expect(total).toBe(3584); }); it('should count files correctly', () => { const files = ['file1', 'file2', 'file3']; expect(files.length).toBe(3); }); it('should handle empty categories', () => { const files: string[] = []; const total = 0; expect(files.length).toBe(0); expect(total).toBe(0); }); it('should track multiple categories', () => { const summary = { 'Category 1': { count: 5, bytes: 1024 }, 'Category 2': { count: 3, bytes: 512 }, 'Category 3': { count: 1, bytes: 256 }, }; const totalCount = Object.values(summary).reduce((sum, cat) => sum + cat.count, 0); const totalBytes = Object.values(summary).reduce((sum, cat) => sum + cat.bytes, 0); expect(totalCount).toBe(9); expect(totalBytes).toBe(1792); }); }); describe('mode comparison logic', () => { it('should identify legacy mode scope', () => { const mode: CleanupMode = 'legacy'; const includesLegacy = mode === 'legacy' || mode === 'all' || mode === 'deep'; expect(includesLegacy).toBe(true); }); it('should identify all mode scope', () => { const mode: CleanupMode = 'all'; const includesCurrent = mode === 'all' || mode === 'deep'; expect(includesCurrent).toBe(true); }); it('should identify deep mode scope', () => { const mode: CleanupMode = 'deep'; const includesOptional = mode === 'deep'; expect(includesOptional).toBe(true); }); it('should order modes by scope', () => { const modes: CleanupMode[] = ['legacy', 'all', 'deep']; // Legacy < All < Deep (in terms of scope) expect(modes.indexOf('legacy')).toBeLessThan(modes.indexOf('all')); expect(modes.indexOf('all')).toBeLessThan(modes.indexOf('deep')); }); }); describe('preserve library flag logic', () => { it('should support preserve library option', () => { const preserveLibrary = true; expect(preserveLibrary).toBe(true); }); it('should default to not preserving library', () => { const preserveLibrary = false; expect(preserveLibrary).toBe(false); }); it('should affect paths when preserving', () => { const allPaths = ['data/', 'data/browser_state', 'data/library.json']; const preserveLibrary = true; const pathsToDelete = preserveLibrary ? allPaths.filter((p) => !p.endsWith('library.json')) : allPaths; expect(pathsToDelete).not.toContain('data/library.json'); expect(pathsToDelete.length).toBeLessThan(allPaths.length); }); it('should delete all paths when not preserving', () => { const allPaths = ['data/', 'data/browser_state', 'data/library.json']; const preserveLibrary = false; const pathsToDelete = preserveLibrary ? allPaths.filter((p) => !p.endsWith('library.json')) : allPaths; expect(pathsToDelete.length).toBe(allPaths.length); }); }); });

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/roomi-fields/notebooklm-mcp'

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