- Add missing toggleUncloseaiEmbeddedModal function for floating button
- Create comprehensive integration test suite (15 tests)
- Tests verify all imports/exports work correctly
- Tests ensure proper module structure after refactoring
- All tests passing ✅ - refactoring is solid!
348 lines
No EOL
11 KiB
JavaScript
Executable file
348 lines
No EOL
11 KiB
JavaScript
Executable file
// 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);
|
|
} |