fix: preserve deadline calendar days (Closes #719)
CI / lint (pull_request) Successful in 1m23s
CI / build-release (pull_request) Successful in 4s
CI / release-candidate (pull_request) Has been skipped

This commit is contained in:
timmy committed 2026-08-13 07:56:26 +00:00
1 parent 9ec88179c3
commit dce9ae04c9
7 files changed
+135 -26

No files matched your search

+30
View File
@@ -54,6 +54,36 @@ async def test_deadline_reminder_sends_one_private_local_day_digest_and_deduplic
assert "private/repo" not in json.dumps(sent)
@pytest.mark.anyio
async def test_deadline_reminder_counts_calendar_days_per_device_timezone(tmp_path):
store = PushSubscriptionStore(tmp_path / "push.sqlite3")
for device, timezone_name in (("tokyo", "Asia/Tokyo"), ("la", "America/Los_Angeles")):
store.upsert(device, {
"endpoint": f"https://push.example/{device}",
"keys": {"p256dh": "public-key", "auth": "auth-secret"},
})
store.set_deadline_preferences(device, enabled=True, timezone=timezone_name, reminder_hour=0)
async def assigned():
return {"complete": True, "items": [
{"id": 1, "due_date": "2026-08-15T23:59:59Z"},
{"id": 2, "due_date": "2026-08-16T23:59:59Z"},
]}
sent = {}
async def send(subscription, payload):
device = subscription["endpoint"].rsplit("/", 1)[-1]
sent[device] = json.loads(payload)["deadline_count"]
delivered = await dispatch_deadline_reminders(
store, PushConfiguration("public", "private", "mailto:ops@example.com"),
assigned, send, now=datetime(2026, 8, 13, 23, 30, tzinfo=timezone.utc),
)
assert delivered == 2
assert sent == {"tokyo": 2, "la": 1}
@pytest.mark.anyio
async def test_deadline_reminder_fails_closed_for_incomplete_snapshot_and_before_local_hour(tmp_path):
store = PushSubscriptionStore(tmp_path / "push.sqlite3")
+18
View File
@@ -83,6 +83,24 @@ run();
}
def test_overdue_replan_orders_by_calendar_day_without_timezone_drift():
script = f"""
const createSweep = require({json.dumps(str(REPLAN))});
const sweep = createSweep({{update:async()=>({{}})}});
const started = sweep.start([
{{key:'o/r#2',repository:'o/r',number:2,due_date:'2026-08-13T01:00:00Z'}},
{{key:'o/r#1',repository:'o/r',number:1,due_date:'2026-08-12T23:59:59Z'}},
]);
process.stdout.write(JSON.stringify(started));
"""
environment = {**__import__('os').environ, "TZ": "Asia/Tokyo"}
result = subprocess.run(
["node", "-e", script], capture_output=True, text=True, env=environment
)
assert result.returncode == 0, result.stderr
assert json.loads(result.stdout)["current"] == "o/r#1"
@pytest.mark.anyio
async def test_mobile_agenda_exposes_thumb_safe_replan_controls_and_wires_existing_mutation():
html = await dashboard()
+33
View File
@@ -109,6 +109,14 @@ async def test_mobile_batch_planning_can_select_and_clear_active_queue_matches()
assert "max-width:100%" in html
@pytest.mark.anyio
async def test_issue_sheet_formats_due_date_as_a_calendar_day_without_local_timestamp_conversion():
source = await dashboard()
assert "formatCalendarDueDate(detail.due_date)" in source
assert "new Date(detail.due_date).toLocaleDateString()" not in source
def test_queue_finder_matches_repository_number_and_title_without_reordering():
script = f"""
const work = require({json.dumps(str(MY_WORK))});
@@ -173,6 +181,31 @@ process.stdout.write(JSON.stringify(work.agendaMyWork(items, new Date('2026-08-1
assert json.loads(result.stdout) == ["a/r#2", "a/r#10", "z/r#1"]
@pytest.mark.parametrize("timezone_name", ["Asia/Tokyo", "America/Los_Angeles"])
def test_mobile_agenda_preserves_the_gitea_calendar_day_in_every_timezone(timezone_name):
script = f"""
const work = require({json.dumps(str(MY_WORK))});
const now = new Date(2026, 7, 13, 12, 0, 0);
const built = work({{
user:{{login:'timmy'}}, notifications:[], pull_requests:[],
issues:[{{number:1,title:'Ship',repository:'o/r',labels:[],assignees:['timmy'],due_date:'2026-08-13T23:59:59Z'}}],
}}, now);
process.stdout.write(JSON.stringify({{
dueLabel:built[0].due_label,
agenda:work.agendaMyWork(built, now).map(item => [item.key, item.agenda_group]),
}}));
"""
environment = {**os.environ, "TZ": timezone_name}
result = subprocess.run(
["node", "-e", script], capture_output=True, text=True, env=environment
)
assert result.returncode == 0, result.stderr
assert json.loads(result.stdout) == {
"dueLabel": "Due today",
"agenda": [["o/r#1", "Today"]],
}
def test_agenda_pager_loads_every_issue_page_single_flight_and_retries_failed_page():
script = f"""
const work = require({json.dumps(str(MY_WORK))});