Add adaptive per-vehicle layouts, full-panel dragging, source controls and automatic preview recovery for RealSense, Insta360 X4 and XGRIDS K1 observation views. Integrate cached Cesium map layers through the private NAS gateway link, retain bounded sensor command receipts, and document validation and operational handoff.
53 lines
3.1 KiB
JavaScript
53 lines
3.1 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import {after,before,test} from 'node:test';
|
|
import {createServer} from 'vite';
|
|
let server,PreviewLiveness,previewPlayback;
|
|
before(async()=>{
|
|
server=await createServer({appType:'custom',logLevel:'silent',server:{middlewareMode:true}});
|
|
({PreviewLiveness}=await server.ssrLoadModule('../../packages/sensor-ui/src/previewLiveness.ts'));
|
|
({previewPlayback}=await server.ssrLoadModule('../../packages/sensor-ui/src/previewPlayback.ts'));
|
|
});
|
|
after(async()=>{await server?.close();});
|
|
test('offscreen RTP decode progress keeps a viewer live without DOM frame callbacks',()=>{
|
|
const h=new PreviewLiveness(0);
|
|
for(let now=2000;now<180000;now+=2000){h.frame(now);assert.equal(h.state(now),'live');}
|
|
});
|
|
test('one stale telemetry sample signals delay, never a camera restart',()=>{
|
|
const h=new PreviewLiveness(0);h.frame(1000);h.source(false,1100);
|
|
assert.equal(h.state(1100),'delayed');h.source(true,1500);h.frame(1500);assert.equal(h.state(1500),'live');
|
|
});
|
|
test('capture recovery requires sustained fresh reports that the source stopped',()=>{
|
|
const h=new PreviewLiveness(0);h.frame(1000);
|
|
for(let now=2000;now<=12000;now+=1000){h.source(false,now);assert.equal(h.state(now),'delayed');}
|
|
h.source(false,14000);assert.equal(h.state(14000),'source-stalled');
|
|
h.source(true,14500);h.frame(14500);assert.equal(h.state(14500),'live');
|
|
});
|
|
test('missing telemetry and a stalled peer cannot be treated as proof to restart capture',()=>{
|
|
const h=new PreviewLiveness(0);h.frame(100);h.source(false,200);
|
|
assert.equal(h.state(13000),'peer-stalled');
|
|
});
|
|
test('negotiation time does not consume the first-frame grace period',()=>{
|
|
const h=new PreviewLiveness(0);h.connected(45000);
|
|
assert.equal(h.state(45001),'waiting');assert.equal(h.state(53001),'peer-stalled');
|
|
});
|
|
test('a browser-paused panel resumes the same stream and coalesces pending playback',async()=>{
|
|
const stream={},attempts=[];
|
|
const video={srcObject:stream,muted:false,paused:true,play(){return new Promise(resolve=>attempts.push(resolve));}};
|
|
const playback=previewPlayback(video);
|
|
playback.resume();playback.resume();assert.equal(attempts.length,1);assert.equal(video.muted,true);
|
|
video.paused=false;attempts[0]();await new Promise(resolve=>setImmediate(resolve));
|
|
playback.resume();assert.equal(attempts.length,1);
|
|
video.paused=true;playback.resume();assert.equal(attempts.length,2);assert.equal(video.srcObject,stream);
|
|
playback.dispose();attempts[1]();await new Promise(resolve=>setImmediate(resolve));
|
|
playback.resume();assert.equal(attempts.length,2);
|
|
});
|
|
test('hidden-panel play rejection is retried on visibility without replacing the stream',async()=>{
|
|
const stream={};let attempts=0;
|
|
const video={srcObject:stream,muted:true,paused:true,play(){attempts++;return Promise.reject(new Error('offscreen'));}};
|
|
const playback=previewPlayback(video);
|
|
playback.resume();await new Promise(resolve=>setImmediate(resolve));
|
|
playback.resume();await new Promise(resolve=>setImmediate(resolve));
|
|
assert.equal(attempts,2);assert.equal(video.srcObject,stream);
|
|
video.srcObject=null;playback.resume();assert.equal(attempts,2);
|
|
});
|