Files
esengine/packages/core/tests/Core.test.ts

465 lines
15 KiB
TypeScript
Raw Normal View History

import { Core } from '../src/Core';
import { Scene } from '../src/ECS/Scene';
import { SceneManager } from '../src/ECS/SceneManager';
import { Entity } from '../src/ECS/Entity';
import { Component } from '../src/ECS/Component';
import { ITimer } from '../src/Utils/Timers/ITimer';
2025-10-10 21:52:43 +08:00
import { Updatable } from '../src/Core/DI';
import type { IService } from '../src/Core/ServiceContainer';
import type { IUpdatable } from '../src/Types/IUpdatable';
// 测试组件
class TestComponent extends Component {
2025-07-31 15:37:40 +08:00
public value: number;
constructor(...args: unknown[]) {
super();
2025-07-31 15:37:40 +08:00
const [value = 0] = args as [number?];
this.value = value;
}
}
// 测试场景
class TestScene extends Scene {
public initializeCalled = false;
public beginCalled = false;
public endCalled = false;
public updateCallCount = 0;
public override initialize(): void {
this.initializeCalled = true;
}
public override begin(): void {
this.beginCalled = true;
}
public override end(): void {
this.endCalled = true;
}
public override update(): void {
this.updateCallCount++;
}
}
2025-10-10 21:52:43 +08:00
// 测试可更新服务
@Updatable()
class TestUpdatableService implements IService, IUpdatable {
public updateCallCount = 0;
2025-10-10 21:52:43 +08:00
public update(): void {
this.updateCallCount++;
}
2025-10-10 21:52:43 +08:00
public dispose(): void {
// 清理资源
}
}
describe('Core - 核心管理系统测试', () => {
let originalConsoleWarn: typeof console.warn;
beforeEach(() => {
// 清除之前的实例
(Core as any)._instance = null;
// 注意WorldManager不再是单例无需reset
// 模拟console.warn以避免测试输出
originalConsoleWarn = console.warn;
console.warn = jest.fn();
});
afterEach(() => {
// 恢复console.warn
console.warn = originalConsoleWarn;
// 清理Core实例
if (Core.Instance) {
Core.destroy();
}
});
describe('实例创建和管理', () => {
test('应该能够创建Core实例', () => {
const core = Core.create(true);
expect(core).toBeDefined();
expect(core).toBeInstanceOf(Core);
expect(core.debug).toBe(true);
expect(Core.entitySystemsEnabled).toBe(true);
});
test('应该能够通过配置对象创建Core实例', () => {
const config = {
debug: false,
enableEntitySystems: false
};
const core = Core.create(config);
expect(core.debug).toBe(false);
expect(Core.entitySystemsEnabled).toBe(false);
});
test('重复调用create应该返回同一个实例', () => {
const core1 = Core.create(true);
const core2 = Core.create(false); // 不同参数
expect(core1).toBe(core2);
});
test('应该能够获取Core实例', () => {
const core = Core.create(true);
const instance = Core.Instance;
expect(instance).toBe(core);
});
test('在未创建实例时调用update应该显示警告', () => {
Core.update(0.016);
2025-08-08 15:41:37 +08:00
expect(console.warn).toHaveBeenCalledWith(expect.stringContaining("Core实例未创建请先调用Core.create()"));
});
});
// 注意场景管理功能已移至SceneManager
// 相关测试请查看 SceneManager.test.ts
2025-10-10 21:52:43 +08:00
describe('更新循环 - 可更新服务', () => {
let core: Core;
2025-10-10 21:52:43 +08:00
let updatableService: TestUpdatableService;
beforeEach(() => {
core = Core.create(true);
2025-10-10 21:52:43 +08:00
updatableService = new TestUpdatableService();
Core.services.registerInstance(TestUpdatableService, updatableService);
});
2025-10-10 21:52:43 +08:00
test('应该能够更新可更新服务', () => {
Core.update(0.016);
2025-10-10 21:52:43 +08:00
expect(updatableService.updateCallCount).toBe(1);
});
test('暂停状态下不应该执行更新', () => {
Core.paused = true;
Core.update(0.016);
2025-10-10 21:52:43 +08:00
expect(updatableService.updateCallCount).toBe(0);
// 恢复状态
Core.paused = false;
});
test('多次更新应该累积调用', () => {
Core.update(0.016);
Core.update(0.016);
Core.update(0.016);
2025-10-10 21:52:43 +08:00
expect(updatableService.updateCallCount).toBe(3);
});
});
2025-10-10 21:52:43 +08:00
describe('服务容器集成', () => {
let core: Core;
2025-10-10 21:52:43 +08:00
let service1: TestUpdatableService;
beforeEach(() => {
core = Core.create(true);
2025-10-10 21:52:43 +08:00
service1 = new TestUpdatableService();
});
2025-10-10 21:52:43 +08:00
test('应该能够通过ServiceContainer注册可更新服务', () => {
Core.services.registerInstance(TestUpdatableService, service1);
// 测试更新是否被调用
Core.update(0.016);
2025-10-10 21:52:43 +08:00
expect(service1.updateCallCount).toBe(1);
});
2025-10-10 21:52:43 +08:00
test('应该能够注销服务', () => {
Core.services.registerInstance(TestUpdatableService, service1);
Core.services.unregister(TestUpdatableService);
// 测试更新不应该被调用
Core.update(0.016);
2025-10-10 21:52:43 +08:00
expect(service1.updateCallCount).toBe(0);
});
2025-10-10 21:52:43 +08:00
test('应该能够通过ServiceContainer解析服务', () => {
Core.services.registerInstance(TestUpdatableService, service1);
2025-10-10 21:52:43 +08:00
const retrieved = Core.services.resolve(TestUpdatableService);
expect(retrieved).toBe(service1);
});
2025-10-10 21:52:43 +08:00
test('解析不存在的服务应该抛出错误', () => {
expect(() => {
Core.services.resolve(TestUpdatableService);
}).toThrow();
});
});
describe('定时器系统', () => {
let core: Core;
beforeEach(() => {
core = Core.create(true);
});
test('应该能够调度定时器', () => {
let callbackExecuted = false;
let timerInstance: ITimer | null = null;
const timer = Core.schedule(0.1, false, null, (timer) => {
callbackExecuted = true;
timerInstance = timer;
});
expect(timer).toBeDefined();
// 模拟时间推进
for (let i = 0; i < 10; i++) {
Core.update(0.016); // 约160ms总计
}
expect(callbackExecuted).toBe(true);
expect(timerInstance).toBe(timer);
});
test('应该能够调度重复定时器', () => {
let callbackCount = 0;
Core.schedule(0.05, true, null, () => {
callbackCount++;
});
// 模拟足够长的时间以触发多次回调
for (let i = 0; i < 15; i++) {
Core.update(0.016); // 约240ms总计应该触发4-5次
}
expect(callbackCount).toBeGreaterThan(1);
});
test('应该支持带上下文的定时器', () => {
const context = { value: 42 };
let receivedContext: any = null;
Core.schedule(0.05, false, context, function(this: any, timer) {
receivedContext = this;
});
// 模拟时间推进
for (let i = 0; i < 5; i++) {
Core.update(0.016);
}
expect(receivedContext).toBe(context);
});
});
describe('调试功能', () => {
test('应该能够启用调试功能', () => {
const core = Core.create(true);
const debugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:8080',
autoReconnect: true,
updateInterval: 1000,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
Core.enableDebug(debugConfig);
expect(Core.isDebugEnabled).toBe(true);
});
test('应该能够禁用调试功能', () => {
const core = Core.create(true);
const debugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:8080',
autoReconnect: true,
updateInterval: 1000,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
Core.enableDebug(debugConfig);
Core.disableDebug();
expect(Core.isDebugEnabled).toBe(false);
});
test('在未创建实例时启用调试应该显示警告', () => {
const debugConfig = {
enabled: true,
websocketUrl: 'ws://localhost:8080',
autoReconnect: true,
updateInterval: 1000,
channels: {
entities: true,
systems: true,
performance: true,
components: true,
scenes: true
}
};
Core.enableDebug(debugConfig);
2025-08-08 15:41:37 +08:00
expect(console.warn).toHaveBeenCalledWith(expect.stringContaining("Core实例未创建请先调用Core.create()"));
});
});
// ECS API 现在由 SceneManager 管理
// 相关测试请查看 SceneManager.test.ts
describe('性能监控集成', () => {
let core: Core;
beforeEach(() => {
core = Core.create(true);
});
test('调试模式下应该启用性能监控', () => {
const performanceMonitor = (core as any)._performanceMonitor;
expect(performanceMonitor).toBeDefined();
// 性能监控器应该在调试模式下被启用
expect(performanceMonitor.isEnabled).toBe(true);
});
test('更新循环应该包含性能监控', () => {
const performanceMonitor = (core as any)._performanceMonitor;
const startMonitoringSpy = jest.spyOn(performanceMonitor, 'startMonitoring');
const endMonitoringSpy = jest.spyOn(performanceMonitor, 'endMonitoring');
Core.update(0.016);
expect(startMonitoringSpy).toHaveBeenCalled();
expect(endMonitoringSpy).toHaveBeenCalled();
});
});
refactor(editor): 提取行为树编辑器为独立包并重构编辑器架构 (#216) * refactor(editor): 提取行为树编辑器为独立包并重构编辑器架构 * feat(editor): 添加插件市场功能 * feat(editor): 重构插件市场以支持版本管理和ZIP打包 * feat(editor): 重构插件发布流程并修复React渲染警告 * fix(plugin): 修复插件发布和市场的路径不一致问题 * feat: 重构插件发布流程并添加插件删除功能 * fix(editor): 完善插件删除功能并修复多个关键问题 * fix(auth): 修复自动登录与手动登录的竞态条件问题 * feat(editor): 重构插件管理流程 * feat(editor): 支持 ZIP 文件直接发布插件 - 新增 PluginSourceParser 解析插件源 - 重构发布流程支持文件夹和 ZIP 两种方式 - 优化发布向导 UI * feat(editor): 插件市场支持多版本安装 - 插件解压到项目 plugins 目录 - 新增 Tauri 后端安装/卸载命令 - 支持选择任意版本安装 - 修复打包逻辑,保留完整 dist 目录结构 * feat(editor): 个人中心支持多版本管理 - 合并同一插件的不同版本 - 添加版本历史展开/折叠功能 - 禁止有待审核 PR 时更新插件 * fix(editor): 修复 InspectorRegistry 服务注册 - InspectorRegistry 实现 IService 接口 - 注册到 Core.services 供插件使用 * feat(behavior-tree-editor): 完善插件注册和文件操作 - 添加文件创建模板和操作处理器 - 实现右键菜单创建行为树功能 - 修复文件读取权限问题(使用 Tauri 命令) - 添加 BehaviorTreeEditorPanel 组件 - 修复 rollup 配置支持动态导入 * feat(plugin): 完善插件构建和发布流程 * fix(behavior-tree-editor): 完整恢复编辑器并修复 Toast 集成 * fix(behavior-tree-editor): 修复节点选中、连线跟随和文件加载问题并优化性能 * fix(behavior-tree-editor): 修复端口连接失败问题并优化连线样式 * refactor(behavior-tree-editor): 移除调试面板功能简化代码结构 * refactor(behavior-tree-editor): 清理冗余代码合并重复逻辑 * feat(behavior-tree-editor): 完善编辑器核心功能增强扩展性 * fix(lint): 修复ESLint错误确保CI通过 * refactor(behavior-tree-editor): 优化编辑器工具栏和编译器功能 * refactor(behavior-tree-editor): 清理技术债务,优化代码质量 * fix(editor-app): 修复字符串替换安全问题
2025-11-18 14:46:51 +08:00
describe('Core.destroy() 生命周期', () => {
// 测试服务类
class TestGameService implements IService {
public disposed = false;
public value = 'test-value';
dispose(): void {
this.disposed = true;
}
}
test('destroy 后应该清理所有服务', () => {
// 创建 Core 并注册服务
Core.create({ debug: true });
const service = new TestGameService();
Core.services.registerInstance(TestGameService, service);
// 验证服务已注册
expect(Core.services.isRegistered(TestGameService)).toBe(true);
// 销毁 Core
Core.destroy();
// 验证服务的 dispose 被调用
expect(service.disposed).toBe(true);
// 验证 Core 实例已清空
expect(Core.Instance).toBeNull();
});
test('destroy 后重新 create 应该能够成功注册服务', () => {
// 第一次:创建 Core 并注册服务
Core.create({ debug: true });
Core.services.registerSingleton(TestGameService);
// 验证服务已注册
expect(Core.services.isRegistered(TestGameService)).toBe(true);
const firstService = Core.services.resolve(TestGameService);
expect(firstService).toBeDefined();
expect(firstService.value).toBe('test-value');
// 销毁 Core
Core.destroy();
// 第二次:重新创建 Core
Core.create({ debug: true });
// 应该能够重新注册相同的服务(不应该报错或 warn
expect(() => {
Core.services.registerSingleton(TestGameService);
}).not.toThrow();
// 验证服务重新注册成功
expect(Core.services.isRegistered(TestGameService)).toBe(true);
const secondService = Core.services.resolve(TestGameService);
expect(secondService).toBeDefined();
expect(secondService.value).toBe('test-value');
// 两次获取的应该是不同的实例
expect(secondService).not.toBe(firstService);
// 第一个实例应该已经被 dispose
expect(firstService.disposed).toBe(true);
});
test('destroy 后旧的服务引用不应该影响新的 Core 实例', () => {
// 第一次:创建 Core 并注册服务
Core.create({ debug: true });
const firstService = new TestGameService();
Core.services.registerInstance(TestGameService, firstService);
// 销毁 Core
Core.destroy();
// 验证旧服务被 dispose
expect(firstService.disposed).toBe(true);
// 第二次:重新创建 Core 并注册新的服务实例
Core.create({ debug: true });
const secondService = new TestGameService();
Core.services.registerInstance(TestGameService, secondService);
// 验证新服务注册成功
const resolved = Core.services.resolve(TestGameService);
expect(resolved).toBe(secondService);
expect(resolved).not.toBe(firstService);
// 新服务应该未被 dispose
expect(secondService.disposed).toBe(false);
});
test('多次调用 destroy 应该安全', () => {
Core.create({ debug: true });
const service = new TestGameService();
Core.services.registerInstance(TestGameService, service);
// 第一次 destroy
Core.destroy();
expect(service.disposed).toBe(true);
expect(Core.Instance).toBeNull();
// 第二次 destroy应该安全不抛出错误
expect(() => {
Core.destroy();
}).not.toThrow();
expect(Core.Instance).toBeNull();
});
});
});