import assert from 'node:assert/strict'; import {test} from 'node:test'; import {createGameRoomProjection} from '../../YouleNexus/assets/framework/sdk/game-room-projection.ts'; import {gameAllowsRoomAction} from '../../YouleNexus/assets/framework/presentation/game-room-presentation.ts'; test('game owns atomic complete projections and exposes no consumer setter',()=>{ const initial={roundPhase:'waiting',selfParticipation:'waiting' as const,scoresBySeat:{0:10},restrictions:{}}; const owner=createGameRoomProjection(initial);const source=owner.source;const versions:any[]=[]; source.subscribe(value=>versions.push(value));owner.commit({roundPhase:'playing',selfParticipation:'playing',scoresBySeat:{0:20},restrictions:{prepare:false}}); assert.deepEqual(versions.map(v=>[v.revision,v.roundPhase,v.scoresBySeat[0]]),[[0,'waiting',10],[1,'playing',20]]); initial.scoresBySeat[0]=999;assert.equal(versions[0].scoresBySeat[0],10); assert.equal('commit' in source,false);assert.ok(Object.isFrozen(source.getSnapshot().scoresBySeat)); assert.equal(gameAllowsRoomAction(false,source.getSnapshot(),'exit'),false);assert.equal(gameAllowsRoomAction(true,source.getSnapshot(),'prepare'),false); assert.throws(()=>owner.commit({...initial,restrictions:{exit:true} as any}),/disable/);assert.equal(source.getSnapshot().revision,1); owner.dispose();assert.throws(()=>owner.commit(initial),/disposed/);assert.throws(()=>source.subscribe(()=>{}),/disposed/); }); test('reentrant projection commits notify complete versions in order and isolate listener failure',()=>{ const initial={roundPhase:'waiting',selfParticipation:'waiting' as const,scoresBySeat:{},restrictions:{}};const owner=createGameRoomProjection(initial);const seen:number[]=[]; owner.source.subscribe(p=>{if(p.revision===1){owner.commit({...initial,roundPhase:'finished'});throw Error('listener failed');}}); owner.source.subscribe(p=>seen.push(p.revision));assert.throws(()=>owner.commit({...initial,roundPhase:'playing'}),/notification/);assert.deepEqual(seen,[0,1,2]); });