/** * Mock for modules/index.js to avoid import.meta issues in Jest */ export const activeModules = new Map(); export const registerModules = jest.fn(async () => { // Use the global mock function if available const globFn = global.importMeta?.glob || (() => ({})); const modules = globFn('./*/index.js', { eager: true }); const domModules = new Set( Array.from(document.querySelectorAll('[data-module]')).map(el => el.dataset.module).filter(Boolean) ); const usedModules = new Set(domModules); const fallbackMode = usedModules.size === 0; // Use the already mocked dependencies from Jest const { dependencyManager } = require('../../../../../resources/js/core/DependencyManager.js'); const { moduleErrorBoundary } = require('../../../../../resources/js/core/ModuleErrorBoundary.js'); const { stateManager } = require('../../../../../resources/js/core/StateManager.js'); // Phase 1: Register all modules with dependency manager Object.entries(modules).forEach(([path, mod]) => { const name = path.split('/').slice(-2, -1)[0]; if(!fallbackMode && !usedModules.has(name)) { return; } if (typeof mod.definition === 'object') { dependencyManager.register(mod.definition); } else { const defaultDef = { name, version: '1.0.0', dependencies: [], provides: [], priority: 0 }; dependencyManager.register(defaultDef); } }); // Phase 2: Calculate initialization order const initOrder = dependencyManager.calculateInitializationOrder(); // Phase 3: Initialize modules in dependency order for (const name of initOrder) { if(!fallbackMode && !usedModules.has(name)) { continue; } const mod = Object.entries(modules).find(([path]) => path.includes(name))?.[1]; if (!mod) continue; const config = {}; const dependencyCheck = dependencyManager.checkDependencies(name); if (!dependencyCheck.satisfied) { activeModules.set(name, { mod: null, config, error: new Error(dependencyCheck.reason), original: mod }); continue; } try { dependencyManager.markInitializing(name); const wrappedMod = moduleErrorBoundary.wrapModule(mod, name); const scopedState = stateManager.createScope(name); if (typeof mod.init === 'function') { await mod.init(config, scopedState); } activeModules.set(name, { mod: wrappedMod, config, state: scopedState, original: mod }); dependencyManager.markInitialized(name); } catch (error) { activeModules.set(name, { mod: null, config, error, original: mod }); } } }); export const destroyModules = jest.fn(() => { for (const [name, moduleData] of activeModules) { try { if (moduleData.mod && typeof moduleData.mod.destroy === 'function') { moduleData.mod.destroy(); } if (moduleData.state && typeof moduleData.state.cleanup === 'function') { moduleData.state.cleanup(); } } catch (error) { // Handle errors gracefully } } activeModules.clear(); // Use the already mocked dependencies const { moduleErrorBoundary } = require('../../../../../resources/js/core/ModuleErrorBoundary.js'); const { stateManager } = require('../../../../../resources/js/core/StateManager.js'); const { dependencyManager } = require('../../../../../resources/js/core/DependencyManager.js'); moduleErrorBoundary.reset(); stateManager.resetAll(); dependencyManager.reset(); }); export const getModuleHealth = jest.fn(() => { const health = { total: activeModules.size, active: 0, failed: 0, modules: {}, errorBoundary: { totalCrashedModules: 0, crashedModules: [], recoveryAttempts: {} } }; for (const [name, moduleData] of activeModules) { if (moduleData.error) { health.failed++; health.modules[name] = { status: 'failed', error: moduleData.error.message }; } else { health.active++; health.modules[name] = { status: 'active' }; } } return health; });