import assert from 'node:assert/strict'; import {after,before,test} from 'node:test'; import {createServer} from 'vite'; let server,layout,source,fanout; before(async()=>{ server=await createServer({appType:'custom',logLevel:'silent',server:{middlewareMode:true}}); layout=await server.ssrLoadModule('/src/core/fleet/observationLayout.ts'); source=await server.ssrLoadModule('../../packages/sensor-ui/src/observation.ts'); ({observationRerun:fanout}=await server.ssrLoadModule('@xgrids-k1/frontend/sensors/observationRerun.ts')); }); after(async()=>{await server?.close();}); test('layout keeps independent identities and restores absent devices without confusing equal model names',()=>{ const a=source.observationKey('camera-1','left'),b=source.observationKey('camera-2','left'),c=source.observationKey('camera-1','right'); assert.notEqual(a,b);assert.notEqual(a,c); const value={...layout.emptyObservationLayout(),order:[b,a],hidden:[a],layers:{[a]:'depth'}}; assert.deepEqual(layout.orderedObservationIDs(value,[a,c]),[a,c]); assert.deepEqual(layout.orderedObservationIDs(value,[a,b,c]),[b,a,c]); assert.deepEqual(layout.moveObservation(value,[a,b,c],c,b).order,[c,b,a]); assert.deepEqual(value.hidden,[a]); }); test('untrusted browser layout is bounded and validates revisions and split numbers',()=>{ const decoded=layout.decodeObservationLayout({version:1,order:['a','a',null,8],hidden:'all',layers:{a:'depth',b:[]},splits:{a:Infinity,b:-8,c:98},arrangement:'bad'}); assert.deepEqual(decoded.order,['a']);assert.deepEqual(decoded.hidden,[]);assert.deepEqual(decoded.splits,{b:20,c:80});assert.deepEqual(decoded.layers,{a:'depth'});assert.equal(decoded.arrangement,'auto'); assert.deepEqual(layout.decodeObservationLayout({version:2}),layout.emptyObservationLayout()); }); test('camera observation exposes only advertised layers with one viewport and RGB default',()=>{ const views=source.cameraObservationViews({name:'RealSense',layers:['depth','private-channel','color','points']}); assert.equal(views.length,1);assert.deepEqual(views[0].layers.map(v=>v.value),['color','depth','points']); assert.deepEqual(source.cameraObservationViews({name:'unknown',layers:[]}),[]); }); test('two Rerun views share bytes, apply independent blueprints once and dispose both hosts',async()=>{ const fetchBefore=globalThis.fetch;globalThis.fetch=async url=>new Response(Uint8Array.of(String(url).includes('plan')?2:1)); const sent=[[],[]],closed=[],started=[];let count=0; const factory=mount=>{const index=count++;return {ready:Promise.resolve({mount,viewer:{start:async()=>started.push(index),open_channel:name=>({ready:true,send_rrd:bytes=>sent[index].push([name,[...bytes]]),close:()=>{}}),get_active_recording_id:()=> 'recording-1',override_panel_state:()=>{},set_active_timeline:()=>{}}}),dispose:()=>closed.push(index)};}; try{ const host=fanout(factory,{current:{id:'top'}})({id:'3d'});const {viewer,mount}=await host.ready; await viewer.start(null,mount,{});const channel=viewer.open_channel('rrd');channel.send_rrd(Uint8Array.of(9,8)); assert.deepEqual(sent[0],[['rrd',[9,8]]]);assert.deepEqual(sent[1],[['rrd',[9,8]]]); viewer.get_active_recording_id();viewer.get_active_recording_id(); assert.deepEqual(sent[0].at(-1),['observation-perspective',[1]]);assert.deepEqual(sent[1].at(-1),['observation-plan',[2]]); assert.equal(sent[0].length,2);assert.deepEqual(started,[0,1]);host.dispose();assert.deepEqual(closed,[0,1]); }finally{globalThis.fetch=fetchBefore;} });