from app.layouts import load_layout, validate_layout def _layout(page, main_components, sidebar=None): return { "schemaVersion": 1, "page": page, "regions": { "sidebar": sidebar or ([{"component": "task-list"}] if page == "task-detail" else []), "main": main_components, }, } def test_valid_home_layout(): assert validate_layout(_layout("home", [{"component": "overview-summary"}, {"component": "task-progress-grid"}]), "home") def test_valid_task_detail_layout(): assert validate_layout(_layout("task-detail", [{"component": "task-header"}, {"component": "today-record"}, {"component": "metric-progress"}, {"component": "activity-heatmap"}, {"component": "task-settings"}]), "task-detail") def test_rejects_component_on_wrong_page(): assert not validate_layout(_layout("home", [{"component": "today-record"}]), "home") def test_rejects_component_in_wrong_region(): layout = _layout("task-detail", [{"component": "task-header"}], sidebar=[{"component": "task-header"}]) assert not validate_layout(layout, "task-detail") def test_rejects_duplicate_component(): layout = _layout("task-detail", [{"component": "today-record"}, {"component": "today-record"}]) assert not validate_layout(layout, "task-detail") def test_load_layout_falls_back_on_invalid(tmp_path): import json bad = tmp_path / "home.json" bad.write_text(json.dumps(_layout("home", [{"component": "today-record"}])), encoding="utf-8") loaded = load_layout(tmp_path, "home") assert loaded["regions"]["main"] != [{"component": "today-record"}]