Class_generator/Legacy/tests/run-tests.js
StillHammer 38920cc858 Complete architectural rewrite with ultra-modular system
Major Changes:
- Moved legacy system to Legacy/ folder for archival
- Built new modular architecture with strict separation of concerns
- Created core system: Module, EventBus, ModuleLoader, Router
- Added Application bootstrap with auto-start functionality
- Implemented development server with ES6 modules support
- Created comprehensive documentation and project context
- Converted SBS-7-8 content to JSON format
- Copied all legacy games and content to new structure

New Architecture Features:
- Sealed modules with WeakMap private data
- Strict dependency injection system
- Event-driven communication only
- Inviolable responsibility patterns
- Auto-initialization without commands
- Component-based UI foundation ready

Technical Stack:
- Vanilla JS/HTML/CSS only
- ES6 modules with proper imports/exports
- HTTP development server (no file:// protocol)
- Modular CSS with component scoping
- Comprehensive error handling and debugging

Ready for Phase 2: Converting legacy modules to new architecture

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-22 07:08:39 +08:00

289 lines
9.0 KiB
JavaScript

#!/usr/bin/env node
/**
* Script principal pour lancer tous les tests
* Usage: node tests/run-tests.js [options]
*/
import { spawn } from 'child_process';
import { readdir } from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Configuration
const config = {
timeout: 30000, // 30 secondes par test
verbose: process.argv.includes('--verbose'),
watch: process.argv.includes('--watch'),
coverage: process.argv.includes('--coverage'),
pattern: process.argv.find(arg => arg.startsWith('--pattern='))?.split('=')[1] || '*',
bail: process.argv.includes('--bail'),
unitOnly: process.argv.includes('--unit-only'),
integrationOnly: process.argv.includes('--integration-only')
};
// Couleurs pour les logs
const colors = {
green: '\x1b[32m',
red: '\x1b[31m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
reset: '\x1b[0m',
bold: '\x1b[1m'
};
function log(message, color = 'reset') {
console.log(`${colors[color]}${message}${colors.reset}`);
}
function logSection(title) {
log(`\n${'='.repeat(60)}`, 'blue');
log(`${title}`, 'bold');
log(`${'='.repeat(60)}`, 'blue');
}
async function findTestFiles(directory, pattern = '*.test.js') {
try {
const files = await readdir(directory);
return files
.filter(file => file.endsWith('.test.js'))
.filter(file => pattern === '*' || file.includes(pattern))
.map(file => path.join(directory, file));
} catch (error) {
log(`⚠️ Impossible de lire ${directory}: ${error.message}`, 'yellow');
return [];
}
}
async function runTests(testFiles, description) {
if (testFiles.length === 0) {
log(`📁 Aucun test trouvé pour ${description}`, 'yellow');
return { success: true, total: 0, passed: 0, failed: 0 };
}
logSection(`🧪 ${description} (${testFiles.length} fichiers)`);
const args = ['--test'];
if (config.coverage) {
args.push('--experimental-test-coverage');
}
args.push(...testFiles);
return new Promise((resolve) => {
const nodeProcess = spawn('node', args, {
stdio: 'pipe',
cwd: path.resolve(__dirname, '..')
});
let output = '';
let errorOutput = '';
nodeProcess.stdout.on('data', (data) => {
const text = data.toString();
output += text;
if (config.verbose) {
process.stdout.write(text);
}
});
nodeProcess.stderr.on('data', (data) => {
const text = data.toString();
errorOutput += text;
if (config.verbose) {
process.stderr.write(text);
}
});
nodeProcess.on('close', (code) => {
const success = code === 0;
// Parser les résultats basiques
const lines = output.split('\n');
const summary = lines.find(line => line.includes('tests') && line.includes('passed'));
let stats = { total: 0, passed: 0, failed: 0 };
if (summary) {
const match = summary.match(/(\\d+) passed.*?(\\d+) failed/);
if (match) {
stats.passed = parseInt(match[1]);
stats.failed = parseInt(match[2]);
stats.total = stats.passed + stats.failed;
}
}
if (success) {
log(`${description} - Tous les tests sont passés!`, 'green');
} else {
log(`${description} - Des tests ont échoué`, 'red');
if (!config.verbose && errorOutput) {
log('Erreurs:', 'red');
console.error(errorOutput);
}
}
resolve({ success, ...stats, output, errorOutput });
});
// Timeout
setTimeout(() => {
nodeProcess.kill();
log(`⏰ Timeout atteint pour ${description}`, 'yellow');
resolve({ success: false, total: 0, passed: 0, failed: 0, timeout: true });
}, config.timeout);
});
}
async function checkDependencies() {
log('🔍 Vérification des dépendances...', 'blue');
// Vérifier que Node.js supporte --test
const nodeVersion = process.version;
const majorVersion = parseInt(nodeVersion.split('.')[0].slice(1));
if (majorVersion < 18) {
log(`❌ Node.js ${nodeVersion} ne supporte pas --test. Version minimale: 18.0.0`, 'red');
return false;
}
log(`✅ Node.js ${nodeVersion} - Support des tests natif OK`, 'green');
return true;
}
async function setupEnvironment() {
log('🔧 Configuration de l\'environnement de test...', 'blue');
// Variables d'environnement pour les tests
process.env.NODE_ENV = 'test';
process.env.TEST_VERBOSE = config.verbose ? '1' : '0';
// Désactiver les logs en mode non-verbose
if (!config.verbose) {
process.env.SILENT_TESTS = '1';
}
log('✅ Environnement configuré', 'green');
}
function printSummary(results) {
logSection('📊 Résumé des Tests');
let totalTests = 0, totalPassed = 0, totalFailed = 0;
let allSuccess = true;
results.forEach(({ description, success, total, passed, failed }) => {
const status = success ? '✅' : '❌';
const stats = total > 0 ? ` (${passed}/${total})` : '';
log(`${status} ${description}${stats}`);
totalTests += total;
totalPassed += passed;
totalFailed += failed;
allSuccess = allSuccess && success;
});
log('\\n' + '─'.repeat(40));
log(`📈 Total: ${totalTests} tests`, 'bold');
log(`✅ Réussis: ${totalPassed}`, 'green');
if (totalFailed > 0) {
log(`❌ Échoués: ${totalFailed}`, 'red');
}
const successRate = totalTests > 0 ? Math.round((totalPassed / totalTests) * 100) : 100;
log(`📊 Taux de réussite: ${successRate}%`, successRate === 100 ? 'green' : 'yellow');
if (allSuccess && totalTests > 0) {
log('\\n🎉 Tous les tests sont passés!', 'green');
} else if (totalFailed > 0) {
log('\\n💥 Certains tests ont échoué', 'red');
}
return allSuccess;
}
function printUsage() {
log('📚 Usage: node tests/run-tests.js [options]\\n', 'bold');
log('Options disponibles:');
log(' --verbose Affichage détaillé des tests');
log(' --watch Mode surveillance (redémarre les tests si changement)');
log(' --coverage Rapport de couverture de code');
log(' --pattern=PATTERN Ne lancer que les tests contenant PATTERN');
log(' --bail Arrêter au premier échec');
log(' --unit-only Lancer seulement les tests unitaires');
log(' --integration-only Lancer seulement les tests d\'intégration');
log(' --help Afficher cette aide');
}
async function main() {
if (process.argv.includes('--help')) {
printUsage();
return;
}
logSection('🚀 Class Generator - Suite de Tests');
// Vérifications préliminaires
if (!(await checkDependencies())) {
process.exit(1);
}
await setupEnvironment();
const results = [];
try {
// Tests unitaires
if (!config.integrationOnly) {
const unitTestDir = path.join(__dirname, 'unit');
const unitTests = await findTestFiles(unitTestDir, config.pattern);
const unitResult = await runTests(unitTests, 'Tests Unitaires');
results.push({ description: 'Tests Unitaires', ...unitResult });
if (config.bail && !unitResult.success) {
log('🛑 Arrêt après échec des tests unitaires (--bail)', 'red');
process.exit(1);
}
}
// Tests d'intégration
if (!config.unitOnly) {
const integrationTestDir = path.join(__dirname, 'integration');
const integrationTests = await findTestFiles(integrationTestDir, config.pattern);
const integrationResult = await runTests(integrationTests, 'Tests d\'Intégration');
results.push({ description: 'Tests d\'Intégration', ...integrationResult });
if (config.bail && !integrationResult.success) {
log('🛑 Arrêt après échec des tests d\'intégration (--bail)', 'red');
process.exit(1);
}
}
// Résumé final
const allSuccess = printSummary(results);
// Code de sortie
process.exit(allSuccess ? 0 : 1);
} catch (error) {
log(`💥 Erreur lors de l'exécution des tests: ${error.message}`, 'red');
console.error(error);
process.exit(1);
}
}
// Mode watch
if (config.watch) {
log('👀 Mode surveillance activé - Ctrl+C pour arrêter', 'yellow');
// TODO: Implémenter la surveillance des fichiers
log('⚠️ Mode watch non encore implémenté', 'yellow');
}
// Lancement
main().catch(error => {
console.error('Erreur fatale:', error);
process.exit(1);
});