"""Porównanie systemów domów naraz (PRE-05). JS-a tu nie ma — sprawdzamy strukturalnie: formularz pozwala zaznaczyć kilka systemów, klient przekazuje je do logiki, a szablon pokazuje kuspy obok siebie. """ import pathlib APP = pathlib.Path(__file__).resolve().parents[1] / "app" CHART = (APP / "templates" / "chart.html").read_text(encoding="utf-8") COMPILE = (APP / "templates" / "compile.html").read_text(encoding="utf-8") OPTS = (APP / "templates" / "_form_options.html").read_text(encoding="utf-8") # wspólne opcje TABLES = (APP / "templates" / "_result_tables.html").read_text(encoding="utf-8") # wspólne tabele MAIN = (APP / "main.py").read_text(encoding="utf-8") from app.house_systems import HOUSE_SYSTEMS, LIMITED, label as house_label # noqa: E402 CLIENT = (APP / "clients" / "logic_client.py").read_text(encoding="utf-8") def test_both_forms_use_shared_option_partial(): """Opcje w jednym pliku — oba formularze go dołączają (koniec duplikacji).""" assert '{% include "_form_options.html" %}' in CHART assert '{% include "_form_options.html" %}' in COMPILE def _render(name: str, **ctx) -> str: """Renderuje szablon z tymi samymi globalsami, co produkcja. Szablony budują listę systemów PĘTLĄ po katalogu, więc sprawdzanie ich surowego tekstu nic już nie mówi — trzeba je wykonać. Przy okazji test łapie literówki w Jinja, których grep po źródle nigdy nie wyłapał.""" from jinja2 import Environment, FileSystemLoader env = Environment(loader=FileSystemLoader(str(APP / "templates")), autoescape=True) env.globals.update(HOUSE_SYSTEMS=HOUSE_SYSTEMS, HOUSE_LIMITED=LIMITED, house_label=house_label, static=lambda p: p) return env.get_template(name).render(**ctx) def test_form_offers_every_system_the_engine_advertises(): """Każdy system z katalogu ma checkbox. Katalog jest jednym źródłem nazw, więc dopisanie systemu bez odświeżenia UI zapali się tutaj.""" html = _render("_form_options.html", form={}) for value, name in HOUSE_SYSTEMS: assert f'name="house_systems" value="{value}"' in html, f"brak checkboxa {value}" assert name in html, f"brak nazwy {name}" def test_form_marks_systems_with_a_domain_limit(): """Placidus i Koch nie istnieją za kołem podbiegunowym — UI ma uprzedzać ZANIM ktoś policzy horoskop dla Tromsø, nie dopiero w ostrzeżeniu wyniku.""" html = _render("_form_options.html", form={}) assert LIMITED, "katalog nie oznacza żadnego systemu jako ograniczonego" for value, name in HOUSE_SYSTEMS: starred = f"{name} *" in html assert starred == (value in LIMITED), f"{value}: gwiazdka={starred}" def test_handler_accepts_and_passes_house_systems(): assert "house_systems: list[str] = Form([])" in MAIN assert "house_systems=house_systems" in MAIN # przekazane do logiki def test_client_forwards_house_systems_to_logic(): assert '"house_systems": house_systems' in CLIENT def test_comparison_table_renders_only_for_multiple_systems(): """Bez dodatkowych systemów nie pokazujemy pustej tabeli porównania.""" assert "result.house_systems | length > 1" in TABLES assert "Porównanie systemów domów" in TABLES def test_comparison_table_shows_cusp_per_system(): """Tabela iteruje po systemach i po 12 domach — kusp w każdej komórce.""" assert "for hs in result.house_systems" in TABLES assert "hs.cusps[i].in_sign" in TABLES def test_checkbox_state_survives_submit(): """Zaznaczone systemy zostają zaznaczone po przeliczeniu.""" html = _render("_form_options.html", form={"house_systems": ["koch", "campanus"]}) for value, _ in HOUSE_SYSTEMS: marker = f'value="{value}" checked' assert (marker in html) == (value in ("koch", "campanus")), value def test_fallback_notice_is_shown_prominently(): """Po fallbacku kosmogram wygląda bezbłędnie — ostrzeżenie jest jedynym sygnałem, że podział domów jest z innego systemu.""" html = _render("_result_tables.html", result={"house_warnings": ["UWAGA: system domów nie ma definicji"]}) assert "house-warning" in html assert "UWAGA: system domów nie ma definicji" in html def test_no_notice_when_nothing_was_substituted(): html = _render("_result_tables.html", result={"house_warnings": []}) assert "house-warning" not in html