71 lines
3.1 KiB
Python
71 lines
3.1 KiB
Python
import json
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
|
|
LOADER = Path(__file__).parents[1] / "frontend" / "feature-loader.js"
|
|
|
|
|
|
def run_loader(scenario: str) -> dict:
|
|
harness = f"""
|
|
const fs=require('fs'); const vm=require('vm');
|
|
const state={{appends:0, removed:0}};
|
|
const document={{
|
|
head:{{appendChild(node){{ state.appends++; state.node=node; }} }},
|
|
createElement(){{ return {{remove(){{state.removed++;}}}}; }},
|
|
}};
|
|
const context={{document, setTimeout, clearTimeout, console}};
|
|
context.globalThis=context;
|
|
vm.createContext(context);
|
|
vm.runInContext(fs.readFileSync({json.dumps(str(LOADER))},'utf8'),context);
|
|
const createFeatureLoader=context.createFeatureLoader;
|
|
(async()=>{{ {scenario} }})().catch(error=>{{console.error(error);process.exit(1);}});
|
|
"""
|
|
completed = subprocess.run(["node", "-e", harness], check=True, capture_output=True, text=True)
|
|
return json.loads(completed.stdout)
|
|
|
|
|
|
def test_concurrent_feature_requests_share_one_script():
|
|
result = run_loader("""
|
|
const loader=createFeatureLoader({document, urls:{'issue-capture':'feature-a.js'}, timeoutMs:100});
|
|
const first=loader.load('issue-capture'); const second=loader.load('issue-capture');
|
|
state.node.onload(); await Promise.all([first,second]);
|
|
console.log(JSON.stringify({appends:state.appends,same:first===second,ready:loader.ready('issue-capture')}));
|
|
""")
|
|
assert result == {"appends": 1, "same": True, "ready": True}
|
|
|
|
|
|
def test_failed_feature_request_can_retry_without_reload():
|
|
result = run_loader("""
|
|
const loader=createFeatureLoader({document, urls:{'issue-capture':'feature-a.js'}, timeoutMs:100});
|
|
const failed=loader.load('issue-capture').catch(error=>error.message); state.node.onerror();
|
|
const message=await failed; const retry=loader.load('issue-capture'); state.node.onload(); await retry;
|
|
console.log(JSON.stringify({appends:state.appends,removed:state.removed,message,ready:loader.ready('issue-capture')}));
|
|
""")
|
|
assert result == {"appends": 2, "removed": 1, "message": "Could not load issue capture.", "ready": True}
|
|
|
|
|
|
def test_feature_gate_exposes_loading_failure_and_success_to_mobile_controls():
|
|
result = run_loader("""
|
|
const trigger={disabled:false}; const status={textContent:''}; let opened=0;
|
|
const loader=createFeatureLoader({document, urls:{'issue-capture':'feature-a.js'}, timeoutMs:100});
|
|
const failed=loader.run('issue-capture',{trigger,status},()=>{opened++;});
|
|
const loading={disabled:trigger.disabled,status:status.textContent}; state.node.onerror();
|
|
const first=await failed;
|
|
const failedState={disabled:trigger.disabled,status:status.textContent,opened};
|
|
const retry=loader.run('issue-capture',{trigger,status},()=>{opened++;}); state.node.onload();
|
|
const second=await retry;
|
|
console.log(JSON.stringify({loading,failedState,first,second,opened,finalStatus:status.textContent}));
|
|
""")
|
|
assert result == {
|
|
"loading": {"disabled": True, "status": "Loading issue capture…"},
|
|
"failedState": {
|
|
"disabled": False,
|
|
"status": "Issue capture could not load. Tap New issue to retry.",
|
|
"opened": 0,
|
|
},
|
|
"first": False,
|
|
"second": True,
|
|
"opened": 1,
|
|
"finalStatus": "",
|
|
} |