uncloseai.com/integration_tests.js
Russell Ballestrini 2d4b52399c fix: add toggleUncloseaiEmbeddedModal + integration tests
- 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!
2025-07-03 16:43:38 -04:00

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);
}