// Integration tests to verify all imports and exports work correctly // Run with: node integration_tests.js import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; import fs from 'fs'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const srcDir = join(__dirname, 'src'); // Test results tracking let tests = 0; let passed = 0; let failed = 0; function test(description, testFn) { tests++; try { testFn(); console.log(`โœ… ${description}`); passed++; } catch (error) { console.error(`โŒ ${description}`); console.error(` Error: ${error.message}`); failed++; } } function assert(condition, message) { if (!condition) { throw new Error(message); } } // Helper to check if file exists function fileExists(filePath) { return fs.existsSync(join(srcDir, filePath)); } // Helper to read file content function readFile(filePath) { return fs.readFileSync(join(srcDir, filePath), 'utf-8'); } // Helper to extract imports from a file function extractImports(content) { // Handle both single-line and multi-line imports const importRegex = /import\s+(?:{[^}]*}|\*\s+as\s+\w+|\w+)\s+from\s+["'](.\/[^"']+)["']/gs; const imports = []; let match; while ((match = importRegex.exec(content)) !== null) { imports.push(match[1]); } return imports; } // Helper to extract exports from a file function extractExports(content) { const exportRegex = /export\s+(?:async\s+)?(?:function|const|let|var|class)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/g; const exports = []; let match; while ((match = exportRegex.exec(content)) !== null) { exports.push(match[1]); } return exports; } console.log('๐Ÿงช Running Integration Tests for Refactored UI Modules\n'); // Test 1: Verify all core files exist test('All core JavaScript files exist', () => { const coreFiles = [ 'ui.js', 'uncloseai-embed-modal.js', 'widget-library.js', 'tts-modal.js', 'translate-modal.js', 'file-upload.js', 'chat.js', 'content.js', 'ui-themes.js', 'ui-translations.js', 'translation.js', 'config.js', 'tts.js' ]; coreFiles.forEach(file => { assert(fileExists(file), `File ${file} does not exist`); }); }); // Test 2: Verify ui.js imports are correct test('ui.js has all required imports', () => { const uiContent = readFile('ui.js'); const imports = extractImports(uiContent); const requiredImports = [ './config.js', './content.js', './language-detection.js', './tts.js', './ui-themes.js', './ui-translations.js', './translation.js', './tts-modal.js', './translate-modal.js', './widget-library.js', './uncloseai-embed-modal.js', './chat.js', './file-upload.js', './page-reader.js' ]; requiredImports.forEach(imp => { assert(imports.includes(imp), `ui.js missing import: ${imp}`); }); }); // Test 3: Verify all imported files exist test('All imported files exist', () => { const uiContent = readFile('ui.js'); const imports = extractImports(uiContent); imports.forEach(importPath => { const filePath = importPath.replace('./', ''); assert(fileExists(filePath), `Imported file does not exist: ${filePath}`); }); }); // Test 4: Verify widget-library.js exports expected functions test('widget-library.js exports required functions', () => { const content = readFile('widget-library.js'); const exports = extractExports(content); const requiredExports = [ 'createFullInterface', 'createCustomInterface', 'createChatFeature', 'createTTSFeature', 'createUploadFeature', 'createTranslateFeature', 'createSmartTranslateFeature', 'createReadFeature', 'createButton', 'handleTTSFromElement', 'handleUploadFromElement', 'handleSmartTranslate' ]; requiredExports.forEach(exp => { assert(exports.includes(exp), `widget-library.js missing export: ${exp}`); }); }); // Test 5: Verify uncloseai-embed-modal.js exports modal functions test('uncloseai-embed-modal.js exports modal functions', () => { const content = readFile('uncloseai-embed-modal.js'); const exports = extractExports(content); const requiredExports = [ 'openUncloseaiEmbeddedModal', 'openUncloseaiEmbeddedModalNew' ]; requiredExports.forEach(exp => { assert(exports.includes(exp), `uncloseai-embed-modal.js missing export: ${exp}`); }); }); // Test 6: Verify ui.js exports key functions test('ui.js exports required functions', () => { const content = readFile('ui.js'); const exports = extractExports(content); const requiredExports = [ 'createFloatingAIButton', 'initializeSystem', 'initializeUncloseaiElements', 'initializeChatInterface', 'toggleUncloseaiEmbeddedModal' ]; requiredExports.forEach(exp => { assert(exports.includes(exp), `ui.js missing export: ${exp}`); }); }); // Test 7: Verify tts-modal.js and translate-modal.js exist and export main functions test('Modal files export their main functions', () => { const ttsContent = readFile('tts-modal.js'); const ttsExports = extractExports(ttsContent); assert(ttsExports.includes('openTTSModal'), 'tts-modal.js missing openTTSModal export'); const translateContent = readFile('translate-modal.js'); const translateExports = extractExports(translateContent); assert(translateExports.includes('openTranslateModal'), 'translate-modal.js missing openTranslateModal export'); }); // Test 8: Verify file-upload.js exports upload functions test('file-upload.js exports upload functions', () => { const content = readFile('file-upload.js'); const exports = extractExports(content); const requiredExports = [ 'handleFileUpload', 'uploadFile', 'showProgressIndicator', 'hideProgressIndicator', 'addFileUploadButton' ]; requiredExports.forEach(exp => { assert(exports.includes(exp), `file-upload.js missing export: ${exp}`); }); }); // Test 9: Check for circular imports (basic check) test('No obvious circular imports detected', () => { const files = ['ui.js', 'uncloseai-embed-modal.js', 'widget-library.js', 'tts-modal.js', 'translate-modal.js']; files.forEach(file => { const content = readFile(file); const imports = extractImports(content); // Check if any file imports ui.js (which could create a cycle) if (file !== 'ui.js') { assert(!imports.includes('./ui.js'), `${file} imports ui.js which could create a circular dependency`); } }); }); // Test 10: Verify language files structure test('Language files directory structure is correct', () => { const languagesDir = join(srcDir, 'languages'); assert(fs.existsSync(languagesDir), 'languages directory does not exist'); const indexFile = join(languagesDir, 'index.js'); assert(fs.existsSync(indexFile), 'languages/index.js does not exist'); // Check for some key language files const keyLanguages = ['en.js', 'es.js', 'fr.js', 'zh.js']; keyLanguages.forEach(lang => { assert(fs.existsSync(join(languagesDir, lang)), `Language file ${lang} does not exist`); }); }); // Test 11: Verify no syntax errors in import statements test('All import statements are syntactically correct', () => { const files = fs.readdirSync(srcDir).filter(f => f.endsWith('.js')); files.forEach(file => { const content = readFile(file); // Check that all imports have proper structure using the same regex as extractImports const importMatches = content.match(/import\s+(?:{[^}]*}|\*\s+as\s+\w+|\w+)\s+from\s+["'][^"']+["']/gs); const importLines = content.match(/import\s+.*?from\s+.*?["'][^"']+["']/gs); if (importLines) { importLines.forEach(importStatement => { assert( importStatement.includes('from') && (importStatement.includes('"') || importStatement.includes("'")), `Invalid import syntax in ${file}: ${importStatement.replace(/\s+/g, ' ').trim()}` ); }); } }); }); // Test 12: Verify ui.js size reduction was successful test('ui.js is properly reduced in size', () => { const content = readFile('ui.js'); const lines = content.split('\n').length; // Should be under 600 lines after refactoring (was ~3600 before) assert(lines < 600, `ui.js is still too large: ${lines} lines (expected < 600)`); console.log(` ui.js is now ${lines} lines (great reduction!)`); }); // Test 13: Check for proper error handling in imports test('No broken import paths detected', () => { const files = fs.readdirSync(srcDir).filter(f => f.endsWith('.js')); files.forEach(file => { const content = readFile(file); const imports = extractImports(content); imports.forEach(importPath => { if (importPath.startsWith('./')) { const targetFile = importPath.replace('./', ''); assert( fileExists(targetFile), `Broken import in ${file}: ${importPath} -> file ${targetFile} does not exist` ); } }); }); }); // Test 14: Verify global exports are properly set test('Global window exports are declared', () => { const uiContent = readFile('ui.js'); const expectedGlobalExports = [ 'window.openTTSModal', 'window.openTranslateModal', 'window.toggleUncloseaiEmbeddedModal' ]; expectedGlobalExports.forEach(exp => { assert(uiContent.includes(exp), `ui.js missing global export: ${exp}`); }); }); // Test 15: Verify proper module structure test('Modules follow proper ES6 export/import patterns', () => { const coreModules = ['widget-library.js', 'uncloseai-embed-modal.js', 'tts-modal.js', 'translate-modal.js']; coreModules.forEach(file => { const content = readFile(file); // Should have at least one export assert(content.includes('export '), `${file} has no exports`); // Should have proper imports (if any) const imports = extractImports(content); if (imports.length > 0) { imports.forEach(imp => { assert(imp.startsWith('./'), `${file} has non-relative import: ${imp}`); }); } }); }); // Run summary console.log('\n๐Ÿ“Š Test Results:'); console.log(`Total tests: ${tests}`); console.log(`Passed: ${passed} โœ…`); console.log(`Failed: ${failed} โŒ`); if (failed === 0) { console.log('\n๐ŸŽ‰ All integration tests passed! The refactored modules are properly structured.'); process.exit(0); } else { console.log('\n๐Ÿ’ฅ Some tests failed. Please fix the issues above before deploying.'); process.exit(1); }