diff --git a/cocoscreator_projects/YouleNexus/assets/framework/net/transport.ts b/cocoscreator_projects/YouleNexus/assets/framework/net/transport.ts new file mode 100644 index 0000000..9f3be63 --- /dev/null +++ b/cocoscreator_projects/YouleNexus/assets/framework/net/transport.ts @@ -0,0 +1,14 @@ +/** + * WebSocket 抽象(依赖注入点,D2)。 + * 生产:Cocos/浏览器 WebSocket adapter(见 cocos-transport.ts)。 + * 测试:内存 FakeTransport(模拟 server)。 + */ +export interface Transport { + send(frame: string): void; + close(): void; + onOpen(cb: () => void): void; + onMessage(cb: (frame: string) => void): void; + onClose(cb: () => void): void; + /** 发起连接(建立后应触发 onOpen)。 */ + connect(url: string): void; +} diff --git a/cocoscreator_projects/framework-tests/helpers/fake-transport.ts b/cocoscreator_projects/framework-tests/helpers/fake-transport.ts new file mode 100644 index 0000000..c8ad944 --- /dev/null +++ b/cocoscreator_projects/framework-tests/helpers/fake-transport.ts @@ -0,0 +1,27 @@ +import type { Transport } from '../../YouleNexus/assets/framework/net/transport.ts'; + +/** 内存 Transport:模拟服务器。用 microtask 队列异步触发回调,贴近真实 WS 时序。 */ +export class FakeTransport implements Transport { + sent: string[] = []; + url = ''; + private openCb?: () => void; + private msgCb?: (f: string) => void; + private closeCb?: () => void; + private pending: Array<() => void> = []; + private closed = false; + + connect(url: string): void { this.url = url; this.pending.push(() => this.openCb?.()); } + send(frame: string): void { if (!this.closed) this.sent.push(frame); } + close(): void { if (this.closed) return; this.closed = true; this.pending.push(() => this.closeCb?.()); } + onOpen(cb: () => void): void { this.openCb = cb; } + onMessage(cb: (f: string) => void): void { this.msgCb = cb; } + onClose(cb: () => void): void { this.closeCb = cb; } + + /** 测试侧:模拟服务器推一帧给客户端。 */ + serverPush(frame: string): void { if (!this.closed) this.pending.push(() => this.msgCb?.(frame)); } + + /** 冲刷所有挂起回调(解析微任务)。 */ + async flush(): Promise { + while (this.pending.length) { const fn = this.pending.shift()!; fn(); await Promise.resolve(); } + } +} diff --git a/cocoscreator_projects/framework-tests/net/transport.test.ts b/cocoscreator_projects/framework-tests/net/transport.test.ts new file mode 100644 index 0000000..03f6114 --- /dev/null +++ b/cocoscreator_projects/framework-tests/net/transport.test.ts @@ -0,0 +1,36 @@ +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { FakeTransport } from '../helpers/fake-transport.ts'; + +test('FakeTransport:connect 后异步触发 onOpen', async () => { + const t = new FakeTransport(); + let opened = false; + t.onOpen(() => { opened = true; }); + t.connect('ws://x'); + await t.flush(); + assert.equal(opened, true); +}); + +test('FakeTransport:客户端 send 进入 sent 队列;serverPush 触发 onMessage', async () => { + const t = new FakeTransport(); + const got: string[] = []; + t.onMessage((f) => got.push(f)); + t.connect('ws://x'); + await t.flush(); + t.send('hello'); + assert.deepEqual(t.sent, ['hello']); + t.serverPush('world'); + await t.flush(); + assert.deepEqual(got, ['world']); +}); + +test('FakeTransport:close 触发 onClose', async () => { + const t = new FakeTransport(); + let closed = false; + t.onClose(() => { closed = true; }); + t.connect('ws://x'); + await t.flush(); + t.close(); + await t.flush(); + assert.equal(closed, true); +});