Files
ucvl-home-vision/test_leadership_ui.js
T

34 lines
3.0 KiB
JavaScript
Raw Permalink Normal View History

const test=require('node:test'),assert=require('node:assert/strict'),fs=require('node:fs'),vm=require('node:vm');
const source=fs.readFileSync('web/households.js','utf8');
test('leadership choices include enabled local members and exclude unrelated or global accounts',()=>{
const context=vm.createContext({});
vm.runInContext(source.slice(source.indexOf('function leadershipCandidates('),source.indexOf('function syncLeadershipSelection(')),context);
const rows=[{id:'a',familyId:'home',role:'member'},{id:'b',familyId:'home',role:'family_admin'},{id:'c',familyId:'home',role:'admin'},{id:'d',familyId:'else',role:'family_admin'},{id:'e',familyId:'home',role:'member',disabled:true}];
assert.equal(JSON.stringify(context.leadershipCandidates(rows,'home').map(x=>x.id)),JSON.stringify(['a','b']));
});
test('empty leadership choices have a member creation path and explicit grant control',()=>{
const markup=fs.readFileSync('frontend/src/components/RuntimeOverlays.vue','utf8');
for(const id of ['leadership-empty','leadership-scope','leadership-new','leadership-members','leadership-grant'])assert.ok(markup.includes(`id="${id}"`));
assert.match(source,/grantManagement=f\.elements\.grantManagement\.checked/);
assert.match(source,/disabled=!leadershipUsers.length/);
assert.match(source,/grantManagement\.checked=false/);
const family=fs.readFileSync('web/family.js','utf8');assert.match(family,/await openLeadership\(returnTo\)/);assert.match(family,/leadershipReturnDraft/);
});
function fullscreenFixture(native){
const classes=new Set(),stage={classList:{contains:k=>classes.has(k),add:k=>classes.add(k),remove:k=>classes.delete(k)}};
if(native)stage.requestFullscreen=async()=>{document.fullscreenElement=stage};
const button={setAttribute(k,v){this[k]=v}},document={fullscreenElement:null,body:{style:{overflow:'auto'},classList:{toggle(){}}},addEventListener(){},exitFullscreen:async()=>{document.fullscreenElement=null}};
const context=vm.createContext({document,$:id=>id==='#page-live'?stage:button});
const monitor=fs.readFileSync('web/monitor.js','utf8');
vm.runInContext(monitor.slice(monitor.indexOf("let wallBodyOverflow="),monitor.indexOf('setInterval(')),context);
return {context,document,stage,button,classes};
}
test('phone fullscreen falls back to viewport and restores scroll on exit',async()=>{
const f=fullscreenFixture(false);await f.button.onclick();assert.ok(f.classes.has('wall-expanded'));assert.equal(f.document.body.style.overflow,'hidden');assert.equal(f.button['aria-pressed'],'true');
f.context.closeWallFullscreen();assert.equal(f.classes.size,0);assert.equal(f.document.body.style.overflow,'auto');assert.equal(f.button['aria-pressed'],'false');
});
test('native fullscreen remains supported and exits without rebuilding video',async()=>{
const f=fullscreenFixture(true);await f.button.onclick();assert.equal(f.document.fullscreenElement,f.stage);assert.equal(f.classes.size,0);await f.button.onclick();assert.equal(f.document.fullscreenElement,null);
const app=fs.readFileSync('web/app.js','utf8');assert.match(app,/page!=='live'.*closeWallFullscreen\(\)/);
});