Files
youle_cocos/cocoscreator_projects/framework-tests/architecture/room-assets.test.mjs
T
joywayer 35216f75e7 feat: integrate room framework and isolated subgame bundles
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.
2026-09-09 03:13:18 +08:00

84 lines
5.5 KiB
JavaScript

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {fileURLToPath} from 'node:url';
import {loadRoomAssetInventory,loadRoomAssetDefinitions,validateRoomAssets,compressUuid,parseRoomAssetDefinitions} from '../../scripts/lib/room-assets.mjs';
const assetsDir=fileURLToPath(new URL('../../YouleNexus/assets/',import.meta.url));
const inventory=()=>loadRoomAssetInventory(assetsDir);
const definitions=loadRoomAssetDefinitions(fileURLToPath(new URL('../../YouleNexus/assets/games',import.meta.url)));
const template=definitions.find(definition=>definition.key==='Game_Surface_3');
const erqiwang=definitions.find(definition=>definition.key==='erqiwang');
const original=inventory();
const copy=()=>structuredClone(original);
const erqiwangPath=erqiwang.resources.createRoom;
const uuidOf=name=>original.scripts.find(script=>script.name===name).uuid;
test('static definition extraction reads the authoritative object without executing game factories',()=>{
const declarations=Object.fromEntries(definitions.map(definition=>[definition.key,definition]));
const text=`throw Error('must never execute'); export const GAME_DEFINITIONS=${JSON.stringify(declarations)} as const satisfies Record<string, GameDefinition>;`;
assert.deepEqual(parseRoomAssetDefinitions(text),definitions);
assert.throws(()=>parseRoomAssetDefinitions(text.replace('"key":"erqiwang"','"key":"another-game"')),/registration erqiwang differs/);
assert.throws(()=>parseRoomAssetDefinitions(text.replace('"createPageClass":"ErqiwangCreateRoomView"','"createPageClass":getClassName()')),/createPageClass must be a nonempty string literal/);
});
test('script UUID compression agrees with an actual serialized component and inherited page metadata',()=>{
const script=original.scripts.find(script=>script.name==='ErqiwangCreateRoomView');
assert.ok(script.contracts.includes('CreateRoomPage'));
assert.ok(original.assets.find(asset=>asset.path===erqiwangPath).objects.some(object=>object.__type__===compressUuid(script.uuid)));
});
test('current template and erqiwang assets have unique pages and matching composition references',()=>{
assert.deepEqual(validateRoomAssets(original,definitions),[]);
});
test('duplicate template component on erqiwang prefab is rejected',()=>{
const data=copy();
const prefab=data.assets.find(asset=>asset.path===erqiwangPath);
prefab.objects.push({__type__:compressUuid(uuidOf('TemplateCreateRoomView')),node:{__id__:1}});
assert.match(validateRoomAssets(data,definitions).join('\n'),/exactly one CreateRoomPage.*found 2/);
});
test('wrong game page and missing page are rejected',()=>{
const data=copy();
const page=data.assets.find(asset=>asset.path===erqiwangPath).objects.find(object=>object.__type__===compressUuid(uuidOf('ErqiwangCreateRoomView')));
page.__type__=compressUuid(uuidOf('TemplateCreateRoomView'));
assert.match(validateRoomAssets(data,definitions).join('\n'),/expected ErqiwangCreateRoomView.*TemplateCreateRoomView/);
page.__type__='cc.Component';
assert.match(validateRoomAssets(data,definitions).join('\n'),/exactly one CreateRoomPage.*found 0/);
});
test('serialized composition cannot retain private prefab references',()=>{
const data=copy();
const composition=data.assets.flatMap(asset=>asset.objects).find(object=>object.gameKey==='erqiwang');
composition.createRoom={__uuid__:data.assets.find(asset=>asset.path===template.resources.createRoom).uuid};
assert.match(validateRoomAssets(data,definitions).join('\n'),/createRoom.*must not be a serialized/);
composition.room={__uuid__:'00000000-0000-0000-0000-000000000000'};
assert.match(validateRoomAssets(data,definitions).join('\n'),/room.*must not be a serialized/);
});
test('unknown configured game, unresolved script and duplicate room views are rejected',()=>{
const data=copy();
const composition=data.assets.flatMap(asset=>asset.objects).find(object=>object.gameKey==='erqiwang');
composition.gameKey='missing-game';
const room=data.assets.find(asset=>asset.path===erqiwang.resources.room);
room.objects.push({__type__:compressUuid(uuidOf('TemplateRoomView')),node:{__id__:1}});
data.assets.find(asset=>asset.path===erqiwangPath).objects.push({__type__:compressUuid('00000000-0000-0000-0000-000000000001'),node:{__id__:1}});
const errors=validateRoomAssets(data,definitions).join('\n');
assert.match(errors,/unknown game missing-game/);
assert.match(errors,/unresolved script/);
assert.match(errors,/exactly one room view.*found 2/);
});
test('inheritance resolves the erqiwang room view through its shared public base',()=>{
const script=original.scripts.find(script=>script.name==='ErqiwangRoomView');
assert.ok(script.contracts.includes('CommonRoomViewBase'));
});
test('component on a child node cannot satisfy the platform root lookup',()=>{
const data=copy();
const page=data.assets.find(asset=>asset.path===erqiwangPath).objects.find(object=>object.__type__===compressUuid(uuidOf('ErqiwangCreateRoomView')));
page.node={__id__:2};
assert.match(validateRoomAssets(data,definitions).join('\n'),/must be attached to prefab root/);
});
test('an orphan component record cannot satisfy the platform root lookup',()=>{
const data=copy();
const prefab=data.assets.find(asset=>asset.path===erqiwangPath);
const pageIndex=prefab.objects.findIndex(object=>object.__type__===compressUuid(uuidOf('ErqiwangCreateRoomView')));
prefab.objects[prefab.objects[0].data.__id__]._components=prefab.objects[prefab.objects[0].data.__id__]._components.filter(reference=>reference.__id__!==pageIndex);
assert.match(validateRoomAssets(data,definitions).join('\n'),/not attached in the root component list/);
});