Files
youle_cocos/cocoscreator_projects/scripts/verify-invite-preview.mjs
T

65 lines
7.4 KiB
JavaScript

/** Run through Cocos MCP in an isolated Game View. Records packets; never binds a real account. */
export async function verifyInvitePreview(){
const e=await System.import('cc'),modules=Array.from(System.entries()).map(([,m])=>m);
const exported=name=>{const m=modules.find(m=>m[name]);if(!m)throw Error(`Missing ${name}`);return m[name];};
const source=e.director.getScene().getChildByName('PlatformServices').getComponent('PlatformStartup');
const config=source.config,assets=source.getComponent('LobbyAssets');
source.unsubscribe?.();source.runtime?.stop();source.panel?.dispose();source.panel=null;
await new Promise((resolve,reject)=>e.director.loadScene('PlatformLobby',err=>err?reject(err):resolve()));
const sent=[],tips=[],checks=[];let receive,panel,pasteResolve;
const assert=(ok,message)=>{if(!ok)throw Error(message);checks.push(message);};
const runtime=new (exported('PlatformRuntime'))({
gameEntry:exported('createLoginStageGameEntry')(config.identity.gameid,()=>{}),resolveRuntimeConfig:async()=>config,
createWireClient:()=>({subscribe:cb=>{receive=cb;return ()=>{};},start:()=>{},stop:()=>{},send:packet=>sent.push(packet),switchServer:()=>{},reconnectCurrent:()=>{}}),
scene:{showLoading:()=>{},showLogin:()=>{},showLobby:()=>{},showRoom:()=>{},showReconnect:()=>{},showKicked:()=>{},showServerDenial:()=>{},showFatal:err=>{throw err;},
showTips:(msg,time,kind)=>{if(kind==='show_message')panel?.cancelInviteRequest();tips.push(msg);}},
loadResources:async()=>{},waitForMinimumDisplay:async()=>{},getLoginDeviceSnapshot:()=>{throw Error('Inbound fixture only');},
});
await runtime.start();receive({type:'open',server:config.servers[0]});
const packet=(rpc,data)=>receive({type:'message',message:{route:'agent',rpc,data}});
const login={state:0,playerid:7,nickname:'邀请码接线验证',avatar:'',sex:0,bean:0,roomcard:3,taskstate:0,score:0,sign:null,ip:'127.0.0.1',openid:'invite-openid',unionid:'invite-unionid',invitecode:null};
packet('player_login',login);
const canvas=e.director.getScene().getChildByName('Canvas'),popup=new e.Node('InviteTestPopup');popup.parent=canvas;popup.layer=canvas.layer;popup.addComponent(e.UITransform).setContentSize(1600,720);
const remote=exported('createRemoteConfig')({gameNoticeShow:-1,agentmode:2},config.identity);
panel=new (exported('LobbyPanel'))(canvas,popup,assets,config,exported('resolveLobbyPolicy')(remote),runtime.state,msg=>tips.push(msg),()=>{},()=>null,()=>{},
exported('resolveLobbyMenuConfig')(remote),{versionState:0,launchMode:0},()=>{},()=>{},()=>{},undefined,
{query:()=>runtime.getPlayerInvitecode(),bind:code=>runtime.bindInvitecode(code),paste:()=>new Promise(resolve=>{pasteResolve=resolve;})});
popup.setSiblingIndex(canvas.children.length-1);
const off=runtime.subscribeState(state=>panel.render(state),err=>{throw err;});
const click=()=>{const node=panel.menuNodes.get(235);if(!node.parent.active)panel.menuNodes.get(3120).emit(e.Button.EventType.CLICK);assert(node.activeInHierarchy,'invite entry is visible');node.emit(e.Button.EventType.CLICK);};
const button=id=>panel.modal.getChildByPath(`group-80/Spirit${id}`).emit(e.Button.EventType.CLICK);
click();click();assert(sent.length===1&&sent[0].rpc==='get_player_invitecode','query suppresses duplicate clicks');
assert(JSON.stringify(sent[0].data)===JSON.stringify({agentid:config.identity.agentid,playerid:7,unionid:'invite-unionid',openid:'invite-openid'}),'query preserves exact identity fields');
assert(panel.modal===null,'query waits for response');
packet('get_player_invitecode',{invitecode:''});assert(panel.modalKind==='invite','query opens authored Bind prefab');
let edit=panel.modal.getChildByPath('group-80/Spirit365/InputEditBox').getComponent(e.EditBox);
assert(edit.textLabel&&edit.placeholderLabel&&edit.maxLength===-1,'native input has persisted label references and no six-digit limit');
for(const l of [edit.textLabel,edit.placeholderLabel]){const anchor=l.node.getComponent(e.UITransform).anchorPoint;assert(anchor.x===0&&anchor.y===1,'EditBox labels use native top-left anchors');}
edit.string='00x1234567';edit.node.emit(e.EditBox.EventType.TEXT_CHANGED);assert(edit.string==='001234567','input removes non-digits while retaining leading zeros');
button(366);pasteResolve('00123');await Promise.resolve();await Promise.resolve();assert(edit.string==='00123','paste callback updates input');
const submit=panel.modal.getChildByPath('group-80/Spirit367');submit.emit(e.Button.EventType.CLICK);submit.emit(e.Button.EventType.CLICK);
assert(panel.modal===null&&sent.length===2,'submit closes dialog and sends once');
assert(JSON.stringify(sent[1].data)===JSON.stringify({agentid:config.identity.agentid,playerid:7,invitecode:'00123'}),'binding preserves exact fields and leading zeros');
packet('binding_invitecode',{state:'1',error:'邀请码无效'});assert(tips.includes('邀请码无效')&&runtime.state.players.entities[7].invitecode==='','string failure state displays server text without changing code');
click();packet('get_player_invitecode',{invitecode:''});assert(panel.modalKind==='invite','unchanged query result reopens dialog');
edit=panel.modal.getChildByPath('group-80/Spirit365/InputEditBox').getComponent(e.EditBox);edit.string='00123';button(367);
packet('binding_invitecode',{state:'0',invitecode:'00123',error:'绑定成功'});assert(runtime.state.players.entities[7].invitecode==='00123'&&tips.includes('绑定成功'),'string success state updates canonical player and shows server text');
click();packet('get_player_invitecode',{invitecode:'00123'});
assert([365,366,367].every(id=>!panel.modal.getChildByPath(`group-80/Spirit${id}`).active),'bound state hides input paste and submit');
assert(panel.modal.getChildByPath('group-80/Spirit368').getComponent(e.Label).string==='您已绑定邀请码,所绑定邀请码为:00123','bound state shows exact code');
await new Promise(resolve=>e.director.once(e.Director.EVENT_AFTER_DRAW,resolve));
const messageBox=panel.modal.getChildByPath('group-80/Spirit368').getComponent(e.UITransform).getBoundingBoxToWorld();
const backgroundBox=panel.modal.getChildByPath('group-80/Spirit363').getComponent(e.UITransform).getBoundingBoxToWorld();
assert(messageBox.x>=backgroundBox.x&&messageBox.xMax<=backgroundBox.xMax,'bound message stays inside authored background');
button(362);assert(panel.modal===null,'mask closes dialog');
click();packet('show_message',{msg:'暂不可用',time:0});assert(panel.invitePending===null,'generic denial releases pending request');
click();packet('get_player_invitecode',{invitecode:''});button(366);button(362);pasteResolve('late');await Promise.resolve();assert(panel.modal===null,'late paste cannot reopen a closed dialog');
click();packet('get_player_invitecode',{invitecode:''});
edit=panel.modal.getChildByPath('group-80/Spirit365/InputEditBox').getComponent(e.EditBox);edit.string='00123';
panel.requestInvite('query',()=>runtime.getPlayerInvitecode());receive({type:'slow'});assert(panel.invitePending===null,'disconnect releases pending request');
const count=sent.length;panel.menuNodes.get(235).emit(e.Button.EventType.CLICK);assert(sent.length===count,'disconnect blocks sending');
await new Promise(resolve=>e.director.once(e.Director.EVENT_AFTER_DRAW,resolve));
globalThis.__inviteVerification={panel,runtime,checks,close:()=>{off();panel.dispose();runtime.stop();popup.destroy();}};
return {checks,packets:sent.map(({rpc,data})=>({rpc,fields:Object.keys(data)}))};
}