a20047ff59
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m8s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m47s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 33s
Testy / Kontrola składni wszystkich warstw (push) Successful in 26s
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 11m6s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m49s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 38s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 23s
Trzecia wskazowka partnerow. Kazda zakladke (Horoskop / Interpretacje / Kalendarz) wypelnialo sie od nowa — te same imie, data, godzina, strefa i miejsce. Teraz raz wpisane dane wedruja za uzytkownikiem, a zmiana w jednej zakladce przenosi sie na pozostale. Nowy formsync.js trzyma stan w localStorage. Dlaczego nie sesja na serwerze: serwer zostaje BEZSTANOWY — zadnego magazynu sesji, zadnych danych urodzeniowych trzymanych po stronie uslugi (spojne z postawa z LOG-32/PRE-16). Przy okazji dane synchronizuja sie tez miedzy osobnymi kartami przegladarki, bo zdarzenie `storage` daje to za darmo. Dolozone pole „imie i nazwisko" (wszystkie trzy zakladki) — potrzebne do naglowka raportu PDF (PRE-24). Handlery przyjmuja je i oddaja, wiec nie znika po przeliczeniu. Dwie rzeczy, ktore trzeba bylo domknac, zeby to dzialalo naprawde: 1. KOLEJNOSC SKRYPTOW. formsync.js ladowany w <head> z `defer` — skrypty defer wykonuja sie w kolejnosci dokumentu, wiec ten zdazy odtworzyc wspolrzedne, ZANIM geo.js zbuduje mape. Mapa startuje od razu we wlasciwym miejscu, zamiast przeskakiwac po chwili. 2. geo.js ustawia pola z KODU (`.value = ...`), co samo z siebie NIE wywoluje zdarzen — bez tego synchronizacja przegapilaby kazdy wybor z mapy, z wyszukiwarki i z „Tu i teraz". Dolozony setVal(), ktory jawnie zglasza `change`. Zakladka bez danego pola (np. Sygnifikatory) nie kasuje wartosci zapamietanej gdzie indziej; uszkodzony wpis w localStorage nie blokuje formularza. Q-14 rozstrzygniete: lancuch LaTeX->PDF stanie jako OSOBNA USLUGA render — spojne z izolacja swisseph (LOG-27), obraz produktu zostaje maly. Weryfikacja na zywym stacku (data+logika+prezentacja) w przegladarce: dane wpisane w Horoskopie pojawily sie w Interpretacjach; zmiana godziny w Interpretacjach dotarla do Kalendarza; pola nieobecne na zakladce (zodiak, system domow) przetrwaly; po POST imie zostalo, a horoskop policzyl sie normalnie. Testy: 22 nowe strukturalne. Calosc: prezentacja 67 passed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
94 lines
4.0 KiB
Python
94 lines
4.0 KiB
Python
"""Wspólne dane formularza między zakładkami + pole imienia (PRE-21).
|
|
|
|
Znów test strukturalny na źródle: synchronizacja żyje w JS, a jej awaria jest
|
|
CICHA — formularz po prostu przestaje pamiętać dane i użytkownik wpisuje je od
|
|
nowa. Pilnujemy więc reguł, które łatwo zgubić przy kolejnych zmianach.
|
|
"""
|
|
import pathlib
|
|
|
|
import pytest
|
|
|
|
APP = pathlib.Path(__file__).resolve().parents[1] / "app"
|
|
TEMPLATES = APP / "templates"
|
|
SYNC_JS = (APP / "static" / "formsync.js").read_text(encoding="utf-8")
|
|
GEO_JS = (APP / "static" / "geo.js").read_text(encoding="utf-8")
|
|
BASE_HTML = (TEMPLATES / "base.html").read_text(encoding="utf-8")
|
|
MAIN_PY = (APP / "main.py").read_text(encoding="utf-8")
|
|
|
|
WITH_FORM = ("chart.html", "interpret.html", "timeline.html")
|
|
|
|
# Pola, które mają wędrować między zakładkami. Gdy dojdzie nowe wspólne pole,
|
|
# ten wykaz ma się nie rozjechać z formsync.js.
|
|
SHARED = ("person", "date", "time", "tz_offset", "lat", "lon",
|
|
"house_system", "zodiac", "place")
|
|
|
|
|
|
# ─────────────────────────────── pole imienia ────────────────────────────
|
|
|
|
@pytest.mark.parametrize("name", WITH_FORM)
|
|
def test_person_field_present_on_every_form(name):
|
|
"""Imię i nazwisko trafia do nagłówka raportu PDF (PRE-24) — musi dać się
|
|
je wpisać z każdej zakładki, bo dane są wspólne."""
|
|
html = (TEMPLATES / name).read_text(encoding="utf-8")
|
|
assert 'name="person"' in html, f"{name}: brak pola imienia"
|
|
|
|
|
|
@pytest.mark.parametrize("name", WITH_FORM)
|
|
def test_person_value_survives_submit(name):
|
|
"""Po wysłaniu formularza pole ma pokazywać to, co wpisano — inaczej znikałoby
|
|
przy każdym przeliczeniu."""
|
|
html = (TEMPLATES / name).read_text(encoding="utf-8")
|
|
assert "form.person" in html, f"{name}: wartość imienia nie wraca po POST"
|
|
|
|
|
|
def test_handlers_accept_and_echo_person():
|
|
"""Trzy handlery renderujące formularz przyjmują `person` i wkładają go
|
|
z powrotem do `form`."""
|
|
assert MAIN_PY.count("person: str = Form") == 3
|
|
assert MAIN_PY.count('"person": person') == 3
|
|
|
|
|
|
# ─────────────────────── synchronizacja między zakładkami ────────────────
|
|
|
|
@pytest.mark.parametrize("key", SHARED)
|
|
def test_every_shared_field_is_synced(key):
|
|
assert f"'{key}'" in SYNC_JS, f"pole {key} nie jest synchronizowane"
|
|
|
|
|
|
def test_sync_script_loaded_before_map_script():
|
|
"""KOLEJNOŚĆ MA ZNACZENIE: formsync w <head> z `defer` wykonuje się przed
|
|
geo.js (skrypty defer idą w kolejności dokumentu), więc mapa startuje już
|
|
z odtworzonymi współrzędnymi zamiast skakać po chwili."""
|
|
assert "formsync.js" in BASE_HTML, "formsync.js nie jest ładowany globalnie"
|
|
assert "defer" in BASE_HTML.split("formsync.js")[0].rsplit("<script", 1)[-1] + "defer"
|
|
|
|
|
|
def test_sync_reacts_to_other_browser_tab():
|
|
"""Zmiana w drugiej otwartej karcie ma dociągnąć się tutaj (zdarzenie storage)."""
|
|
assert "'storage'" in SYNC_JS
|
|
|
|
|
|
def test_sync_persists_on_submit():
|
|
assert "'submit'" in SYNC_JS
|
|
|
|
|
|
def test_corrupt_storage_does_not_break_the_page():
|
|
"""Uszkodzony wpis w localStorage nie może zablokować formularza."""
|
|
assert "catch" in SYNC_JS and "JSON.parse" in SYNC_JS
|
|
|
|
|
|
def test_map_changes_are_reported_to_sync():
|
|
"""geo.js ustawia pola z KODU (`.value = ...`), co samo z siebie nie wywołuje
|
|
zdarzeń — bez jawnego `change` synchronizacja przegapiłaby wybór z mapy."""
|
|
assert "function setVal" in GEO_JS
|
|
assert "dispatchEvent(new Event('change'" in GEO_JS
|
|
# wszystkie miejsca ustawiające pola idą przez setVal
|
|
assert "latEl.value =" not in GEO_JS.replace("el.value = value", "")
|
|
assert "searchEl.value = d.name" not in GEO_JS
|
|
|
|
|
|
def test_sync_does_not_wipe_fields_missing_on_a_tab():
|
|
"""Zakładka bez danego pola (np. Sygnifikatory) nie może wyczyścić wartości
|
|
zapamiętanej z innej zakładki."""
|
|
assert "if (!el) return;" in SYNC_JS
|