f34016a4a5
build / build (push) Successful in 58s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m4s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m53s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 38s
Testy / Kontrola składni wszystkich warstw (push) Successful in 25s
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>
89 lines
3.8 KiB
Python
89 lines
3.8 KiB
Python
"""Poprawki zgłoszone przez partnerów: offset względem GMT i lokalizacja po
|
|
kliknięciu „Tu i teraz" (PRE-19, PRE-20).
|
|
|
|
JS-a tu nie uruchomimy, więc pilnujemy tego strukturalnie — tak samo jak
|
|
niezmienników klienta HTTP. Obie regresje są ciche (nic się nie wywala, tylko
|
|
formularz pokazuje nieprawdę), więc test na źródle jest tu wart więcej niż zwykle.
|
|
"""
|
|
import pathlib
|
|
|
|
import pytest
|
|
|
|
APP = pathlib.Path(__file__).resolve().parents[1] / "app"
|
|
TEMPLATES = APP / "templates"
|
|
GEO_JS = APP / "static" / "geo.js"
|
|
|
|
WITH_OFFSET = ("chart.html", "interpret.html", "timeline.html")
|
|
|
|
|
|
# ───────────────────────────── PRE-19: offset względem GMT ───────────────
|
|
|
|
@pytest.mark.parametrize("name", WITH_OFFSET)
|
|
def test_offset_label_says_relative_to_gmt(name):
|
|
"""Etykieta musi mówić, WZGLĘDEM CZEGO liczymy przesunięcie."""
|
|
html = (TEMPLATES / name).read_text(encoding="utf-8")
|
|
assert "Offset względem GMT" in html, f"{name}: etykieta nie mówi o GMT"
|
|
|
|
|
|
@pytest.mark.parametrize("name", WITH_OFFSET)
|
|
def test_offset_step_is_quarter_hour(name):
|
|
"""Krok 15 minut = 0,25 h. Strefy pół- i ćwierćgodzinne (Indie +5:30,
|
|
Nepal +5:45) są realne — przy kroku 1 h nie dało się ich ustawić."""
|
|
html = (TEMPLATES / name).read_text(encoding="utf-8")
|
|
assert 'name="tz_offset" step="0.25"' in html, f"{name}: krok inny niż 15 minut"
|
|
|
|
|
|
@pytest.mark.parametrize("name", WITH_OFFSET)
|
|
def test_offset_range_covers_real_zones(name):
|
|
html = (TEMPLATES / name).read_text(encoding="utf-8")
|
|
assert 'min="-12"' in html and 'max="14"' in html, f"{name}: brak sensownego zakresu stref"
|
|
|
|
|
|
# ──────────────────── PRE-20: „Tu i teraz" odświeża nazwę miejsca ────────
|
|
|
|
def _geo_source() -> str:
|
|
return GEO_JS.read_text(encoding="utf-8")
|
|
|
|
|
|
def _handler_body() -> str:
|
|
"""Ciało handlera zdarzenia astrololo:coords (wysyłanego przez „Tu i teraz").
|
|
|
|
Szukamy KONKRETNIE `addEventListener`, nie samej nazwy zdarzenia — ta pada
|
|
także w komentarzu nagłówkowym pliku i wtedy wycięlibyśmy komentarz zamiast
|
|
kodu (test przechodziłby albo padał z niewłaściwego powodu).
|
|
"""
|
|
src = _geo_source()
|
|
start = src.index("addEventListener('astrololo:coords'")
|
|
end = src.index("});", start)
|
|
return src[start:end]
|
|
|
|
|
|
def test_now_button_handler_refreshes_place_name():
|
|
"""REGRESJA: po „Tu i teraz" pineska i współrzędne skakały na nowe miejsce,
|
|
a w polu tekstowym zostawała stara nazwa — formularz pokazywał jedno miejsce,
|
|
a liczył dla innego."""
|
|
assert "reverseName(" in _handler_body(), (
|
|
"handler astrololo:coords nie odświeża nazwy miejsca (reverseName)"
|
|
)
|
|
|
|
|
|
def test_reverse_name_clears_field_before_lookup():
|
|
"""Nazwa jest czyszczona ZANIM przyjdzie odpowiedź. Gdyby /reverse nie
|
|
odpowiedziało (brak sieci), zostałaby stara nazwa — czyli pole kłamałoby
|
|
o lokalizacji. Lepiej puste pole niż nieprawdziwe."""
|
|
src = _geo_source()
|
|
start = src.index("function reverseName")
|
|
body = src[start:src.index("\n }", start)]
|
|
# sposób zapisu może się zmienić (bezpośrednie .value albo setVal, które
|
|
# dodatkowo zgłasza `change`) — pilnujemy KOLEJNOŚCI, nie składni
|
|
clear_at = max(body.find("searchEl.value = ''"), body.find("setVal(searchEl, '')"))
|
|
fetch_at = body.find("fetch(")
|
|
assert clear_at != -1, "reverseName nie czyści pola nazwy"
|
|
assert clear_at < fetch_at, "pole czyszczone dopiero po zapytaniu — stara nazwa zdąży zostać"
|
|
|
|
|
|
def test_now_button_still_syncs_map():
|
|
"""Odświeżenie nazwy nie może zastąpić przesunięcia pineski i widoku mapy."""
|
|
body = _handler_body()
|
|
assert "marker.setLatLng" in body and "map.setView" in body
|