feat: integrate platform room entry, UI migration and erqiwang documentation
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
/** Run in Cocos Game View. The actual socket is stopped before all local fixtures. */
|
||||
export async function verifyRoomEntryPreview(e,loginFixture){
|
||||
const checks=[],assert=(ok,text)=>{if(!ok)throw Error(text);checks.push(text);};
|
||||
const sleep=ms=>new Promise(r=>setTimeout(r,ms));
|
||||
const load=id=>new Promise((r,j)=>e.assetManager.loadAny(id,(err,a)=>err?j(err):r(a)));
|
||||
const exported=name=>Array.from(System.entries()).map(([,m])=>m).find(m=>m[name])?.[name];
|
||||
const startup=e.director.getScene().getComponentInChildren('PlatformStartup');
|
||||
assert(startup,'persistent Startup loaded');startup.unsubscribe?.();startup.unsubscribe=null;startup.runtime.stop();startup.panel?.dispose();startup.panel=null;
|
||||
const canvas=e.director.getScene().getChildByName('Canvas');
|
||||
let node=null;const tips=[],sent=[];let cancel=0;
|
||||
const mount=async id=>{if(node){node.destroy();await sleep(50);}node=e.instantiate(await load(id));node.parent=canvas;node.setPosition(0,0,0);const w=node.getComponent(e.Widget);if(w){w.target=canvas;w.updateAlignment();}await sleep(100);return node;};
|
||||
let pointer=30;
|
||||
const click=async n=>{const camera=canvas.getComponent(e.Canvas).cameraComponent,p=camera.worldToScreen(n.worldPosition);const touch=new e.Touch(p.x,p.y,pointer++);
|
||||
e.input._dispatchEventTouch(new e.EventTouch([touch],false,e.Input.EventType.TOUCH_START,[touch]));
|
||||
e.input._dispatchEventTouch(new e.EventTouch([touch],false,e.Input.EventType.TOUCH_END,[touch]));await sleep(25);};
|
||||
const keys=['tsgame_roomtype_','tsgame_shortcode_'].map(k=>k+startup.config.identity.gameid+startup.config.identity.agentid);
|
||||
const old=keys.map(k=>localStorage.getItem(k));
|
||||
let runtime=null;
|
||||
try{
|
||||
await mount('98e42432-0731-4b9e-a158-72032b2c157d');const join=node.getComponent('JoinRoomView');
|
||||
assert(join&&join.slots.every(s=>!!s.font),'join prefab has wired BitmapFont slots');
|
||||
join.open({initialCode:'',submit:n=>{sent.push(n);join.setBusy(true);},cancel:()=>cancel++,paste:async()=> '房号123-456789',reportError:t=>tips.push(t)});
|
||||
for(const d of [0,1,2,3,4,5])await click(join.digitButtons[d].node);
|
||||
assert(sent.length===1&&sent[0]===12345,'coordinate keypad submits numeric code on sixth digit');
|
||||
assert(join.slots.map(s=>s.string).join('')==='012345','join slots render all six digits including leading zero');
|
||||
await click(join.submitButton.node);assert(sent.length===1,'busy submit does not duplicate request');
|
||||
await click(join.cancelButtons[1].node);assert(cancel===1,'close callback works while busy');
|
||||
join.setBusy(false);await click(join.deleteButton.node);assert(join.slots.filter(s=>s.node.active).length===5,'delete hides final slot');
|
||||
await click(join.clearButton.node);assert(join.slots.every(s=>!s.node.active),'clear hides all slots');
|
||||
await click(join.pasteButton.node);assert(sent[1]===123456,'clipboard strips separators and truncates to six digits');
|
||||
let finishPaste;const late=[];
|
||||
join.open({initialCode:'',submit:n=>late.push(n),cancel(){},paste:()=>new Promise(r=>finishPaste=r),reportError:t=>tips.push(t)});
|
||||
await click(join.pasteButton.node);
|
||||
const panel=Object.create(exported('LobbyPanel').prototype);panel.roomPage=join;panel.modal=node;panel.modalKind='join';panel.modalReleases=[];
|
||||
panel.cancelRankRequest=panel.cancelInviteRequest=panel.cancelTaskRequest=()=>{};
|
||||
panel.cancelRoomPage();node=null;finishPaste('123456');await sleep(40);
|
||||
assert(late.length===0&&panel.roomPage===null,'disconnect closes room page and invalidates deferred clipboard auto-submit');
|
||||
await mount('584dbb85-4acc-4bea-9d9b-e0cbeb8741da');const create=node.getComponent('CreateRoomPage');
|
||||
assert(create&&create.constructor.name==='TemplateCreateRoomView','platform resolves subgame through base page component');
|
||||
const packets=[];create.open({previousRoomtype:null,submit:r=>{packets.push(r);create.setBusy(true);},cancel:()=>cancel++,reportError:t=>tips.push(t)});
|
||||
assert(create.options[0].isChecked&&create.options[2].isChecked,'template initial options match source');
|
||||
await click(create.options[1].node);await click(create.options[3].node);
|
||||
assert(!create.options[0].isChecked&&create.options[1].isChecked&&!create.options[2].isChecked&&create.options[3].isChecked,'Cocos ToggleContainer enforces each option group');
|
||||
await click(create.options[1].node);assert(create.options[1].isChecked,'clicking the selected option keeps it selected like the source');
|
||||
await click(create.submitButton.node);await click(create.submitButton.node);
|
||||
const roomtype=[1,4,1,2,2,[1,1,[1,2000,10],null,null,1],[1,0,5]];
|
||||
assert(packets.length===1&&JSON.stringify(packets[0])===JSON.stringify(roomtype),'create page submits source fixed array once');
|
||||
create.close();create.open({previousRoomtype:roomtype,submit:()=>{},cancel:()=>{},reportError:t=>tips.push(t)});
|
||||
assert(!create.options[2].isChecked&&!create.options[3].isChecked,'saved template index 4 does not invent a matching option');
|
||||
node.destroy();node=null;await sleep(50);
|
||||
// Exercise the real runtime + GameEntry + Startup scene callback with a local wire.
|
||||
const game=exported('createTemplateGame')(startup.config.identity.gameid),listeners=new Set(),wire={sent:[],subscribe:fn=>{listeners.add(fn);return()=>listeners.delete(fn);},start(){},stop(){},send(p){this.sent.push(p);},switchServer(){},reconnectCurrent(){},emit(ev){for(const fn of [...listeners])fn(ev);}};
|
||||
startup.game=game;startup.loginResponse=null;let roomPromise=Promise.resolve(),lobbies=0;const fatal=[];
|
||||
runtime=new (exported('PlatformRuntime'))({gameEntry:game.entry,resolveRuntimeConfig:async()=>startup.config,createWireClient:()=>wire,
|
||||
scene:{showLoading(){},showLogin(){},showLobby(){lobbies++;},showRoom(){roomPromise=startup.showRoom();},showReconnect(){startup.endRoomRequest();},showTips:t=>tips.push(t),showServerDenial(){startup.endRoomRequest();},showKicked(){},showFatal:error=>fatal.push(String(error))},
|
||||
loadResources:async()=>{},waitForMinimumDisplay:async()=>{},getLoginDeviceSnapshot:()=>({ip:'127.0.0.1',location:null,machineid:'preview',machineroom:'',deviceLogin:{enabled:false},loginPlayerId:{enabled:false}})});
|
||||
startup.runtime=runtime;await runtime.start();wire.emit({type:'open'});
|
||||
runtime.login({openid:'o1',unionid:'test_unionid',nickname:'测试号',avatar:'',sex:0,province:'江西',city:'南昌'});
|
||||
wire.emit({type:'message',message:{...loginFixture,data:{...loginFixture.data,avatar:''}}});
|
||||
assert(runtime.state.room.kind==='outside'&&lobbies===1,'local login commits lobby state');
|
||||
const originalTimer=window.setTimeout;let expire;
|
||||
try{window.setTimeout=(fn,ms,...args)=>ms===15000?(expire=fn,999999):originalTimer(fn,ms,...args);
|
||||
startup.requestRoom('create_room',()=>{});
|
||||
}finally{window.setTimeout=originalTimer;}
|
||||
const originalTip=startup.tip;startup.tip=t=>tips.push(t);expire();startup.tip=originalTip;
|
||||
assert(startup.roomPending===null&&tips.pop()==='房间请求超时,请重试','room timeout releases guard and reports retry');
|
||||
startup.requestRoom('create_room',()=>runtime.createRoom({roomtype,ip:'127.0.0.1',location:null}));
|
||||
startup.requestRoom('create_room',()=>{throw Error('duplicate request invoked');});
|
||||
assert(wire.sent.filter(p=>p.rpc==='create_room').length===1,'Startup suppresses duplicate room requests');
|
||||
wire.emit({type:'message',message:{route:'agent',rpc:'create_room',data:{state:7,showerror:1,error:'测试拒绝'}}});
|
||||
assert(runtime.state.room.kind==='outside'&&startup.roomPending===null,'denial releases wait and keeps lobby');
|
||||
startup.requestRoom('create_room',()=>runtime.createRoom({roomtype,ip:'127.0.0.1',location:null}));
|
||||
const created={state:0,roomcode:'654321',seat:0,roomtype,makewar:0,asetcount:10};startup.roomReceipt={rpc:'create_room',data:created};
|
||||
wire.emit({type:'message',message:{route:'agent',rpc:'create_room',data:created}});await roomPromise;await sleep(100);
|
||||
assert(fatal.length===0&&runtime.state.room.kind==='inside'&&e.director.getScene().name==='TemplateRoom','create success crosses real Startup scene load');
|
||||
const roomRoot=e.director.getScene().getChildByName('Canvas').getChildByName('TemplateRoom'),roomView=roomRoot.getComponent('TemplateRoomView');
|
||||
assert(roomView.roomLabel.string.includes('654321')&&roomView.playersLabel.string.includes('测试号'),'room view consumes module snapshot');
|
||||
wire.emit({type:'message',message:{route:'agent',rpc:'create_room',data:created}});await sleep(50);
|
||||
assert(e.isValid(roomRoot),'duplicate successful reply does not remount room');
|
||||
roomView.prepareButton.node.emit(e.Button.EventType.CLICK);assert(wire.sent.at(-1).rpc==='player_prepare','subgame prepare travels through GameHost');
|
||||
wire.emit({type:'message',message:{route:'room',rpc:'player_prepare',data:{seat:0}}});
|
||||
roomView.exitButton.node.emit(e.Button.EventType.CLICK);assert(wire.sent.at(-1).rpc==='self_exit_room','subgame exit travels through GameHost');
|
||||
wire.emit({type:'message',message:{route:'room',rpc:'self_exit_room',data:{seat:0}}});
|
||||
assert(runtime.state.room.kind==='outside'&&lobbies===2&&roomView.actions===null,'exit clears canonical room and disposes view binding');
|
||||
startup.requestRoom('self_join_room',()=>runtime.joinRoom({roomcode:123456,ip:'127.0.0.1',location:null}));
|
||||
assert(wire.sent.at(-1).data.roomcode===123456,'manual join preserves numeric wire roomcode');
|
||||
const players=Array(10).fill(null);players[2]={...loginFixture.data,avatar:'',isprepare:0,onstate:0};
|
||||
const deskinfo={round:2,cards:[1,2,3]};
|
||||
wire.emit({type:'message',message:{route:'agent',rpc:'self_join_room',data:{state:0,roomcode:'123456',seat:2,roomtype,players,deskinfo,deskwar:1,needprepare:1,infinite:0}}});
|
||||
await roomPromise;await sleep(80);
|
||||
assert(fatal.length===0&&runtime.state.room.selfSeat===2&&game.restoredSnapshot===deskinfo,'join and reconnect snapshot reach template module unchanged');
|
||||
assert(e.director.getScene().getChildByName('Canvas').getChildByName('TemplateRoom').getComponent('TemplateRoomView').roomLabel.string.includes('123456'),'join success binds its own room scene');
|
||||
assert(tips.length===0&&fatal.length===0,'no unexpected fixture UI errors');
|
||||
return {checks,count:checks.length};
|
||||
}finally{node?.destroy();runtime?.stop();startup.endRoomRequest();keys.forEach((key,i)=>old[i]===null?localStorage.removeItem(key):localStorage.setItem(key,old[i]));}
|
||||
}
|
||||
Reference in New Issue
Block a user