Release Vulpes OS 2.7-preview.22
This commit is contained in:
parent
200d1fb235
commit
a138f97877
294 changed files with 515786 additions and 187 deletions
93
tests/keypad-browser.test.mjs
Normal file
93
tests/keypad-browser.test.mjs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
import {test} from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {readFileSync} from 'node:fs';
|
||||
import vm from 'node:vm';
|
||||
import {nextKeypadTarget} from '../services/keypad-navigation.mjs';
|
||||
|
||||
function actor(name, globals={}) {
|
||||
const source=readFileSync(new URL(`../host/actors/${name}.sys.mjs`,import.meta.url),'utf8')
|
||||
.replace(/^import .*;\n/gm,'').replace('export class','class');
|
||||
return vm.runInNewContext(source+`; new ${name}();`,{
|
||||
JSWindowActorChild:class {}, JSWindowActorParent:class {},
|
||||
KeypadText:class {commit() {}}, nextKeypadTarget, ...globals});
|
||||
}
|
||||
|
||||
test('Up from an empty page returns to the browser toolbar, but other apps do not',()=>{
|
||||
const messages=[],scrolls=[];
|
||||
const child=actor('KeypadChild');
|
||||
child.document={activeElement:{localName:'body'},location:{hostname:'example.org'},
|
||||
querySelectorAll:()=>[],documentElement:{dataset:{}}};
|
||||
child.contentWindow={scrollY:0,scrollBy:v=>scrolls.push(v)};
|
||||
child.sendAsyncMessage=name=>messages.push(name);
|
||||
child.receiveMessage({name:'Vulpes:Navigate',data:{key:'ArrowUp',browserContent:true}});
|
||||
assert.deepEqual(messages,['Vulpes:KeypadToolbar']);
|
||||
messages.length=0;
|
||||
child.receiveMessage({name:'Vulpes:Navigate',data:{key:'ArrowUp'}});
|
||||
assert.deepEqual(messages,[]);
|
||||
child.contentWindow.scrollY=80;
|
||||
child.receiveMessage({name:'Vulpes:Navigate',data:{key:'ArrowUp',browserContent:true}});
|
||||
assert.deepEqual(messages,[]);
|
||||
assert.equal(scrolls.at(-1).top,-80);
|
||||
});
|
||||
|
||||
test('external browser views receive keys through their owned placeholder only',()=>{
|
||||
const messages=[];
|
||||
const root={},child={id:8,parent:root,currentWindowGlobal:{getActor:()=>({sendAsyncMessage:()=>{throw Error('Placeholder used');}})}};
|
||||
const view={browser:{style:{visibility:'visible'},browsingContext:{currentWindowGlobal:{
|
||||
getActor:()=>({sendAsyncMessage:(name,data)=>messages.push({name,data})})}}}};
|
||||
const parent=actor('KeypadParent',{Services:{env:{get:()=> '1'}},
|
||||
BrowsingContext:{get:()=>child},Views:{entries:new Map([[8,view]])}});
|
||||
parent.browsingContext=root;
|
||||
parent.receiveMessage({name:'Vulpes:KeypadRoute',data:{contextId:8,key:'ArrowDown',browserContent:true}});
|
||||
assert.equal(messages[0].name,'Vulpes:Navigate');
|
||||
assert.equal(messages[0].data.browserContent,true);
|
||||
parent.browsingContext={};
|
||||
parent.receiveMessage({name:'Vulpes:KeypadRoute',data:{contextId:8,key:'ArrowDown'}});
|
||||
assert.equal(messages.length,1);
|
||||
});
|
||||
|
||||
test('toolbar focus does not select a bar hidden behind the lockscreen or a dialog',()=>{
|
||||
let selected=0;
|
||||
const bar={checkVisibility:()=>true,getBoundingClientRect:()=>({x:0,y:20,width:200,height:40}),contains:()=>false};
|
||||
const child=actor('KeypadChild');
|
||||
child.document={location:{hostname:'system.localhost'},querySelectorAll:()=>[bar],elementFromPoint:()=>({})};
|
||||
child.select=()=>selected++;
|
||||
child.receiveMessage({name:'Vulpes:FocusBrowserToolbar'});
|
||||
assert.equal(selected,0);
|
||||
bar.contains=()=>true;
|
||||
child.receiveMessage({name:'Vulpes:FocusBrowserToolbar'});
|
||||
assert.equal(selected,1);
|
||||
});
|
||||
|
||||
test('Down leaves the toolbar and routes to its page instead of retaining toolbar focus',()=>{
|
||||
let focused=false;
|
||||
const messages=[];
|
||||
const frame={checkVisibility:()=>true,getBoundingClientRect:()=>({x:0,y:70,width:240,height:200}),
|
||||
browsingContext:{id:9},focus:()=>focused=true,closest:()=>({querySelector:()=>({})})};
|
||||
const child=actor('KeypadChild');
|
||||
child.document={location:{hostname:'system.localhost'},activeElement:{closest:()=>({})},
|
||||
querySelectorAll:selector=>selector==='iframe'?[frame]:[],elementFromPoint:()=>frame};
|
||||
child.contentWindow={innerWidth:240,innerHeight:320};
|
||||
child.sendAsyncMessage=(name,data)=>messages.push({name,data});
|
||||
child.receiveMessage({name:'Vulpes:Navigate',data:{key:'ArrowDown'}});
|
||||
assert.equal(focused,true);
|
||||
assert.equal(messages[0].name,'Vulpes:KeypadRoute');
|
||||
assert.equal(messages[0].data.browserContent,true);
|
||||
assert.equal(messages[0].data.contextId,9);
|
||||
});
|
||||
|
||||
test('Up escapes a Gecko error page even when its retry button is offscreen',()=>{
|
||||
const messages=[];
|
||||
const root={currentWindowGlobal:{getActor:()=>({sendAsyncMessage:name=>messages.push(name)})}};
|
||||
root.top=root;
|
||||
root.embedderElement={ownerDocument:{getElementById:()=>({browsingContext:root})}};
|
||||
const child={id:9,parent:root};
|
||||
const view={browser:{style:{visibility:'visible'},browsingContext:{currentWindowGlobal:{
|
||||
documentURI:{spec:'about:neterror?e=dnsNotFound&u=https://example.invalid/'},
|
||||
getActor:()=>{throw Error('Error-page controls must not trap Up');}}}}};
|
||||
const parent=actor('KeypadParent',{Services:{env:{get:()=> '1'}},
|
||||
BrowsingContext:{get:()=>child},Views:{entries:new Map([[9,view]])}});
|
||||
parent.browsingContext=root;
|
||||
parent.receiveMessage({name:'Vulpes:KeypadRoute',data:{contextId:9,key:'ArrowUp',browserContent:true}});
|
||||
assert.deepEqual(messages,['Vulpes:FocusBrowserToolbar']);
|
||||
});
|
||||
Loading…
Reference in a new issue