const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const vm = require('node:vm'); const html = fs.readFileSync(path.join(__dirname, '../src/renderer/public/slam-viewer/index.html'), 'utf8'); const source = html.slice(html.indexOf('function hasLiveCameraState()'), html.indexOf("cameraPreview?.addEventListener('load'")); let now = 10000; let requests = 0; let ok = true; let visible = false; let afterBlob = () => {}; const context = vm.createContext({ ENABLE_CAMERA_PREVIEW: true, cameraFrameRequestInFlight: false, cameraFrameRetryAt: 0, cameraFrameObjectUrl: null, cameraPreview: {}, latestSlamState: null, latestSlamStateReceivedAt: now, document: { hidden: false }, Date: { now: () => now }, BACKEND_URL: 'http://localhost:8765', AbortSignal, URL: { createObjectURL: () => 'blob:frame', revokeObjectURL() {} }, setCameraPreviewAvailable(value) { visible = value; }, async fetch() { requests++; return { ok, async blob() { afterBlob(); return {}; } }; }, }); vm.runInContext(source, context); const refresh = () => context.refreshCameraFrame(); const available = (value) => { context.latestSlamState = { topic_status: { camera_image: { available: value } } }; context.latestSlamStateReceivedAt = now; }; (async () => { await refresh(); available(false); await refresh(); assert.equal(requests, 0, 'Absent camera must not fetch frames'); available(true); await refresh(); assert.equal(requests, 1); assert.equal(context.cameraPreview.src, 'blob:frame'); now += 3001; await refresh(); assert.equal(requests, 1, 'Stale websocket state must stop polling'); assert.equal(visible, false); available(true); ok = false; await refresh(); await refresh(); assert.equal(requests, 2, 'HTTP errors must back off'); now += 5000; available(true); ok = true; afterBlob = () => available(false); context.cameraPreview.src = ''; await refresh(); assert.equal(context.cameraPreview.src, '', 'Late responses must not revive a disconnected camera'); assert.equal(context.cameraFrameRequestInFlight, false); afterBlob = () => {}; available(true); await refresh(); assert.equal(context.cameraPreview.src, 'blob:frame', 'Camera reconnect must resume frames'); console.log('camera preview polling tests passed'); })().catch((error) => { console.error(error); process.exitCode = 1; });