import json import subprocess from pathlib import Path BOOTSTRAP = Path(__file__).parents[1] / "frontend" / "workspace-bootstrap.js" INDEX = Path(__file__).parents[1] / "frontend" / "index.html" CSS = Path(__file__).parents[1] / "frontend" / "dashboard.css" def run_bootstrap(scenario: str) -> dict: harness = f""" const loadWorkspace = require({json.dumps(str(BOOTSTRAP))}); (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_workspace_bootstrap_loads_content_addressed_feature_before_startup(): result = run_bootstrap(""" const status={textContent:''}; const document={ querySelector(selector) { if (selector === 'meta[name="stackchain-feature-today-timer"]') return {content:'feature-workspace-abc.js'}; if (selector === 'meta[name="stackchain-feature-planning"]') return {content:'feature-planning-def.js'}; if (selector === '#my-work-action-status') return status; return null; } }; const requested=[]; const createLoader=options=>({load:async name=>{requested.push(name + ':' + options.urls[name]);}}); await loadWorkspace({document,createLoader}); console.log(JSON.stringify({requested,status:status.textContent})); """) assert result == { "requested": [ "today-timer:feature-workspace-abc.js", "planning:feature-planning-def.js", ], "status": "", } def test_workspace_bootstrap_recovers_one_transient_failure_in_place(): result = run_bootstrap(""" const status={textContent:''}; const retry={hidden:true,disabled:false}; let attempts=0; const document={querySelector(selector) { if (selector.startsWith('meta[')) return {content:'feature-workspace-abc.js'}; if (selector === '#my-work-action-status') return status; if (selector === '#retry-workspace') return retry; return null; }}; const createLoader=()=>({load:async()=>{attempts++; if (attempts === 1) throw new Error('brief outage');}}); const schedule=callback=>{callback();}; await loadWorkspace({document,createLoader,schedule}); console.log(JSON.stringify({attempts,status:status.textContent,retryHidden:retry.hidden})); """) assert result == {"attempts": 4, "status": "", "retryHidden": True} def test_workspace_bootstrap_offers_single_flight_manual_retry_without_reloading(): result = run_bootstrap(""" const status={textContent:''}; const listeners={}; let reloads=0; let attempts=0; const retry={hidden:true,disabled:false,addEventListener(name,callback){listeners[name]=callback;}}; const document={querySelector(selector) { if (selector.startsWith('meta[')) return {content:'feature-workspace-abc.js'}; if (selector === '#my-work-action-status') return status; if (selector === '#retry-workspace') return retry; return null; }}; const window={location:{reload(){reloads++;}},addEventListener(){},removeEventListener(){}}; const createLoader=()=>({load:async()=>{attempts++; if (attempts < 5) throw new Error('offline');}}); const loading=loadWorkspace({document,window,createLoader,schedule:callback=>callback()}); await new Promise(resolve=>setImmediate(resolve)); const offered={hidden:retry.hidden,disabled:retry.disabled,status:status.textContent}; const first=listeners.click(); const second=listeners.click(); await Promise.all([first,second,loading]); console.log(JSON.stringify({attempts,reloads,offered,status:status.textContent,retryHidden:retry.hidden})); """) assert result == { "attempts": 6, "reloads": 0, "offered": { "hidden": False, "disabled": False, "status": "Workspace unavailable. Reconnect or retry.", }, "status": "", "retryHidden": True, } def test_workspace_retry_control_is_accessible_and_touch_safe(): index = INDEX.read_text() css = CSS.read_text() assert '' in index assert ".retry-work-route { min-height:44px;" in css def test_workspace_bootstrap_reconnect_retries_in_place_without_reloading(): result = run_bootstrap(""" const status={textContent:''}; const listeners={}; let reloads=0; let attempts=0; const retry={hidden:true,disabled:false,addEventListener(){},removeEventListener(){}}; const document={querySelector(selector) { if (selector.startsWith('meta[')) return {content:'feature-workspace-abc.js'}; if (selector === '#my-work-action-status') return status; if (selector === '#retry-workspace') return retry; return null; }}; const window={ location:{reload(){reloads++;}}, addEventListener(name,callback) { listeners[name]=callback; }, removeEventListener(name,callback) { if (listeners[name] === callback) delete listeners[name]; }, }; const createLoader=()=>({load:async()=>{attempts++; if (attempts < 5) throw new Error('offline');}}); const loading=loadWorkspace({document,window,createLoader,schedule:callback=>callback()}); await new Promise(resolve=>setImmediate(resolve)); const waiting=Boolean(listeners.online); if (listeners.online) listeners.online(); await loading; console.log(JSON.stringify({attempts,waiting,reloads,status:status.textContent})); """) assert result == { "attempts": 6, "waiting": True, "reloads": 0, "status": "", } def test_workspace_bootstrap_replays_online_event_after_dashboard_registers_handlers(): result = run_bootstrap(""" const status={textContent:''}; const listeners={}; const document={querySelector(selector) { if (selector.startsWith('meta[')) return {content:'feature-workspace-abc.js'}; if (selector === '#my-work-action-status') return status; return null; }}; const window={ addEventListener(name,callback) { listeners[name]=callback; }, removeEventListener(name,callback) { if (listeners[name] === callback) delete listeners[name]; }, }; const createLoader=()=>({load:async()=>{listeners.online();}}); const lifecycle=await loadWorkspace({document,window,createLoader}); let reconnects=0; lifecycle.replayOnline(()=>{reconnects++;}); lifecycle.replayOnline(()=>{reconnects++;}); console.log(JSON.stringify({reconnects,listening:Boolean(listeners.online)})); """) assert result == {"reconnects": 1, "listening": False}