fix: keep retained mobile planning available (#289)
This commit is contained in:
1 parent
80417abd5b
commit
8c4e729c4a
5 files changed
+121
-20
No files matched your search
+58
-5
@@ -825,7 +825,7 @@ process.stdout.write(JSON.stringify({{
|
||||
)
|
||||
|
||||
assert json.loads(result.stdout) == {
|
||||
"deferred": True,
|
||||
"deferred": "deferred",
|
||||
"timmy": {
|
||||
"active": 0,
|
||||
"later": [{
|
||||
@@ -838,6 +838,33 @@ process.stdout.write(JSON.stringify({{
|
||||
}
|
||||
|
||||
|
||||
def test_later_queue_reports_invalid_identity_and_failed_storage_without_false_success():
|
||||
script = f"""
|
||||
const createLaterWork = require({json.dumps(str(LATER_WORK))});
|
||||
let login = '';
|
||||
const item = {{kind:'issue',repository:'stackchain/api',number:17}};
|
||||
const unavailable = createLaterWork({{
|
||||
storage: {{getItem:() => null,setItem:() => {{ throw new Error('quota'); }},removeItem:() => {{}}}},
|
||||
getLogin:() => login, now:() => new Date('2026-08-08T12:00:00Z'),
|
||||
}});
|
||||
const noIdentity = unavailable.defer(item, new Date('2026-08-08T16:00:00Z'));
|
||||
login = 'timmy';
|
||||
const invalid = unavailable.defer(item, new Date('2026-08-08T11:00:00Z'));
|
||||
const failedWrite = unavailable.defer(item, new Date('2026-08-08T16:00:00Z'));
|
||||
process.stdout.write(JSON.stringify({{noIdentity, invalid, failedWrite}}));
|
||||
"""
|
||||
|
||||
result = subprocess.run(
|
||||
["node", "-e", script], check=True, capture_output=True, text=True
|
||||
)
|
||||
|
||||
assert json.loads(result.stdout) == {
|
||||
"noIdentity": "unavailable",
|
||||
"invalid": "invalid",
|
||||
"failedWrite": "unavailable",
|
||||
}
|
||||
|
||||
|
||||
def test_later_queue_prunes_missing_work_and_wakes_expired_items_without_reload():
|
||||
script = f"""
|
||||
const createLaterWork = require({json.dumps(str(LATER_WORK))});
|
||||
@@ -964,7 +991,7 @@ let sessionActive = false;
|
||||
const controller = createDetailDefer({{
|
||||
laterWork: {{
|
||||
presetUntil:preset => new Date(preset === 'today' ? '2026-08-08T16:00:00Z' : '2026-08-09T09:00:00Z'),
|
||||
defer:(item, until) => {{ calls.push(['defer', item.title, until.toISOString()]); return true; }},
|
||||
defer:(item, until) => {{ calls.push(['defer', item.title, until.toISOString()]); return 'deferred'; }},
|
||||
}},
|
||||
session: {{ active:() => sessionActive }},
|
||||
close:() => calls.push(['close']),
|
||||
@@ -1000,6 +1027,32 @@ process.stdout.write(JSON.stringify({{outside,session,calls}}));
|
||||
}
|
||||
|
||||
|
||||
def test_detail_defer_reports_storage_failure_without_closing_or_refreshing():
|
||||
script = f"""
|
||||
const createDetailDefer = require({json.dumps(str(DETAIL_DEFER))});
|
||||
const calls = [];
|
||||
const controller = createDetailDefer({{
|
||||
laterWork: {{
|
||||
presetUntil:() => new Date('2026-08-08T16:00:00Z'),
|
||||
defer:() => 'unavailable',
|
||||
}},
|
||||
session: {{active:() => false}},
|
||||
close:() => calls.push('close'), refresh:() => calls.push('refresh'),
|
||||
focus:() => calls.push('focus'), announce:message => calls.push(message),
|
||||
}});
|
||||
const saved = controller.defer({{kind:'issue',repository:'stackchain/api',number:17}}, 'today');
|
||||
process.stdout.write(JSON.stringify({{saved,calls}}));
|
||||
"""
|
||||
result = subprocess.run(
|
||||
["node", "-e", script], check=True, capture_output=True, text=True
|
||||
)
|
||||
|
||||
assert json.loads(result.stdout) == {
|
||||
"saved": False,
|
||||
"calls": ["Could not save Later on this device."],
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_mobile_detail_sheets_offer_touch_safe_defer_without_a_gitea_mutation():
|
||||
html = await dashboard()
|
||||
@@ -1023,16 +1076,16 @@ async def test_mobile_my_work_wires_touch_safe_non_mutating_later_actions():
|
||||
assert 'data-work-filter="later"' in html
|
||||
assert 'data-work-count="later"' in html
|
||||
assert 'const laterWork = createLaterWork({' in html
|
||||
assert 'getLogin: () => confirmedOwnerLogin' in html
|
||||
assert 'getLogin: () => planningOwnerLogin' in html
|
||||
assert 'laterWork.partition(lastMyWork,' in html
|
||||
assert 'data-later-preset="today"' in html
|
||||
assert 'data-later-preset="tomorrow"' in html
|
||||
assert 'data-later-restore' in html
|
||||
assert "Deferred until ' + escapeHtml(fmt(item.deferred_until))" in html
|
||||
assert "laterWork.defer(item, laterWork.presetUntil(button.dataset.laterPreset))" in html
|
||||
assert "const result = laterWork.defer(item, until)" in html
|
||||
assert 'laterWork.restore(item)' in html
|
||||
assert '.later-actions button { min-height:44px;' in html
|
||||
assert 'Deferred work stays unread and unchanged in Gitea.' in html
|
||||
assert "'Deferred until ' + fmt(until)" in html
|
||||
|
||||
|
||||
def test_milestone_lane_composes_with_type_filter_and_updates_confirmed_snapshot():
|
||||
|
||||
@@ -94,3 +94,20 @@ async def test_dashboard_runs_the_curated_today_queue_as_a_mobile_work_flow():
|
||||
assert 'data-today-move="down"' in html
|
||||
assert 'Today is limited to 5 items' in html
|
||||
assert '.today-actions button' in html and 'min-height:44px' in html
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_retained_authenticated_context_keeps_local_planning_separate_from_fresh_delivery():
|
||||
html = await dashboard()
|
||||
|
||||
assert "let planningOwnerLogin = '';" in html
|
||||
assert html.count("getLogin: () => planningOwnerLogin") == 2
|
||||
assert "const retainedPlanningLogin = !snapshot.context.error ?" in html
|
||||
assert "planningOwnerLogin = retainedPlanningLogin;" in html
|
||||
assert "button.disabled = !planningOwnerLogin;" in html
|
||||
assert "activeFlushLogin = contextIdentityFresh ?" in html
|
||||
assert "getOwnerLogin: () => confirmedOwnerLogin" in html
|
||||
assert "Planning is unavailable until your operator identity is restored." in html
|
||||
assert "Could not save Today on this device." in html
|
||||
assert "Could not save Later on this device." in html
|
||||
assert "data-planning-disabled" in html
|
||||
Reference in new issue
Block a user