Files
Halloween/tests/test_endpoints_ui.js
2026-10-16 01:38:10 +02:00

116 lines
6.7 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Verify endpoint presentation and that starting never saves stray form limits.
const assert = require('node:assert/strict');
const fs = require('node:fs');
const vm = require('node:vm');
const html = fs.readFileSync(require('node:path').join(__dirname,'../halloween/camera.html'),'utf8');
const state = html.slice(html.indexOf(' function endpointState('),html.indexOf(' async function pollFollow()'));
const begin = html.slice(html.indexOf(' async function beginFollow('),html.indexOf(" $('follow-preview').onclick"));
const save = html.slice(html.indexOf(' async function saveFollow()'),html.indexOf(" for (const [id,hue]"));
const config={search_enabled:false,follow_speed:80,hue:85,tolerance:18,pan_min:1400,pan_max:1600,tilt_min:1400,tilt_max:1600,pan_reverse:false,tilt_reverse:false,pan_setup_min:1100,pan_setup_max:1900,tilt_setup_min:1100,tilt_setup_max:1900};
const nodes={'follow-speed':{value:80}}, calls=[];
const ctx=vm.createContext({
$:id => nodes[id] || (nodes[id]={checked:false,value:18}),
setupReady:true, manualLimitsDirty:false, configEpoch:0, followConfig:{...config}, followLatest:null,
releaseJog:()=>{}, jogSequence:0, followSession:null, followSample:null, followEpoch:0,
api:async (url,body) => {calls.push({url,body}); return url.endsWith('/start') ? {session:'test'} : body;},
fillFollow:c=>{ctx.followConfig=c;}
});
vm.runInContext(state+begin+save,ctx);
(async()=>{
ctx.sample={config:{...config},pan_us:1100,tilt_us:1500};
vm.runInContext('renderEndpoints(sample)',ctx);
assert.equal(nodes['setup-value-left'].textContent,'Gespeichert: 1400 µs');
assert.equal(nodes['setup-save-left'].disabled,false);
assert.match(nodes['setup-hint-left'].textContent,/1110/);
assert.equal(nodes['setup-save-right'].disabled,true);
assert.equal(nodes['setup-save-up'].disabled,true);
ctx.sample={config:{...config,pan_reverse:true},pan_us:1100,tilt_us:1900};
vm.runInContext('renderEndpoints(sample)',ctx);
assert.equal(nodes['setup-save-left'].disabled,true);
assert.equal(nodes['setup-save-right'].disabled,false);
assert.equal(nodes['setup-save-down'].disabled,false);
ctx.sample={config:{...config,pan_min:1728,pan_max:1800},pan_us:1718,tilt_us:1500,setup_origin:{pan:1750,tilt:1500}};
vm.runInContext('renderEndpoints(sample)',ctx);
assert.equal(nodes['setup-save-left'].disabled,false); // above 1500 is valid
assert.equal(nodes['setup-save-right'].disabled,true);
ctx.sample.pan_us=1751;
vm.runInContext('renderEndpoints(sample)',ctx);
assert.equal(nodes['setup-save-left'].disabled,true); // original session centre
ctx.sample.centering=true;
ctx.sample.pan_us=1718;
vm.runInContext('renderEndpoints(sample)',ctx);
assert.equal(nodes['setup-save-left'].disabled,true);
assert.match(nodes['setup-hint-left'].textContent,/Mittelstellungsfahrt/);
ctx.sample.centering=false;
ctx.setupReady=false;
vm.runInContext('renderEndpoints(sample)',ctx);
assert.equal(nodes['setup-save-right'].disabled,true);
assert.match(nodes['setup-hint-right'].textContent,/Einrichtmodus/);
await vm.runInContext("beginFollow(false,'setup')",ctx);
assert.deepEqual(calls.map(c=>c.url),['/api/follow/start']);
assert.equal(ctx.followSession,'test');
nodes['follow-pan-reverse'].checked=true;
await assert.rejects(vm.runInContext("beginFollow(false)",ctx),/zuerst dort speichern/);
assert.equal(calls.length,1);
nodes['follow-pan-reverse'].checked=false;
nodes['follow-speed'].value=400;
await assert.rejects(vm.runInContext("beginFollow(false)",ctx),/zuerst dort speichern/);
nodes['follow-speed'].value=80;
nodes['follow-search'].checked=true;
await assert.rejects(vm.runInContext("beginFollow(false)",ctx),/zuerst dort speichern/);
nodes['follow-speed'].value=400;
nodes['follow-pan-reverse'].checked=true;
// A settings save only changes colour/direction/speed, never endpoint values.
nodes['follow-pan-min']={value:500}; nodes['follow-pan-max']={value:500};
await vm.runInContext('saveFollow()',ctx);
assert.equal(calls[1].body.pan_min,1400);
assert.equal(calls[1].body.pan_max,1600);
assert.equal(calls[1].body.pan_reverse,true);
assert.equal(calls[1].body.follow_speed,400);
assert.equal(calls[1].body.search_enabled,true);
assert.ok(html.includes('id="follow-pan-min"'));
assert.ok(html.includes('Diese Position als Links speichern'));
ctx.manualLimitsDirty=true;
await assert.rejects(vm.runInContext("beginFollow(false)",ctx),/noch nicht gespeichert/);
ctx.manualLimitsDirty=false;
const manual=html.slice(html.indexOf(' function fillManualLimits('),html.indexOf(' // Manual limit form bindings.'));
vm.runInContext(manual,ctx);
vm.runInContext('fillManualLimits(followConfig)',ctx);
nodes['follow-pan-min'].value=1200; nodes['follow-pan-max'].value=1800;
nodes['follow-tilt-min']={value:1300}; nodes['follow-tilt-max']={value:1700};
await vm.runInContext('saveManualLimits()',ctx);
assert.equal(calls.at(-1).body.pan_min,1200);
assert.equal(calls.at(-1).body.tilt_max,1700);
assert.equal(calls.at(-1).body.pan_reverse,true);
assert.match(nodes['manual-limits-status'].textContent,/gespeichert/);
assert.equal(calls.at(-1).body.follow_speed,400);
assert.equal(calls.at(-1).body.search_enabled,true);
nodes['follow-tilt-min'].value=1700; nodes['follow-tilt-max'].value=1800;
await vm.runInContext('saveManualLimits()',ctx);
assert.equal(calls.at(-1).body.tilt_min,1700); // range need not contain 1500
const count=calls.length;
nodes['follow-pan-max'].value=2500;
await assert.rejects(vm.runInContext('saveManualLimits()',ctx),/500–2500/);
assert.equal(calls.length,count);
nodes['follow-pan-setup-max'].value=2500;
await vm.runInContext('saveManualLimits()',ctx);
assert.equal(calls.at(-1).body.pan_max,2500);
assert.equal(calls.at(-1).body.pan_setup_max,2500);
nodes['follow-pan-setup-max'].value=2501;
await assert.rejects(vm.runInContext('saveManualLimits()',ctx),/500–2500/);
const centerCode=html.slice(html.indexOf(' async function centerSetup()'),html.indexOf(" $('setup-center').onclick"));
vm.runInContext(centerCode,ctx);
ctx.setupReady=false;
await assert.rejects(vm.runInContext('centerSetup()',ctx),/Einrichtmodus/);
ctx.setupReady=true; ctx.followSession='test'; ctx.jogSequence=5;
ctx.api=async (url,body)=>{calls.push({url,body});return {accepted:true};};
ctx.sendJog=async direction=>{calls.push({url:'/api/follow/jog',body:{direction,sequence:++ctx.jogSequence}});};
await vm.runInContext('centerSetup()',ctx);
assert.equal(calls.at(-1).url,'/api/follow/center');
assert.equal(calls.at(-1).body.sequence,6);
await vm.runInContext('stopSetupMotion()',ctx);
assert.equal(calls.at(-1).body.direction,null);
assert.equal(calls.at(-1).body.sequence,7);
console.log('Endpoint UI tests passed');
})().catch(e=>{console.error(e);process.exit(1);});