"""Zapamiętane predykcje okresowe (PRE-22). Magazyn żyje w JS (localStorage), więc znów pilnujemy go strukturalnie. Sedno: predykcje mają PRZEŻYĆ przejście na inną zakładkę i trafić do raportu, a lista nie może puchnąć od powtórzonych prób na tym samym okresie. """ import pathlib APP = pathlib.Path(__file__).resolve().parents[1] / "app" JS = (APP / "static" / "predictions.js").read_text(encoding="utf-8") PROGRESS = (APP / "static" / "progress.js").read_text(encoding="utf-8") TIMELINE = (APP / "templates" / "timeline.html").read_text(encoding="utf-8") # ─────────────────────────────── podpięcie ─────────────────────────────── def test_script_loaded_on_calendar_tab(): assert "predictions.js" in TIMELINE def test_loaded_after_progress_script(): """Nasłuchuje zdarzenia, które wysyła progress.js — musi być załadowany po nim, inaczej przegapi pierwsze wywołanie.""" assert TIMELINE.index("progress.js") < TIMELINE.index("predictions.js") def test_calendar_has_container_for_the_list(): assert 'id="savedPredictions"' in TIMELINE def test_progress_announces_finished_horoscope(): """Okno postępu ogłasza gotowy horoskop zdarzeniem, zamiast samo go zapisywać — to okno postępu, a nie magazyn.""" assert "astrololo:horoscope" in PROGRESS assert "profile" in PROGRESS.split("astrololo:horoscope")[1][:200] # ─────────────────────────────── zachowanie ────────────────────────────── def test_only_period_horoscopes_are_stored(): """Interpretacja natalna ma NIE trafiać na listę predykcji okresowych.""" assert "'period'" in JS def test_same_period_replaces_instead_of_duplicating(): """Ponowne policzenie tego samego zakresu podmienia wpis. Inaczej lista puchłaby przy każdej próbie z innym modelem.""" assert "function upsert" in JS assert "p.from_date === entry.from_date" in JS assert "p.to_date === entry.to_date" in JS def test_entry_carries_period_and_text(): for field in ("from_date", "to_date", "text", "saved_at"): assert field in JS, f"wpis nie niesie pola {field}" def test_incomplete_result_is_not_stored(): """Bez tekstu albo bez dat nie ma czego zapamiętać — nie zapisujemy śmieci.""" assert "if (!text || !from || !to) return null;" in JS def test_list_can_be_pruned(): assert "function remove" in JS assert "data-drop" in JS def test_full_storage_is_reported_not_swallowed(): """Horoskopy bywają długie. Gdy magazyn się przepełni, użytkownik musi się o tym dowiedzieć, zamiast po cichu stracić wynik.""" assert "pełny" in JS or "pelny" in JS assert "return false;" in JS def test_corrupt_storage_does_not_break_the_page(): assert "catch" in JS and "Array.isArray" in JS def test_storage_is_exposed_for_the_compile_tab(): """Zakładka „Skompiluj" (PRE-23) ma czytać to samo miejsce — jedno źródło prawdy.""" assert "window.astrololoPredictions" in JS def test_does_nothing_on_other_tabs(): assert "if (!document.getElementById('savedPredictions')) return;" in JS def test_reload_does_not_duplicate(): """Wariant bez strumienia zapisuje przy wczytaniu strony — klucz to okres, więc odświeżenie nie mnoży wpisów.""" assert "id: from + '..' + to" in JS