Files

40 lines
8.6 KiB
TypeScript

const wait=(ms=50)=>new Promise(r=>setTimeout(r,ms));const until=async(f:()=>unknown)=>{for(let i=0;i<220;i++){if(f())return;await wait();}throw Error('Timed out '+document.body.innerText.slice(-600));};
history.replaceState(null,'','/manager');let language='en-US',created=false;const home='/home/steamos',input:string[]=[];
const plugin={manifest:{id:'demo',name:'Frame Mic Tuner',version:'1.0.0',description:'Adjust microphone gain on your Frame.',author:'Community',ui:{windows:{}}},enabled:true,favorite:false,order:0};
const database:any={language,plugins:{demo:plugin},sources:[],safeMode:false,launcher:{primaryTrigger:false,menuAutoClose:true,menuTimeoutSeconds:10,allCategories:['plugin','steam','lepton','desktop']},networkPanel:{enabled:true,port:15915,passwordEnabled:true},proxy:{http:'',github:''}};
const files=[{name:'Downloads',path:home+'/Downloads',directory:true,size:0,mode:493,uid:1000,gid:1000},{name:'notes.txt',path:home+'/notes.txt',directory:false,size:123,mode:420,uid:1000,gid:1000}];
class Socket {static OPEN=1;readyState=0;onopen:any;onmessage:any;onclose:any;onerror:any;constructor(){setTimeout(()=>{this.readyState=1;this.onopen?.();this.reply(btoa('steamos@frame:~$ '));},50);}reply(data=''){this.onmessage?.({data:JSON.stringify({writable:true,exited:false,data})});}send(value:string){const v=JSON.parse(value);if(v.input)input.push(atob(v.input));this.reply();}close(){this.readyState=3;this.onclose?.();}}
(window as any).WebSocket=Socket;
window.fetch=async(url,init)=>{let result:any=true;const u=String(url),p=JSON.parse(String(init?.body??'{}'));
if(u==='/manager-api/files'){
if(p.operation==='preferences')result=[];else if(p.operation==='view.preferences')result={view:'list',folders:{},uploadConcurrency:3};
else if(p.operation==='list')result={path:p.path||home,parent:'/',total:p.hidden?1:2,roots:[{name:'Home',path:home},{name:'Downloads',path:home+'/Downloads'}],entries:p.hidden?files.filter(f=>f.directory):files};else throw Error('files '+p.operation);
}else if(u==='/manager-api/terminal'){if(p.operation==='create')created=true;result=p.operation==='create'?{id:'session',name:'steamos'}:created?[{id:'session',name:'steamos',controlled:true,exited:false}]:[];
}else{const {method}=p;
if(method==='status'){database.language=language;result={version:'0.6.0',agreement:{version:1,accepted:true},database,running:[],notifications:[],inbox:[]};}
else if(method==='language.list')result={packs:[],invalidFiles:[]};else if(method==='ui.events')result={cursor:0,events:[]};else if(method==='network.status')result={passwordConfigured:true,localOrigin:'http://localhost:15915',ips:[],listener:{}};
else if(method==='catalog.start')result={job:'catalog'};else if(method==='apk.cleanup.list')result=[];
else if(method==='apk.list.start')result={job:'apk'};else if(method==='job.status')result=p.params?.job==='catalog'?{phase:'done',result:[]}:{phase:'done',result:{apps:[{id:'wolvic/com.igalia.wolvic',context:'wolvic',metadata:{name:'Wolvic',package:'com.igalia.wolvic',version:'1.0',activities:['Main'],declaredActivities:['Main']},installed:true,size:1024}],containers:[],warnings:[],roots:[],available:true}};
}return new Response(JSON.stringify({result}));};
const button=(text:string,parent:ParentNode=document)=>{const node=Array.from(parent.querySelectorAll<HTMLButtonElement>('button')).find(b=>b.textContent?.trim()===text);if(!node||!node.getClientRects().length)throw Error('Missing visible button '+text);return node;};
const section=(key:string)=>document.querySelector<HTMLButtonElement>(`.manager-switcher button:nth-child(${({plugins:1,apk:2,terminal:3,files:4,settings:5} as any)[key]})`)!.click();
const shot=async(name:string)=>{await wait(1200);console.log('FRAMELY_PREVIEW_INSTALL_MOBILE_'+name);await wait(200);};
const noOverflow=()=>{if(document.documentElement.scrollWidth>innerWidth+1)throw Error('Page horizontal overflow');const content=document.querySelector<HTMLElement>('.content');if(content&&content.scrollWidth>content.clientWidth+2)throw Error('Content overflow '+location.hash+' '+content.scrollWidth+'/'+content.clientWidth);};
(window as any).runInstallReviewChecks=async()=>{try{
await until(()=>document.querySelector('.plugin-row'));const mobile=innerWidth<768;
if(mobile){const nav=document.querySelector('.manager-switcher')!.getBoundingClientRect();if(nav.bottom<innerHeight-4||nav.top<innerHeight-120)throw Error('Navigation not at thumb reach');if(document.querySelector('.workspace>nav')!.getBoundingClientRect().height)throw Error('Desktop subnav still visible');}
await shot('PLUGINS_EN');noOverflow();
if(mobile){document.querySelector<HTMLButtonElement>('[aria-label="Manage Frame Mic Tuner"]')!.click();await until(()=>document.querySelector('.manage-dialog'));const rect=document.querySelector('.manage-dialog')!.getBoundingClientRect();if(Math.abs(rect.bottom-innerHeight)>2)throw Error('Dialog is not a bottom sheet');await shot('PLUGIN_ACTIONS_EN');document.dispatchEvent(new KeyboardEvent('keydown',{key:'Escape',bubbles:true}));await until(()=>!document.querySelector('.manage-dialog'));}
section('settings');await until(()=>document.querySelector('.network-password'));
if(mobile){document.querySelector<HTMLButtonElement>('.mobile-page-picker>button')!.click();await until(()=>document.querySelector('.mobile-page-options'));button('Launcher',document.querySelector('.mobile-page-options')!).click();}else location.hash='launcher-settings';
await until(()=>document.querySelector('.launcher-settings'));await shot('SETTINGS_EN');section('files');await until(()=>document.querySelector('.file-list-scroll')?.getAttribute('aria-busy')==='false');
if(mobile){document.querySelector<HTMLButtonElement>('[aria-label="Browse folders"]')!.click();await until(()=>document.querySelector('.file-navigation-open'));await shot('FOLDERS_EN');button('Downloads',document.querySelector('.file-sidebar')!).click();await until(()=>!document.querySelector('.file-navigation-open'));await until(()=>document.querySelector('.file-table input[aria-label="notes.txt"]'));button('Filters and view').click();await until(()=>document.querySelector('.mobile-sheet'));if(!document.querySelector('.mobile-sheet .file-sort'))throw Error('Missing sort controls');document.querySelector<HTMLButtonElement>('.mobile-sheet header button')!.click();button('Create and upload').click();await until(()=>document.querySelector('.mobile-sheet'));if(!button('Upload folder',document.querySelector('.mobile-sheet')!))throw Error('Missing folder upload');document.querySelector<HTMLButtonElement>('.mobile-sheet header button')!.click();button('Select').click();document.querySelector<HTMLInputElement>('.file-table input[aria-label="notes.txt"]')!.click();await until(()=>document.querySelector('.file-mobile-selection'));button('Actions',document.querySelector('.file-mobile-selection')!).click();await until(()=>document.querySelector('.mobile-sheet'));await shot('FILE_ACTIONS_EN');document.querySelector<HTMLButtonElement>('.mobile-sheet header button')!.click();}
await shot('FILES_EN');noOverflow();section('terminal');await until(()=>document.querySelector('.terminal-manager'));document.querySelector<HTMLButtonElement>('.terminal-tabbar>button')!.click();await until(()=>document.querySelector('.terminal-connection')?.textContent==='Interactive');
if(mobile){button('Ctrl+C').click();button('Tab').click();await until(()=>input.includes('\x03')&&input.includes('\t'));}await shot('TERMINAL_EN');section('apk');await until(()=>document.querySelector('.apk-row'));await shot('APK_EN');noOverflow();
language='zh-CN';await until(()=>document.documentElement.lang==='zh-CN');await shot('APK_ZH');section('files');await until(()=>document.querySelector('.file-list-scroll'));await shot('FILES_ZH');section('settings');await until(()=>document.querySelector('.launcher-settings'));await shot('SETTINGS_ZH');noOverflow();
for(const page of ['settings','about','updates','notification-settings','sources','apk-settings','apk-containers','apk-cleanup']){location.hash=page;await wait(350);noOverflow();if(!document.querySelector('.content'))throw Error('Missing page '+page);}
if(mobile&&visualViewport){Object.defineProperty(visualViewport,'height',{value:innerHeight-300,configurable:true});visualViewport.dispatchEvent(new Event('resize'));await wait();if(getComputedStyle(document.querySelector('.manager-switcher')!).display!=='none')throw Error('Keyboard did not hide navigation');delete (visualViewport as any).height;visualViewport.dispatchEvent(new Event('resize'));await wait();}
console.log('FRAMELY_BRIDGE_PASS');
}catch(e){console.error('FRAMELY_BRIDGE_FAIL '+e+' '+(e as Error).stack);}};
void import('../ui/src/main');console.log('FRAMELY_VIEW_READY');