stackchain-dashboard/tests/test_mobile_start_day.py
timmy d4aafbf351
All checks were successful
CI / lint (pull_request) Successful in 1m54s
CI / build-release (pull_request) Successful in 5s
CI / browser-journey (pull_request) Successful in 57s
CI / release-candidate (pull_request) Has been skipped
feat: guide mobile start-day review (Closes #897)
2026-08-15 14:31:37 +00:00

130 lines
4.6 KiB
Python

import json
import subprocess
from pathlib import Path
import pytest
from tests.dashboard_bundle import dashboard
START_DAY = Path(__file__).resolve().parents[1] / "frontend" / "mobile-start-day.js"
def run_node(script: str) -> dict:
result = subprocess.run(["node", "-e", script], capture_output=True, text=True)
assert result.returncode == 0, result.stderr
return json.loads(result.stdout)
def test_start_day_briefing_guides_urgent_review_before_today():
script = f"""
const createStartDay = require({json.dumps(str(START_DAY))});
let counts = {{agenda:2, attention:3, update:4, filed:1, today:5}};
const opened = [];
const controller = createStartDay({{
getCounts: () => counts,
openQueue: name => opened.push(name),
}});
const first = controller.briefing();
controller.startNext();
counts = {{agenda:0, attention:3, update:4, filed:1, today:5}};
const second = controller.briefing();
controller.startNext();
counts = {{agenda:0, attention:0, update:0, filed:0, today:5}};
const ready = controller.briefing();
controller.startNext();
process.stdout.write(JSON.stringify({{first, second, ready, opened}}));
"""
result = run_node(script)
assert result == {
"first": {
"total": 10,
"next": "agenda",
"label": "Review Agenda",
"summary": "10 items before Today · 5 planned",
"phases": [
{"name": "agenda", "label": "Agenda", "count": 2},
{"name": "attention", "label": "Attention", "count": 3},
{"name": "update", "label": "Updates", "count": 4},
{"name": "filed", "label": "Filed", "count": 1},
],
},
"second": {
"total": 8,
"next": "attention",
"label": "Review Attention",
"summary": "8 items before Today · 5 planned",
"phases": [
{"name": "attention", "label": "Attention", "count": 3},
{"name": "update", "label": "Updates", "count": 4},
{"name": "filed", "label": "Filed", "count": 1},
],
},
"ready": {
"total": 0,
"next": "today",
"label": "Continue Today",
"summary": "Review clear · 5 planned",
"phases": [],
},
"opened": ["agenda", "attention", "today"],
}
def test_start_day_view_renders_refreshed_phases_and_launches_primary_action():
script = f"""
const createStartDay = require({json.dumps(str(START_DAY))});
const elements = {{
summary: {{textContent:''}},
phases: {{textContent:''}},
action: {{textContent:'', listeners:{{}}, addEventListener(name, fn) {{ this.listeners[name] = fn; }}}},
}};
const opened = [];
let counts = {{agenda:0, attention:2, update:1, filed:0, today:3}};
const controller = createStartDay({{
getCounts: () => counts,
openQueue: name => opened.push(name),
elements,
}});
controller.start();
const first = {{summary:elements.summary.textContent, phases:elements.phases.textContent, action:elements.action.textContent}};
elements.action.listeners.click();
counts = {{agenda:0, attention:0, update:0, filed:0, today:3}};
controller.render();
const ready = {{summary:elements.summary.textContent, phases:elements.phases.textContent, action:elements.action.textContent}};
process.stdout.write(JSON.stringify({{first, ready, opened}}));
"""
assert run_node(script) == {
"first": {
"summary": "3 items before Today · 3 planned",
"phases": "Attention 2 · Updates 1",
"action": "Review Attention",
},
"ready": {
"summary": "Review clear · 3 planned",
"phases": "All urgent queues reviewed",
"action": "Continue Today",
},
"opened": ["attention"],
}
@pytest.mark.anyio
async def test_dashboard_wires_thumb_safe_start_day_briefing_into_offline_mobile_bundle():
html = await dashboard()
service_worker = (START_DAY.parent / "service-worker.js").read_text()
assert 'class="mobile-start-day"' in html
assert 'id="mobile-start-day-summary"' in html
assert 'id="mobile-start-day-phases"' in html
assert 'id="mobile-start-day-action"' in html
assert '<script src="static/mobile-start-day.js"></script>' in html
assert "const mobileStartDay = createMobileStartDay({" in html
assert "openQueue: name => name === 'find'" in html
assert "mobileStartDay.render();" in html
assert ".mobile-start-day-action { width:100%; min-height:48px;" in html
assert "max-width:100%; overflow-wrap:anywhere;" in html
assert "BASE + 'static/mobile-start-day.js'" in service_worker