import { remoteFixture } from '../fixtures/remote-config.ts'; import { test } from 'node:test'; import assert from 'node:assert/strict'; import { StartupOrchestrator } from '../../YouleNexus/assets/framework/platform/startup.ts'; import { PlatformSession } from '../../YouleNexus/assets/framework/platform/session.ts'; import { EventBus } from '../../YouleNexus/assets/framework/core/events.ts'; import type { NetClientEvents } from '../../YouleNexus/assets/framework/net/net-client.ts'; import type { BootstrapResult } from '../../YouleNexus/assets/framework/config/bootstrap.ts'; const IDENTITY = { agentid: 'A', channelid: 'C', gameid: 'G', marketid: 4, version: 10000 }; function bootstrapOf(): BootstrapResult { return { mode: 'debug', isDebugger: true, identity: IDENTITY, servers: ['ws://test'], ...remoteFixture(), profile: { name: 'debug' }, }; } test('StartupOrchestrator: 启动流程 bootstrap → onLogin → ready', async () => { const bus = new EventBus(); const session = new PlatformSession(bus); let startedRoomBus = false; const orch = new StartupOrchestrator({ session, bus, getBootstrapResult: async () => bootstrapOf(), makeNetClient: () => ({ bus }) as any, identity: IDENTITY, roomBusFactory: () => ({ start() { startedRoomBus = true; }, stop() { startedRoomBus = false; }, } as any), }); await orch.bootstrap(); assert.equal(orch.bootstrapResult?.servers[0], 'ws://test'); assert.equal(session.app.state.value.servers[0], 'ws://test', 'servers 应写入 AppStore'); assert.equal(session.app.state.value.identity?.agentid, 'A', 'identity 应写入 AppStore'); // 模拟 NetClient 发出 login 事件(让 session 把 phase 推到 loggedIn) bus.emit('login', { state: 0, playerid: 100, nickname: '甲', agentid: 'A', channelid: 'C' } as any); await orch.onLogin(); assert.equal(session.app.state.value.phase, 'loggedIn'); assert.equal(startedRoomBus, true, 'RoomRPCBus 应已 start'); assert.equal(orch.isReady(), true); await orch.waitForReady(); }); test('StartupOrchestrator: bootstrap 失败显式抛错', async () => { const bus = new EventBus(); const session = new PlatformSession(bus); const orch = new StartupOrchestrator({ session, bus, getBootstrapResult: async () => { throw new Error('远程配置抓取失败'); }, makeNetClient: () => ({} as any), identity: IDENTITY, roomBusFactory: () => ({ start() {}, stop() {} } as any), }); await assert.rejects(() => orch.bootstrap(), /远程配置抓取失败/); assert.equal(orch.bootstrapResult, null, 'bootstrap 失败时不写入 result'); }); test('StartupOrchestrator: waitForReady 在 ready 之前不 resolve', async () => { const bus = new EventBus(); const session = new PlatformSession(bus); const orch = new StartupOrchestrator({ session, bus, getBootstrapResult: async () => bootstrapOf(), makeNetClient: () => ({}) as any, identity: IDENTITY, roomBusFactory: () => ({ start() {}, stop() {} } as any), }); let resolved = false; const p = orch.waitForReady().then(() => { resolved = true; }); await new Promise((r) => setImmediate(r)); assert.equal(resolved, false, 'ready 之前不应 resolve'); await orch.onLogin(); await p; assert.equal(resolved, true); }); test('StartupOrchestrator: shutdown 停止 RoomRPCBus', async () => { const bus = new EventBus(); const session = new PlatformSession(bus); let stopped = false; const orch = new StartupOrchestrator({ session, bus, getBootstrapResult: async () => bootstrapOf(), makeNetClient: () => ({}) as any, identity: IDENTITY, roomBusFactory: () => ({ start() {}, stop() { stopped = true; }, } as any), }); await orch.bootstrap(); await orch.onLogin(); orch.shutdown(); assert.equal(stopped, true); }); test('StartupOrchestrator: bootstrap 可独立调用(不依赖 onLogin)', async () => { const bus = new EventBus(); const session = new PlatformSession(bus); const orch = new StartupOrchestrator({ session, bus, getBootstrapResult: async () => bootstrapOf(), makeNetClient: () => ({}) as any, identity: IDENTITY, roomBusFactory: () => ({ start() {}, stop() {} } as any), }); await orch.bootstrap(); // waitForReady 还未 resolve(未调 onLogin) const ready = orch.waitForReady(); let resolved = false; ready.then(() => { resolved = true; }); await new Promise((r) => setImmediate(r)); assert.equal(resolved, false, '仅 bootstrap 不足以触发 ready'); });