Files
esengine/packages/core/tests/Core.test.ts
YHH bce3a6e253 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

465 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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';
import { Updatable } from '../src/Core/DI';
import type { IService } from '../src/Core/ServiceContainer';
import type { IUpdatable } from '../src/Types/IUpdatable';
// 测试组件
class TestComponent extends Component {
public value: number;
constructor(...args: unknown[]) {
super();
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++;
}
}
// 测试可更新服务
@Updatable()
class TestUpdatableService implements IService, IUpdatable {
public updateCallCount = 0;
public update(): void {
this.updateCallCount++;
}
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);
expect(console.warn).toHaveBeenCalledWith(expect.stringContaining("Core实例未创建请先调用Core.create()"));
});
});
// 注意场景管理功能已移至SceneManager
// 相关测试请查看 SceneManager.test.ts
describe('更新循环 - 可更新服务', () => {
let core: Core;
let updatableService: TestUpdatableService;
beforeEach(() => {
core = Core.create(true);
updatableService = new TestUpdatableService();
Core.services.registerInstance(TestUpdatableService, updatableService);
});
test('应该能够更新可更新服务', () => {
Core.update(0.016);
expect(updatableService.updateCallCount).toBe(1);
});
test('暂停状态下不应该执行更新', () => {
Core.paused = true;
Core.update(0.016);
expect(updatableService.updateCallCount).toBe(0);
// 恢复状态
Core.paused = false;
});
test('多次更新应该累积调用', () => {
Core.update(0.016);
Core.update(0.016);
Core.update(0.016);
expect(updatableService.updateCallCount).toBe(3);
});
});
describe('服务容器集成', () => {
let core: Core;
let service1: TestUpdatableService;
beforeEach(() => {
core = Core.create(true);
service1 = new TestUpdatableService();
});
test('应该能够通过ServiceContainer注册可更新服务', () => {
Core.services.registerInstance(TestUpdatableService, service1);
// 测试更新是否被调用
Core.update(0.016);
expect(service1.updateCallCount).toBe(1);
});
test('应该能够注销服务', () => {
Core.services.registerInstance(TestUpdatableService, service1);
Core.services.unregister(TestUpdatableService);
// 测试更新不应该被调用
Core.update(0.016);
expect(service1.updateCallCount).toBe(0);
});
test('应该能够通过ServiceContainer解析服务', () => {
Core.services.registerInstance(TestUpdatableService, service1);
const retrieved = Core.services.resolve(TestUpdatableService);
expect(retrieved).toBe(service1);
});
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);
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();
});
});
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();
});
});
});