63 lines
4.9 KiB
JavaScript
63 lines
4.9 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import {after,before,test} from 'node:test';
|
|
import {createServer} from 'vite';
|
|
let server,layout,source,fanout,catalog;
|
|
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');
|
|
catalog=await server.ssrLoadModule('../../packages/sensor-ui/src/observationCatalog.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;}
|
|
});
|
|
|
|
|
|
test('known offline D455 remains selectable; connected capabilities override the catalog',()=>{
|
|
const offline={name:'RealSense D455',model:'RealSense D455',online:false,layers:[]};
|
|
assert.deepEqual(source.cameraObservationViews(offline)[0].layers.map(v=>v.value),['color','depth','infrared1','infrared2','points','motion']);
|
|
assert.deepEqual(source.cameraObservationViews({...offline,online:true,layers:['depth']})[0].layers.map(v=>v.value),['depth']);
|
|
assert.deepEqual(source.cameraObservationViews({...offline,model:'unknown'}),[]);
|
|
});
|
|
test('unbound catalog views have no device authority; connected instances replace templates without aliasing',()=>{
|
|
const plugin={kind:'k1',observation:{catalog:{label:'K1',views:[{id:'points',label:'Points'},{id:'camera',label:'Camera'}]}}};
|
|
const entries=catalog.unboundObservationViews([],[plugin]);
|
|
assert.equal(entries.length,2);assert.notEqual(entries[0].key,entries[1].key);
|
|
assert.equal(entries[0].deviceID,undefined);assert.equal(entries[0].device,undefined);
|
|
assert.deepEqual(catalog.unboundObservationViews([{id:'one',kind:'k1'}],[plugin]),[]);
|
|
assert.deepEqual(catalog.unboundObservationViews([],[plugin,plugin]),[]);
|
|
const persisted=layout.decodeObservationLayout({...layout.emptyObservationLayout(),catalogVisible:[entries[0].key,entries[0].key,null]});
|
|
assert.deepEqual(persisted.catalogVisible,[entries[0].key]);
|
|
});
|