Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
343
tests/core/DependencyManager.test.js
Normal file
343
tests/core/DependencyManager.test.js
Normal file
@@ -0,0 +1,343 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import { DependencyManager } from '../../resources/js/core/DependencyManager.js';
|
||||
|
||||
// Mock Logger
|
||||
jest.mock('../../resources/js/core/logger.js', () => ({
|
||||
Logger: {
|
||||
info: jest.fn(),
|
||||
warn: jest.fn(),
|
||||
error: jest.fn()
|
||||
}
|
||||
}));
|
||||
|
||||
describe('DependencyManager', () => {
|
||||
let depManager;
|
||||
|
||||
beforeEach(() => {
|
||||
depManager = new DependencyManager();
|
||||
});
|
||||
|
||||
describe('Module registration', () => {
|
||||
test('should register module with valid definition', () => {
|
||||
const definition = {
|
||||
name: 'test-module',
|
||||
version: '1.0.0',
|
||||
dependencies: [],
|
||||
provides: ['test-service'],
|
||||
priority: 0
|
||||
};
|
||||
|
||||
depManager.register(definition);
|
||||
|
||||
expect(depManager.getModule('test-module')).toEqual(definition);
|
||||
});
|
||||
|
||||
test('should reject invalid module definitions', () => {
|
||||
const invalidDefinitions = [
|
||||
{ version: '1.0.0', dependencies: [] }, // No name
|
||||
{ name: 'test', dependencies: [] }, // No version
|
||||
{ name: 'test', version: '1.0.0' }, // No dependencies array
|
||||
{ name: 'test', version: '1.0.0', dependencies: [{}] } // Invalid dependency
|
||||
];
|
||||
|
||||
invalidDefinitions.forEach(def => {
|
||||
depManager.register(def);
|
||||
expect(depManager.getModule(def.name)).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
test('should not allow duplicate registration', () => {
|
||||
const definition1 = {
|
||||
name: 'duplicate',
|
||||
version: '1.0.0',
|
||||
dependencies: [],
|
||||
provides: [],
|
||||
priority: 0
|
||||
};
|
||||
|
||||
const definition2 = {
|
||||
name: 'duplicate',
|
||||
version: '2.0.0',
|
||||
dependencies: [],
|
||||
provides: [],
|
||||
priority: 0
|
||||
};
|
||||
|
||||
depManager.register(definition1);
|
||||
depManager.register(definition2);
|
||||
|
||||
expect(depManager.getModule('duplicate').version).toBe('1.0.0');
|
||||
});
|
||||
|
||||
test('should build dependents map correctly', () => {
|
||||
const moduleA = {
|
||||
name: 'module-a',
|
||||
version: '1.0.0',
|
||||
dependencies: [],
|
||||
provides: [],
|
||||
priority: 0
|
||||
};
|
||||
|
||||
const moduleB = {
|
||||
name: 'module-b',
|
||||
version: '1.0.0',
|
||||
dependencies: [{ name: 'module-a', version: '1.0.0', optional: false }],
|
||||
provides: [],
|
||||
priority: 0
|
||||
};
|
||||
|
||||
depManager.register(moduleA);
|
||||
depManager.register(moduleB);
|
||||
|
||||
expect(depManager.getDependents('module-a')).toContain('module-b');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Dependency resolution', () => {
|
||||
beforeEach(() => {
|
||||
// Register test modules
|
||||
depManager.register({
|
||||
name: 'core',
|
||||
version: '1.0.0',
|
||||
dependencies: [],
|
||||
provides: ['core-service'],
|
||||
priority: 100
|
||||
});
|
||||
|
||||
depManager.register({
|
||||
name: 'ui',
|
||||
version: '1.0.0',
|
||||
dependencies: [{ name: 'core', version: '1.0.0', optional: false }],
|
||||
provides: ['ui-service'],
|
||||
priority: 50
|
||||
});
|
||||
|
||||
depManager.register({
|
||||
name: 'advanced',
|
||||
version: '1.0.0',
|
||||
dependencies: [
|
||||
{ name: 'core', version: '1.0.0', optional: false },
|
||||
{ name: 'ui', version: '1.0.0', optional: false }
|
||||
],
|
||||
provides: ['advanced-service'],
|
||||
priority: 10
|
||||
});
|
||||
});
|
||||
|
||||
test('should calculate correct initialization order', () => {
|
||||
const order = depManager.calculateInitializationOrder();
|
||||
|
||||
expect(order).toEqual(['core', 'ui', 'advanced']);
|
||||
});
|
||||
|
||||
test('should handle optional dependencies', () => {
|
||||
depManager.register({
|
||||
name: 'optional-dep',
|
||||
version: '1.0.0',
|
||||
dependencies: [
|
||||
{ name: 'core', version: '1.0.0', optional: false },
|
||||
{ name: 'missing-optional', version: '1.0.0', optional: true }
|
||||
],
|
||||
provides: [],
|
||||
priority: 0
|
||||
});
|
||||
|
||||
const order = depManager.calculateInitializationOrder();
|
||||
|
||||
expect(order).toContain('optional-dep');
|
||||
});
|
||||
|
||||
test('should detect circular dependencies', () => {
|
||||
depManager.register({
|
||||
name: 'circular-a',
|
||||
version: '1.0.0',
|
||||
dependencies: [{ name: 'circular-b', version: '1.0.0', optional: false }],
|
||||
provides: [],
|
||||
priority: 0
|
||||
});
|
||||
|
||||
depManager.register({
|
||||
name: 'circular-b',
|
||||
version: '1.0.0',
|
||||
dependencies: [{ name: 'circular-a', version: '1.0.0', optional: false }],
|
||||
provides: [],
|
||||
priority: 0
|
||||
});
|
||||
|
||||
expect(() => {
|
||||
depManager.calculateInitializationOrder();
|
||||
}).toThrow('Circular dependency detected');
|
||||
});
|
||||
|
||||
test('should respect priority in initialization order', () => {
|
||||
depManager.register({
|
||||
name: 'high-priority',
|
||||
version: '1.0.0',
|
||||
dependencies: [],
|
||||
provides: [],
|
||||
priority: 200
|
||||
});
|
||||
|
||||
const order = depManager.calculateInitializationOrder();
|
||||
|
||||
expect(order.indexOf('high-priority')).toBeLessThan(order.indexOf('core'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('Dependency checking', () => {
|
||||
beforeEach(() => {
|
||||
depManager.register({
|
||||
name: 'dependency',
|
||||
version: '1.0.0',
|
||||
dependencies: [],
|
||||
provides: [],
|
||||
priority: 0
|
||||
});
|
||||
|
||||
depManager.register({
|
||||
name: 'dependent',
|
||||
version: '1.0.0',
|
||||
dependencies: [{ name: 'dependency', version: '1.0.0', optional: false }],
|
||||
provides: [],
|
||||
priority: 0
|
||||
});
|
||||
});
|
||||
|
||||
test('should check dependencies correctly', () => {
|
||||
const check = depManager.checkDependencies('dependent');
|
||||
|
||||
expect(check.satisfied).toBe(false);
|
||||
expect(check.missing).toContain('dependency (not initialized)');
|
||||
});
|
||||
|
||||
test('should pass dependency check when dependencies are initialized', () => {
|
||||
depManager.markInitialized('dependency');
|
||||
const check = depManager.checkDependencies('dependent');
|
||||
|
||||
expect(check.satisfied).toBe(true);
|
||||
expect(check.missing).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('should handle optional dependencies in check', () => {
|
||||
depManager.register({
|
||||
name: 'optional-user',
|
||||
version: '1.0.0',
|
||||
dependencies: [
|
||||
{ name: 'dependency', version: '1.0.0', optional: false },
|
||||
{ name: 'missing-optional', version: '1.0.0', optional: true }
|
||||
],
|
||||
provides: [],
|
||||
priority: 0
|
||||
});
|
||||
|
||||
depManager.markInitialized('dependency');
|
||||
const check = depManager.checkDependencies('optional-user');
|
||||
|
||||
expect(check.satisfied).toBe(true);
|
||||
expect(check.optional).toContain('missing-optional');
|
||||
});
|
||||
|
||||
test('should check readiness for initialization', () => {
|
||||
expect(depManager.isReadyToInitialize('dependency')).toBe(true);
|
||||
expect(depManager.isReadyToInitialize('dependent')).toBe(false);
|
||||
|
||||
depManager.markInitialized('dependency');
|
||||
expect(depManager.isReadyToInitialize('dependent')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Module state tracking', () => {
|
||||
beforeEach(() => {
|
||||
depManager.register({
|
||||
name: 'test-module',
|
||||
version: '1.0.0',
|
||||
dependencies: [],
|
||||
provides: [],
|
||||
priority: 0
|
||||
});
|
||||
});
|
||||
|
||||
test('should track initialization state', () => {
|
||||
expect(depManager.initialized.has('test-module')).toBe(false);
|
||||
expect(depManager.initializing.has('test-module')).toBe(false);
|
||||
|
||||
depManager.markInitializing('test-module');
|
||||
expect(depManager.initializing.has('test-module')).toBe(true);
|
||||
|
||||
depManager.markInitialized('test-module');
|
||||
expect(depManager.initialized.has('test-module')).toBe(true);
|
||||
expect(depManager.initializing.has('test-module')).toBe(false);
|
||||
});
|
||||
|
||||
test('should provide status report', () => {
|
||||
depManager.register({
|
||||
name: 'module-2',
|
||||
version: '1.0.0',
|
||||
dependencies: [],
|
||||
provides: [],
|
||||
priority: 0
|
||||
});
|
||||
|
||||
depManager.markInitialized('test-module');
|
||||
depManager.markInitializing('module-2');
|
||||
|
||||
const status = depManager.getStatus();
|
||||
|
||||
expect(status.total).toBe(2);
|
||||
expect(status.initialized).toBe(1);
|
||||
expect(status.initializing).toBe(1);
|
||||
expect(status.pending).toBe(0);
|
||||
expect(status.modules.initialized).toContain('test-module');
|
||||
expect(status.modules.initializing).toContain('module-2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Definition builder', () => {
|
||||
test('should create definition with builder pattern', () => {
|
||||
const definition = DependencyManager.createDefinition('builder-test', '2.0.0')
|
||||
.depends('dep1', '1.0.0')
|
||||
.depends('dep2', '2.0.0', true)
|
||||
.provides('service1', 'service2')
|
||||
.priority(50);
|
||||
|
||||
expect(definition.name).toBe('builder-test');
|
||||
expect(definition.version).toBe('2.0.0');
|
||||
expect(definition.dependencies).toHaveLength(2);
|
||||
expect(definition.dependencies[0]).toEqual({
|
||||
name: 'dep1',
|
||||
version: '1.0.0',
|
||||
optional: false
|
||||
});
|
||||
expect(definition.dependencies[1]).toEqual({
|
||||
name: 'dep2',
|
||||
version: '2.0.0',
|
||||
optional: true
|
||||
});
|
||||
expect(definition.provides).toEqual(['service1', 'service2']);
|
||||
expect(definition.priority).toBe(50);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Reset and cleanup', () => {
|
||||
test('should reset all state', () => {
|
||||
depManager.register({
|
||||
name: 'test',
|
||||
version: '1.0.0',
|
||||
dependencies: [],
|
||||
provides: [],
|
||||
priority: 0
|
||||
});
|
||||
|
||||
depManager.markInitialized('test');
|
||||
|
||||
depManager.reset();
|
||||
|
||||
expect(depManager.modules.size).toBe(0);
|
||||
expect(depManager.initialized.size).toBe(0);
|
||||
expect(depManager.dependents.size).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user