import test from 'node:test'; import assert from 'node:assert/strict'; import {createRequire} from 'node:module'; const {createWindowControls}=createRequire(import.meta.url)('../apps/browser/window-controls.cjs'); function fixture(options={}){ let destroyed=false,current=true,window,context; const calls=[],state={visible:true,focused:false,minimized:false,maximized:false,fullScreen:false}; const contents={isDestroyed:()=>false}; window={webContents:contents,isDestroyed:()=>destroyed,getBounds:()=>({x:-500,y:90,width:1280,height:800,title:'secret'}),...Object.fromEntries(Object.entries(state).map(([key])=>['is'+key[0].toUpperCase()+key.slice(1),()=>state[key]])),minimize(){calls.push('minimize');state.minimized=true;},maximize(){calls.push('maximize');state.maximized=true;},restore(){calls.push('restore');state.minimized=false;state.maximized=false;},focus(){calls.push('focus');state.focused=true;}}; context={ready:true,policy:{version:1,agents:{enabled:true,scopes:['window:state','window:control']}}}; const controls=createWindowControls({getWindow:()=>window,getContext:()=>context,isCurrent:()=>current,...options}); return {controls,calls,state,get window(){return window;},get context(){return context;},replace:()=>window={...window},invalidate:()=>current=false,destroy:()=>destroyed=true}; } test('window state exports only bounded dimensions and booleans',async()=>{ const f=fixture();assert.deepEqual(await f.controls.state(),{width:1280,height:800,visible:true,focused:false,minimized:false,maximized:false,fullScreen:false}); f.window.getBounds=()=>({width:Infinity,height:1});await assert.rejects(f.controls.state(),/dimensions/); f.window.getBounds=()=>({width:1,height:1});f.window.isVisible=()=> 'secret';await assert.rejects(f.controls.state(),/state/); }); test('the four allowed commands execute once and return fresh state',async()=>{ const f=fixture();for(const command of ['minimize','maximize','restore','focus'])assert.equal((await f.controls.control({command})).completed,true); assert.deepEqual(f.calls,['minimize','maximize','restore','focus']);assert.equal((await f.controls.state()).focused,true); }); test('state and control scopes are independent and global disable denies both',async()=>{ const f=fixture();f.context.policy.agents.scopes=['window:state'];await f.controls.state();await assert.rejects(f.controls.control({command:'focus'}),/scope/); f.context.policy.agents.scopes=['window:control'];await assert.rejects(f.controls.state(),/scope/);await f.controls.control({command:'focus'}); f.context.policy.agents.enabled=false;await assert.rejects(f.controls.control({command:'focus'}),/scope/);assert.deepEqual(f.calls,['focus']); }); test('no close, resize, arbitrary OS command, extra input or prototype access',async()=>{ const f=fixture();for(const args of [{command:'close'},{command:'setBounds'},{command:'__proto__'},{command:'focus',path:'secret'},null,Object.create({command:'focus'})])await assert.rejects(f.controls.control(args),/Invalid/); await assert.rejects(f.controls.state({command:'focus'}),/Invalid/);assert.deepEqual(f.calls,[]); }); test('expired and malformed policy, stale identity and destroyed native window deny effects',async()=>{ for(const mutate of [f=>f.context.policy.expiresAt='2000-01-01',f=>f.context.policy.expiresAt='invalid',f=>f.context.policy.agents.scopes='window:control',f=>f.invalidate(),f=>f.destroy(),f=>f.context.ready=false]){ const f=fixture();mutate(f);await assert.rejects(f.controls.control({command:'focus'}));assert.deepEqual(f.calls,[]); } }); test('asynchronous authorization cannot release a stale policy, native window or cancellation',async()=>{ for(const mutation of ['policy','window','cancel','grant']){ const controller=new AbortController();let f,counter=0;f=fixture({authorize:async()=>{if(++counter===1){if(mutation==='policy')f.context.policy={...f.context.policy};if(mutation==='window')f.replace();if(mutation==='cancel')controller.abort();if(mutation==='grant')f.invalidate();}return true;}}); await assert.rejects(f.controls.control({command:'focus'},{signal:controller.signal}));assert.deepEqual(f.calls,[]); } }); test('an effect is not repeated when it revokes policy or cancellation suppresses output',async()=>{ for(const mutation of ['policy','cancel']){ const f=fixture(),controller=new AbortController();f.window.focus=()=>{f.calls.push('focus');if(mutation==='policy')f.context.policy.agents.enabled=false;else controller.abort();}; await assert.rejects(f.controls.control({command:'focus'},{signal:controller.signal}));assert.deepEqual(f.calls,['focus']); } }); test('fresh grant checks apply before the effect and native state getters cannot export after revocation',async()=>{ let checks=0;const f=fixture({authorize:async()=>++checks<2});await assert.rejects(f.controls.control({command:'focus'}),/authorization/);assert.deepEqual(f.calls,[]); const g=fixture();g.window.getBounds=()=>{g.invalidate();return {width:1,height:1};};await assert.rejects(g.controls.state(),/changed/); }); test('operation tracing wraps execution and failed native effects are never retried',async()=>{ const names=[],f=fixture({traceOperation:async(name,fn)=>{names.push(name);return fn();}});await f.controls.state();f.window.focus=()=>{f.calls.push('focus');throw Error('sensitive native failure');};await assert.rejects(f.controls.control({command:'focus'}),/^Error: Managed window operation failed$/);assert.deepEqual(names,['window:state','window:control']);assert.deepEqual(f.calls,['focus']); });