Complete room UI and protocol integration, move game definitions and resources behind bundle entries, publish authoritative version XML, and document single-game builds. Include all current resource changes and experiment artifacts.
32 lines
4.1 KiB
TypeScript
32 lines
4.1 KiB
TypeScript
import {readFileSync} from 'node:fs';
|
|
import {test} from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {PlatformStore} from '../../YouleNexus/assets/framework/platform/stores/platform-store.ts';
|
|
import {parseLoginResponse,parseOtherExitRoomPayload} from '../../YouleNexus/assets/framework/protocol/contracts/index.ts';
|
|
function setup(){const data=JSON.parse(readFileSync(new URL('../fixtures/contracts/player-login-room.json',import.meta.url),'utf8')).data;data.players[0]={...data.players[1],playerid:777,nickname:'other'};const store=new PlatformStore();store.applyLoginSuccess(parseLoginResponse(data));return store;}
|
|
|
|
test('local message IDs remain stable across append and do not come from raw server input',()=>{
|
|
const store=setup();store.applyRoomSocial('send_text',{seat:1,text:'same',id:999});
|
|
const first=store.getState().roomSocial!.history[0];store.applyRoomSocial('send_text',{seat:1,text:'same',id:999});
|
|
const history=store.getState().roomSocial!.history;assert.equal(history[0],first);assert.notEqual(history[1].id,first.id);assert.notEqual(first.id,999);
|
|
});
|
|
test('chat retains sender snapshot after leaving, accepts raw phrase indices and announcement without seat',()=>{const store=setup();store.applyRoomSocial('send_text',{seat:0,text:'你好',type:0});const first=store.getState().roomSocial!.history[0];store.playerExit(parseOtherExitRoomPayload({seat:0}));assert.equal(store.getState().roomSocial!.history[0],first);assert.ok(Object.isFrozen(first.sender));store.applyRoomSocial('send_text',{seat:1,text:'2',type:3});assert.equal(store.getState().roomSocial!.history[1].kind,'phrase');store.applyRoomSocial('send_text',{text:'公告',type:1});assert.deepEqual(store.getState().roomSocial!.announcements,['公告']);});
|
|
test('invalid social input never commits, voice retains original duration, room exit clears history',()=>{const store=setup();store.applyRoomSocial('send_voice',{seat:1,voiceurl:'https://audio/one',time:'1.25'});assert.equal(store.getState().roomSocial!.history[0].time,1.25);const state=store.getState();assert.throws(()=>store.applyRoomSocial('send_phiz',{seat:1,text:0}));assert.equal(store.getState(),state);store.clearRoom();assert.equal(store.getState().roomSocial,undefined);});
|
|
test('change_seat swaps occupancy and own seat without altering sender history',()=>{const store=setup();store.applyRoomSocial('send_text',{seat:1,text:'a'});const before=store.getState().room;assert.ok(before.kind==='inside');store.changeSeats({seat1:1,seat2:0});const room=store.getState().room;assert.ok(room.kind==='inside');assert.equal(room.selfSeat,0);assert.equal(room.seatPlayerIds[0],before.seatPlayerIds[1]);assert.equal(store.getState().roomSocial!.history[0].sender.seat,1);});
|
|
|
|
test('ordinary voice auto-plays while robot voice remains history only',()=>{
|
|
const store=setup();
|
|
for(const type of [undefined,0,'0',2,'2'])store.applyRoomSocial('send_voice',{seat:1,voiceurl:'https://audio',time:1,...(type===undefined?{}:{type}),...(Number(type)===2?{info:{nickname:'客服'}}:{})});
|
|
assert.deepEqual(store.getState().roomSocial!.history.map(message=>message.autoPlay),[true,true,true,false,false]);
|
|
const snapshot=store.getState();assert.throws(()=>store.applyRoomSocial('send_voice',{type:1,seat:1,voiceurl:'url',time:1}));assert.equal(store.getState(),snapshot);
|
|
});
|
|
|
|
test('room owner notice comes only from ownerNotice and empty source has explicit null semantics',()=>{
|
|
const source=()=>JSON.parse(readFileSync(new URL('../fixtures/contracts/player-login-room.json',import.meta.url),'utf8')).data;
|
|
for(const value of [undefined,null,'','房主公告内容']){
|
|
const data=source();if(value!==undefined)data.ownerNotice=value;data.ownerNote='private note must not replace notice';
|
|
const store=new PlatformStore();store.applyLoginSuccess(parseLoginResponse(data));const room=store.getState().room;assert.ok(room.kind==='inside');assert.equal(room.ownerNotice,value?value:null);
|
|
}
|
|
const store=setup(),before=store.getState(),bad=source();bad.ownerNotice={text:'not string'};assert.throws(()=>store.applyLoginSuccess(parseLoginResponse(bad)));assert.equal(store.getState(),before);
|
|
});
|