Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
351
tools/test-feedback.py
Normal file
351
tools/test-feedback.py
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Regression checks for the September desktop feedback, in actual Gaia UI."""
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import time
|
||||
from pathlib import Path
|
||||
from marionette_client import Client
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--restart-check", action="store_true")
|
||||
args = parser.parse_args()
|
||||
results = {}
|
||||
with Client(2857) as client:
|
||||
engine = client.execute("return Services.appinfo.platformVersion;")
|
||||
assert (
|
||||
client.execute("return PathUtils.profileDir;").split("/")[-1].startswith("host-")
|
||||
), "Test profile required"
|
||||
client.execute(
|
||||
"try{ChromeUtils.registerWindowActor('VulpesProbe',{child:{esModuleURI:'resource://vulpes/tests/ProbeChild.sys.mjs'},allFrames:true,safeForUntrustedWebProcess:true});}catch(_){}"
|
||||
)
|
||||
|
||||
def ev(app, code, path="/"):
|
||||
prefix = "http://" + app + ".localhost:8765" + path
|
||||
script = """const done=arguments[arguments.length-1];const w=Services.wm.getMostRecentWindow('vulpes:host');
|
||||
if(!w?.document.getElementById('system')){done({missing:true});return;}
|
||||
const bc=(function find(b){if(b.currentWindowGlobal?.documentURI.spec.startsWith(PREFIX))return b;for(const c of b.children){const f=find(c);if(f)return f;}return null;})(w.document.getElementById('system').browsingContext);
|
||||
if(!bc){done({missing:true});return;}bc.currentWindowGlobal.getActor('VulpesProbe').sendQuery('Evaluate',CODE).then(result=>done({result}),error=>done({error:String(error)}));""".replace(
|
||||
"PREFIX", json.dumps(prefix)
|
||||
).replace(
|
||||
"CODE", json.dumps(code)
|
||||
)
|
||||
r = client.call(
|
||||
"WebDriver:ExecuteAsyncScript",
|
||||
{
|
||||
"script": script,
|
||||
"args": [],
|
||||
"newSandbox": True,
|
||||
"sandbox": "system",
|
||||
"scriptTimeout": 15000,
|
||||
},
|
||||
)["value"]
|
||||
if "error" in r:
|
||||
raise AssertionError(r)
|
||||
return r.get("result")
|
||||
|
||||
def wait(app, code, path="/"):
|
||||
for _ in range(70):
|
||||
r = ev(app, code, path)
|
||||
if r:
|
||||
return r
|
||||
time.sleep(0.15)
|
||||
raise AssertionError("Timeout: " + app + " " + code)
|
||||
|
||||
def check(name, condition):
|
||||
results[name] = condition
|
||||
print(name + ": " + json.dumps(condition, ensure_ascii=False), flush=True)
|
||||
assert condition is True, (name, condition)
|
||||
|
||||
def launch(app, entry=None):
|
||||
ev(
|
||||
"system",
|
||||
'await VulpesCompat.call("apps.launch",'
|
||||
+ json.dumps(
|
||||
{"manifestURL": f"http://{app}.localhost:8765/manifest.webapp", "entryPoint": entry}
|
||||
)
|
||||
+ ");return true;",
|
||||
)
|
||||
wait(app, "return document.readyState==='complete';")
|
||||
time.sleep(0.5)
|
||||
|
||||
def focus():
|
||||
client.execute(
|
||||
"const w=Services.wm.getMostRecentWindow('vulpes:host');w.focus();w.document.getElementById('system').focus();return true;"
|
||||
)
|
||||
subprocess.run(
|
||||
["xdotool", "search", "--name", "^Vulpes", "windowraise", "windowfocus"],
|
||||
check=True,
|
||||
stdout=subprocess.DEVNULL,
|
||||
)
|
||||
|
||||
def tap(app, selector, path="/"):
|
||||
pos = ev(
|
||||
app,
|
||||
"const e="
|
||||
+ selector
|
||||
+ ';e.scrollIntoView({block:"nearest"});await new Promise(r=>setTimeout(r,150));const b=e.getBoundingClientRect();return {x:mozInnerScreenX+b.x+b.width/2,y:mozInnerScreenY+b.y+b.height/2};',
|
||||
path,
|
||||
)
|
||||
focus()
|
||||
subprocess.run(
|
||||
["xdotool", "mousemove", str(round(pos["x"])), str(round(pos["y"])), "click", "1"],
|
||||
check=True,
|
||||
)
|
||||
time.sleep(0.4)
|
||||
|
||||
def shot(name):
|
||||
focus()
|
||||
subprocess.run(
|
||||
["import", "-window", "root", str(ROOT / "logs" / ("feedback-" + name + ".png"))],
|
||||
check=True,
|
||||
)
|
||||
|
||||
try:
|
||||
wait(
|
||||
"system",
|
||||
"return document.body?.getAttribute('ready-state')==='fullyLoaded' && !!document.querySelector('#statusbar-time');",
|
||||
)
|
||||
ev("system", "ScreenManager.turnScreenOn(true);return true;")
|
||||
time.sleep(.5)
|
||||
ev("system", "lockScreen.unlock(true);return true;")
|
||||
wait("system", "return !lockScreen.locked;")
|
||||
time.sleep(.5)
|
||||
if args.restart_check:
|
||||
launch("communications", "contacts")
|
||||
check(
|
||||
"contacts-survive-restart",
|
||||
ev(
|
||||
"communications",
|
||||
"const c=await navigator.mozContacts.find({filterBy:['name'],filterValue:'Vulpes Regression',filterOp:'equals'});return c.length===1 && c[0].tel[0].value==='0612345678' && Object.prototype.toString.call(c[0].updated)==='[object Date]' && Number.isFinite(c[0].updated.getTime());",
|
||||
"/contacts/",
|
||||
),
|
||||
)
|
||||
check(
|
||||
"passcode-survives-restart",
|
||||
ev(
|
||||
"system",
|
||||
"await LazyLoader.load('/shared/js/passcode_helper.js');return await PasscodeHelper.check('9876');",
|
||||
),
|
||||
)
|
||||
raise SystemExit(0)
|
||||
check(
|
||||
"clock-at-right",
|
||||
ev(
|
||||
"system",
|
||||
"const b=document.querySelector('#statusbar-time').getBoundingClientRect();return b.right>innerWidth-15 && b.left>innerWidth/2;",
|
||||
),
|
||||
)
|
||||
check(
|
||||
"status-tray-icons",
|
||||
ev(
|
||||
"system",
|
||||
"UtilityTray.show(true);await new Promise(r=>setTimeout(r,300));return [...document.querySelectorAll('#quick-settings a')].filter(e=>e.getBoundingClientRect().width>0 && e.getBoundingClientRect().top>0).length>=4;",
|
||||
),
|
||||
)
|
||||
ev("system", "UtilityTray.hide(true);return true;")
|
||||
launch("communications", "dialer")
|
||||
tap("communications", "document.querySelector('[data-value=\"1\"]')", "/dialer/")
|
||||
tap("communications", "document.querySelector('[data-value=\"2\"]')", "/dialer/")
|
||||
check(
|
||||
"dialpad-physical-taps",
|
||||
ev("communications", "return KeypadManager._phoneNumber.endsWith('12');", "/dialer/"),
|
||||
)
|
||||
tap("communications", "document.getElementById('option-recents')", "/dialer/")
|
||||
check(
|
||||
"dialer-recents-tab",
|
||||
wait(
|
||||
"communications",
|
||||
"return document.body.innerText.includes('Journal d’appels');",
|
||||
"/dialer/",
|
||||
),
|
||||
)
|
||||
tap("communications", "document.getElementById('option-contacts')", "/dialer/")
|
||||
check(
|
||||
"dialer-contacts-tab",
|
||||
wait(
|
||||
"communications",
|
||||
"return document.readyState==='complete' && document.body.innerText.includes('Contacts');",
|
||||
"/contacts/",
|
||||
),
|
||||
)
|
||||
shot("contacts")
|
||||
check(
|
||||
"contact-store-roundtrip",
|
||||
ev(
|
||||
"communications",
|
||||
"""const old=await navigator.mozContacts.find({filterBy:['name'],filterValue:'Vulpes Regression',filterOp:'equals'});for(const c of old)await navigator.mozContacts.remove(c);const c=new mozContact({name:['Vulpes Regression'],givenName:['Vulpes'],familyName:['Regression'],tel:[{value:'0612345678',type:['mobile']}]});await navigator.mozContacts.save(c);window.__testContactId=c.id;const list=await navigator.mozContacts.find({filterBy:['id'],filterValue:c.id,filterOp:'equals'});return list.length===1 && list[0].name[0]==='Vulpes Regression';""",
|
||||
"/contacts/",
|
||||
),
|
||||
)
|
||||
check(
|
||||
"contact-list-updates",
|
||||
wait(
|
||||
"communications",
|
||||
"return document.body.innerText.includes('Regression');",
|
||||
"/contacts/",
|
||||
),
|
||||
)
|
||||
check(
|
||||
"contacts-permission-isolation",
|
||||
ev(
|
||||
"homescreen",
|
||||
"const r=await navigator.vulpesRequest({version:1,id:500,method:'contacts.request',params:{operation:'all'}});return r.error?.code==='PERMISSION_DENIED';",
|
||||
),
|
||||
)
|
||||
launch("sms")
|
||||
check(
|
||||
"sms-empty-view",
|
||||
wait("sms", "return document.body.innerText.includes('Aucun message');"),
|
||||
)
|
||||
shot("sms")
|
||||
tap("sms", "document.querySelector('#threads-composer-link')")
|
||||
check(
|
||||
"sms-composer-ready",
|
||||
wait(
|
||||
"sms",
|
||||
"return location.hash==='#/composer' && !!document.querySelector('#messages-input');",
|
||||
),
|
||||
)
|
||||
tap("sms", "document.querySelector('#messages-input')")
|
||||
subprocess.run(["xdotool", "type", "--clearmodifiers", "Brouillon Vulpes"], check=True)
|
||||
check(
|
||||
"sms-composer-typing",
|
||||
wait(
|
||||
"sms",
|
||||
"return document.querySelector('#messages-input').textContent.includes('Brouillon Vulpes');",
|
||||
),
|
||||
)
|
||||
check(
|
||||
"sms-no-fake-send",
|
||||
ev(
|
||||
"sms",
|
||||
"try{await navigator.mozMobileMessage.send('0612345678','test');return false;}catch(e){return e.name==='RadioDisabledError';}",
|
||||
),
|
||||
)
|
||||
check(
|
||||
"sms-segment-count",
|
||||
ev(
|
||||
"sms",
|
||||
"const s=await navigator.mozMobileMessage.getSegmentInfoForText('a'.repeat(161));return s.segments===2 && s.charsPerSegment===153;",
|
||||
),
|
||||
)
|
||||
launch("settings")
|
||||
ev(
|
||||
"settings",
|
||||
"await new Promise(r=>require(['modules/settings_service'],s=>{s.navigate('root');r();}));return true;",
|
||||
)
|
||||
wait("settings", "return !!document.querySelector('#root.current');")
|
||||
time.sleep(0.5)
|
||||
tap("settings", "document.querySelector('a[href=\"#about\"]')")
|
||||
wait("settings", "return !!document.querySelector('#about.current');")
|
||||
check(
|
||||
"back-arrow-visible",
|
||||
ev(
|
||||
"settings",
|
||||
"const h=document.querySelector('#about gaia-header'),b=h.shadowRoot.querySelector('button');return getComputedStyle(h).display==='block' && getComputedStyle(b,'::before').content==='\"left\"' && b.getBoundingClientRect().width===50;",
|
||||
),
|
||||
)
|
||||
tap("settings", "document.querySelector('a[href=\"#about-moreInfo\"]')")
|
||||
check(
|
||||
"actual-versions-in-panel",
|
||||
wait(
|
||||
"settings",
|
||||
"return document.querySelector('#about-moreInfo.current') && document.body.innerText.includes("
|
||||
+ json.dumps(engine)
|
||||
+ ") && document.body.innerText.includes('2.7');",
|
||||
),
|
||||
)
|
||||
shot("versions")
|
||||
check(
|
||||
"passcode-byte-roundtrip",
|
||||
ev(
|
||||
"system",
|
||||
"await LazyLoader.load('/shared/js/passcode_helper.js');await PasscodeHelper.set('9876');const yes=await PasscodeHelper.check('9876'),no=await PasscodeHelper.check('1111');return yes && !no;",
|
||||
),
|
||||
)
|
||||
check(
|
||||
"iac-forged-route-denied",
|
||||
ev(
|
||||
"homescreen",
|
||||
"try{await VulpesCompat.call('iac.connect',{keyword:'search'});return false;}catch(e){return e.name==='CONNECTION_DENIED';}",
|
||||
),
|
||||
)
|
||||
launch("search")
|
||||
check(
|
||||
"firefox-newtab-ready",
|
||||
wait(
|
||||
"search",
|
||||
"return document.readyState==='complete' && !!document.querySelector('#top-sites');",
|
||||
"/newtab.html",
|
||||
),
|
||||
)
|
||||
tap("system", "document.querySelector('.appWindow.active .urlbar-hit-area')")
|
||||
wait("system", "return document.querySelector('#rocketbar').classList.contains('active');")
|
||||
tap("system", "document.querySelector('#rocketbar-input')")
|
||||
subprocess.run(
|
||||
[
|
||||
"xdotool",
|
||||
"key",
|
||||
"ctrl+a",
|
||||
"type",
|
||||
"--clearmodifiers",
|
||||
"--delay",
|
||||
"40",
|
||||
"https://example.com",
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
check(
|
||||
"rocketbar-physical-typing",
|
||||
ev(
|
||||
"system",
|
||||
"return document.querySelector('#rocketbar-input').value==='https://example.com';",
|
||||
),
|
||||
)
|
||||
subprocess.run(["xdotool", "key", "Return"], check=True)
|
||||
check(
|
||||
"rocketbar-submit-creates-browser",
|
||||
wait(
|
||||
"system",
|
||||
"return [...document.querySelectorAll('iframe')].some(f=>f.src==='https://example.com/');",
|
||||
),
|
||||
)
|
||||
time.sleep(1)
|
||||
shot("browser")
|
||||
client.execute(
|
||||
"Services.wm.getMostRecentWindow('vulpes:host').document.getElementById('home').click();return true;"
|
||||
)
|
||||
time.sleep(0.7)
|
||||
check(
|
||||
"browser-return-home",
|
||||
client.execute(
|
||||
"return [...Services.wm.getMostRecentWindow('vulpes:host').document.querySelectorAll('browser')].filter(b=>b.id!=='system').every(b=>b.style.visibility==='hidden');"
|
||||
),
|
||||
)
|
||||
check(
|
||||
"apps-fill-height",
|
||||
ev(
|
||||
"system",
|
||||
"return !document.querySelector('#screen').classList.contains('software-button-enabled');",
|
||||
),
|
||||
)
|
||||
print(
|
||||
"APP DIAGNOSTICS",
|
||||
json.dumps(
|
||||
{
|
||||
a: ev(a, "return window.__vulpesDiagnostics;")
|
||||
for a in ["system", "communications", "sms", "settings", "search"]
|
||||
},
|
||||
ensure_ascii=False,
|
||||
),
|
||||
flush=True,
|
||||
)
|
||||
finally:
|
||||
(
|
||||
ROOT
|
||||
/ "logs"
|
||||
/ ("feedback-restart-results.json" if args.restart_check else "feedback-results.json")
|
||||
).write_text(json.dumps(results, indent=2) + "\n")
|
||||
Loading…
Reference in a new issue