import json import subprocess from pathlib import Path import pytest from src.views import dashboard TODAY_WORK = Path(__file__).parents[1] / "frontend" / "today-work.js" def run_node(script): return subprocess.run( ["node", "-e", script], check=True, capture_output=True, text=True ).stdout def test_today_queue_is_account_scoped_ordered_unique_and_bounded(): script = f""" const createTodayWork = require({json.dumps(str(TODAY_WORK))}); const values = new Map(); const storage = {{ getItem: key => values.has(key) ? values.get(key) : null, setItem: (key, value) => values.set(key, value), removeItem: key => values.delete(key), }}; let login = 'timmy'; const queue = createTodayWork({{storage, getLogin: () => login, limit: 3}}); const issue = number => ({{kind:'issue', repository:'stackchain/dashboard', number, title:'Issue ' + number}}); const first = queue.add(issue(1)); const duplicate = queue.add(issue(1)); queue.add(issue(2)); queue.add(issue(3)); const full = queue.add(issue(4)); queue.move(issue(3), 'up'); queue.move(issue(3), 'up'); const timmy = queue.reconcile([issue(1), issue(2), issue(3), issue(4)]).map(item => item.number); const persisted = createTodayWork({{storage, getLogin: () => login, limit: 3}}) .reconcile([issue(1), issue(2), issue(3)]).map(item => item.number); login = 'alexander'; const isolated = queue.reconcile([issue(1), issue(2), issue(3)]).map(item => item.number); process.stdout.write(JSON.stringify({{first, duplicate, full, timmy, persisted, isolated}})); """ assert json.loads(run_node(script)) == { "first": "added", "duplicate": "exists", "full": "full", "timmy": [3, 1, 2], "persisted": [3, 1, 2], "isolated": [], } def test_today_queue_exposes_reorder_boundaries_for_touch_controls(): script = f""" const createTodayWork = require({json.dumps(str(TODAY_WORK))}); const values = new Map(); const storage = {{ getItem: key => values.get(key) || null, setItem: (key, value) => values.set(key, value), removeItem: key => values.delete(key), }}; const queue = createTodayWork({{storage, getLogin: () => 'timmy'}}); const item = number => ({{kind:'issue', repository:'stackchain/dashboard', number}}); queue.add(item(1)); queue.add(item(2)); queue.add(item(3)); process.stdout.write(JSON.stringify([ queue.position(item(1)), queue.position(item(2)), queue.position(item(3)), queue.position(item(9)) ])); """ assert json.loads(run_node(script)) == [ {"can_up": False, "can_down": True}, {"can_up": True, "can_down": True}, {"can_up": True, "can_down": False}, {"can_up": False, "can_down": False}, ] @pytest.mark.anyio async def test_dashboard_runs_the_curated_today_queue_as_a_mobile_work_flow(): html = await dashboard() assert '' in html assert 'data-work-filter="today"' in html assert 'data-work-count="today"' in html assert "const todayWork = createTodayWork({" in html assert "const filter = todayMyWork.length ? 'today' : (counts.attention ? 'attention' : 'all');" in html assert "selectedWorkFilter === 'today' ? todayMyWork : activeMyWork" in html assert 'data-today-add' in html assert 'data-today-remove' in html assert 'data-today-move="up"' in html 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