|
|
|
@@ -185,12 +185,86 @@ process.stdout.write(JSON.stringify({{opened,cancelled,started,expired,final:{{c
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_confirming_the_account_renders_a_persisted_break_immediately():
|
|
|
|
|
dashboard = (ROOT / "frontend" / "dashboard.js").read_text()
|
|
|
|
|
confirmation = dashboard.split("if (activeFlushLogin) {", 1)[1].split("}", 1)[0]
|
|
|
|
|
def test_identity_ready_restore_renders_break_again_after_sync_recovery_settles():
|
|
|
|
|
script = f"""
|
|
|
|
|
const createBreak = require({json.dumps(str(BREAK))});
|
|
|
|
|
global.createTodayBreak = createBreak;
|
|
|
|
|
global.setInterval = () => 1;
|
|
|
|
|
global.clearInterval = () => {{}};
|
|
|
|
|
Date.now = () => 100000;
|
|
|
|
|
const createTimer = require({json.dumps(str(TIMER))});
|
|
|
|
|
const createSync = require({json.dumps(str(ROOT / "frontend" / "today-sync.js"))});
|
|
|
|
|
const values = new Map();
|
|
|
|
|
const storage = {{
|
|
|
|
|
get length(){{return values.size;}},
|
|
|
|
|
key:index=>Array.from(values.keys())[index]??null,
|
|
|
|
|
getItem:key=>values.get(key)||null,
|
|
|
|
|
setItem:(key,value)=>values.set(key,value),
|
|
|
|
|
removeItem:key=>values.delete(key),
|
|
|
|
|
}};
|
|
|
|
|
let login = '';
|
|
|
|
|
values.set('stackchain.today-timer.v1.timmy', JSON.stringify({{
|
|
|
|
|
version:1, active_identity:'issue:r:42:',
|
|
|
|
|
entries:{{'issue:r:42:':{{elapsed_ms:12000,started_at:null,running:false}}}},
|
|
|
|
|
away_at:null,pending_interruption:null,attention_interruption:null,capture_interruption:null,
|
|
|
|
|
search_interruption:null,detour_interruption:null,
|
|
|
|
|
timed_break:{{identity:'issue:r:42:',deadline_at:400000}},
|
|
|
|
|
}}));
|
|
|
|
|
const status = {{hidden:false,textContent:''}}, resume = {{hidden:false,addEventListener(){{}}}};
|
|
|
|
|
const opener = {{hidden:false,addEventListener(){{}}}};
|
|
|
|
|
const elements = {{'#today-break-status':[status],'#resume-today-break':[resume],'[data-today-break-open]':[opener]}};
|
|
|
|
|
const timer = createTimer({{storage,getLogin:()=>login,now:()=>100000}});
|
|
|
|
|
const view = createTimer.createView({{
|
|
|
|
|
timer,isActive:()=>true,queryAll:selector=>elements[selector]||[],
|
|
|
|
|
formatEstimate:value=>String(value),getItem:()=>({{title:'Ship mobile capture'}}),
|
|
|
|
|
}});
|
|
|
|
|
login = 'timmy';
|
|
|
|
|
values.set('stackchain.today-sync.v1.timmy.operation.broken', '{{not-json');
|
|
|
|
|
const statuses = [];
|
|
|
|
|
const sync = createSync({{
|
|
|
|
|
storage,getLogin:()=>login,now:()=>100000,
|
|
|
|
|
fetchJson:async()=>({{revision:1,ids:['issue:r:42:'],capacity_minutes:null,estimates:{{}}}}),
|
|
|
|
|
onStatus:(state,detail)=>statuses.push([state,detail.discarded||0]),
|
|
|
|
|
}});
|
|
|
|
|
const recovery = sync.flush();
|
|
|
|
|
const restoring = view.restore(recovery);
|
|
|
|
|
const immediate = {{hidden:status.hidden,text:status.textContent,openerHidden:opener.hidden}};
|
|
|
|
|
status.hidden = true; status.textContent = ''; opener.hidden = false;
|
|
|
|
|
restoring.then(result => {{
|
|
|
|
|
const settled = {{hidden:status.hidden,text:status.textContent,openerHidden:opener.hidden}};
|
|
|
|
|
status.hidden = true; status.textContent = ''; opener.hidden = false;
|
|
|
|
|
return view.restore(Promise.reject(new Error('coordinator unavailable'))).then(rejected =>
|
|
|
|
|
process.stdout.write(JSON.stringify({{
|
|
|
|
|
immediate, settled, rejectedSettled:{{hidden:status.hidden,text:status.textContent,openerHidden:opener.hidden}},
|
|
|
|
|
result,rejected,statuses,
|
|
|
|
|
}}))
|
|
|
|
|
);
|
|
|
|
|
}});
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
assert "confirmedOwnerLogin = activeFlushLogin;" in confirmation
|
|
|
|
|
assert "timerView.render();" in confirmation
|
|
|
|
|
assert run_node(script) == {
|
|
|
|
|
"immediate": {
|
|
|
|
|
"hidden": False,
|
|
|
|
|
"text": "On break · resume in 5:00",
|
|
|
|
|
"openerHidden": True,
|
|
|
|
|
},
|
|
|
|
|
"settled": {
|
|
|
|
|
"hidden": False,
|
|
|
|
|
"text": "On break · resume in 5:00",
|
|
|
|
|
"openerHidden": True,
|
|
|
|
|
},
|
|
|
|
|
"rejectedSettled": {
|
|
|
|
|
"hidden": False,
|
|
|
|
|
"text": "On break · resume in 5:00",
|
|
|
|
|
"openerHidden": True,
|
|
|
|
|
},
|
|
|
|
|
"result": True,
|
|
|
|
|
"rejected": True,
|
|
|
|
|
"statuses": [["recovered", 1]],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dashboard = (ROOT / "frontend" / "dashboard.js").read_text()
|
|
|
|
|
assert "timerView.restore(todaySync.flush());" in dashboard
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_timed_break_is_packaged_as_an_accessible_mobile_flow():
|
|
|
|
|