from __future__ import annotations import importlib.util import json import os import uuid from pathlib import Path def load_module(module_path: Path, data_dir: Path, plans_dir: Path): try: import flask # noqa: F401 except ModuleNotFoundError: import pytest pytest.skip("Flask ist in dieser isolierten Testumgebung nicht installiert") os.environ["TRAININGSTRACKER_DATA_DIR"] = str(data_dir) os.environ["TRAININGSTRACKER_PLANS_DIR"] = str(plans_dir) name = f"tracker_test_app_{uuid.uuid4().hex}" spec = importlib.util.spec_from_file_location(name, module_path) module = importlib.util.module_from_spec(spec) assert spec.loader spec.loader.exec_module(module) return module def sample_plan() -> dict: return { "name": "Testplan", "revision": 4, "published_revision": 4, "config": { "schema_version": 5, "contract_version": 4, "plan_id": "testplan", "meta": {"title": "Testplan"}, "exercises": [ { "id": "exercise-push", "name": "Push-up-Progression", "progressions": [ {"id": "progression-high-plank", "name": "High Plank"}, {"id": "progression-negative", "name": "Negative"}, ], "current_progression_id": "progression-high-plank", } ], "days": [ { "id": "day-1", "num": 1, "name": "Tag 1", "warmup": {"items": ["Mobilisieren"]}, "cooldown": {"items": ["Atmen"]}, "exercises": [{"id": "item-1", "exercise_id": "exercise-push"}], } ], }, "draft": { "schema_version": 5, "contract_version": 4, "plan_id": "testplan", "meta": {"title": "Testplan"}, "exercises": [ { "id": "exercise-push", "name": "Push-up-Progression", "progressions": [ {"id": "progression-high-plank", "name": "High Plank"}, {"id": "progression-negative", "name": "Negative"}, ], "current_progression_id": "progression-high-plank", } ], "days": [ { "id": "day-1", "num": 1, "name": "Tag 1", "warmup": {"items": ["Mobilisieren"]}, "cooldown": {"items": ["Atmen"]}, "exercises": [{"id": "item-1", "exercise_id": "exercise-push"}], } ], }, } def test_lists_only_training_plans_and_returns_slim_detail(tmp_path: Path): plans = tmp_path / "data" / "trainingsplan" / "plans" data_dir = tmp_path / "data" / "trainingstracker" plans.mkdir(parents=True) (plans / "training.json").write_text(json.dumps(sample_plan()), encoding="utf-8") (plans / "food.json").write_text(json.dumps({"name": "Essen", "config": {"type": "recipe", "days": []}}), encoding="utf-8") module = load_module(Path(__file__).parents[1] / "app.py", data_dir, plans) client = module.app.test_client() listed = client.get("/api/plans").get_json() assert [item["id"] for item in listed["plans"]] == ["training.json"] detail = client.get("/api/plans/training.json").get_json() cfg = detail["plan"]["config"] assert cfg["schema_version"] == 5 assert cfg["contract_version"] == 4 assert cfg["days"][0]["exercises"][0]["exercise"]["current_progression"]["name"] == "High Plank" def test_current_progression_update_writes_config_and_draft(tmp_path: Path): plans = tmp_path / "data" / "trainingsplan" / "plans" data_dir = tmp_path / "data" / "trainingstracker" plans.mkdir(parents=True) plan_file = plans / "training.json" plan_file.write_text(json.dumps(sample_plan()), encoding="utf-8") module = load_module(Path(__file__).parents[1] / "app.py", data_dir, plans) client = module.app.test_client() response = client.patch( "/api/plans/training.json/exercises/exercise-push/current", json={"current_progression_id": "progression-negative"}, ) assert response.status_code == 200 payload = response.get_json() exercise = payload["plan"]["config"]["exercises"][0] assert exercise["current_progression_id"] == "progression-negative" saved = json.loads(plan_file.read_text(encoding="utf-8")) assert saved["config"]["exercises"][0]["current_progression_id"] == "progression-negative" assert saved["draft"]["exercises"][0]["current_progression_id"] == "progression-negative" assert saved["revision"] == 5 assert saved["published_revision"] == 5 def test_frontend_no_longer_contains_session_or_analysis_surfaces(): source = (Path(__file__).parents[1] / "static" / "index.html").read_text(encoding="utf-8") assert "data-current-progression" in source assert "analysis/status" not in source assert "sessionView" not in source assert "week" not in source.lower() def test_frontend_embeds_plugin_mount_path(tmp_path: Path): plans = tmp_path / "data" / "trainingsplan" / "plans" data_dir = tmp_path / "data" / "trainingstracker" plans.mkdir(parents=True) (plans / "training.json").write_text(json.dumps(sample_plan()), encoding="utf-8") module = load_module(Path(__file__).parents[1] / "app.py", data_dir, plans) client = module.app.test_client() html = client.get("/", environ_overrides={"SCRIPT_NAME": "/plugins/trainingstracker"}).get_data(as_text=True) assert 'data-base="/plugins/trainingstracker"' in html