feat: show timed Today breaks on lock screen (Closes #1050)
This commit is contained in:
1 parent
af86034339
commit
ed15392097
4 files changed
+112
-12
No files matched your search
@@ -531,6 +531,40 @@ def test_active_today_message_replaces_one_privacy_safe_lock_screen_notification
|
||||
assert "secret" not in json.dumps(result["notifications"])
|
||||
|
||||
|
||||
def test_live_today_break_shows_return_time_and_safe_resume_controls():
|
||||
result = run_worker_scenario(
|
||||
"""
|
||||
const deadline = Date.now() + 5 * 60 * 1000;
|
||||
await dispatchMessage({type:'stackchain-today-lock-screen',active:true,running:false,breakDeadlineAt:deadline,identity:'secret/repo#42',actionToken:'opaque-token-1234567890'});
|
||||
process.stdout.write(JSON.stringify(state));
|
||||
"""
|
||||
)
|
||||
|
||||
notification = result["notifications"][0]
|
||||
assert notification["title"] == "On a Today break"
|
||||
assert notification["options"]["body"].startswith("Return at ")
|
||||
assert notification["options"]["actions"] == [
|
||||
{"action": "resume-today", "title": "Resume now"},
|
||||
{"action": "open-today", "title": "Open Today"},
|
||||
]
|
||||
assert notification["options"]["data"]["actionToken"] == "opaque-token-1234567890"
|
||||
assert "secret" not in json.dumps(notification)
|
||||
|
||||
|
||||
def test_invalid_or_expired_break_deadline_falls_back_to_paused_controls():
|
||||
result = run_worker_scenario(
|
||||
"""
|
||||
await dispatchMessage({type:'stackchain-today-lock-screen',active:true,running:false,breakDeadlineAt:Date.now()-1,actionToken:'opaque-token-1234567890'});
|
||||
process.stdout.write(JSON.stringify(state));
|
||||
"""
|
||||
)
|
||||
|
||||
assert result["notifications"][0]["title"] == "Today session paused"
|
||||
assert result["notifications"][0]["options"]["actions"][0] == {
|
||||
"action": "resume-today", "title": "Resume"
|
||||
}
|
||||
|
||||
|
||||
def test_inactive_today_message_closes_the_lock_screen_notification():
|
||||
result = run_worker_scenario(
|
||||
"""
|
||||
@@ -610,6 +644,27 @@ def test_finish_today_lock_screen_action_forwards_only_its_opaque_token():
|
||||
}]
|
||||
|
||||
|
||||
def test_break_resume_action_forwards_opaque_token_to_reject_stale_breaks():
|
||||
result = run_worker_scenario(
|
||||
"""
|
||||
state.clientMessages=[];
|
||||
state.clientList=[{
|
||||
url:'https://forge.example/dashboard/#/my-work/today',
|
||||
postMessage:message=>state.clientMessages.push(message),
|
||||
focus:async()=>state.focused.push('today'),
|
||||
}];
|
||||
await dispatchNotificationClick('#/my-work/today','resume-today',null,'stackchain-today-session',null,'opaque-token-1234567890');
|
||||
process.stdout.write(JSON.stringify(state));
|
||||
"""
|
||||
)
|
||||
|
||||
assert result["clientMessages"] == [{
|
||||
"type": "stackchain-today-timer-action",
|
||||
"action": "resume",
|
||||
"actionToken": "opaque-token-1234567890",
|
||||
}]
|
||||
|
||||
|
||||
def test_background_mutation_abort_also_cancels_stalled_csrf_lookup():
|
||||
result = run_worker_scenario(
|
||||
"""
|
||||
|
||||
@@ -28,7 +28,7 @@ const historyRef = {replaceState:(_a,_b,url)=>{locationRef.href=new URL(url, loc
|
||||
let tokenCounter = 0;
|
||||
const tokens = ['opaque-token-1234567890', 'new-opaque-token-0987654321'];
|
||||
(async()=>{
|
||||
const lockScreen = createTodayLockScreen({storage,getLogin:()=> 'Timmy',serviceWorker,NotificationRef,control,status,locationRef,historyRef,randomToken:()=> tokens[tokenCounter++],fingerprint:async (_token, identity)=>identity.startsWith('issue:') ? 'opaque-issue-fingerprint' : 'opaque-pull-fingerprint',onAction:(action, identity)=>actions.push([action, identity])});
|
||||
const lockScreen = createTodayLockScreen({storage,getLogin:()=> 'Timmy',serviceWorker,NotificationRef,control,status,locationRef,historyRef,randomToken:()=> tokens[tokenCounter++],fingerprint:async (_token, identity)=>identity.includes('break:1000000') ? 'opaque-break-fingerprint' : identity.startsWith('issue:') ? 'opaque-issue-fingerprint' : 'opaque-pull-fingerprint',onAction:(action, identity)=>actions.push([action, identity])});
|
||||
%SCENARIO%
|
||||
})().catch(error=>{console.error(error);process.exit(1)});
|
||||
""".replace("%SCENARIO%", scenario)
|
||||
@@ -110,6 +110,29 @@ def test_finish_action_is_bound_to_the_exact_active_identity_and_consumed_once()
|
||||
assert all("private/repo" not in json.dumps(message) for message in result["messages"])
|
||||
|
||||
|
||||
def test_break_sync_carries_deadline_and_resume_is_bound_to_that_exact_break():
|
||||
result = run_scenario(r"""
|
||||
await lockScreen.enable();
|
||||
await lockScreen.sync({identity:'issue:private/repo:42:',running:false,break_deadline_at:1000000}, true);
|
||||
const resumed = await lockScreen.consumeAction('resume', 'opaque-token-1234567890');
|
||||
await lockScreen.sync({identity:'issue:private/repo:42:',running:false,break_deadline_at:2000000}, true);
|
||||
const stale = await lockScreen.consumeAction('resume', 'opaque-token-1234567890');
|
||||
process.stdout.write(JSON.stringify({resumed,stale,actions,messages,stored:[...values.entries()]}));
|
||||
""")
|
||||
|
||||
assert result["resumed"] is True
|
||||
assert result["stale"] is False
|
||||
assert result["actions"] == [["resume", "issue:private/repo:42:"]]
|
||||
assert result["messages"][0] == {
|
||||
"type": "stackchain-today-lock-screen",
|
||||
"active": True,
|
||||
"running": False,
|
||||
"breakDeadlineAt": 1_000_000,
|
||||
"actionToken": "opaque-token-1234567890",
|
||||
}
|
||||
assert "private/repo" not in json.dumps(result["messages"])
|
||||
|
||||
|
||||
def test_cold_launch_finish_action_is_removed_from_history_before_completion():
|
||||
result = run_scenario(r"""
|
||||
await lockScreen.enable();
|
||||
|
||||
Reference in new issue
Block a user