feat: integrate platform room entry, UI migration and erqiwang documentation
This commit is contained in:
@@ -1,223 +1,283 @@
|
||||
import { STARTUP_CONFIG as EDITABLE_STARTUP_CONFIG } from '../../YouleNexus/assets/framework/config/profiles.ts';
|
||||
// 固定测试来源,允许开发者独立切换项目的 local/remote 开关。
|
||||
const STARTUP_CONFIG = Object.freeze({...EDITABLE_STARTUP_CONFIG, configSource:'remote' as const});
|
||||
import { remoteFixture } from '../fixtures/remote-config.ts';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { test } from 'node:test';
|
||||
import type { RuntimeConfig } from '../../YouleNexus/assets/framework/config/runtime-config.ts';
|
||||
import type { OutboundEnvelope } from '../../YouleNexus/assets/framework/core/types/envelope.ts';
|
||||
import { PlatformCommands } from '../../YouleNexus/assets/framework/platform/commands.ts';
|
||||
import { PlatformStore } from '../../YouleNexus/assets/framework/platform/stores/platform-store.ts';
|
||||
import {
|
||||
parseLoginResponse,
|
||||
} from '../../YouleNexus/assets/framework/protocol/contracts/index.ts';
|
||||
|
||||
const RUNTIME_CONFIG: RuntimeConfig = Object.freeze({
|
||||
startupConfig: {...STARTUP_CONFIG,mode:'release' as const,useLocalServer:false}, mode: 'release',
|
||||
isDebugger: false,
|
||||
identity: Object.freeze({
|
||||
agentid: 'agent-from-config',
|
||||
channelid: 'channel-from-config',
|
||||
gameid: 'game-from-config',
|
||||
marketid: 'market-from-config',
|
||||
version: 41,
|
||||
}),
|
||||
servers: Object.freeze(['ws://fixture']),
|
||||
source: 'remote',
|
||||
gameserver: 'https://fixture/config',
|
||||
...remoteFixture(),
|
||||
});
|
||||
|
||||
function fixture(name: string): { data: Record<string, unknown> } {
|
||||
return JSON.parse(readFileSync(new URL(`../fixtures/contracts/${name}`, import.meta.url), 'utf8'));
|
||||
}
|
||||
|
||||
function makeStore(location: 'outside' | 'inside', stage = 0, infinite = 0): PlatformStore {
|
||||
const store = new PlatformStore();
|
||||
const source = fixture(location === 'inside' ? 'player-login-room.json' : 'player-login-success.json');
|
||||
if (location === 'inside') {
|
||||
source.data.isbattle = stage;
|
||||
source.data.infinite = infinite;
|
||||
}
|
||||
store.applyLoginSuccess(parseLoginResponse(source.data));
|
||||
return store;
|
||||
}
|
||||
|
||||
import { STARTUP_CONFIG as EDITABLE_STARTUP_CONFIG } from '../../YouleNexus/assets/framework/config/profiles.ts';
|
||||
// 固定测试来源,允许开发者独立切换项目的 local/remote 开关。
|
||||
const STARTUP_CONFIG = Object.freeze({...EDITABLE_STARTUP_CONFIG, configSource:'remote' as const});
|
||||
import { remoteFixture } from '../fixtures/remote-config.ts';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { test } from 'node:test';
|
||||
import type { RuntimeConfig } from '../../YouleNexus/assets/framework/config/runtime-config.ts';
|
||||
import type { OutboundEnvelope } from '../../YouleNexus/assets/framework/core/types/envelope.ts';
|
||||
import { PlatformCommands } from '../../YouleNexus/assets/framework/platform/commands.ts';
|
||||
import { PlatformStore } from '../../YouleNexus/assets/framework/platform/stores/platform-store.ts';
|
||||
import {
|
||||
parseLoginResponse,
|
||||
} from '../../YouleNexus/assets/framework/protocol/contracts/index.ts';
|
||||
|
||||
const RUNTIME_CONFIG: RuntimeConfig = Object.freeze({
|
||||
startupConfig: {...STARTUP_CONFIG,mode:'release' as const,useLocalServer:false}, mode: 'release',
|
||||
isDebugger: false,
|
||||
identity: Object.freeze({
|
||||
agentid: 'agent-from-config',
|
||||
channelid: 'channel-from-config',
|
||||
gameid: 'game-from-config',
|
||||
marketid: 'market-from-config',
|
||||
version: 41,
|
||||
}),
|
||||
servers: Object.freeze(['ws://fixture']),
|
||||
source: 'remote',
|
||||
gameserver: 'https://fixture/config',
|
||||
...remoteFixture(),
|
||||
});
|
||||
|
||||
function fixture(name: string): { data: Record<string, unknown> } {
|
||||
return JSON.parse(readFileSync(new URL(`../fixtures/contracts/${name}`, import.meta.url), 'utf8'));
|
||||
}
|
||||
|
||||
function makeStore(location: 'outside' | 'inside', stage = 0, infinite = 0): PlatformStore {
|
||||
const store = new PlatformStore();
|
||||
const source = fixture(location === 'inside' ? 'player-login-room.json' : 'player-login-success.json');
|
||||
if (location === 'inside') {
|
||||
source.data.isbattle = stage;
|
||||
source.data.infinite = infinite;
|
||||
}
|
||||
store.applyLoginSuccess(parseLoginResponse(source.data));
|
||||
return store;
|
||||
}
|
||||
|
||||
function makeCommands(store: PlatformStore): {
|
||||
readonly commands: PlatformCommands;
|
||||
readonly sent: OutboundEnvelope[];
|
||||
} {
|
||||
const sent: OutboundEnvelope[] = [];
|
||||
return {
|
||||
commands: new PlatformCommands({
|
||||
runtimeConfig: RUNTIME_CONFIG,
|
||||
store,
|
||||
send: { send: (envelope) => { sent.push(envelope); } },
|
||||
}),
|
||||
sent,
|
||||
};
|
||||
readonly commands: PlatformCommands;
|
||||
readonly sent: OutboundEnvelope[];
|
||||
} {
|
||||
const sent: OutboundEnvelope[] = [];
|
||||
return {
|
||||
commands: new PlatformCommands({
|
||||
runtimeConfig: RUNTIME_CONFIG,
|
||||
store,
|
||||
send: { send: (envelope) => { sent.push(envelope); } },
|
||||
}),
|
||||
sent,
|
||||
};
|
||||
}
|
||||
|
||||
test('VIP query and both entry forms use the exact agent protocol',()=>{
|
||||
test('invite query and binding preserve exact legacy fields and leading zeros',()=>{
|
||||
const store=makeStore('outside'),{commands,sent}=makeCommands(store);
|
||||
commands.getVipRooms(['123456']);commands.joinVipRoom('123456',null);commands.joinVipRoom(900001,{city:'测试'});
|
||||
assert.deepEqual(sent[0],{app:'youle',route:'agent',rpc:'getInfoByShortCode',data:{agentid:'agent-from-config',gameid:'game-from-config',shortcodeList:['123456']}});
|
||||
assert.deepEqual(sent[1],{app:'youle',route:'agent',rpc:'self_join_room',data:{agentid:'agent-from-config',playerid:430511,gameid:'game-from-config',roomcode:'123456',joinmode:0,location:null,ip:store.getState().players.entities[430511].ip}});
|
||||
assert.equal((sent[2].data as {roomcode:number}).roomcode,900001);
|
||||
assert.throws(()=>makeCommands(new PlatformStore()).commands.getVipRooms([]),/logged-in/);
|
||||
});
|
||||
|
||||
test('task requests preserve legacy identity fields and reject unclaimable entries',()=>{
|
||||
const store=makeStore('outside');const {commands,sent}=makeCommands(store);
|
||||
commands.getPlayerTasks();
|
||||
store.applyTaskList({tasks:[{taskid:7,title:'任务',award:1,finish:1,total:1,state:1}]});
|
||||
commands.claimTask(7);
|
||||
commands.getPlayerInvitecode();commands.bindInvitecode('00123');
|
||||
assert.deepEqual(sent,[
|
||||
{app:'youle',route:'agent',rpc:'get_player_task',data:{agentid:'agent-from-config',playerid:430511,gameid:'game-from-config'}},
|
||||
{app:'youle',route:'agent',rpc:'get_task_award',data:{agentid:'agent-from-config',playerid:430511,taskid:7}},
|
||||
{app:'youle',route:'agent',rpc:'get_player_invitecode',data:{agentid:'agent-from-config',playerid:430511,unionid:'test_unionid',openid:'o1'}},
|
||||
{app:'youle',route:'agent',rpc:'binding_invitecode',data:{agentid:'agent-from-config',playerid:430511,invitecode:'00123'}},
|
||||
]);
|
||||
store.applyTaskAward({taskid:7,taskstate:0});
|
||||
assert.equal(store.getState().tasks?.[0].state,2);
|
||||
assert.equal(store.getState().players.entities[430511].taskstate,0);
|
||||
assert.throws(()=>commands.claimTask(7),/claimable/);
|
||||
const before=store.getState();
|
||||
assert.throws(()=>store.applyTaskList({tasks:[{taskid:7}]}));
|
||||
assert.equal(store.getState(),before);
|
||||
assert.throws(()=>makeCommands(new PlatformStore()).commands.getPlayerTasks(),/logged-in/);
|
||||
assert.throws(()=>makeCommands(new PlatformStore()).commands.getPlayerInvitecode(),/logged-in/);
|
||||
assert.throws(()=>makeCommands(makeStore('inside')).commands.bindInvitecode('1'),/logged-in/);
|
||||
});
|
||||
|
||||
test('task numeric strings normalize at ingestion and invalid values never commit',()=>{
|
||||
const store=makeStore('outside');
|
||||
const task={taskid:'7',title:'任务',award:'3',finish:'2',total:'5',state:'0'};
|
||||
store.applyTaskList({tasks:[task]});
|
||||
assert.deepEqual(store.getState().tasks,[{...task,award:3,finish:2,total:5,state:0}]);
|
||||
assert.equal(task.award,'3');
|
||||
test('invite responses publish even unchanged codes, update only on success, and reject malformed data atomically',()=>{
|
||||
const store=makeStore('outside');let updates=0;store.subscribe(()=>updates++);
|
||||
store.applyInvitecode({invitecode:''});store.applyInvitecode({invitecode:''});
|
||||
assert.equal(updates,2);
|
||||
store.applyInviteBinding({state:0,invitecode:'00123',error:'绑定成功'});
|
||||
assert.equal(store.getState().players.entities[430511].invitecode,'00123');
|
||||
store.applyInviteBinding({state:1,error:'邀请码无效'});
|
||||
assert.equal(store.getState().players.entities[430511].invitecode,'00123');
|
||||
const before=store.getState();
|
||||
for(const field of ['award','finish','total','state']){
|
||||
for(const value of ['', ' ', 'abc', 'Infinity', null, true, [], {}, undefined]){
|
||||
assert.throws(()=>store.applyTaskList({tasks:[{...task,[field]:value}]}),new RegExp(field));
|
||||
assert.equal(store.getState(),before);
|
||||
}
|
||||
assert.throws(()=>store.applyInvitecode({}),/invitecode/);
|
||||
assert.throws(()=>store.applyInviteBinding({state:0,invitecode:123,error:'bad'}),/invitecode/);
|
||||
assert.throws(()=>store.applyInviteBinding({state:0,invitecode:'wrong'}),/error/);
|
||||
for(const state of ['',null,true,'invalid','0.5']){
|
||||
assert.throws(()=>store.applyInviteBinding({state,invitecode:'wrong',error:'bad'}),/state/);
|
||||
}
|
||||
assert.throws(()=>store.applyTaskList({tasks:[{...task,state:'1.5'}]}),/state/);
|
||||
assert.equal(store.getState(),before);
|
||||
});
|
||||
|
||||
test('VIP query and both entry forms use the exact agent protocol',()=>{
|
||||
const store=makeStore('outside'),{commands,sent}=makeCommands(store);
|
||||
commands.getVipRooms(['123456']);commands.joinVipRoom('123456',null);commands.joinVipRoom(900001,{city:'测试'});
|
||||
assert.deepEqual(sent[0],{app:'youle',route:'agent',rpc:'getInfoByShortCode',data:{agentid:'agent-from-config',gameid:'game-from-config',shortcodeList:['123456']}});
|
||||
assert.deepEqual(sent[1],{app:'youle',route:'agent',rpc:'self_join_room',data:{agentid:'agent-from-config',playerid:430511,gameid:'game-from-config',roomcode:'123456',joinmode:0,location:null,ip:store.getState().players.entities[430511].ip}});
|
||||
assert.equal((sent[2].data as {roomcode:number}).roomcode,900001);
|
||||
assert.throws(()=>makeCommands(new PlatformStore()).commands.getVipRooms([]),/logged-in/);
|
||||
});
|
||||
|
||||
test('prepare and exitRoom use the first-slice builders with authoritative config and room state', () => {
|
||||
const { commands, sent } = makeCommands(makeStore('inside', 0));
|
||||
|
||||
commands.prepare();
|
||||
commands.exitRoom();
|
||||
|
||||
assert.deepEqual(sent, [
|
||||
{
|
||||
app: 'youle',
|
||||
route: 'room',
|
||||
rpc: 'player_prepare',
|
||||
data: {
|
||||
agentid: 'agent-from-config',
|
||||
playerid: 430511,
|
||||
gameid: 'game-from-config',
|
||||
roomcode: '100001',
|
||||
},
|
||||
},
|
||||
{
|
||||
app: 'youle',
|
||||
route: 'room',
|
||||
rpc: 'self_exit_room',
|
||||
data: {
|
||||
agentid: 'agent-from-config',
|
||||
playerid: 430511,
|
||||
gameid: 'game-from-config',
|
||||
roomcode: '100001',
|
||||
},
|
||||
},
|
||||
test('ranking and redemption use exact legacy fields, preserving card text',()=>{
|
||||
const {commands,sent}=makeCommands(makeStore('outside'));
|
||||
commands.getTreasureList();commands.redeemCard('00Ab-12');
|
||||
assert.deepEqual(sent,[
|
||||
{app:'youle',route:'agent',rpc:'get_treasurelist',data:{agentid:'agent-from-config',gameid:'game-from-config'}},
|
||||
{app:'youle',route:'agent',rpc:'topup_card',data:{agentid:'agent-from-config',playerid:430511,cardno:'00Ab-12'}},
|
||||
]);
|
||||
assert.equal(commands.prepare.length, 0);
|
||||
assert.equal(commands.exitRoom.length, 0);
|
||||
assert.throws(()=>commands.redeemCard(' '),/cardno/);
|
||||
assert.throws(()=>makeCommands(new PlatformStore()).commands.getTreasureList(),/logged-in/);
|
||||
});
|
||||
|
||||
test('task requests preserve legacy identity fields and reject unclaimable entries',()=>{
|
||||
const store=makeStore('outside');const {commands,sent}=makeCommands(store);
|
||||
commands.getPlayerTasks();
|
||||
store.applyTaskList({tasks:[{taskid:7,title:'任务',award:1,finish:1,total:1,state:1}]});
|
||||
commands.claimTask(7);
|
||||
assert.deepEqual(sent,[
|
||||
{app:'youle',route:'agent',rpc:'get_player_task',data:{agentid:'agent-from-config',playerid:430511,gameid:'game-from-config'}},
|
||||
{app:'youle',route:'agent',rpc:'get_task_award',data:{agentid:'agent-from-config',playerid:430511,taskid:7}},
|
||||
]);
|
||||
store.applyTaskAward({taskid:7,taskstate:0});
|
||||
assert.equal(store.getState().tasks?.[0].state,2);
|
||||
assert.equal(store.getState().players.entities[430511].taskstate,0);
|
||||
assert.throws(()=>commands.claimTask(7),/claimable/);
|
||||
const before=store.getState();
|
||||
assert.throws(()=>store.applyTaskList({tasks:[{taskid:7}]}));
|
||||
assert.equal(store.getState(),before);
|
||||
assert.throws(()=>makeCommands(new PlatformStore()).commands.getPlayerTasks(),/logged-in/);
|
||||
});
|
||||
|
||||
test('task numeric strings normalize at ingestion and invalid values never commit',()=>{
|
||||
const store=makeStore('outside');
|
||||
const task={taskid:'7',title:'任务',award:'3',finish:'2',total:'5',state:'0'};
|
||||
store.applyTaskList({tasks:[task]});
|
||||
assert.deepEqual(store.getState().tasks,[{...task,award:3,finish:2,total:5,state:0}]);
|
||||
assert.equal(task.award,'3');
|
||||
const before=store.getState();
|
||||
for(const field of ['award','finish','total','state']){
|
||||
for(const value of ['', ' ', 'abc', 'Infinity', null, true, [], {}, undefined]){
|
||||
assert.throws(()=>store.applyTaskList({tasks:[{...task,[field]:value}]}),new RegExp(field));
|
||||
assert.equal(store.getState(),before);
|
||||
}
|
||||
}
|
||||
assert.throws(()=>store.applyTaskList({tasks:[{...task,state:'1.5'}]}),/state/);
|
||||
});
|
||||
|
||||
test('prepare and exitRoom use the first-slice builders with authoritative config and room state', () => {
|
||||
const { commands, sent } = makeCommands(makeStore('inside', 0));
|
||||
|
||||
commands.prepare();
|
||||
commands.exitRoom();
|
||||
|
||||
assert.deepEqual(sent, [
|
||||
{
|
||||
app: 'youle',
|
||||
route: 'room',
|
||||
rpc: 'player_prepare',
|
||||
data: {
|
||||
agentid: 'agent-from-config',
|
||||
playerid: 430511,
|
||||
gameid: 'game-from-config',
|
||||
roomcode: '100001',
|
||||
},
|
||||
},
|
||||
{
|
||||
app: 'youle',
|
||||
route: 'room',
|
||||
rpc: 'self_exit_room',
|
||||
data: {
|
||||
agentid: 'agent-from-config',
|
||||
playerid: 430511,
|
||||
gameid: 'game-from-config',
|
||||
roomcode: '100001',
|
||||
},
|
||||
},
|
||||
]);
|
||||
assert.equal(commands.prepare.length, 0);
|
||||
assert.equal(commands.exitRoom.length, 0);
|
||||
});
|
||||
|
||||
test('joinRoom uses authenticated Store identity and requires every non-optional environment field', () => {
|
||||
const { commands, sent } = makeCommands(makeStore('outside'));
|
||||
const location = { latitude: 28.7, longitude: 115.8 };
|
||||
|
||||
commands.joinRoom({
|
||||
roomcode: '654321',
|
||||
location,
|
||||
ip: '203.0.113.7',
|
||||
vipMatch: 1,
|
||||
match_id: 'match-9',
|
||||
});
|
||||
|
||||
assert.deepEqual(sent, [{
|
||||
app: 'youle',
|
||||
route: 'agent',
|
||||
rpc: 'self_join_room',
|
||||
data: {
|
||||
agentid: 'agent-from-config',
|
||||
playerid: 430511,
|
||||
gameid: 'game-from-config',
|
||||
roomcode: '654321',
|
||||
location,
|
||||
ip: '203.0.113.7',
|
||||
vipMatch: 1,
|
||||
match_id: 'match-9',
|
||||
},
|
||||
}]);
|
||||
assert.equal((sent[0]!.data as { location: unknown }).location, location);
|
||||
assert.equal(commands.joinRoom.length, 1);
|
||||
|
||||
assert.throws(
|
||||
() => commands.joinRoom({ roomcode: '654321', ip: '203.0.113.7' } as never),
|
||||
/location/i,
|
||||
);
|
||||
assert.throws(
|
||||
() => commands.joinRoom({ roomcode: '654321', location } as never),
|
||||
/ip/i,
|
||||
);
|
||||
assert.equal(sent.length, 1);
|
||||
});
|
||||
|
||||
test('exitRoom sends self_exit_room while an infinite room is in battle', () => {
|
||||
const { commands, sent } = makeCommands(makeStore('inside', 1, 1));
|
||||
|
||||
commands.exitRoom();
|
||||
|
||||
assert.deepEqual(sent, [{
|
||||
app: 'youle',
|
||||
route: 'room',
|
||||
rpc: 'self_exit_room',
|
||||
data: {
|
||||
agentid: 'agent-from-config',
|
||||
playerid: 430511,
|
||||
gameid: 'game-from-config',
|
||||
roomcode: '100001',
|
||||
},
|
||||
}]);
|
||||
});
|
||||
|
||||
test('command preconditions reject missing authentication, wrong room location, and battle exit without sending', () => {
|
||||
const unauthenticated = makeCommands(new PlatformStore());
|
||||
assert.throws(
|
||||
() => unauthenticated.commands.joinRoom({ roomcode: '654321', location: null, ip: '' }),
|
||||
/authenticated|player/i,
|
||||
);
|
||||
|
||||
const outside = makeCommands(makeStore('outside'));
|
||||
assert.throws(() => outside.commands.prepare(), /inside.*room|room.*inside/i);
|
||||
assert.throws(() => outside.commands.exitRoom(), /inside.*room|room.*inside/i);
|
||||
|
||||
const inside = makeCommands(makeStore('inside', 0));
|
||||
assert.throws(
|
||||
() => inside.commands.joinRoom({ roomcode: '654321', location: null, ip: '' }),
|
||||
/outside.*room|already.*room/i,
|
||||
);
|
||||
|
||||
const battle = makeCommands(makeStore('inside', 1));
|
||||
assert.throws(() => battle.commands.exitRoom(), /room\.exit.*stage=0/i);
|
||||
|
||||
assert.equal(unauthenticated.sent.length, 0);
|
||||
assert.equal(outside.sent.length, 0);
|
||||
assert.equal(inside.sent.length, 0);
|
||||
assert.equal(battle.sent.length, 0);
|
||||
});
|
||||
|
||||
test('VIP rank and owned room requests preserve legacy exact fields',()=>{
|
||||
const {commands,sent}=makeCommands(makeStore('outside'));
|
||||
commands.getVipRankList(10);commands.joinOwnedRoom(123456,{city:'x'});
|
||||
assert.deepEqual(sent,[
|
||||
{app:'youle',route:'agent',rpc:'getVipRankList',data:{agentid:'agent-from-config',limit:10}},
|
||||
{app:'youle',route:'agent',rpc:'self_join_room',data:{agentid:'agent-from-config',playerid:430511,gameid:'game-from-config',roomcode:123456,joinmode:1,location:{city:'x'},ip:'127.0.0.1'}}]);
|
||||
assert.throws(()=>commands.getVipRankList(-1));
|
||||
});
|
||||
|
||||
test('joinRoom uses authenticated Store identity and requires every non-optional environment field', () => {
|
||||
const { commands, sent } = makeCommands(makeStore('outside'));
|
||||
const location = { latitude: 28.7, longitude: 115.8 };
|
||||
|
||||
commands.joinRoom({
|
||||
roomcode: '654321',
|
||||
location,
|
||||
ip: '203.0.113.7',
|
||||
vipMatch: 1,
|
||||
match_id: 'match-9',
|
||||
});
|
||||
|
||||
assert.deepEqual(sent, [{
|
||||
app: 'youle',
|
||||
route: 'agent',
|
||||
rpc: 'self_join_room',
|
||||
data: {
|
||||
agentid: 'agent-from-config',
|
||||
playerid: 430511,
|
||||
gameid: 'game-from-config',
|
||||
roomcode: '654321',
|
||||
location,
|
||||
ip: '203.0.113.7',
|
||||
vipMatch: 1,
|
||||
match_id: 'match-9',
|
||||
},
|
||||
}]);
|
||||
assert.equal((sent[0]!.data as { location: unknown }).location, location);
|
||||
assert.equal(commands.joinRoom.length, 1);
|
||||
|
||||
assert.throws(
|
||||
() => commands.joinRoom({ roomcode: '654321', ip: '203.0.113.7' } as never),
|
||||
/location/i,
|
||||
);
|
||||
assert.throws(
|
||||
() => commands.joinRoom({ roomcode: '654321', location } as never),
|
||||
/ip/i,
|
||||
);
|
||||
assert.equal(sent.length, 1);
|
||||
});
|
||||
|
||||
test('exitRoom sends self_exit_room while an infinite room is in battle', () => {
|
||||
const { commands, sent } = makeCommands(makeStore('inside', 1, 1));
|
||||
|
||||
commands.exitRoom();
|
||||
|
||||
assert.deepEqual(sent, [{
|
||||
app: 'youle',
|
||||
route: 'room',
|
||||
rpc: 'self_exit_room',
|
||||
data: {
|
||||
agentid: 'agent-from-config',
|
||||
playerid: 430511,
|
||||
gameid: 'game-from-config',
|
||||
roomcode: '100001',
|
||||
},
|
||||
}]);
|
||||
});
|
||||
|
||||
test('command preconditions reject missing authentication, wrong room location, and battle exit without sending', () => {
|
||||
const unauthenticated = makeCommands(new PlatformStore());
|
||||
assert.throws(
|
||||
() => unauthenticated.commands.joinRoom({ roomcode: '654321', location: null, ip: '' }),
|
||||
/authenticated|player/i,
|
||||
);
|
||||
|
||||
const outside = makeCommands(makeStore('outside'));
|
||||
assert.throws(() => outside.commands.prepare(), /inside.*room|room.*inside/i);
|
||||
assert.throws(() => outside.commands.exitRoom(), /inside.*room|room.*inside/i);
|
||||
|
||||
const inside = makeCommands(makeStore('inside', 0));
|
||||
assert.throws(
|
||||
() => inside.commands.joinRoom({ roomcode: '654321', location: null, ip: '' }),
|
||||
/outside.*room|already.*room/i,
|
||||
);
|
||||
|
||||
const battle = makeCommands(makeStore('inside', 1));
|
||||
assert.throws(() => battle.commands.exitRoom(), /room\.exit.*stage=0/i);
|
||||
|
||||
assert.equal(unauthenticated.sent.length, 0);
|
||||
assert.equal(outside.sent.length, 0);
|
||||
assert.equal(inside.sent.length, 0);
|
||||
assert.equal(battle.sent.length, 0);
|
||||
});
|
||||
test('create command emits exact legacy packet and numeric keypad join stays numeric', () => {
|
||||
const {commands,sent}=makeCommands(makeStore('outside'));
|
||||
const roomtype=[1,4,[7,8],{option:true}];
|
||||
commands.createRoom({roomtype,ip:'127.0.0.8',location:null});
|
||||
commands.joinRoom({roomcode:12345,ip:'127.0.0.8',location:null});
|
||||
assert.deepEqual(sent[0],{app:'youle',route:'agent',rpc:'create_room',data:{agentid:'agent-from-config',playerid:430511,gameid:'game-from-config',roomtype,ip:'127.0.0.8',location:null}});
|
||||
assert.deepEqual(sent[1].data,{agentid:'agent-from-config',playerid:430511,gameid:'game-from-config',roomcode:12345,ip:'127.0.0.8',location:null});
|
||||
assert.throws(()=>commands.createRoom({roomtype:[undefined],ip:'x',location:null}),/JSON/);
|
||||
assert.throws(()=>makeCommands(makeStore('inside')).commands.createRoom({roomtype,ip:'x',location:null}),/outside|lobby/);
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user