feat(prezentacja): zakladka „Skompiluj" — zbiorczy raport (PRE-23)
build / build (push) Successful in 52s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m16s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m57s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 32s
Testy / Kontrola składni wszystkich warstw (push) Failing after 8s
build / build (push) Successful in 52s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m16s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m57s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 32s
Testy / Kontrola składni wszystkich warstw (push) Failing after 8s
Czwarta wskazowka partnerow. Nowa zakladka sklada w jedno trzy kawalki liczone w roznych miejscach: policzony horoskop, interpretacje natalna z AI i wszystkie zapamietane predykcje okresowe. Uklad sekcji dokladnie wg prosby: imie i nazwisko -> wprowadzone dane -> RYSUNEK kosmogramu -> interpretacja natalna -> predykcje okresowe. Test pilnuje tej kolejnosci, bo to jedyna rzecz, ktora latwo przestawic przy refaktorze, a partnerzy podali ja wprost. Skad material: - HOROSKOP liczymy TU NA NOWO z danych formularza, zamiast go zapamietywac. To czysta funkcja wejscia — tanio powtorzyc, a odpada trzymanie w przegladarce duzego wyniku, ktory moglby sie rozjechac z aktualnym formularzem. - INTERPRETACJA NATALNA — nowy natal.js, odpowiednik predictions.js. Natalna jest JEDNA (dotyczy momentu urodzenia, nie okresu), wiec ponowne wygenerowanie podmienia slot zamiast dokladac wpis. - PREDYKCJE — z magazynu z PRE-22. compile.js czyta magazyny przez ICH API (window.astrololoNatal / astrololoPredictions), a nie siegajac wprost do localStorage — format danych ma jednego wlasciciela: modul, ktory je zapisuje. Test tego pilnuje. Zakladka MOWI, CZEGO BRAKUJE: panel gotowosci z trzema pozycjami i podpowiedzia, na ktorej zakladce uzupelnic. Bez tego uzytkownik zlozylby niekompletny raport i dowiedzialby sie o tym dopiero po otwarciu PDF-a. Tresc od modelu jest ESKEJPOWANA przed wstawieniem do DOM — to tekst z zewnatrz, wiec bez tego mielibysmy wektor wstrzykniecia. Weryfikacja na zywej aplikacji: dwie predykcje zapisane w Kalendarzu, natalna w Interpretacjach, obie odczytane na Skompiluj (panel: brak horoskopu na zolto, dwa pozostale na zielono). Po zlozeniu wszystkie trzy zielone, a raport zaczyna sie od „Jan Kowalski" i danych wejsciowych. Kolejnosc sekcji sprawdzona na wyrenderowanym HTML: naglowek 2931 < dane 3033 < kosmogram 3158 < natalna 26544 < predykcje 26575. Testy: 16 nowych. Poprawione tez trzy wlasne testy, ktore lapaly nazwy plikow w KOMENTARZACH zamiast w tagach skryptow. Calosc: prezentacja 117 passed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit was merged in pull request #31.
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
"""Zakładka „Skompiluj" — zbiorczy raport (PRE-23).
|
||||
|
||||
Raport składa się z trzech kawałków liczonych w różnych miejscach: horoskopu
|
||||
(serwer), interpretacji natalnej i predykcji okresowych (magazyn przeglądarki).
|
||||
Pilnujemy, żeby zakładka umiała je zebrać, a przede wszystkim — żeby POWIEDZIAŁA,
|
||||
czego brakuje. Niekompletny raport, o którym dowiadujesz się dopiero z PDF-a,
|
||||
byłby najgorszym wynikiem.
|
||||
"""
|
||||
import pathlib
|
||||
|
||||
from starlette.testclient import TestClient
|
||||
|
||||
APP = pathlib.Path(__file__).resolve().parents[1] / "app"
|
||||
TPL = (APP / "templates" / "compile.html").read_text(encoding="utf-8")
|
||||
BASE = (APP / "templates" / "base.html").read_text(encoding="utf-8")
|
||||
JS = (APP / "static" / "compile.js").read_text(encoding="utf-8")
|
||||
NATAL_JS = (APP / "static" / "natal.js").read_text(encoding="utf-8")
|
||||
INTERPRET = (APP / "templates" / "interpret.html").read_text(encoding="utf-8")
|
||||
MAIN = (APP / "main.py").read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def _client():
|
||||
import os
|
||||
|
||||
os.environ.pop("APP_PASSWORD", None) # bez bramki logowania w teście
|
||||
from app.main import app
|
||||
|
||||
return TestClient(app)
|
||||
|
||||
|
||||
# ───────────────────────────────── nawigacja i trasa ─────────────────────
|
||||
|
||||
def test_tab_is_in_the_menu():
|
||||
assert 'href="/compile"' in BASE and "Skompiluj" in BASE
|
||||
|
||||
|
||||
def test_get_renders_empty_form():
|
||||
r = _client().get("/compile")
|
||||
assert r.status_code == 200
|
||||
assert "Złóż podsumowanie" in r.text
|
||||
|
||||
|
||||
def test_routes_exist():
|
||||
assert '@app.get("/compile"' in MAIN and '@app.post("/compile"' in MAIN
|
||||
|
||||
|
||||
# ─────────────────────────── kolejność w raporcie ────────────────────────
|
||||
|
||||
def test_report_order_matches_the_brief():
|
||||
"""Prośba partnerów: najpierw imię i nazwisko, potem wprowadzone dane, potem
|
||||
RYSUNEK kosmogramu, a dopiero po nim interpretacja natalna i predykcje."""
|
||||
person = TPL.index('id="reportPerson"')
|
||||
wheel = TPL.index("wheel_svg")
|
||||
natal = TPL.index('id="reportNatal"')
|
||||
preds = TPL.index('id="reportPredictions"')
|
||||
assert person < wheel < natal < preds
|
||||
|
||||
|
||||
def test_person_name_heads_the_report():
|
||||
assert 'id="reportPerson"' in TPL
|
||||
assert "form.person" in TPL
|
||||
|
||||
|
||||
# ──────────────────────── zbieranie materiału z magazynów ────────────────
|
||||
|
||||
def test_reads_stores_through_their_api_not_raw_storage():
|
||||
"""Format danych ma jednego właściciela — moduł, który je zapisuje.
|
||||
Sięganie tu wprost do localStorage rozjechałoby się przy pierwszej zmianie."""
|
||||
assert "window.astrololoNatal" in JS
|
||||
assert "window.astrololoPredictions" in JS
|
||||
# chodzi o brak BEZPOŚREDNIEGO dostępu, nie o samo słowo (pada w komentarzu)
|
||||
assert "localStorage.getItem" not in JS
|
||||
assert "localStorage.setItem" not in JS
|
||||
|
||||
|
||||
def test_stores_are_loaded_on_the_tab():
|
||||
for src in ("natal.js", "predictions.js", "compile.js"):
|
||||
assert src in TPL, f"brak {src} na zakładce"
|
||||
|
||||
|
||||
def test_stores_load_before_the_assembler():
|
||||
"""Szukamy TAGÓW skryptów, nie samych nazw — te padają też w komentarzach."""
|
||||
def tag(name):
|
||||
return TPL.index('src="/static/' + name + '"')
|
||||
|
||||
assert tag("natal.js") < tag("compile.js")
|
||||
assert tag("predictions.js") < tag("compile.js")
|
||||
|
||||
|
||||
# ─────────────────────────── mówi, czego brakuje ─────────────────────────
|
||||
|
||||
def test_shows_what_is_missing():
|
||||
assert 'id="readiness"' in TPL
|
||||
assert "rdy-missing" in JS
|
||||
for hint in ("Interpretacje", "Kalendarz"):
|
||||
assert hint in JS, f"brak podpowiedzi, gdzie uzupełnić: {hint}"
|
||||
|
||||
|
||||
def test_all_three_parts_are_checked():
|
||||
for label in ("Policzony horoskop", "Interpretacja natalna", "Predykcje okresowe"):
|
||||
assert label in JS
|
||||
|
||||
|
||||
# ───────────────────────────── natalna zapamiętywana ─────────────────────
|
||||
|
||||
def test_natal_is_captured_on_interpret_tab():
|
||||
assert "natal.js" in INTERPRET
|
||||
assert 'id="natalNote"' in INTERPRET
|
||||
|
||||
|
||||
def test_natal_store_keeps_a_single_entry():
|
||||
"""Natalna jest JEDNA — dotyczy momentu urodzenia, nie okresu. Ponowne
|
||||
wygenerowanie ma podmienić, nie dokładać."""
|
||||
assert "setItem" in NATAL_JS and "push" not in NATAL_JS
|
||||
|
||||
|
||||
def test_natal_only_stores_natal_profile():
|
||||
assert "'natal'" in NATAL_JS
|
||||
|
||||
|
||||
def test_full_storage_is_reported():
|
||||
assert "pełny" in NATAL_JS
|
||||
|
||||
|
||||
# ─────────────────────────────── bezpieczeństwo ──────────────────────────
|
||||
|
||||
def test_ai_text_is_escaped_before_injection():
|
||||
"""Treść od modelu wstawiamy do DOM — bez ucieczki byłby to wektor wstrzyknięcia."""
|
||||
assert "function esc" in JS
|
||||
assert "replace(/</g, '<')" in JS
|
||||
|
||||
|
||||
def test_does_nothing_on_other_tabs():
|
||||
assert "if (!document.getElementById('readiness')) return;" in JS
|
||||
Reference in New Issue
Block a user